我正在尝试创建一个递归方法来取消选择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中工作。
答案 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));
}
}
结果:
VisualTreeHelper.Whatever()
内容,不需要因UI虚拟化等原因而导致各种问题的复杂操作。SelectAll()
和SelectNone()
方法中,我只是通过Data Items
而不是UI元素进行迭代,并相应地设置它们的值。然后,WPF通过DataBinding引擎更新UI。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方法。根据开关,您可以选择或取消选择全部。