假设我有一个像这样的3级数据绑定WPF TreeView:
所选节点在 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;
}
}
答案 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