TreeView的扩展(转载)

using System;
using System.Windows.Forms;
using System.Collections.Generic;

namespace X.WinForms.Controls
{
    /// <summary>
    /// 标题:TreeView 的勾选模式
    /// </summary>
    public enum TreeViewCheckMode
    {
        /// <summary>
        /// 默认(保留)
        /// </summary>
        Default = -1,

        /// <summary>
        /// 无法选择
        /// </summary>
        None = 0,
        
        /// <summary>
        /// 只能选择一项。
        /// </summary>
        One = 1,

        /// <summary>
        /// 可以选择多项。
        /// </summary>
        Multi = 2,
    }

    public enum DefaultBoolean
    {
        False = 0,
        True = 1,
        Default = 2
    }

    /// <summary>
    /// 标题:多选上级节点的模式
    /// </summary>
    public enum TreeViewParentCheckMode
    {
        AnyCheck,
        AllCheckOnSameLevel
    }

    /// <summary>
    /// 多选选项
    /// </summary>
    public class TreeViewMutiCheckOptions
    {
        private DefaultBoolean fAllowCheckParent = DefaultBoolean.True;
        private TreeViewParentCheckMode fCheckParentMode = TreeViewParentCheckMode.AnyCheck;
        private DefaultBoolean fAllowCheckChild = DefaultBoolean.True;

        /// <summary>
        /// 获取或设置一个值,它表示是否选中上级节点。
        /// </summary>
        public DefaultBoolean AllowCheckParent
        {
            get { return fAllowCheckParent; }
            set { fAllowCheckParent = value; }
        }

        /// <summary>
        /// 获取或设置一个值,它表示选中上级节点的模式。
        /// </summary>
        public TreeViewParentCheckMode CheckParentMode
        {
            get { return fCheckParentMode; }
            set { fCheckParentMode = value; }
        }

        /// <summary>
        /// 获取或设置一个值,它表示是否选中子节点。
        /// </summary>
        public DefaultBoolean AllowCheckChild
        {
            get { return fAllowCheckChild; }
            set { fAllowCheckChild = value; }
        }

        public TreeViewMutiCheckOptions(DefaultBoolean fAllowCheckParent, TreeViewParentCheckMode fCheckParentMode, DefaultBoolean fAllowCheckChild)
        {
            this.fAllowCheckParent = fAllowCheckParent;
            this.fCheckParentMode = fCheckParentMode;
            this.fAllowCheckChild = fAllowCheckChild;
        }
    }

    /// <summary>
    /// 标题:TreeView 控件扩展
    /// 描述:2010-02-28 增加几种 CheckBox 的勾选模式。
    ///        1 “单选”
    ///        2 “多选子节点”
    ///        3 “勾选任意节点同中父节点”
    ///        4 “勾选同级节点中的所有节点同进返回中父节点”
    /// </summary>
    public class TreeViewEx : TreeView
    {
        protected SysAction SysAction = new SysAction();

        private TreeViewCheckMode fCheckMode;
        private TreeViewMutiCheckOptions fMutiCheckOptions;

        /// <summary>
        /// 获取或设置一个值,它表示当前 TreeView 的勾选模式。
        /// </summary>
        public virtual TreeViewCheckMode CheckMode
        {
            get { return fCheckMode; }
            set { fCheckMode = value; }
        }

       /// <summary>
       /// 获取或设置一个值,它表示多选模式下的选项。
       /// </summary>
        public TreeViewMutiCheckOptions MutiCheckOptions
        {
            get
            {
                if (this.fMutiCheckOptions == null)
                    this.fMutiCheckOptions = new TreeViewMutiCheckOptions(DefaultBoolean.True, TreeViewParentCheckMode.AnyCheck, DefaultBoolean.True);

                return this.fMutiCheckOptions;
            }
            set { fMutiCheckOptions = value; }
        }

        /// <summary>
        /// 获取 TreeView 所有节点
        /// </summary>
        public List<TreeNode> AllNodes
        {
            get
            {
                List<TreeNode> array = new List<TreeNode>();

                foreach (TreeNode node in this.Nodes)
                {
                    array.Add(node);
                    GetAllNodes(array, node);
                }

                return array;
            }
        }

        private void GetAllNodes(List<TreeNode> array, TreeNode parentNode)
        {
            foreach (TreeNode node in parentNode.Nodes)
            {
                array.Add(node);
                GetAllNodes(array, node);
            }
        }

        protected override void OnBeforeCheck(TreeViewCancelEventArgs e)
        {
            if (!this.SysAction.Running)
            {
                if (this.CheckMode == TreeViewCheckMode.None)
                {
                    e.Cancel = true;
                }
                else if (this.CheckMode == TreeViewCheckMode.Multi)
                {
                    if (this.MutiCheckOptions.AllowCheckParent == DefaultBoolean.True)
                    {
                        if (this.MutiCheckOptions.CheckParentMode == TreeViewParentCheckMode.AnyCheck)
                        {
                            // 如果子节点有选中项,则不能取消选择。
                            bool hasCheckOne = false;

                            foreach (TreeNode node in e.Node.Nodes)
                            {
                                if (node.Checked)
                                {
                                    hasCheckOne = true;
                                    break;
                                }
                            }

                            if (hasCheckOne)
                            {
                                e.Cancel = true;
                            }
                        }
                    }
                }
            }

            base.OnBeforeCheck(e);
        }

        protected override void OnAfterCheck(TreeViewEventArgs e)
        {
            if (this.CheckMode == TreeViewCheckMode.One)
            {
                this.CheckAllNode(new List<TreeNode>(new TreeNode[] { e.Node }), false);
            }
            else if (this.CheckMode == TreeViewCheckMode.Multi)
            {
                if (this.MutiCheckOptions.AllowCheckChild == DefaultBoolean.True)
                {
                    this.CheckAllNode(e.Node, new List<TreeNode>(new TreeNode[] { e.Node }), e.Node.Checked);
                }

                if (this.MutiCheckOptions.AllowCheckParent == DefaultBoolean.True)
                {
                    if (!this.SysAction.Running)
                    {
                        DefaultBoolean allowCheckChild = this.MutiCheckOptions.AllowCheckChild;

                        try
                        {
                            this.MutiCheckOptions.AllowCheckChild = DefaultBoolean.False;
                            this.CheckParent(e.Node, this.MutiCheckOptions.CheckParentMode);
                        }
                        finally
                        {
                            this.MutiCheckOptions.AllowCheckChild = allowCheckChild;
                        }
                    }
                }
            }

            base.OnAfterCheck(e);
        }

        public virtual void CheckAllNode(bool checkedValue)
        {
            this.CheckAllNode(null, checkedValue);
        }

        public virtual void CheckAllNode(List<TreeNode> excludeNodes, bool checkedValue)
        {
            this.CheckAllNode(null, excludeNodes, checkedValue);
        }

        /// <summary>
        /// 设置某个节点及它的所有子节点的选中状态,当 parentNode 为 Null 时表示根节点。
        /// </summary>
        /// <param name="parentNode">需要设置的节点</param>
        /// <param name="excludeNodes">排除不处理的节点</param>
        /// <param name="checkedValue">选中状态</param>
        public virtual void CheckAllNode(TreeNode parentNode, List<TreeNode> excludeNodes, bool checkedValue)
        {
            if (parentNode != null && parentNode.Checked != checkedValue)
            {
                if (excludeNodes != null && !excludeNodes.Contains(parentNode))
                    this.TrySafeSetCheckValue(parentNode, checkedValue);
            }

            TreeNodeCollection nodes = (parentNode == null)
                ? this.Nodes 
                : parentNode.Nodes;

            foreach (TreeNode node in nodes)
                this.CheckAllNode(node, excludeNodes, checkedValue);
        }

        public void CheckParent(TreeNode checkedNode, TreeViewParentCheckMode mode)
        {
            TreeNode parentNode = checkedNode.Parent;

            if (parentNode == null)
                return;

            if (mode == TreeViewParentCheckMode.AnyCheck)
            {
                bool checkedValue = false;
                // 若同一级都没有选择,同时取消父节点的选择。
                foreach (TreeNode node in parentNode.Nodes)
                {
                    if (node.Checked)
                    {
                        checkedValue = true;
                        break;
                    }
                }

                this.TrySafeSetCheckValue(parentNode, checkedValue);
                this.CheckParent(parentNode, mode);
                
            }
            else if (mode == TreeViewParentCheckMode.AllCheckOnSameLevel)
            {
                bool checkedValue = true;

                foreach (TreeNode node in parentNode.Nodes)
                {
                    if (!node.Checked)
                    {
                        checkedValue = false;
                        break;
                    }
                }

                this.TrySafeSetCheckValue(parentNode, checkedValue);
                this.CheckParent(parentNode, mode);
            }
        }

        public void TrySafeSetCheckValue(TreeNode node, bool checkedValue)
        {
            if (node == null) return;

            try
            {
                this.SysAction.Begin();
                if (node.Checked != checkedValue)
                    node.Checked = checkedValue;
            }
            finally
            {
                this.SysAction.End();
            }
        }
    }

    public class SysAction
    {
        private bool fRunning = false;

        public bool Running
        {
            get { return fRunning; }
        }

        public void Begin()
        {
            this.fRunning = true;
        }

        public void End()
        {
            this.fRunning = false;
        }
    }
}

使用:

this.treeView1.CheckMode = X.WinForms.Controls.TreeViewCheckMode.Multi;
            this.treeView1.MutiCheckOptions.AllowCheckParent = DefaultBoolean.True;
            this.treeView1.MutiCheckOptions.AllowCheckChild = DefaultBoolean.True;
            this.treeView1.MutiCheckOptions.CheckParentMode = TreeViewParentCheckMode.AllCheckOnSameLevel;

转自:https://social.msdn.microsoft.com/Forums/zh-CN/d0d60151-f433-4ba2-abe5-e4524885208f/treeview?forum=visualcshartzhchs

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF TreeView 控件默认提供了展开/折叠图标和单个CheckBox选中功能,如果需要实现扩展图标和多选功能,可以通过自定义TreeViewItem样式来实现。 下面是一个简单的示例,展示如何在WPF TreeView中实现扩展图标和多选功能: 1. 创建一个自定义TreeViewItem样式,并在其中添加一个扩展图标和多选CheckBox: ``` <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TreeViewItem}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel Orientation="Horizontal" Grid.Column="0"> <Image x:Name="ExpandCollapseImage" Source="Expand.png" Width="16" Height="16" Margin="0,0,5,0" Visibility="Collapsed" /> <CheckBox x:Name="CheckBox" VerticalAlignment="Center" Margin="0,0,5,0"/> <ContentPresenter ContentSource="Header" /> </StackPanel> <ItemsPresenter Grid.Column="1" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="True"> <Setter TargetName="ExpandCollapseImage" Property="Source" Value="Collapse.png" /> <Setter TargetName="ExpandCollapseImage" Property="Visibility" Value="Visible" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="IsSelectionActive" Value="True"/> </MultiTrigger.Conditions> <Setter TargetName="CheckBox" Property="IsChecked" Value="True"/> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> ``` 2. 在TreeView中应用自定义样式: ``` <TreeView x:Name="TreeView" ItemContainerStyle="{StaticResource TreeViewItemStyle}"> <!-- 树节点内容 --> </TreeView> ``` 3. 处理TreeViewItem的展开/折叠事件: ``` private void TreeViewItem_Expanded(object sender, RoutedEventArgs e) { TreeViewItem item = e.OriginalSource as TreeViewItem; if (item != null) { Image image = FindChild<Image>(item, "ExpandCollapseImage"); if (image != null) { image.Source = new BitmapImage(new Uri("Collapse.png", UriKind.Relative)); } } } private void TreeViewItem_Collapsed(object sender, RoutedEventArgs e) { TreeViewItem item = e.OriginalSource as TreeViewItem; if (item != null) { Image image = FindChild<Image>(item, "ExpandCollapseImage"); if (image != null) { image.Source = new BitmapImage(new Uri("Expand.png", UriKind.Relative)); } } } private T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject { if (parent == null) return null; T child = null; int childrenCount = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < childrenCount; i++) { DependencyObject childElement = VisualTreeHelper.GetChild(parent, i); if (childElement is T && ((FrameworkElement)childElement).Name == childName) { child = (T)childElement; break; } else { child = FindChild<T>(childElement, childName); if (child != null) break; } } return child; } ``` 4. 处理TreeViewItem的多选事件: ``` private void CheckBox_Click(object sender, RoutedEventArgs e) { TreeViewItem item = FindParent<TreeViewItem>(sender as DependencyObject); if (item != null) { // 获取父节点 TreeViewItem parentItem = FindParent<TreeViewItem>(item.Parent); if (parentItem != null) { // 获取所有子节点 List<TreeViewItem> childItems = new List<TreeViewItem>(); GetChildItems(parentItem, childItems); // 更新所有节点的多选状态 foreach (TreeViewItem childItem in childItems) { CheckBox checkBox = FindChild<CheckBox>(childItem, "CheckBox"); if (checkBox != null) { checkBox.IsChecked = GetChildCheckedState(parentItem); } } } } } private TreeViewItem FindParent<T>(DependencyObject child) where T : DependencyObject { if (child == null) return null; DependencyObject parent = VisualTreeHelper.GetParent(child); while (parent != null && !(parent is T)) { parent = VisualTreeHelper.GetParent(parent); } return parent as TreeViewItem; } private void GetChildItems(TreeViewItem item, List<TreeViewItem> childItems) { int childrenCount = VisualTreeHelper.GetChildrenCount(item); for (int i = 0; i < childrenCount; i++) { DependencyObject childElement = VisualTreeHelper.GetChild(item, i); if (childElement is TreeViewItem) { childItems.Add(childElement as TreeViewItem); GetChildItems(childElement as TreeViewItem, childItems); } } } private bool GetChildCheckedState(TreeViewItem parent) { int childrenCount = VisualTreeHelper.GetChildrenCount(parent); bool isChecked = false; for (int i = 0; i < childrenCount; i++) { DependencyObject childElement = VisualTreeHelper.GetChild(parent, i); if (childElement is TreeViewItem) { CheckBox checkBox = FindChild<CheckBox>(childElement as TreeViewItem, "CheckBox"); if (checkBox != null && checkBox.IsChecked == true) { isChecked = true; break; } else { isChecked = GetChildCheckedState(childElement as TreeViewItem); if (isChecked) break; } } } return isChecked; } ``` 通过以上步骤,我们就可以在WPF TreeView中实现扩展图标和多选功能了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值