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

时间:2013-12-20 16:21:05

标签: c# wpf treeview

我正在尝试创建一个递归方法来取消选择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);
        }
    }
}

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

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

在.Net 4.0中工作。

2 个答案:

答案 0 :(得分:5)

确定。删除所有代码并从头开始。

如果你正在使用WPF,你真的需要抛弃恐龙技术(如winforms)的所有古老习俗,理解并接受The WPF Mentality

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

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

相反,您需要创建一个合适的DataModel和一个ViewModel来分别保存数据和应用程序逻辑。

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

基本上是这样的:

<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>

代码背后:

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
        }
    }
}

数据项:

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));
    }
}

结果:

enter image description here

  • 了解如何操作任何UI元素没有一行代码。一切都是通过DataBinding简单,简单属性和INotifyPropertyChanged 完成的。这就是你在WPF中编程的方式。不需要复杂的VisualTreeHelper.Whatever()内容,不需要因UI虚拟化等原因而导致各种问题的复杂操作。
  • SelectAll()SelectNone()方法中,我只是通过Data Items而不是UI元素进行迭代,并相应地设置它们的值。然后,WPF通过DataBinding引擎更新UI。
  • 了解如何不需要任何东西,以及我如何使用自己的简单类而不必处理复杂,神秘的WPF对象模型。
  • 忘记winforms。它是一种无用的恐龙,不支持任何东西。
  • WPF Rocks 。只需将我的代码复制并粘贴到File -> New Project -> WPF Application中,然后自行查看结果即可。请注意,您需要在CreateData()方法中向集合中添加项目。
  • 如果您需要进一步的帮助,请告诉我。

答案 1 :(得分:1)

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

你做错了是传递Items集合,它不包含TreeViewItem类型的子节点,而是传递那些数据项。

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

像这样:

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看起来像这样:

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

我稍微更改了TreeViewDeselectAll方法。根据开关,您可以选择或取消选择全部。