当前位置:  开发笔记 > 运维 > 正文

自定义TreeView以允许多选

如何解决《自定义TreeView以允许多选》经验,为你挑选了2个好方法。

内置的WPF TreeView控件不允许多选,就像ListBox一样.如何自定义TreeView以允许多重选择而无需重写.



1> Zamboni..:

当我考虑重写控件的基本行为时,比如树视图,我总是喜欢考虑与我的决定相关的可用性和努力.

在树视图的特定情况下,我发现切换到列表视图并结合零个,一个或多个控件,可以提供更易于实现的更有用的解决方案.

例如,考虑常见的"打开"对话框或Windows资源管理器应用程序.



2> 小智..:

我在SoMoS实现上有一个变体,它使用在基本TreeView控件派生时声明的附加属性来跟踪TreeViewItems的选择状态。这将使选择跟踪保持在TreeViewItem元素本身上,并远离由树视图呈现的模型对象。

这是新的TreeView类派生。

using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Collections;
using System.Collections.Generic;

namespace MultiSelectTreeViewDemo
{
    public sealed class MultiSelectTreeView : TreeView
    {
        #region Fields

        // Used in shift selections
        private TreeViewItem _lastItemSelected;

        #endregion Fields
        #region Dependency Properties

        public static readonly DependencyProperty IsItemSelectedProperty =
            DependencyProperty.RegisterAttached("IsItemSelected", typeof(bool), typeof(MultiSelectTreeView));

        public static void SetIsItemSelected(UIElement element, bool value)
        {
            element.SetValue(IsItemSelectedProperty, value);
        }
        public static bool GetIsItemSelected(UIElement element)
        {
            return (bool)element.GetValue(IsItemSelectedProperty);
        }

        #endregion Dependency Properties
        #region Properties

        private static bool IsCtrlPressed
        {
            get { return Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl); }
        }
        private static bool IsShiftPressed
        {
            get { return Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift); }
        }

        public IList SelectedItems
        {
            get
            {
                var selectedTreeViewItems = GetTreeViewItems(this, true).Where(GetIsItemSelected);
                var selectedModelItems = selectedTreeViewItems.Select(treeViewItem => treeViewItem.Header);

                return selectedModelItems.ToList();
            }
        }

        #endregion Properties
        #region Event Handlers

        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseDown(e);

            // If clicking on a tree branch expander...
            if (e.OriginalSource is Shape || e.OriginalSource is Grid || e.OriginalSource is Border)
                return;

            var item = GetTreeViewItemClicked((FrameworkElement)e.OriginalSource);
            if (item != null) SelectedItemChangedInternal(item);
        }

        #endregion Event Handlers
        #region Utility Methods

        private void SelectedItemChangedInternal(TreeViewItem tvItem)
        {
            // Clear all previous selected item states if ctrl is NOT being held down
            if (!IsCtrlPressed)
            {
                var items = GetTreeViewItems(this, true);
                foreach (var treeViewItem in items)
                    SetIsItemSelected(treeViewItem, false);
            }

            // Is this an item range selection?
            if (IsShiftPressed && _lastItemSelected != null)
            {
                var items = GetTreeViewItemRange(_lastItemSelected, tvItem);
                if (items.Count > 0)
                {
                    foreach (var treeViewItem in items)
                        SetIsItemSelected(treeViewItem, true);

                    _lastItemSelected = items.Last();
                }
            }
            // Otherwise, individual selection
            else
            {
                SetIsItemSelected(tvItem, true);
                _lastItemSelected = tvItem;
            }
        }
        private static TreeViewItem GetTreeViewItemClicked(DependencyObject sender)
        {
            while (sender != null && !(sender is TreeViewItem))
                sender = VisualTreeHelper.GetParent(sender);
            return sender as TreeViewItem;
        }
        private static List GetTreeViewItems(ItemsControl parentItem, bool includeCollapsedItems, List itemList = null)
        {
            if (itemList == null)
                itemList = new List();

            for (var index = 0; index < parentItem.Items.Count; index++)
            {
                var tvItem = parentItem.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
                if (tvItem == null) continue;

                itemList.Add(tvItem);
                if (includeCollapsedItems || tvItem.IsExpanded)
                    GetTreeViewItems(tvItem, includeCollapsedItems, itemList);
            }
            return itemList;
        }
        private List GetTreeViewItemRange(TreeViewItem start, TreeViewItem end)
        {
            var items = GetTreeViewItems(this, false);

            var startIndex = items.IndexOf(start);
            var endIndex = items.IndexOf(end);
            var rangeStart = startIndex > endIndex || startIndex == -1 ? endIndex : startIndex;
            var rangeCount = startIndex > endIndex ? startIndex - endIndex + 1 : endIndex - startIndex + 1;

            if (startIndex == -1 && endIndex == -1)
                rangeCount = 0;

            else if (startIndex == -1 || endIndex == -1)
                rangeCount = 1;

            return rangeCount > 0 ? items.GetRange(rangeStart, rangeCount) : new List();
        }

        #endregion Utility Methods
    }
}

这是XAML。请注意,最重要的部分是使用MultiSelectTreeViewItemStyle中的新“ IsItemSelected”附加属性替换使用单数“ IsSelected”属性的两个触发器,以实现可视状态。

还要注意,我没有将新的TreeView控件聚合到UserControl中。



    
        
        
        
        
        
        
        
        
        
        
        
        
        
    

    
        
            
            
        
        
            
                
                    
                        
                    
                
            
        
        

这是一个俗气的视图模型来驱动它(出于演示目的)。

using System.Collections.ObjectModel;

namespace MultiSelectTreeViewDemo
{
    public sealed class DemoViewModel
    {
        public ObservableCollection FoodGroups { get; set; }

        public DemoViewModel()
        {
            var redMeat = new FoodItem { Name = "Reds" };
            redMeat.Add(new FoodItem { Name = "Beef" });
            redMeat.Add(new FoodItem { Name = "Buffalo" });
            redMeat.Add(new FoodItem { Name = "Lamb" });

            var whiteMeat = new FoodItem { Name = "Whites" };
            whiteMeat.Add(new FoodItem { Name = "Chicken" });
            whiteMeat.Add(new FoodItem { Name = "Duck" });
            whiteMeat.Add(new FoodItem { Name = "Pork" });
            var meats = new FoodItem { Name = "Meats", Children = { redMeat, whiteMeat } };

            var veggies = new FoodItem { Name = "Vegetables" };
            veggies.Add(new FoodItem { Name = "Potato" });
            veggies.Add(new FoodItem { Name = "Corn" });
            veggies.Add(new FoodItem { Name = "Spinach" });

            var fruits = new FoodItem { Name = "Fruits" };
            fruits.Add(new FoodItem { Name = "Apple" });
            fruits.Add(new FoodItem { Name = "Orange" });
            fruits.Add(new FoodItem { Name = "Pear" });

            FoodGroups = new ObservableCollection { meats, veggies, fruits };
        }
    }
    public sealed class FoodItem
    {
        public string Name { get; set; }
        public ObservableCollection Children { get; set; }

        public FoodItem()
        {
            Children = new ObservableCollection();
        }
        public void Add(FoodItem item)
        {
            Children.Add(item);
        }
    }
}

这是MainWindow代码后面的按钮单击处理程序,用于显示MessageBox中的选择。

    private void GetSelectionsButton_OnClick(object sender, RoutedEventArgs e)
    {
        var selectedMesg = "";
        var selectedItems = multiSelectTreeView.SelectedItems;

        if (selectedItems.Count > 0)
        {
            selectedMesg = selectedItems.Cast()
                .Where(mod

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有