如何绑定到WPF TreeView的特定级别?

时间:2011-08-12 17:53:48

标签: .net wpf data-binding treeview

假设我有一个像这样的3级数据绑定WPF TreeView:

  • 一个
    • AA
      • AAA
      • BBB
      • CCC
  • b
    • AA
    • BB
      • AAA
  • C
    • AA
      • AAA
    • BB
    • CC
      • AAA
      • BBB
      • CCC

所选节点在 c 下的 cc bbb 。是否有办法从居住在TreeView外部的某个控件绑定 cc

更新

我试图在这里使用以下语法类似于如何使用以下语法绑定到ListBox中的选定项目:

<TextBox Text="{Binding Path=VM.Definitions/term}" />

其中ListBox ItemsSource绑定到VM.Definitions和ListBox.IsSynchronizedWithCurrentItem设置为True。我试图弄清楚是否有类似的方法绑定到具有作用域HierarchicalDataTemplates的TreeView的特定级别。

我如何工作:

我接受了H.B.答案,但这是他和蒂姆墨菲的答案的组合,使我“看到光明”。事情就是你不能(AFAIK)绑定到TreeView的级别,就像你可以绑定到ListBox的单个级别一样(实际上你可以,但不能绑定到特定的级别)。

所以我意识到我所要做的就是在选择发生变化时,无论在TreeView的每个级别上选择什么,都要链接回我的VM。例如,假设您有一个TreeView,其中包含Customer,Order,OrderItem三个级别。在SelectedItemChanged中,您将在每个级别设置回VM。

如果所选项目是Customer,则将VM.SelectedCustomer设置为Customer,将VM.SelectedOrder和VM.SelectedOrderItem设置为null。如果所选项是订单,则将VM.SelectedCustomer设置为所选项的父项,将VM.SelectedOrder设置为所选项,并将VM.SelectedOrderItem设置为null。等等。

一个简单的例子(不是我的实际代码,只是为了演示这个概念):

void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    if (treeViewLesson.SelectedItem == null) {
        VM.SelectedOrderItem = null;
        VM.SelectedOrder = null;
        VM.SelectedCustomer = null;
    }
    else if (treeViewLesson.SelectedItem is Customer) {
        VM.SelectedOrderItem = null;
        VM.SelectedOrder = null;
        VM.SelectedCustomer = treeViewLesson.SelectedItem as Customer;
    }
    else if (treeViewLesson.SelectedItem is Order) {
        VM.SelectedOrderItem = null;
        VM.SelectedOrder = treeViewLesson.SelectedItem as Order;
        VM.SelectedCustomer = VM.SelectedOrder.ParentCustomer;
    }
    else if (treeViewLesson.SelectedItem is OrderItem) {
        VM.SelectedOrderItem = treeViewLesson.SelectedItem as OrderItem;
        VM.SelectedOrder = VM.SelectedOrderItem.ParentOrder;
        VM.SelectedCustomer = VM.SelectedOrder.ParentCustomer;
    }
}

2 个答案:

答案 0 :(得分:2)

编辑:这种行为相当复杂,TreeView为您提供的工具并不十分惊心动魄。可悲的是,我不能给你一个完整的答案,但只有几个指针。

  • 您的虚拟机可能会公开CurrentItem属性,该属性返回当前级别所选路径上的项目,即拥有最终包含所选项目的子分支的项目。
  • 在我认为这种情况下,向上导航会非常有用,所以拥有Parent也可能是一个好主意。例如如果所选项目被更改,您可以上升树并分别更改CurrentItem属性(以下可能是相当糟糕/不正确的示例代码)

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        var oldItem = e.OldValue as TreeViewModel;
        // "Deselect" old branch
        var parent = oldItem.Parent;
        while (parent != null)
        {
            parent.CurrentItem = null;
            parent = parent.Parent;
        }
        // "Select" new branch
        var newItem = e.NewValue as TreeViewModel;
        parent = newItem.Parent;
        while (parent != null)
        {
            parent.CurrentItem = newItem;
            newItem = parent;
            parent = parent.Parent;
        }
    }
    
  • 然后可以通过CurrentItems属性:

    的路径完成绑定
    {Binding Root.CurrentItem.CurrentItem.Value}
    

嗯,你几乎可以绑定任何东西,问题通常是你如何指向它。

假设TreeView被命名为tv,也假定所有项目都是TreeViewItems而不是数据) 在这种情况下,如果您可以相对于选择进行绑定以获取cc

{Binding SelectedItem.Parent, ElementName=tv}

这当然会与任何子选择绑定到cc,而不仅仅是bbb

或者您可以通过索引向下钻取,独立于任何选择:

{Binding Items[2].Items[2], ElementName=tv}

您可能希望更具体地了解您想要实现的目标。

答案 1 :(得分:0)

如果您已经在使用MVVM模式,那么该过程相当容易。

将IsSelected属性添加到视图模型中。当用户选择TreeViewItem时,将设置绑定对象的IsSelected属性。

现在,在IsSelected属性中,更新选择树视图项时要更改的控件的属性。

C#示例

public class TreeViewItemViewModel
{

    public bool IsSelected {
        get { return _isSelected; }
        set {
            if (value != _isSelected) {
                _isSelected = value;
                this.IsSelectedChanged();
            }
        }
    }

    protected virtual void IsSelectedChanged()
    {
        this.RaisePropertyChanged("IsSelected");
        // do custom code
    }

}

VB.NET示例

Public Class TreeViewItemViewModel

    Public Property IsSelected As Boolean
        Get
            Return _isSelected
        End Get
        Set(value As Boolean)
            If value <> _isSelected Then
                _isSelected = value
                Me.IsSelectedChanged()
            End If
        End Set
    End Property

    Protected Overridable Sub IsSelectedChanged()
        Me.RaisePropertyChanged("IsSelected")
        ' do custom code '
    End Sub

End Class