TreeView在View模型中同步到SelectedItem

时间:2009-11-12 16:29:33

标签: wpf treeview viewmodel selecteditem

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

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

有没有人为此提供干净的解决方案?

2 个答案:

答案 0 :(得分:1)

我可以提供一个例子。 我所做的是在视图模型中设置IsSelected(而不是TreeViewItem本身)的TreeView属性,因为您可以绑定到此属性。

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

在视图模型中,我设置了数据类IsExpanded的{​​{1}}和IsSelected属性。由于下面定义的样式,他们会将此设置传递给YourDomainType

这对你有用吗?

TreeViewItem

答案 1 :(得分:0)

您可以使用某种代理类将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}"/>