TreeView 同步到视图模型中的 SelectedItem

Posted

技术标签:

【中文标题】TreeView 同步到视图模型中的 SelectedItem【英文标题】:TreeView Sync to SelectedItem in View Model 【发布时间】:2010-12-15 23:06:05 【问题描述】:

我在 WPF TreeView 控件之上有一个 ViewModel。我希望 ViewModel 能够从 TreeView 设置和读取 SelectedItem。但是,TreeView 的 SelectedItem 属性不可绑定。

我能够在后面的代码中设置和获取选定的项目(使用 ItemContainerGenerator 和 TreeViewItem.IsSelected = true),但这会导致后面的代码和 ViewModel 之间的通信出现一些丑陋的情况。

有人对此有干净的解决方案吗?

【问题讨论】:

你解决过这个问题吗?我正好有这个问题。 我认为这个问题与***.com/questions/1000040/…重复 【参考方案1】:

我可以举个例子。 我所做的是在视图模型中设置TreeViewItemIsSelected 属性(不是TreeView 本身),因为您可以绑定到它。

在我的视图模型中,我有一个属性ElementInViewModel,它是一个自身形成树的数据结构。 我在 Xaml 中使用 HierarchicalDataTemplate 来显示它。 数据对象本身的类型为YourDomainType,其子元素(相同类型)在其ChildElements 属性中。

在视图模型中,我设置了我的数据类YourDomainTypeIsExpandedIsSelected 属性。由于下面定义的样式,他们会将此设置传递给TreeViewItem

这对你有用吗?

<UserControl>

    <UserControl.Resources>        
        <CollectionViewSource Source="Binding Path=ElementInViewModel" x:Key="Cvs">
        </CollectionViewSource>

        <HierarchicalDataTemplate DataType="x:Type DomainModel:YourDomainType"
                                  ItemsSource="Binding Path=ChildElements">
            <TextBlock Text="Binding Path=Name"/>            
        </HierarchicalDataTemplate>        

        <Style TargetType="x:Type TreeViewItem">
            <Setter Property="IsExpanded" Value="Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged">
            </Setter>
            <Setter Property="IsSelected" Value="Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged">
            </Setter>            
        </Style>

    </UserControl.Resources>


    <DockPanel>
        <TreeView ItemsSource="Binding Source=StaticResource Cvs"/>
    </DockPanel>

</UserControl>

【讨论】:

【参考方案2】:

您可以使用某种代理类将 SelectedItem 属性绑定到 In 属性,并将 Out 属性绑定到您的 ViewModel:

    public class Proxy : FrameworkElement
    
    public static readonly DependencyProperty InProperty;
    public static readonly DependencyProperty OutProperty;

    public Proxy()
    
        Visibility = Visibility.Collapsed;
    

    static Proxy()
    
        var inMetadata = new FrameworkPropertyMetadata(
            delegate(DependencyObject p, DependencyPropertyChangedEventArgs args)
                
                    if (null != BindingOperations.GetBinding(p, OutProperty))
                    
                        var proxy = p as Proxy;
                        if (proxy != null)
                            proxy.Out = args.NewValue;
                    
                );

        inMetadata.BindsTwoWayByDefault = false;
        inMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

        InProperty = DependencyProperty.Register("In",
                                                 typeof (object),
                                                 typeof (Proxy),
                                                 inMetadata);

        var outMetadata = new FrameworkPropertyMetadata(
            delegate(DependencyObject p, DependencyPropertyChangedEventArgs args)
                
                    ValueSource source = DependencyPropertyHelper.GetValueSource(p, args.Property);

                    if (source.BaseValueSource != BaseValueSource.Local)
                    
                        var proxy = p as Proxy;
                        if (proxy != null)
                        
                            var expected = proxy.In;
                            if (!ReferenceEquals(args.NewValue, expected))
                            
                                Dispatcher.CurrentDispatcher.BeginInvoke(
                                    DispatcherPriority.DataBind, new Action(delegate
                                                                                
                                                                                    proxy.Out = proxy.In;
                                                                                ));
                            
                        
                    
                );

        outMetadata.BindsTwoWayByDefault = true;
        outMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

        OutProperty = DependencyProperty.Register("Out",
                                                  typeof (object),
                                                  typeof (Proxy),
                                                  outMetadata);
    

    public object In
    
        get  return GetValue(InProperty); 
        set  SetValue(InProperty, value); 
    

    public object Out
    
        get  return GetValue(OutProperty); 
        set  SetValue(OutProperty, value); 
    

<Proxy In="Binding ElementName=Tree, Path=SelectedItem" Out="Binding SelectedItem, UpdateSourceTrigger=PropertyChanged"/>
<TreeView x:Name="Tree" ItemsSource="Binding Path=Items"/>

【讨论】:

以上是关于TreeView 同步到视图模型中的 SelectedItem的主要内容,如果未能解决你的问题,请参考以下文章

从 Vuejs 中的多个 Treeview 组件中选择数据

使用WPF在虚拟化TreeView中选择节点

php中treeview中的子节点

如何以编程方式选择WPF TreeView中的项目?

TreeView SelectedItem 返回类型

在 XAML 中的 TreeView 中未选择任何内容时禁用 TreeView 上下文菜单项