如何检索在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在这个问题上显然是行不通的。绑定到SelectedItem是显而易见的。叹息)
我需要解决方案来正确地与TreeViewItem的IsSelected属性交互,所以这是我是如何做到的:
// the Type CustomThing needs to implement IsSelected with notification
// for this to work.
public class CustomTreeView : TreeView
{
public CustomThing SelectedCustomThing
{
get
{
return (CustomThing)GetValue(SelectedNode_Property);
}
set
{
SetValue(SelectedNode_Property, value);
if(value != null) value.IsSelected = true;
}
}
public static DependencyProperty SelectedNode_Property =
DependencyProperty.Register(
"SelectedCustomThing",
typeof(CustomThing),
typeof(CustomTreeView),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.None,
SelectedNodeChanged));
public CustomTreeView(): base()
{
this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(SelectedItemChanged_CustomHandler);
}
void SelectedItemChanged_CustomHandler(object sender, RoutedPropertyChangedEventArgs<object> e)
{
SetValue(SelectedNode_Property, SelectedItem);
}
private static void SelectedNodeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var treeView = d as CustomTreeView;
var newNode = e.NewValue as CustomThing;
treeView.SelectedCustomThing = (CustomThing)e.NewValue;
}
}
用这个XAML:
<local:CustonTreeView ItemsSource="{Binding TreeRoot}"
SelectedCustomThing="{Binding SelectedNode,Mode=TwoWay}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
</local:CustonTreeView>
这可以以一种“更好”的方式完成,只使用绑定和GalaSoft MVVM Light库的EventToCommand。在您的VM中添加一个命令,当所选项目发生变化时将调用该命令,并初始化该命令以执行任何必要的操作。在这个例子中,我使用了一个RelayCommand,只设置SelectedCluster属性。
public class ViewModel
{
public ViewModel()
{
SelectedClusterChanged = new RelayCommand<Cluster>( c => SelectedCluster = c );
}
public RelayCommand<Cluster> SelectedClusterChanged { get; private set; }
public Cluster SelectedCluster { get; private set; }
}
然后在xaml中添加EventToCommand行为。使用混合非常简单。
<TreeView
x:Name="lstClusters"
ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource HoofdCLusterTemplate}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding SelectedClusterChanged}" CommandParameter="{Binding ElementName=lstClusters,Path=SelectedValue}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
我提出了这个解决方案(我认为这是最简单的,并且没有内存泄漏),它非常适合从视图的选定项更新ViewModel的选定项。
请注意,从ViewModel中更改所选项不会更新视图中的所选项。
public class TreeViewEx : TreeView
{
public static readonly DependencyProperty SelectedItemExProperty = DependencyProperty.Register("SelectedItemEx", typeof(object), typeof(TreeViewEx), new FrameworkPropertyMetadata(default(object))
{
BindsTwoWayByDefault = true // Required in order to avoid setting the "BindingMode" from the XAML
});
public object SelectedItemEx
{
get => GetValue(SelectedItemExProperty);
set => SetValue(SelectedItemExProperty, value);
}
protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
{
SelectedItemEx = e.NewValue;
}
}
XAML usage
<l:TreeViewEx ItemsSource="{Binding Path=Items}" SelectedItemEx="{Binding Path=SelectedItem}" >