WPF Tree控件多选,附加依赖项属性

使用附加依赖项属性搞定

附加依赖项属性类 TreeViewExtensions.cs  
public class TreeViewExtensions : TreeView
    {
        /// <summary>
        /// Gets the value of the dependency property "EnableMultiSelect".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <returns></returns>
        public static bool GetEnableMultiSelect(DependencyObject obj)
        {
            return (bool)obj.GetValue(EnableMultiSelectProperty);
        }

        /// <summary>
        /// Sets the value of the dependency property "EnableMultiSelect".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <param name="value"></param>
        public static void SetEnableMultiSelect(DependencyObject obj, bool value)
        {
            obj.SetValue(EnableMultiSelectProperty, value);
        }

        // Using a DependencyProperty as the backing store for EnableMultiSelect.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EnableMultiSelectProperty =
            DependencyProperty.RegisterAttached("EnableMultiSelect", typeof(bool), typeof(TreeViewExtensions), new FrameworkPropertyMetadata(false)
            {
                PropertyChangedCallback = EnableMultiSelectChanged,
                BindsTwoWayByDefault = true
            });

        /// <summary>
        /// Gets the value of the dependency property "SelectedItems".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <returns></returns>
        public static IList GetSelectedItems(DependencyObject obj)
        {
            return (IList)obj.GetValue(SelectedItemsProperty);
        }

        /// <summary>
        /// Sets the value of the dependency property "SelectedItems".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <param name="value"></param>
        public static void SetSelectedItems(DependencyObject obj, IList value)
        {
            obj.SetValue(SelectedItemsProperty, value);
        }

        // Using a DependencyProperty as the backing store for SelectedItems.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedItemsProperty =
            DependencyProperty.RegisterAttached("SelectedItems", typeof(IList), typeof(TreeViewExtensions), new PropertyMetadata(null));

        /// <summary>
        /// Gets the value of the dependency property "AnchorItem".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <returns></returns>
        static TreeViewItem GetAnchorItem(DependencyObject obj)
        {
            return (TreeViewItem)obj.GetValue(AnchorItemProperty);
        }

        /// <summary>
        /// Sets the value of the dependency property "AnchorItem".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <param name="value"></param>
        static void SetAnchorItem(DependencyObject obj, TreeViewItem value)
        {
            obj.SetValue(AnchorItemProperty, value);
        }

        // Using a DependencyProperty as the backing store for AnchorItem.  This enables animation, styling, binding, etc...
        static readonly DependencyProperty AnchorItemProperty =
            DependencyProperty.RegisterAttached("AnchorItem", typeof(TreeViewItem), typeof(TreeViewExtensions), new PropertyMetadata(null));

        /// <summary>
        /// Gets the value of the dependency property "IsSelected".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <returns></returns>
        public static bool GetIsSelected(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsSelectedProperty);
        }

        /// <summary>
        /// Sets the value of the dependency property "IsSelected".
        /// </summary>
        /// <param name="obj">Dependency Object</param>
        /// <param name="value"></param>
        public static void SetIsSelected(DependencyObject obj, bool value)
        {
            if (value)
            {
                GradientStopCollection gradientStopCollection = new GradientStopCollection();
                gradientStopCollection.Add(new GradientStop()
                {
                    Color = (Color)ColorConverter.ConvertFromString("#FF303030"),
                    Offset = 1
                });
//                gradientStopCollection.Add(new GradientStop()
//                {
//                    Color = (Color)ColorConverter.ConvertFromString("#FF3832B8"),
//                    Offset = 1
//                });
                LinearGradientBrush brush = new LinearGradientBrush(gradientStopCollection, new Point(0.5, 0), new Point(0.5, 1));
                (obj as TreeViewItem).Background = brush;
            }
            else
            {
                (obj as TreeViewItem).Background = Brushes.Transparent;
            }
            obj.SetValue(IsSelectedProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.RegisterAttached("IsSelected", typeof(bool), typeof(TreeViewExtensions), new PropertyMetadata(false)
            {
                PropertyChangedCallback = RealSelectedChanged
            });

        /// <summary>
        /// "EnableMultiSelect" changed event.
        /// </summary>
        /// <param name="s">Dependency Object</param>
        /// <param name="args">Event parameter</param>
        static void EnableMultiSelectChanged(DependencyObject s, DependencyPropertyChangedEventArgs args)
        {
            TreeView tree = (TreeView)s;
            var wasEnable = (bool)args.OldValue;
            var isEnabled = (bool)args.NewValue;
            if (wasEnable)
            {
                tree.RemoveHandler(TreeViewItem.MouseDownEvent, new MouseButtonEventHandler(ItemClicked));
                tree.RemoveHandler(TreeView.KeyDownEvent, new KeyEventHandler(KeyDown));
            }
            if (isEnabled)
            {
                tree.AddHandler(TreeViewItem.MouseDownEvent, new MouseButtonEventHandler(ItemClicked), true);
                tree.AddHandler(TreeView.KeyDownEvent, new KeyEventHandler(KeyDown));
            }
        }

        /// <summary>
        /// Gets TreeView which contains the TreeViewItem.
        /// </summary>
        /// <param name="item">item</param>
        /// <returns>TreeView</returns>
        static TreeView GetTree(TreeViewItem item)
        {
            Func<DependencyObject, DependencyObject> getParent = (o) => VisualTreeHelper.GetParent(o);
            FrameworkElement currentItem = item;
            while (!(getParent(currentItem) is TreeView))
            {
                currentItem = (FrameworkElement)getParent(currentItem);
            }
            return (TreeView)getParent(currentItem);
        }

        /// <summary>
        /// TreeViewItem seleted changed event.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="args">event parameter</param>
        static void RealSelectedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            TreeViewItem item = (TreeViewItem)sender;
            var selectedItems = GetSelectedItems(GetTree(item));
            if (selectedItems != null)
            {
                var isSelected = GetIsSelected(item);
                if (isSelected)
                {
                    try
                    {
                        selectedItems.Add(item.Header);
                    }
                    catch (ArgumentException)
                    {
                    }
                }
                else
                {
                    selectedItems.Remove(item.Header);
                }
            }

        }
        /// <summary>
        /// Key down event.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">event parameter</param>
        static void KeyDown(object sender, KeyEventArgs e)
        {
            TreeView tree = (TreeView)sender;
            if (e.Key == Key.A && e.KeyboardDevice.Modifiers == ModifierKeys.Control)
            {
                foreach (var item in GetExpandedTreeViewItems(tree))
                {
                    SetIsSelected(item, true);
                }
                e.Handled = true;
            }
        }

        /// <summary>
        /// Item clicked event.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">event parameter</param>
        static void ItemClicked(object sender, MouseButtonEventArgs e)
        {
            TreeViewItem item = FindTreeViewItem(e.OriginalSource);
            if (item == null)
            {
                return;
            }
            TreeView tree = (TreeView)sender;

            var mouseButton = e.ChangedButton;
            if (mouseButton != MouseButton.Left)
            {
                if ((mouseButton == MouseButton.Right) && ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) == ModifierKeys.None))
                {
                    if (GetIsSelected(item))
                    {
                        UpdateAnchorAndActionItem(tree, item);
                        return;
                    }
                    MakeSingleSelection(tree, item);
                }
                return;
            }
            if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != (ModifierKeys.Shift | ModifierKeys.Control))
            {
                if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
                {
                    MakeToggleSelection(tree, item);
                    return;
                }
                if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
                {
                    MakeAnchorSelection(tree, item, true);
                    return;
                }
                MakeSingleSelection(tree, item);
                return;
            }
        }

        /// <summary>
        /// Find TreeViewItem which contains the object.
        /// </summary>
        /// <param name="obj">obj</param>
        /// <returns></returns>
        private static TreeViewItem FindTreeViewItem(object obj)
        {
            DependencyObject dpObj = obj as DependencyObject;
            if (dpObj == null)
            {
                return null;
            }
            if (dpObj is TreeViewItem)
            {
                return (TreeViewItem)dpObj;
            }
            return FindTreeViewItem(VisualTreeHelper.GetParent(dpObj));
        }

        /// <summary>
        /// Gets all expanded TreeViewItems.
        /// </summary>
        /// <param name="tree">TreeView</param>
        /// <returns></returns>
        private static IEnumerable<TreeViewItem> GetExpandedTreeViewItems(ItemsControl tree)
        {
            for (int i = 0; i < tree.Items.Count; i++)
            {
                var item = (TreeViewItem)tree.ItemContainerGenerator.ContainerFromIndex(i);
                if (item == null)
                {
                    continue;
                }
                yield return item;
//                if (item.IsExpanded)
//                {
                    foreach (var subItem in GetExpandedTreeViewItems(item))
                    {
                        yield return subItem;
                    }
//                }
            }
        }

        /// <summary>
        /// Select by Shift key.
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="actionItem"></param>
        /// <param name="clearCurrent"></param>
        private static void MakeAnchorSelection(TreeView tree, TreeViewItem actionItem, bool clearCurrent)
        {
            if (GetAnchorItem(tree) == null)
            {
                var selectedItems = GetSelectedTreeViewItems(tree);
                if (selectedItems.Count > 0)
                {
                    SetAnchorItem(tree, selectedItems[selectedItems.Count - 1]);
                }
                else
                {
                    SetAnchorItem(tree, GetExpandedTreeViewItems(tree).Skip(3).FirstOrDefault());
                }
                if (GetAnchorItem(tree) == null)
                {
                    return;
                }
            }

            var anchor = GetAnchorItem(tree);

            var items = GetExpandedTreeViewItems(tree);
            bool betweenBoundary = false;
            foreach (var item in items)
            {
                bool isBoundary = item == anchor || item == actionItem;
                if (isBoundary)
                {
                    betweenBoundary = !betweenBoundary;
                }
                if (betweenBoundary || isBoundary)
                {
                    SetIsSelected(item, true);
                }
                else
                {
                    if (clearCurrent)
                    {
                        SetIsSelected(item, false);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Gets all selected TreeViewItems.
        /// </summary>
        /// <param name="tree">TreeView</param>
        /// <returns></returns>
        private static List<TreeViewItem> GetSelectedTreeViewItems(TreeView tree)
        {
            return GetExpandedTreeViewItems(tree).Where(i => GetIsSelected(i)).ToList();
        }

        /// <summary>
        /// Select by left mouse button.
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="item"></param>
        private static void MakeSingleSelection(TreeView tree, TreeViewItem item)
        {
            foreach (TreeViewItem selectedItem in GetExpandedTreeViewItems(tree))
            {
                if (selectedItem == null)
                {
                    continue;
                }
                if (selectedItem != item)
                {
                    SetIsSelected(selectedItem, false);
                }
                else
                {
                    SetIsSelected(selectedItem, true);
                }
            }
            UpdateAnchorAndActionItem(tree, item);
        }

        /// <summary>
        /// Select by Ctrl key.
        /// </summary>
        /// <param name="tree">TreeView</param>
        /// <param name="item">TreeViewItem</param>
        private static void MakeToggleSelection(TreeView tree, TreeViewItem item)
        {
            SetIsSelected(item, !GetIsSelected(item));
            UpdateAnchorAndActionItem(tree, item);
        }

        /// <summary>
        /// Update the Anchor TreeViewItem.
        /// </summary>
        /// <param name="tree">TreeView</param>
        /// <param name="item">TreeViewItem</param>
        private static void UpdateAnchorAndActionItem(TreeView tree, TreeViewItem item)
        {
            SetAnchorItem(tree, item);
        }
    }

 

 

使用

resource是TreeViewExtensions的程序集

resource:TreeViewExtensions.EnableMultiSelect="true" resource:TreeViewExtensions.SelectedItems="{Binding Root.SelectedTreeNodes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
获取WPF自定义控件依赖属性的数据流程如下: 1. 定义依赖属性:在自定义控件的代码中,定义一个依赖属性并注册该属性。例如: ``` public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register( "MyProperty", typeof(string), typeof(MyControl), new PropertyMetadata("Default Value")); public string MyProperty { get { return (string)GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value); } } ``` 2. 绑定依赖属性:在XAML中,将自定义控件依赖属性绑定到其他控件或数据源。例如: ``` <local:MyControl MyProperty="{Binding MyData}" /> ``` 3. 获取依赖属性的值:当自定义控件被渲染时,WPF框架会自动调用依赖属性的get方法,从绑定的数据源中获取属性的值。如果没有绑定任何数据源,则使用属性的默认值。例如: ``` string myPropertyValue = myControlInstance.MyProperty; ``` 4. 监听依赖属性的变化:如果需要在属性值发生变化时执行一些自定义逻辑,可以在自定义控件中注册属性值变化的回调函数。例如: ``` public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register( "MyProperty", typeof(string), typeof(MyControl), new PropertyMetadata("Default Value", OnMyPropertyChanged)); private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Execute custom logic when MyProperty value changes } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值