xwt/Xwt.WPF/Xwt.WPFBackend/TreeViewBackend.cs

450 строки
14 KiB
C#
Исходник Обычный вид История

//
2012-01-24 03:01:53 +04:00
// TreeViewBackend.cs
//
2012-01-24 03:01:53 +04:00
// Author:
// Eric Maupin <ermau@xamarin.com>
//
2012-04-12 23:44:45 +04:00
// Copyright (c) 2012 Xamarin, Inc.
//
2012-01-24 03:01:53 +04:00
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
2012-01-24 03:01:53 +04:00
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
2012-01-24 03:01:53 +04:00
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Data;
2012-06-09 02:55:29 +04:00
using System.Windows.Documents;
using System.Windows.Markup;
2012-04-11 19:58:14 +04:00
using System.Windows.Media;
using System.Windows.Shapes;
2012-11-23 16:00:42 +04:00
2012-01-24 03:01:53 +04:00
using Xwt.Backends;
using Xwt.WPFBackend.Utilities;
using System.Windows;
2012-01-24 03:01:53 +04:00
using SWC=System.Windows.Controls;
using System.Windows.Controls;
2012-01-24 03:01:53 +04:00
namespace Xwt.WPFBackend
{
public class TreeViewBackend
: WidgetBackend, ITreeViewBackend
2012-01-24 03:01:53 +04:00
{
private static readonly ResourceDictionary TreeResourceDictionary;
static TreeViewBackend()
2012-01-24 03:01:53 +04:00
{
Uri uri = new Uri ("pack://application:,,,/Xwt.WPF;component/XWT.WPFBackend/TreeView.xaml");
TreeResourceDictionary = (ResourceDictionary)XamlReader.Load (System.Windows.Application.GetResourceStream (uri).Stream);
2012-01-24 03:01:53 +04:00
}
public TreeViewBackend ()
{
Tree = new ExTreeView();
Tree.Resources.MergedDictionaries.Add (TreeResourceDictionary);
2012-04-11 19:58:14 +04:00
Tree.ItemTemplate = new HierarchicalDataTemplate { ItemsSource = new Binding ("Children") };
2012-04-17 18:42:30 +04:00
Tree.SetValue (VirtualizingStackPanel.IsVirtualizingProperty, true);
}
2013-07-30 19:04:29 +04:00
2014-02-19 22:14:07 +04:00
public ScrollViewer ScrollViewer {
get {
Decorator border = System.Windows.Media.VisualTreeHelper.GetChild(Tree, 0) as Decorator;
if (border != null)
return border.Child as ScrollViewer;
else
return null;
}
}
2013-07-30 19:04:29 +04:00
public TreePosition CurrentEventRow { get; set; }
2012-04-11 20:08:12 +04:00
public ScrollPolicy VerticalScrollPolicy {
get { return ScrollViewer.GetVerticalScrollBarVisibility (Tree).ToXwtScrollPolicy (); }
set { ScrollViewer.SetVerticalScrollBarVisibility (Tree, value.ToWpfScrollBarVisibility ()); }
}
2012-04-11 20:08:12 +04:00
public ScrollPolicy HorizontalScrollPolicy {
get { return ScrollViewer.GetHorizontalScrollBarVisibility (Tree).ToXwtScrollPolicy (); }
set { ScrollViewer.SetHorizontalScrollBarVisibility (Tree, value.ToWpfScrollBarVisibility ()); }
2012-01-24 03:01:53 +04:00
}
2014-02-19 22:14:07 +04:00
public IScrollControlBackend CreateVerticalScrollControl()
{
return new ScrollControlBackend(ScrollViewer, true);
}
public IScrollControlBackend CreateHorizontalScrollControl()
{
return new ScrollControlBackend(ScrollViewer, false);
}
2012-04-11 20:08:12 +04:00
public TreePosition[] SelectedRows {
get { return Tree.SelectedItems.Cast<TreePosition> ().ToArray (); }
2012-01-24 03:01:53 +04:00
}
2012-04-11 19:58:14 +04:00
private bool headersVisible = true;
public bool HeadersVisible {
get { return this.headersVisible; }
set
{
this.headersVisible = value;
if (value) {
if (Tree.View.ColumnHeaderContainerStyle != null)
Tree.View.ColumnHeaderContainerStyle.Setters.Remove (HideHeaderSetter);
} else {
if (Tree.View.ColumnHeaderContainerStyle == null)
Tree.View.ColumnHeaderContainerStyle = new Style();
Tree.View.ColumnHeaderContainerStyle.Setters.Add (HideHeaderSetter);
}
}
2012-01-24 03:01:53 +04:00
}
2012-03-22 03:32:53 +04:00
public void SelectRow (TreePosition pos)
2012-01-24 03:01:53 +04:00
{
Tree.SelectedItems.Add (pos);
2012-01-24 03:01:53 +04:00
}
2012-03-22 03:32:53 +04:00
public void UnselectRow (TreePosition pos)
2012-02-27 21:35:54 +04:00
{
Tree.SelectedItems.Remove (pos);
2012-02-27 21:35:54 +04:00
}
2012-03-22 03:32:53 +04:00
public bool IsRowSelected (TreePosition row)
2012-01-24 03:01:53 +04:00
{
return Tree.SelectedItems.Contains (row);
2012-03-22 03:32:53 +04:00
}
public bool IsRowExpanded (TreePosition row)
{
return ((TreeStoreNode) row).IsExpanded;
2012-03-22 03:32:53 +04:00
}
public void ExpandToRow (TreePosition pos)
{
TreeStoreNode parent = ((TreeStoreNode) pos).Parent;
if (parent != null)
parent.IsExpanded = true;
2012-02-27 21:35:54 +04:00
}
2012-01-24 03:01:53 +04:00
public void ExpandRow (TreePosition row, bool expandChildren)
{
TreeStoreNode node = ((TreeStoreNode) row);
node.IsExpanded = true;
if (expandChildren) {
foreach (TreeStoreNode childNode in node.Children)
childNode.IsExpanded = true;
}
2012-01-24 03:01:53 +04:00
}
public void CollapseRow (TreePosition row)
{
((TreeStoreNode) row).IsExpanded = false;
2012-01-24 03:01:53 +04:00
}
2012-02-27 21:35:54 +04:00
public void ScrollToRow (TreePosition pos)
{
GetVisibleTreeItem (pos).BringIntoView();
}
public void SetSelectionMode (SelectionMode mode)
{
Tree.SelectionMode = (mode == SelectionMode.Single)
? SWC.SelectionMode.Single
: SWC.SelectionMode.Extended;
}
public void SelectAll ()
{
Tree.SelectAllExpanded();
2012-02-27 21:35:54 +04:00
}
2012-01-24 03:01:53 +04:00
public void UnselectAll ()
{
Tree.UnselectAll();
2012-01-24 03:01:53 +04:00
}
public void SetSource (ITreeDataSource source, IBackend sourceBackend)
2012-01-24 03:01:53 +04:00
{
Tree.ItemsSource = (TreeStoreBackend) sourceBackend;
2012-01-24 03:01:53 +04:00
}
public object AddColumn (ListViewColumn column)
2012-01-24 03:01:53 +04:00
{
var col = new GridViewColumn ();
2012-04-11 19:58:14 +04:00
UpdateColumn (column, col, ListViewColumnChange.Title);
2012-04-11 19:58:14 +04:00
Tree.View.Columns.Add (col);
UpdateColumn (column, col, ListViewColumnChange.Cells);
return col;
2012-01-24 03:01:53 +04:00
}
public void UpdateColumn (ListViewColumn column, object handle, ListViewColumnChange change)
{
var col = ((GridViewColumn) handle);
switch (change) {
case ListViewColumnChange.Title:
col.Header = column.Title;
break;
2012-04-11 19:58:14 +04:00
case ListViewColumnChange.Cells:
2014-02-24 18:12:30 +04:00
var cellTemplate = CellUtil.CreateBoundColumnTemplate(Frontend, column.Views);
2012-04-11 19:58:14 +04:00
col.CellTemplate = new DataTemplate { VisualTree = cellTemplate };
int index = Tree.View.Columns.IndexOf (col);
if (index == 0) {
2012-04-11 20:08:12 +04:00
var dockFactory = CreateExpanderDock ();
2012-04-11 19:58:14 +04:00
dockFactory.AppendChild (cellTemplate);
col.CellTemplate.VisualTree = dockFactory;
}
break;
}
2012-01-24 03:01:53 +04:00
}
public void RemoveColumn (ListViewColumn column, object handle)
{
2012-04-11 19:58:14 +04:00
Tree.View.Columns.Remove ((GridViewColumn) handle);
2012-01-24 03:01:53 +04:00
}
2012-06-09 02:55:29 +04:00
private RowDropPosition dropPosition;
private ExTreeViewItem dropTarget;
private Adorner dropAdorner;
public bool GetDropTargetRow (double x, double y, out RowDropPosition pos, out TreePosition nodePosition)
2012-01-24 03:01:53 +04:00
{
nodePosition = null;
2012-06-09 02:55:29 +04:00
this.dropPosition = pos = RowDropPosition.Into;
var result = VisualTreeHelper.HitTest (Tree, new System.Windows.Point (x, y)) as PointHitTestResult;
2012-06-09 02:55:29 +04:00
var element = (result != null) ? result.VisualHit as FrameworkElement : null;
while (element != null) {
if (element is ExTreeViewItem)
break;
if (element is ExTreeView) // We can't succeed past this point
return false;
element = VisualTreeHelper.GetParent (element) as FrameworkElement;
}
2012-06-09 02:55:29 +04:00
this.dropTarget = (ExTreeViewItem)element;
if (element == null)
return false;
2012-06-09 02:55:29 +04:00
var point = ((UIElement)result.VisualHit).TranslatePoint (result.PointHit, element);
2012-06-07 02:33:53 +04:00
double edge = element.ActualHeight * 0.15;
2012-06-09 02:55:29 +04:00
if (point.Y <= edge)
this.dropPosition = pos = RowDropPosition.Before;
else if (point.Y >= element.ActualHeight - edge)
this.dropPosition = pos = RowDropPosition.After;
nodePosition = element.DataContext as TreeStoreNode;
return true;
}
public override void EnableEvent (object eventId)
{
base.EnableEvent (eventId);
2012-04-11 20:08:12 +04:00
if (eventId is TableViewEvent) {
switch ((TableViewEvent)eventId) {
case TableViewEvent.SelectionChanged:
Tree.SelectedItemsChanged += OnSelectedItemsChanged;
break;
}
}
}
public override void DisableEvent (object eventId)
{
base.DisableEvent (eventId);
2012-04-11 20:08:12 +04:00
if (eventId is TableViewEvent) {
switch ((TableViewEvent)eventId) {
case TableViewEvent.SelectionChanged:
Tree.SelectedItemsChanged -= OnSelectedItemsChanged;
break;
}
}
2012-01-24 03:01:53 +04:00
}
2012-04-11 20:08:12 +04:00
protected ExTreeView Tree {
get { return (ExTreeView)Widget; }
set { Widget = value; }
}
2012-04-11 20:08:12 +04:00
protected ITreeViewEventSink TreeViewEventSink {
get { return (ITreeViewEventSink)EventSink; }
}
protected override double DefaultNaturalHeight {
get { return -1; }
}
protected override double DefaultNaturalWidth {
get { return -1; }
}
2013-05-31 11:44:45 +04:00
public override Size GetPreferredSize (SizeConstraint widthConstraint, SizeConstraint heightConstraint)
{
2013-05-31 11:44:45 +04:00
return Size.Zero;
}
private void OnSelectedItemsChanged (object sender, EventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (TreeViewEventSink.OnSelectionChanged);
}
2012-06-09 02:55:29 +04:00
protected override void OnDragOver (object sender, DragOverEventArgs e)
{
AdornerLayer layer = AdornerLayer.GetAdornerLayer (Widget);
if (this.dropAdorner != null)
layer.Remove (this.dropAdorner);
base.OnDragOver (sender, e);
if (this.dropTarget != null)
layer.Add (this.dropAdorner = new TreeViewDropAdorner (this.dropTarget, this.dropPosition));
}
protected override void OnDragLeave (object sender, EventArgs e)
{
base.OnDragLeave (sender, e);
if (this.dropAdorner != null)
AdornerLayer.GetAdornerLayer (Widget).Remove (this.dropAdorner);
}
protected override void OnDragFinished (object sender, DragFinishedEventArgs e)
{
base.OnDragFinished (sender, e);
if (this.dropAdorner != null)
AdornerLayer.GetAdornerLayer (Widget).Remove (this.dropAdorner);
}
private ExTreeViewItem GetVisibleTreeItem (TreePosition pos, Action<ExTreeViewItem> walk = null)
{
Tree.UpdateLayout();
Stack<TreeStoreNode> nodes = new Stack<TreeStoreNode> ();
TreeStoreNode node = (TreeStoreNode) pos;
do {
nodes.Push (node);
node = node.Parent;
} while (node != null);
ExTreeViewItem treeItem = null;
2012-06-09 02:55:29 +04:00
ItemContainerGenerator g = Tree.ItemContainerGenerator;
while (nodes.Count > 0) {
node = nodes.Pop ();
treeItem = (ExTreeViewItem) g.ContainerFromItem (node);
treeItem.UpdateLayout ();
g = treeItem.ItemContainerGenerator;
if (walk != null)
walk (treeItem);
}
return treeItem;
}
2012-04-11 19:58:14 +04:00
private FrameworkElementFactory CreateExpanderDock ()
{
2012-04-11 19:58:14 +04:00
var dockFactory = new FrameworkElementFactory (typeof (DockPanel));
var source = new RelativeSource (RelativeSourceMode.FindAncestor, typeof (ExTreeViewItem), 1);
Style expanderStyle = new Style (typeof (SWC.Primitives.ToggleButton));
expanderStyle.Setters.Add (new Setter (UIElement.FocusableProperty, false));
expanderStyle.Setters.Add (new Setter (FrameworkElement.WidthProperty, 19d));
expanderStyle.Setters.Add (new Setter (FrameworkElement.HeightProperty, 13d));
var expanderTemplate = new ControlTemplate (typeof (SWC.Primitives.ToggleButton));
var outerBorderFactory = new FrameworkElementFactory (typeof (Border));
outerBorderFactory.SetValue (FrameworkElement.WidthProperty, 19d);
outerBorderFactory.SetValue (FrameworkElement.HeightProperty, 13d);
outerBorderFactory.SetValue (Control.BackgroundProperty, Brushes.Transparent);
outerBorderFactory.SetBinding (UIElement.VisibilityProperty,
new Binding ("HasItems") { RelativeSource = source, Converter = BoolVisibilityConverter });
var innerBorderFactory = new FrameworkElementFactory (typeof (Border));
innerBorderFactory.SetValue (FrameworkElement.WidthProperty, 9d);
innerBorderFactory.SetValue (FrameworkElement.HeightProperty, 9d);
innerBorderFactory.SetValue (Control.BorderThicknessProperty, new Thickness (1));
innerBorderFactory.SetValue (Control.BorderBrushProperty, new SolidColorBrush (Color.FromRgb (120, 152, 181)));
innerBorderFactory.SetValue (Border.CornerRadiusProperty, new CornerRadius (1));
innerBorderFactory.SetValue (UIElement.SnapsToDevicePixelsProperty, true);
innerBorderFactory.SetValue (Control.BackgroundProperty, ExpanderBackgroundBrush);
var pathFactory = new FrameworkElementFactory (typeof (Path));
pathFactory.SetValue (FrameworkElement.MarginProperty, new Thickness (1));
pathFactory.SetValue (Shape.FillProperty, Brushes.Black);
pathFactory.SetBinding (Path.DataProperty,
new Binding ("IsChecked") {
RelativeSource = new RelativeSource (RelativeSourceMode.FindAncestor, typeof (SWC.Primitives.ToggleButton), 1),
Converter = BooleanGeometryConverter
});
innerBorderFactory.AppendChild (pathFactory);
outerBorderFactory.AppendChild (innerBorderFactory);
expanderTemplate.VisualTree = outerBorderFactory;
expanderStyle.Setters.Add (new Setter (Control.TemplateProperty, expanderTemplate));
var toggleFactory = new FrameworkElementFactory (typeof (SWC.Primitives.ToggleButton));
toggleFactory.SetValue (FrameworkElement.StyleProperty, expanderStyle);
toggleFactory.SetBinding (FrameworkElement.MarginProperty,
new Binding ("Level") { RelativeSource = source, Converter = LevelConverter });
toggleFactory.SetBinding (SWC.Primitives.ToggleButton.IsCheckedProperty,
new Binding ("IsExpanded") { RelativeSource = source });
toggleFactory.SetValue (SWC.Primitives.ButtonBase.ClickModeProperty, ClickMode.Press);
dockFactory.AppendChild (toggleFactory);
return dockFactory;
}
private static readonly LevelToIndentConverter LevelConverter = new LevelToIndentConverter();
private static readonly BooleanToVisibilityConverter BoolVisibilityConverter = new BooleanToVisibilityConverter();
2012-04-11 19:58:14 +04:00
private static readonly LinearGradientBrush ExpanderBackgroundBrush = new LinearGradientBrush {
StartPoint = new System.Windows.Point (0, 0),
EndPoint = new System.Windows.Point (1, 1),
GradientStops = new GradientStopCollection {
new GradientStop (Colors.White, 0.2),
new GradientStop (Color.FromRgb (192, 183, 166), 1)
}
2012-04-11 19:58:14 +04:00
};
2012-04-11 19:58:14 +04:00
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");
private static readonly Geometry Minus = Geometry.Parse ("M 0 2 L 0 3 L 5 3 L 5 2 Z");
private static readonly BooleanToValueConverter BooleanGeometryConverter =
new BooleanToValueConverter { TrueValue = Minus, FalseValue = Plus };
private static readonly Setter HideHeaderSetter = new Setter (UIElement.VisibilityProperty, Visibility.Collapsed);
}
2012-01-24 03:01:53 +04:00
}