【问题标题】:How can I bind to a specific level of a WPF TreeView?如何绑定到 WPF TreeView 的特定级别?
【发布时间】:2011-08-12 17:53:48
【问题描述】:

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

  • 一个
    • aa
      • aaa
      • bbb
      • ccc
  • b
    • bb
      • aaa
  • c
    • aa
      • aaa
    • bb
    • 抄送
      • 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。例如,假设您有一个包含三个级别 Customer、Order、OrderItem 的 TreeView。在 SelectedItemChanged 中,您在 VM 中设置了每个级别。

如果所选项目是客户,则您将 VM.SelectedCustomer 设置为客户,并将 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;
    }
}

【问题讨论】:

  • 你在使用 MVVM 模式吗?您喜欢哪种语言阅读?
  • 我相信我所做的主要是遵循 MVVM 模式; “代码隐藏”是 C#

标签: .net wpf data-binding treeview


【解决方案1】:

编辑:这种行为相当复杂,TreeView 为您提供的工具并不令人兴奋。很遗憾,我不能给你一个完整的答案,只能给你一些建议。

  • 您的 VM 可以公开一个 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}

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

【讨论】:

  • 我更新了我的问题以澄清我想要完成的工作。
  • 是的,谢谢您的回答对推动正确方向的思考有很大帮助。你可以看到我是如何让它工作的更新。
【解决方案2】:

如果您已经在使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-09-23
    • 2013-02-22
    • 2017-07-09
    • 2011-01-31
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多