Как я могу привязаться к определенному уровню WPF TreeView? - PullRequest
2 голосов
/ 12 августа 2011

Скажем, у меня есть трехуровневый WPF TreeView с привязкой к данным, подобный этому:

  • а
    • аа
      • ааа
      • 1010 * ГЭБ *
      • ссс
  • б
    • аа
    • бб
      • ааа
  • с
    • аа
      • ааа
    • бб
    • см
      • ааа
      • 1050 * ГЭБ *
      • ссс

где выбранный узел bbb в cc в c . Есть ли способ связать, скажем, cc , от какого-либо элемента управления, живущего вне TreeView?

UPDATE

Здесь я пытаюсь найти нечто похожее на то, как вы можете привязать выбранный элемент в ListBox, используя этот синтаксис:

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

, где ListBox ItemsSource связан с VM.Definitions и ListBox.IsSynchronizedWithCurrentItem установлен в True. Я пытаюсь выяснить, существует ли подобный подход для привязки к определенному уровню TreeView с областью действия HierarchicalDataTemplates.

КАК ЭТО РАБОТАЕТ:

Я принял H.B. ответы, но это была комбинация ответов его и Тима Мерфи, которые заставили меня «увидеть свет». Дело в том, что вы не можете (AFAIK) привязать к уровням TreeView, как вы можете привязать к одному уровню ListBox (на самом деле вы можете, но не к определенному уровню ).

Итак, я понял, что все, что мне нужно сделать, это связать обратно с моей виртуальной машиной все, что выбрано на каждом уровне TreeView, всякий раз, когда выбор изменяется. Например, скажем, у вас есть TreeView с тремя уровнями Customer, Order, OrderItem. В SelectedItemChanged вы устанавливаете в своей виртуальной машине каждый уровень.

Если выбранный элемент является Customer, тогда для VM.SelectedCustomer установлено значение Customer, а для VM.SelectedOrder и VM.SelectedOrderItem установлено значение null. Если выбранный элемент является Порядком, то вы устанавливаете VM.SelectedCustomer в родительский элемент выбранного элемента, вы устанавливаете VM.SelectedOrder для выбранного элемента, а VM.SelectedOrderItem равным нулю. И так далее.

Быстрый пример (не мой настоящий код, просто для демонстрации концепции):

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 ]

2 голосов
/ 12 августа 2011

Редактировать: Такое поведение значительно усложняется, и инструменты, предоставляемые 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}

Возможно, вы захотите конкретнее рассказать о том, чего хотите достичь.

0 голосов
/ 14 августа 2011

Если вы уже используете шаблон 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
...