Say I have a 3-level data-bound WPF TreeView like this one:
- a
- aa
- aaa
- bbb
- ccc
- aa
- b
- aa
- bb
- aaa
- c
- aa
- aaa
- bb
- cc
- aaa
- bbb
- ccc
- aa
where the selected node is bbb under cc under c. Is there a way to bind to say, cc, from some control living outside the TreeView?
UPDATE
Where I’m trying to get at here is to something similar to how you can bind to a selected item in a ListBox using this syntax:
<TextBox Text="{Binding Path=VM.Definitions/term}" />
where a ListBox ItemsSource is bound to VM.Definitions and ListBox.IsSynchronizedWithCurrentItem is set to True. I’m trying to figure out if there is a similar approach to bind to a specific level of a TreeView with scoped HierarchicalDataTemplates.
HOW I MADE IT WORK:
I accepted H.B. answers, but it was a combination of both his and Tim Murphy’s answers that made me “see the light”. Thing is that you can’t (AFAIK) bind to levels of a TreeView like you can bind to the single level of a ListBox (actually you can, but not to a specific level).
So I realized that all I have to do is to link back to my VM whatever is selected on each level of the TreeView whenever the selection changes. For example, say you have a TreeView with three levels Customer, Order, OrderItem. In the SelectedItemChanged, you set back in your VM each level.
If the selected item is a Customer, you then have VM.SelectedCustomer set to the Customer, and VM.SelectedOrder and VM.SelectedOrderItem set to null. If the selected item is an Order, then you set VM.SelectedCustomer to the parent item of the selected item, you set VM.SelectedOrder to the selected item, and VM.SelectedOrderItem to null. And so on.
A quick example (not my actual code, just to demo the concept):
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;
}
}
Edit: This kind of behavior is considerably complicated and the tools the TreeView gives you are not exactly thrilling. Sadly i cannot give you a complete answer on this but only a few pointers.
CurrentItemproperty which returns the item on the path of the selection at the current level, i.e. the item which owns the subbranch which ultimately contains the selected item.Upward navigation would be quite helpful in this case i think, so having a
Parentmay be a good idea as well. e.g. if the selected item is changed you can go up the tree and change theCurrentItemproperty respectively, (the following may be rather bad/incorrect example code)Bindings could then be done via a path of
CurrentItemsproperties:Well, you can bind to pretty much anything, the question normally is how do you point to it.
(Assume
TreeViewto be namedtv, also assumes all items to beTreeViewItemsrather than data)In this case if you can make a binding relative to the selection to get to that
cc:This of course will bind to
ccwith any subselection, not onlybbb.Or you can drill down via indices, independent from any selection:
You might want to be more specific about what you want to achieve.