如何检索在WPF-treeview中选择的项?我想在XAML中这样做,因为我想绑定它。
您可能认为它是SelectedItem,但显然它不存在是只读的,因此不可用。
这就是我想做的:
<TreeView ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource ClusterTemplate}"
SelectedItem="{Binding Path=Model.SelectedCluster}" />
我想将SelectedItem绑定到我的Model上的一个属性。
但这给了我一个错误:
“SelectedItem”属性是只读的,不能从标记中设置。
编辑:
这就是我解决这个问题的方法:
<TreeView
ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource HoofdCLusterTemplate}"
SelectedItemChanged="TreeView_OnSelectedItemChanged" />
在我的xaml的代码背后文件:
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
Model.SelectedCluster = (Cluster)e.NewValue;
}
也可以使用TreeView项的IsSelected属性来完成。我是这么做的,
public delegate void TreeviewItemSelectedHandler(TreeViewItem item);
public class TreeViewItem
{
public static event TreeviewItemSelectedHandler OnItemSelected = delegate { };
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
if (value)
OnItemSelected(this);
}
}
}
然后在包含TreeView绑定到的数据的ViewModel中,只需订阅TreeViewItem类中的事件。
TreeViewItem.OnItemSelected += TreeViewItemSelected;
最后,在同一个ViewModel中实现这个处理器,
private void TreeViewItemSelected(TreeViewItem item)
{
//Do something
}
当然,绑定,
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
走吧
... 是一个更好的答案,但没有提到一种在ViewModel中获取/设置SelectedItem的方法。
添加一个IsSelected布尔属性到ItemViewModel,并在TreeViewItem的样式设置器中绑定到它。
在ViewModel中添加SelectedItem属性,作为TreeView的DataContext。这是上面解决方案中缺少的部分。
' ItemVM...
Public Property IsSelected As Boolean
Get
Return _func.SelectedNode Is Me
End Get
Set(value As Boolean)
If IsSelected value Then
_func.SelectedNode = If(value, Me, Nothing)
End If
RaisePropertyChange()
End Set
End Property
' TreeVM...
Public Property SelectedItem As ItemVM
Get
Return _selectedItem
End Get
Set(value As ItemVM)
If _selectedItem Is value Then
Return
End If
Dim prev = _selectedItem
_selectedItem = value
If prev IsNot Nothing Then
prev.IsSelected = False
End If
If _selectedItem IsNot Nothing Then
_selectedItem.IsSelected = True
End If
End Set
End Property
<TreeView ItemsSource="{Binding Path=TreeVM}"
BorderBrush="Transparent">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
我建议对Steve Greatrex提供的行为进行补充。他的行为并不反映来自源的更改,因为它可能不是TreeViewItems的集合。
所以这是一个在树中找到TreeViewItem的问题,它的数据上下文是来自源的selectedValue。
TreeView有一个名为“ItemsHost”的受保护属性,它包含TreeViewItem集合。我们可以通过反射获得它,并遍历树搜索所选项目。
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var behavior = sender as BindableSelectedItemBehaviour;
if (behavior == null) return;
var tree = behavior.AssociatedObject;
if (tree == null) return;
if (e.NewValue == null)
foreach (var item in tree.Items.OfType<TreeViewItem>())
item.SetValue(TreeViewItem.IsSelectedProperty, false);
var treeViewItem = e.NewValue as TreeViewItem;
if (treeViewItem != null)
{
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
}
else
{
var itemsHostProperty = tree.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (itemsHostProperty == null) return;
var itemsHost = itemsHostProperty.GetValue(tree, null) as Panel;
if (itemsHost == null) return;
foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
if (WalkTreeViewItem(item, e.NewValue)) break;
}
}
public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue) {
if (treeViewItem.DataContext == selectedValue)
{
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
treeViewItem.Focus();
return true;
}
foreach (var item in treeViewItem.Items.OfType<TreeViewItem>())
if (WalkTreeViewItem(item, selectedValue)) return true;
return false;
}
这种方式的行为适用于双向绑定。或者,也可以将ItemsHost获取移动到Behavior的OnAttached方法,从而节省每次绑定更新时使用反射的开销。