1

我在 WPF 中有一个自定义树视图类。我想在字符串列表中获取选定的节点文本。

规则:

  • 如果选择了 parent 中的所有节点,则仅返回父节点文本。

  • 如果父节点中的所有节点都没有被选中,则返回一个parentName_childName被选中节点的列表。

    以上两条规则适用于所有级别。对于具有 2 个层次结构的树视图,将名称返回为parentName_child1Name_child1ChildName.

节点模板c#代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace TreeViewCheckBox
{
    public struct CheckBoxId
    {
        public static string IDCheckBox;
    }

    public class Node : INotifyPropertyChanged
    {
        private readonly ObservableCollection<Node> children = new ObservableCollection<Node>();    
        private readonly ObservableCollection<Node> parent = new ObservableCollection<Node>();
        private bool? isChecked = true;
        private bool isExpanded;
        private string text;
        
        public Node()
        {
            this.Id = Guid.NewGuid().ToString();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public ObservableCollection<Node> Children
        {
            get { return this.children; }
        }
        public string Id { get; set; }
        public bool? IsChecked
        {
            get { return this.isChecked; }
            set
            {
                this.isChecked = value;
                this.RaisePropertyChanged("IsChecked");
            }
        }
        public bool IsExpanded
        {
            get { return this.isExpanded; }
            set
            {
                this.isExpanded = value;
                this.RaisePropertyChanged("IsExpanded");
            }
        }       
        public ObservableCollection<Node> Parent
        {
            get { return this.parent; }
        }
        public string Text
        {
            get { return this.text; }
            set
            {
                this.text = value;
                this.RaisePropertyChanged("Text");
            }
        }
        private void CheckedTreeChild(IEnumerable<Node> items, int countCheck)
        {
            bool isNull = false;
            foreach (Node paren in items)
            {
                foreach (Node child in paren.Children)
                {
                    if (child.IsChecked == true || child.IsChecked == null)
                    {
                        countCheck++;
                        if (child.IsChecked == null)
                        {
                            isNull = true;
                        }
                    }
                }
                if (countCheck != paren.Children.Count && countCheck != 0)
                {
                    paren.IsChecked = null;
                }
                else if (countCheck == 0)
                {
                    paren.IsChecked = false;
                }
                else if (countCheck == paren.Children.Count && isNull)
                {
                    paren.IsChecked = null;
                }
                else if (countCheck == paren.Children.Count && !isNull)
                {
                    paren.IsChecked = true;
                }

                if (paren.Parent.Count != 0)
                {
                    this.CheckedTreeChild(paren.Parent, 0);
                }
            }
        }
        private void CheckedTreeChildMiddle(
            IEnumerable<Node> itemsParent, IEnumerable<Node> itemsChild, bool? isCheckBoxChecked)
        {
            const int CountCheck = 0;
            this.CheckedTreeParent(itemsChild, isCheckBoxChecked);
            this.CheckedTreeChild(itemsParent, CountCheck);
        }
        private void CheckedTreeParent(IEnumerable<Node> items, bool? isCheckBoxChecked)
        {
            foreach (Node item in items)
            {
                item.IsChecked = isCheckBoxChecked;
                if (item.Children.Count != 0)
                {
                    this.CheckedTreeParent(item.Children, isCheckBoxChecked);
                }
            }
        }
        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }

            const int CountCheck = 0;
            if (propertyName == "IsChecked")
            {
                if (this.Id == CheckBoxId.IDCheckBox && this.Parent.Count == 0 && this.Children.Count != 0)
                {
                    this.CheckedTreeParent(this.Children, this.IsChecked);
                }

                if (this.Id == CheckBoxId.IDCheckBox && this.Parent.Count > 0 && this.Children.Count > 0)
                {
                    this.CheckedTreeChildMiddle(this.Parent, this.Children, this.IsChecked);
                }

                if (this.Id == CheckBoxId.IDCheckBox && this.Parent.Count > 0 && this.Children.Count == 0)
                {
                    this.CheckedTreeChild(this.Parent, CountCheck);
                }
            }
        }
    }
}

用户控件 XAML 代码:

<UserControl x:Class="TreeViewCheckBox.CustomTreeView"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:TreeViewWithImageCheckBox="clr-namespace:TreeViewCheckBox"
                 mc:Ignorable="d">
        <UserControl.Resources>
            <HierarchicalDataTemplate DataType="{x:Type TreeViewCheckBox:Node}" ItemsSource="{Binding Children}">
                <StackPanel Orientation="Horizontal">
                    <StackPanel.Margin>2</StackPanel.Margin>
                    <CheckBox Margin="1" IsChecked="{Binding IsChecked}"
                              PreviewMouseLeftButtonDown="CheckBox_PreviewMouseLeftButtonDown"
                              Uid="{Binding Id}" />
                    <TextBlock Margin="1" Text="{Binding Text}" />
                </StackPanel>
            </HierarchicalDataTemplate>
            <Style TargetType="TreeViewItem">
                <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}" />
            </Style>
        </UserControl.Resources>
        <Grid>
            <TreeView Name="tvMain" Grid.ColumnSpan="2" x:FieldModifier="private" />
        </Grid>
</UserControl>

用户控件 c# 代码:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Windows.Controls;
namespace TreeViewCheckBox
{
    public partial class CustomTreeView
    {
        public CustomTreeView()
        {
            this.Nodes = new ObservableCollection<Node>();
            this.InitializeComponent();
            this.FillTree();
        }
        private ObservableCollection<Node> Nodes { get; set; }

        public void FillTree()
        {
            this.Nodes.Clear();
            for (int i = 0; i < 5; i++)
            {
                var level1Items = new Node { Text = " Level 1 Item " + (i + 1) };
                for (int j = 0; j < 2; j++)
                {
                    var level2Items = new Node { Text = " Level 2 Item " + (j + 1) };
                    level2Items.Parent.Add(level1Items);
                    level1Items.Children.Add(level2Items);
                    for (int n = 0; n < 2; n++)
                    {
                        var level3Items = new Node { Text = " Level 3 Item " + (n + 1) };
                        level3Items.Parent.Add(level2Items);
                        level2Items.Children.Add(level3Items);
                    }
                }

                this.Nodes.Add(level1Items);
            }

            this.tvMain.ItemsSource = this.Nodes;
        }

        private void CheckBox_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var currentCheckBox = (CheckBox)sender;
            CheckBoxId.IDCheckBox = currentCheckBox.Uid;
        }
    }
   }

如何获取列表中的选定节点?

4

2 回答 2

1

您可能必须遍历 Nodes 集合并检查 IsChecked 属性的值。像这样的东西:

private List<string> SelectedNodes = new List<string>();

private void GetSelectedNodeText(NodeCollection nodes)
{
    foreach (Node node in nodes)
    {
        if (node.IsChecked != true && node.IsChecked != false)
        {
            SelectedNodes.Add(node.Text + "_" + GetSelectedChildNodeText(node.ChildNodes));
        }
        else if (node.IsChecked == true)
        {
            SelectedNodes.Add(node.Text);
        }
    }
}

private string GetSelectedChildNodeText(NodeCollection nodes)
{
    string retValue = string.Empty;

    foreach (Node node in nodes)
    {
        if (node.IsChecked != true && node.IsChecked != false)
        {
            retValue = node.Text + "_" + GetSelectedChildNodeText(node.ChildNodes);
        }
        else if (node.IsChecked == true)
        {
            retValue = node.Text;
        }
    }

    return retVal;
}

我的假设:

  1. IsChecked 属性在其所有子项都被选中时具有真值。
  2. 当所有子项都被取消选择时,IsChecked 属性的值为 false。
  3. IsChecked 属性在只有部分子项被选中时既没有真值也没有假值。
  4. 您在 Node.Text 属性中有节点的文本。
于 2012-08-16T07:37:06.177 回答
0

感谢 Sandeep 的想法。

以下代码工作正常..

public List<string> GetSelectedNodes()
{
    var listNodes = new List<string>();
    foreach (Node node in this.Nodes)
    {
        if (node.IsChecked == null)
        {
            this.GetSelectedChildNodeText(node.Text, node.Children, ref listNodes);
        }
        else if (node.IsChecked == true)
        {
            listNodes.Add(node.Text);
        }
    }

    return listNodes;
}

private void GetSelectedChildNodeText(string nodeName, IEnumerable<Node> nodes, ref List<string> listNodes)
{
    foreach (Node node in nodes)
    {
        string currentName = string.Format("{0}_{1}", nodeName, node.Text);
        if (node.IsChecked == null)
        {
            this.GetSelectedChildNodeText(currentName, node.Children, ref listNodes);
        }
        else if (node.IsChecked == true)
        {
            listNodes.Add(currentName);
        }
    }
}
于 2012-08-16T09:42:29.790 回答