5
// Eric Maupin <ermau@xamarin.com>
7
// Copyright (c) 2012 Xamarin, Inc.
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
using System.Collections.Generic;
30
using System.Windows.Data;
31
using System.Windows.Documents;
32
using System.Windows.Markup;
33
using System.Windows.Media;
34
using System.Windows.Shapes;
37
using Xwt.WPFBackend.Utilities;
39
using SWC=System.Windows.Controls;
40
using System.Windows.Controls;
42
namespace Xwt.WPFBackend
44
public class TreeViewBackend
45
: WidgetBackend, ITreeViewBackend
47
private static readonly ResourceDictionary TreeResourceDictionary;
48
static TreeViewBackend()
50
Uri uri = new Uri ("pack://application:,,,/Xwt.WPF;component/XWT.WPFBackend/TreeView.xaml");
51
TreeResourceDictionary = (ResourceDictionary)XamlReader.Load (System.Windows.Application.GetResourceStream (uri).Stream);
54
public TreeViewBackend ()
56
Tree = new ExTreeView();
57
Tree.Resources.MergedDictionaries.Add (TreeResourceDictionary);
58
Tree.ItemTemplate = new HierarchicalDataTemplate { ItemsSource = new Binding ("Children") };
59
Tree.SetValue (VirtualizingStackPanel.IsVirtualizingProperty, true);
62
public ScrollPolicy VerticalScrollPolicy {
63
get { return ScrollViewer.GetVerticalScrollBarVisibility (Tree).ToXwtScrollPolicy (); }
64
set { ScrollViewer.SetVerticalScrollBarVisibility (Tree, value.ToWpfScrollBarVisibility ()); }
67
public ScrollPolicy HorizontalScrollPolicy {
68
get { return ScrollViewer.GetHorizontalScrollBarVisibility (Tree).ToXwtScrollPolicy (); }
69
set { ScrollViewer.SetHorizontalScrollBarVisibility (Tree, value.ToWpfScrollBarVisibility ()); }
72
public TreePosition[] SelectedRows {
73
get { return Tree.SelectedItems.Cast<TreePosition> ().ToArray (); }
76
private bool headersVisible = true;
77
public bool HeadersVisible {
78
get { return this.headersVisible; }
81
this.headersVisible = value;
83
if (Tree.View.ColumnHeaderContainerStyle != null)
84
Tree.View.ColumnHeaderContainerStyle.Setters.Remove (HideHeaderSetter);
86
if (Tree.View.ColumnHeaderContainerStyle == null)
87
Tree.View.ColumnHeaderContainerStyle = new Style();
89
Tree.View.ColumnHeaderContainerStyle.Setters.Add (HideHeaderSetter);
94
public void SelectRow (TreePosition pos)
96
Tree.SelectedItems.Add (pos);
99
public void UnselectRow (TreePosition pos)
101
Tree.SelectedItems.Remove (pos);
104
public bool IsRowSelected (TreePosition row)
106
return Tree.SelectedItems.Contains (row);
109
public bool IsRowExpanded (TreePosition row)
111
return ((TreeStoreNode) row).IsExpanded;
114
public void ExpandToRow (TreePosition pos)
116
TreeStoreNode parent = ((TreeStoreNode) pos).Parent;
118
parent.IsExpanded = true;
121
public void ExpandRow (TreePosition row, bool expandChildren)
123
TreeStoreNode node = ((TreeStoreNode) row);
124
node.IsExpanded = true;
126
if (expandChildren) {
127
foreach (TreeStoreNode childNode in node.Children)
128
childNode.IsExpanded = true;
132
public void CollapseRow (TreePosition row)
134
((TreeStoreNode) row).IsExpanded = false;
137
public void ScrollToRow (TreePosition pos)
139
GetVisibleTreeItem (pos).BringIntoView();
142
public void SetSelectionMode (SelectionMode mode)
144
Tree.SelectionMode = (mode == SelectionMode.Single)
145
? SWC.SelectionMode.Single
146
: SWC.SelectionMode.Extended;
149
public void SelectAll ()
151
Tree.SelectAllExpanded();
154
public void UnselectAll ()
159
public void SetSource (ITreeDataSource source, IBackend sourceBackend)
161
Tree.ItemsSource = (TreeStoreBackend) sourceBackend;
164
public object AddColumn (ListViewColumn column)
166
var col = new GridViewColumn ();
168
UpdateColumn (column, col, ListViewColumnChange.Title);
170
Tree.View.Columns.Add (col);
172
UpdateColumn (column, col, ListViewColumnChange.Cells);
177
public void UpdateColumn (ListViewColumn column, object handle, ListViewColumnChange change)
179
var col = ((GridViewColumn) handle);
181
case ListViewColumnChange.Title:
182
col.Header = column.Title;
185
case ListViewColumnChange.Cells:
186
var cellTemplate = CellUtil.CreateBoundColumnTemplate (column.Views);
188
col.CellTemplate = new DataTemplate { VisualTree = cellTemplate };
190
int index = Tree.View.Columns.IndexOf (col);
192
var dockFactory = CreateExpanderDock ();
193
dockFactory.AppendChild (cellTemplate);
195
col.CellTemplate.VisualTree = dockFactory;
202
public void RemoveColumn (ListViewColumn column, object handle)
204
Tree.View.Columns.Remove ((GridViewColumn) handle);
207
private RowDropPosition dropPosition;
208
private ExTreeViewItem dropTarget;
209
private Adorner dropAdorner;
210
public bool GetDropTargetRow (double x, double y, out RowDropPosition pos, out TreePosition nodePosition)
213
this.dropPosition = pos = RowDropPosition.Into;
215
x *= WidthPixelRatio;
216
y *= HeightPixelRatio;
218
var result = VisualTreeHelper.HitTest (Tree, new System.Windows.Point (x, y)) as PointHitTestResult;
220
var element = (result != null) ? result.VisualHit as FrameworkElement : null;
221
while (element != null) {
222
if (element is ExTreeViewItem)
224
if (element is ExTreeView) // We can't succeed past this point
227
element = VisualTreeHelper.GetParent (element) as FrameworkElement;
230
this.dropTarget = (ExTreeViewItem)element;
235
var point = ((UIElement)result.VisualHit).TranslatePoint (result.PointHit, element);
237
double edge = element.ActualHeight * 0.15;
239
this.dropPosition = pos = RowDropPosition.Before;
240
else if (point.Y >= element.ActualHeight - edge)
241
this.dropPosition = pos = RowDropPosition.After;
243
nodePosition = element.DataContext as TreeStoreNode;
247
public override void EnableEvent (object eventId)
249
base.EnableEvent (eventId);
250
if (eventId is TableViewEvent) {
251
switch ((TableViewEvent)eventId) {
252
case TableViewEvent.SelectionChanged:
253
Tree.SelectedItemsChanged += OnSelectedItemsChanged;
259
public override void DisableEvent (object eventId)
261
base.DisableEvent (eventId);
262
if (eventId is TableViewEvent) {
263
switch ((TableViewEvent)eventId) {
264
case TableViewEvent.SelectionChanged:
265
Tree.SelectedItemsChanged -= OnSelectedItemsChanged;
271
protected ExTreeView Tree {
272
get { return (ExTreeView)Widget; }
273
set { Widget = value; }
276
protected ITreeViewEventSink TreeViewEventSink {
277
get { return (ITreeViewEventSink)EventSink; }
280
protected override double DefaultNaturalHeight {
284
protected override double DefaultNaturalWidth {
288
public override WidgetSize GetPreferredHeight()
290
return new WidgetSize (0);
293
public override WidgetSize GetPreferredHeightForWidth(double width)
295
return GetPreferredHeight ();
298
public override WidgetSize GetPreferredWidth()
300
return new WidgetSize (0);
303
public override WidgetSize GetPreferredWidthForHeight(double height)
305
return GetPreferredWidth ();
308
private void OnSelectedItemsChanged (object sender, EventArgs e)
310
Toolkit.Invoke (TreeViewEventSink.OnSelectionChanged);
313
protected override void OnDragOver (object sender, DragOverEventArgs e)
315
AdornerLayer layer = AdornerLayer.GetAdornerLayer (Widget);
316
if (this.dropAdorner != null)
317
layer.Remove (this.dropAdorner);
319
base.OnDragOver (sender, e);
321
if (this.dropTarget != null)
322
layer.Add (this.dropAdorner = new TreeViewDropAdorner (this.dropTarget, this.dropPosition));
325
protected override void OnDragLeave (object sender, EventArgs e)
327
base.OnDragLeave (sender, e);
329
if (this.dropAdorner != null)
330
AdornerLayer.GetAdornerLayer (Widget).Remove (this.dropAdorner);
333
protected override void OnDragFinished (object sender, DragFinishedEventArgs e)
335
base.OnDragFinished (sender, e);
337
if (this.dropAdorner != null)
338
AdornerLayer.GetAdornerLayer (Widget).Remove (this.dropAdorner);
341
private ExTreeViewItem GetVisibleTreeItem (TreePosition pos, Action<ExTreeViewItem> walk = null)
344
Stack<TreeStoreNode> nodes = new Stack<TreeStoreNode> ();
346
TreeStoreNode node = (TreeStoreNode) pos;
350
} while (node != null);
352
ExTreeViewItem treeItem = null;
353
ItemContainerGenerator g = Tree.ItemContainerGenerator;
354
while (nodes.Count > 0) {
356
treeItem = (ExTreeViewItem) g.ContainerFromItem (node);
357
treeItem.UpdateLayout ();
358
g = treeItem.ItemContainerGenerator;
367
private FrameworkElementFactory CreateExpanderDock ()
369
var dockFactory = new FrameworkElementFactory (typeof (DockPanel));
371
var source = new RelativeSource (RelativeSourceMode.FindAncestor, typeof (ExTreeViewItem), 1);
373
Style expanderStyle = new Style (typeof (SWC.Primitives.ToggleButton));
374
expanderStyle.Setters.Add (new Setter (UIElement.FocusableProperty, false));
375
expanderStyle.Setters.Add (new Setter (FrameworkElement.WidthProperty, 19d));
376
expanderStyle.Setters.Add (new Setter (FrameworkElement.HeightProperty, 13d));
378
var expanderTemplate = new ControlTemplate (typeof (SWC.Primitives.ToggleButton));
380
var outerBorderFactory = new FrameworkElementFactory (typeof (Border));
381
outerBorderFactory.SetValue (FrameworkElement.WidthProperty, 19d);
382
outerBorderFactory.SetValue (FrameworkElement.HeightProperty, 13d);
383
outerBorderFactory.SetValue (Control.BackgroundProperty, Brushes.Transparent);
384
outerBorderFactory.SetBinding (UIElement.VisibilityProperty,
385
new Binding ("HasItems") { RelativeSource = source, Converter = BoolVisibilityConverter });
387
var innerBorderFactory = new FrameworkElementFactory (typeof (Border));
388
innerBorderFactory.SetValue (FrameworkElement.WidthProperty, 9d);
389
innerBorderFactory.SetValue (FrameworkElement.HeightProperty, 9d);
390
innerBorderFactory.SetValue (Control.BorderThicknessProperty, new Thickness (1));
391
innerBorderFactory.SetValue (Control.BorderBrushProperty, new SolidColorBrush (Color.FromRgb (120, 152, 181)));
392
innerBorderFactory.SetValue (Border.CornerRadiusProperty, new CornerRadius (1));
393
innerBorderFactory.SetValue (UIElement.SnapsToDevicePixelsProperty, true);
395
innerBorderFactory.SetValue (Control.BackgroundProperty, ExpanderBackgroundBrush);
397
var pathFactory = new FrameworkElementFactory (typeof (Path));
398
pathFactory.SetValue (FrameworkElement.MarginProperty, new Thickness (1));
399
pathFactory.SetValue (Shape.FillProperty, Brushes.Black);
400
pathFactory.SetBinding (Path.DataProperty,
401
new Binding ("IsChecked") {
402
RelativeSource = new RelativeSource (RelativeSourceMode.FindAncestor, typeof (SWC.Primitives.ToggleButton), 1),
403
Converter = BooleanGeometryConverter
406
innerBorderFactory.AppendChild (pathFactory);
407
outerBorderFactory.AppendChild (innerBorderFactory);
409
expanderTemplate.VisualTree = outerBorderFactory;
411
expanderStyle.Setters.Add (new Setter (Control.TemplateProperty, expanderTemplate));
413
var toggleFactory = new FrameworkElementFactory (typeof (SWC.Primitives.ToggleButton));
414
toggleFactory.SetValue (FrameworkElement.StyleProperty, expanderStyle);
415
toggleFactory.SetBinding (FrameworkElement.MarginProperty,
416
new Binding ("Level") { RelativeSource = source, Converter = LevelConverter });
417
toggleFactory.SetBinding (SWC.Primitives.ToggleButton.IsCheckedProperty,
418
new Binding ("IsExpanded") { RelativeSource = source });
419
toggleFactory.SetValue (SWC.Primitives.ButtonBase.ClickModeProperty, ClickMode.Press);
421
dockFactory.AppendChild (toggleFactory);
425
private static readonly LevelToIndentConverter LevelConverter = new LevelToIndentConverter();
426
private static readonly BooleanToVisibilityConverter BoolVisibilityConverter = new BooleanToVisibilityConverter();
428
private static readonly LinearGradientBrush ExpanderBackgroundBrush = new LinearGradientBrush {
429
StartPoint = new System.Windows.Point (0, 0),
430
EndPoint = new System.Windows.Point (1, 1),
431
GradientStops = new GradientStopCollection {
432
new GradientStop (Colors.White, 0.2),
433
new GradientStop (Color.FromRgb (192, 183, 166), 1)
437
private static readonly Geometry Plus = Geometry.Parse ("M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z");
438
private static readonly Geometry Minus = Geometry.Parse ("M 0 2 L 0 3 L 5 3 L 5 2 Z");
440
private static readonly BooleanToValueConverter BooleanGeometryConverter =
441
new BooleanToValueConverter { TrueValue = Minus, FalseValue = Plus };
443
private static readonly Setter HideHeaderSetter = new Setter (UIElement.VisibilityProperty, Visibility.Collapsed);