在 WPF 中,如何以编程方式取消选择 Treeview 中的所有项目?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20707788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:16:28  来源:igfitidea点击:

In WPF, how do you programmatically deselect all Items in a Treeview?

c#wpftreeview

提问by Clay Acord

I'm trying to create a recursive method to deselect all items in a WPF TreeView. The thing that complicates things is that each TreeViewItem is not a mini-TreeView. This causes you to have to do a lot of casting back and forth. So, here's what I have tried:

我正在尝试创建一个递归方法来取消选择 WPF TreeView 中的所有项目。使事情复杂化的是每个 TreeViewItem 都不是迷你 TreeView。这导致您必须来回进行大量转换。所以,这是我尝试过的:

TreeViewDeselectAll(myTreeView.Items);      

// Must send in ItemCollection to allow the recursive call
private void TreeViewDeselectAll(ItemCollection myTreeViewItems)
{
    // The only way to get to the IsSelected property is to turn it back into a TreeViewItem
    foreach (TreeViewItem currentItem in myTreeViewItems)
    {
        currentItem.IsSelected = false;
        if (currentItem.HasItems)
        {
             // Recursify!
             TreeViewDeselectAll(currentItem.Items);
        }
    }
}

Has anyone successfully deselected all items in a TreeView? Have you even been able to traverse a TreeView in a recursive manner?

有没有人成功取消选择 TreeView 中的所有项目?您甚至能够以递归方式遍历 TreeView 吗?

The Winforms TreeView has a Nodes collection, which is really a mini-TreeView. This allows recursion just fine. But the WPF TreeView does not have Nodes.

Winforms TreeView 有一个 Nodes 集合,它实际上是一个迷你 TreeView。这允许递归就好了。但是 WPF TreeView 没有节点。

Working in .Net 4.0.

在 .Net 4.0 中工作。

采纳答案by dev hedgehog

Each TreeViewItem is a Mini-TreeView. You got the wrong impression or you read something wrong about TreeViewItems.

每个 TreeViewItem 都是一个 Mini-TreeView。你有错误的印象,或者你读错了关于 TreeViewItems 的东西。

What you doing wrong is passing the Items collection which doesnt contain children of type TreeViewItem but instead those are the data items.

您做错了什么是传递不包含 TreeViewItem 类型的子项而是那些是数据项的 Items 集合。

Pass the children collection and you should do fine.

通过儿童收藏,你应该做得很好。

Like this:

像这样:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

    }

    private bool @switch = false;

    private void TreeViewDeselectAll(IEnumerable myTreeViewItems, bool value)
    {
        if (myTreeViewItems != null)
        {
            foreach (var currentItem in myTreeViewItems)
            {
                if (currentItem is TreeViewItem)
                {
                    TreeViewItem item = (TreeViewItem)currentItem;
                    item.IsSelected = value;
                    if (item.HasItems)
                    {
                        TreeViewDeselectAll(LogicalTreeHelper.GetChildren(item), value);
                    }
                }
            }
        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.TreeViewDeselectAll(LogicalTreeHelper.GetChildren(this.treeView), this.@switch);
    }
}

XAML would look like this for example:

例如,XAML 看起来像这样:

<StackPanel>
    <TreeView Name="treeView">
        <TreeViewItem Header="First Level">
            <TreeViewItem Header="Second Level"/>
        </TreeViewItem>
    </TreeView>
    <Button Click="Button_Click">select/unselect all</Button>
</StackPanel>

I changed your TreeViewDeselectAll method a little bit. Based on switch you can select or unselect all.

我稍微改变了你的 TreeViewDeselectAll 方法。根据开关,您可以全选或取消全选。

回答by Federico Berasategui

Ok. Delete all your code and start all over.

好的。删除所有代码并重新开始。

If you're working with WPF, you really need to leave behind all the archaic practices from dinosaur technologies (such as winforms) and understand and embrace The WPF Mentality.

如果您正在使用 WPF,您真的需要抛开恐龙技术(例如 winforms)的所有陈旧做法,并理解并接受WPF Mentality

In WPF, You don't "select a TreeViewItem" programatically, simply because UI is Not Data.

在 WPF 中,您不会以编程方式“选择 TreeViewItem”,仅仅因为UI 不是 Data

The UI is not responsible for keeping track of the selection state of your Data items, which are displayed in a TreeView, or any other UI element.

UI 不负责跟踪显示在 TreeView 或任何其他 UI 元素中的数据项的选择状态。

Instead, you create a proper DataModel and a ViewModelto hold the data and the application logic, respectively.

相反,您可以创建一个适当的 DataModel 和 aViewModel来分别保存数据和应用程序逻辑。

There is a very interesting articleby Josh Smithexplaining how to deal with a TreeView in WPF, the right way.

Josh Smith一篇非常有趣的文章,解释了如何以正确的方式在 WPF 中处理 TreeView。

Basically something like this:

基本上是这样的:

<Window x:Class="MiscSamples.MVVMTreeViewSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MVVMTreeViewSample" Height="300" Width="300">
    <DockPanel>
        <Button Content="Select All" Click="SelectAll" DockPanel.Dock="Top"/>
        <Button Content="Select None" Click="SelectNone" DockPanel.Dock="Top"/>

        <TreeView ItemsSource="{Binding}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding DisplayName}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </DockPanel>
</Window>

Code Behind:

背后的代码:

public partial class MVVMTreeViewSample : Window
{
    private ObservableCollection<HierarchicalData> Data; 

    public MVVMTreeViewSample()
    {
        InitializeComponent();
        DataContext = Data = CreateData();
    }

    private void Select(IEnumerable<HierarchicalData> items, bool isselected)
    {
        while (items.Any())
        {
            items.ToList().ForEach(x => x.IsSelected = isselected);
            items = items.SelectMany(x => x.Children);
        }  
    }

    private void SelectAll(object sender, RoutedEventArgs e)
    {
        Select(Data, true);
    }

    private void SelectNone(object sender, RoutedEventArgs e)
    {
        Select(Data, false);
    }

    private ObservableCollection<HierarchicalData> CreateData()
    {
        return new ObservableCollection<HierarchicalData>
        {
            //... Dummy Data here
        }
    }
}

Data Item:

数据项:

public class HierarchicalData : System.ComponentModel.INotifyPropertyChanged
{

    public string DisplayName { get; set; }

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }

    public ObservableCollection<HierarchicalData> Children { get; private set; }

    public HierarchicalData()
    {
        Children = new ObservableCollection<HierarchicalData>();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Result:

结果:

enter image description here

在此处输入图片说明

  • See how there is NOT a single line of code that manipulates ANY UI element. Everything is done via DataBindingto Simple, Simple Properties and INotifyPropertyChanged. That's how you program in WPF. No need for complicated VisualTreeHelper.Whatever()stuff, no need for complicated manipulations which incur in all sorts of issues due to UI virtualization or the like.
  • In the SelectAll()and SelectNone()methods, I'm just iterating thru Data Itemsrather than UI elements, and setting their values accordingly. WPF then updates the UI via the DataBinding engine.
  • See how there is no need to cast anything to anything, and how I'm working with my own simple classes rather than having to deal with the complex, arcane WPF Object Model.
  • forget winforms. it'a useless dinosaur that doesn't support anything.
  • WPF Rocks. Just copy and paste my code in a File -> New Project -> WPF Applicationand see the results for yourself. Notice that you will need to add items to the collection in the CreateData()method.
  • Let me know if you need further help.
  • 看看没有一行代码可以操作任何 UI 元素。一切都是通过DataBindingto Simple、Simple Properties 和 INotifyPropertyChanged 完成的。这就是您在 WPF 中编程的方式。不需要复杂的VisualTreeHelper.Whatever()东西,不需要复杂的操作,因为 UI 虚拟化或类似的问题会导致各种问题。
  • SelectAll()SelectNone()方法中,我只是遍历Data Items而不是 UI 元素,并相应地设置它们的值。WPF 然后通过 DataBinding 引擎更新 UI。
  • 了解如何无需将任何内容强制转换为任何内容,以及我如何使用自己的简单类而不必处理复杂、神秘的 WPF 对象模型。
  • 忘记winforms。它是一个无用的恐龙,不支持任何东西。
  • WPF 摇滚。只需将我的代码复制并粘贴到 a 中,File -> New Project -> WPF Application然后自己查看结果。请注意,您需要在CreateData()方法中向集合中添加项目。
  • 如果您需要进一步的帮助,请告诉我。