WPF TreeView 多选行为
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14837171/
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
WPF TreeView MultiSelect Behavior
提问by Mike
I have written a multi select behavior based on this post:WPF TreeView with Multiple Selection
我根据这篇文章编写了一个多选行为:WPF TreeView with Multiple Selection
However my behavior does't seem to work as expected..Can you please help?
但是我的行为似乎没有按预期工作..你能帮忙吗?
The following is my xaml code:
以下是我的 xaml 代码:
<Window x:Class="TreeView.Spike.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Spike="clr-namespace:TreeView.Spike"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<TreeView ItemsSource="{Binding Nodes}" Grid.Row="0" x:Name="treeView" Grid.Column="0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}">
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add"></MenuItem>
<MenuItem Header="Delete"></MenuItem>
</ContextMenu>
</TreeView.ContextMenu>
<i:Interaction.Behaviors>
<Spike:MultipleItemSelectionAttachedBehavior AllSelectedItems="{Binding Path=AllSelectedNodes}"/>
</i:Interaction.Behaviors>
</TreeView>
</Grid>
</Window>
My attached behavior:
我的附加行为:
public class MultipleItemSelectionAttachedBehavior:Behavior<System.Windows.Controls.TreeView>
{
public static DependencyProperty AllSelectedItemsProperty =
DependencyProperty.RegisterAttached("AllSelectedItems", typeof(object), typeof(MultipleItemSelectionAttachedBehavior),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Inherits));
private static readonly PropertyInfo IsSelectionChangeActiveProperty = typeof(System.Windows.Controls.TreeView).GetProperty("IsSelectionChangeActive",
BindingFlags.NonPublic | BindingFlags.Instance);
public object AllSelectedItems
{
get
{
return (object)GetValue(AllSelectedItemsProperty);
}
set
{
SetValue(AllSelectedItemsProperty, value);
}
}
public static bool GetAllSelectedItems(DependencyObject obj)
{
return (bool)obj.GetValue(AllSelectedItemsProperty);
}
public static void SetAllSelectedItems(DependencyObject obj, bool value)
{
obj.SetValue(AllSelectedItemsProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItemChanged += AssociatedObject_SelectedItemChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectedItemChanged -= AssociatedObject_SelectedItemChanged;
}
void AssociatedObject_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (IsSelectionChangeActiveProperty == null) return;
var selectedItems = new List<Node>();
var treeViewItem = AssociatedObject.SelectedItem as Node;
if (treeViewItem == null) return;
// allow multiple selection
// when control key is pressed
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
var isSelectionChangeActive = IsSelectionChangeActiveProperty.GetValue(AssociatedObject, null);
IsSelectionChangeActiveProperty.SetValue(AssociatedObject, true, null);
selectedItems.ForEach(item => item.IsSelected = true);
IsSelectionChangeActiveProperty.SetValue(AssociatedObject, isSelectionChangeActive, null);
}
else
{
// deselect all selected items except the current one
selectedItems.ForEach(item => item.IsSelected = (item == treeViewItem));
selectedItems.Clear();
}
if (!selectedItems.Contains(treeViewItem))
{
selectedItems.Add(treeViewItem);
}
else
{
// deselect if already selected
treeViewItem.IsSelected = false;
selectedItems.Remove(treeViewItem);
}
AllSelectedItems = selectedItems;
}
}
..and my ViewModel
..和我的 ViewModel
public class ViewModel :NotificationObject
{
public ViewModel()
{
AllSelectedNodes = new ObservableCollection<Node>();
}
private ObservableCollection<Node> _allSelectedNodes;
public ObservableCollection<Node> AllSelectedNodes
{
get { return _allSelectedNodes; }
set
{
_allSelectedNodes = value;
RaisePropertyChanged(() => AllSelectedNodes);
}
}
}
My Model:
我的型号:
public class Node:NotificationObject
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged(() => Name);
}
}
private bool _isExpanded = true;
public bool IsExpanded
{
get { return _isExpanded; }
set
{
_isExpanded = value;
RaisePropertyChanged(() => IsExpanded);
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
RaisePropertyChanged(() => IsSelected);
}
}
private ObservableCollection<Node> _nodes;
public ObservableCollection<Node> Nodes
{
get { return _nodes; }
set
{
_nodes = value;
RaisePropertyChanged(() => Nodes);
}
}
public static IList<Node> Create()
{
return new List<Node>()
{
new Node()
{
Name = "Activity",
Nodes = new ObservableCollection<Node>()
{
new Node() {Name = "Company",Nodes = new ObservableCollection<Node>(){ new Node() {Name = "Company1",Existing = false}}},
new Node() {Name = "Strategy",Nodes = new ObservableCollection<Node>(){ new Node() {Name = "Strategy1"}}},
new Node() {Name = "Vehicle",Nodes = new ObservableCollection<Node>(){ new Node() {Name = "Vehicle1",Existing = false}}}
}
}
};
}
}
..and my initialization clode:
..和我的初始化代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var viewModel = new ViewModel();
this.DataContext = viewModel;
viewModel.Nodes = new ObservableCollection<Node>(Node.Create());
}
}
The issue is that, it still selects only one while it's supposed to select multiple while holding back control key.
问题是,它仍然只选择一个,而它应该在按住控制键的同时选择多个。
回答by Jake Gaston
In AssociatedObject_SelectedItemChanged, how is the selectedItems count ever anything but zero when you just instantiate it or 1 when you add the treeViewItem to it a bit later? Try setting it to the AllSelectedItems property. Also, shouldn't the AllSelectedItems property be a list or IEnumerable of some sort?
在 AssociatedObject_SelectedItemChanged 中,当您刚刚实例化它时,selectedItems 是如何计数的,而当您稍后将 treeViewItem 添加到它时,它是如何计数的?尝试将其设置为 AllSelectedItems 属性。此外,AllSelectedItems 属性不应该是某种列表或 IEnumerable 吗?
if(AllSelectedItems == null)
{
AllSelectedItems = new List<Node>();
}
List<Node> selectedItems = AllSelectedItems;
回答by kbax
you are missing the binding of the IsSelected property:
您缺少 IsSelected 属性的绑定:
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</TreeView.ItemContainerStyle>
回答by zish
you need to add Selection mode property to treeview like this
您需要像这样将选择模式属性添加到树视图中
SelectionMode="Multiple"

