How is it possible to programmatically select an item in a WPF TreeView
? The ItemsControl
model seems to prevent it.
You need to get the TreeViewItem
and then set IsSelected
to true
.
Try with this
/// <summary>
/// Selects the tree view item.
/// </summary>
/// <param name="Collection">The collection.</param>
/// <param name="Value">The value.</param>
/// <returns></returns>
private TreeViewItem SelectTreeViewItem(ItemCollection Collection, String Value)
{
if (Collection == null) return null;
foreach(TreeViewItem Item in Collection)
{
/// Find in current
if (Item.Header.Equals(Value))
{
Item.IsSelected = true;
return Item;
}
/// Find in Childs
if (Item.Items != null)
{
TreeViewItem childItem = this.SelectTreeViewItem(Item.Items, Value);
if (childItem != null)
{
Item.IsExpanded = true;
return childItem;
}
}
}
return null;
}
Reference: http://amastaneh.blogspot.com/2011/06/wpf-selectedvalue-for-treeview.html
This is my solution. The others failed for me in various ways. You need to walk the tree from top to bottom, looking for the tree item at each level, expanding and updating the layout along the way.
This function takes a stack of nodes where the first one out of the stack is the top most node, and each subsequent node on the stack is a child of the previous parent. The second argument is the TreeView.
As each item is found, that item is expanded, and the final item is returned, where the caller can select it.
TreeViewItem FindTreeViewItem( Stack<object> nodeStack, TreeView treeView )
{
ItemsControl itemsControl = treeView;
while (nodeStack.Count > 0) {
object node = nodeStack.Pop();
bool found = false;
foreach (object item in itemsControl.Items) {
if (item == node) {
found = true;
if (itemsControl.ItemContainerGenerator.ContainerFromItem( item ) is TreeViewItem treeViewItem) {
if (nodeStack.Count == 0) {
return treeViewItem;
}
itemsControl = treeViewItem;
treeViewItem.IsExpanded = true;
treeViewItem.UpdateLayout();
break;
}
}
}
if (!found) {
return null;
}
}
return null;
}
Example of how to call it:
// Build nodeStack here from your data
TreeViewItem treeViewItem = FindTreeViewItem( nodeStack, treeView );
if (treeViewItem != null) {
treeViewItem.IsSelected = true;
treeViewItem.BringIntoView();
}
It's a real pain for some strange reason, you have to use ContainerFromItem to get the container, then invoke the select method.
// selectedItemObject is not a TreeViewItem, but an item from the collection that
// populated the TreeView.
var tvi = treeView.ItemContainerGenerator.ContainerFromItem(selectedItemObject)
as TreeViewItem;
if (tvi != null)
{
tvi.IsSelected = true;
}
There once was a blog entry on how to do it here, but the link is dead now.
For those who are still looking for the right solution to this problem here is the one below. I found this one in the comments to the Code Project article “WPF TreeView Selection” http://www.codeproject.com/KB/WPF/TreeView_SelectionWPF.aspx by DaWanderer. It was posted by Kenrae on Nov 25 2008. This worked great for me. Thanks Kenrae!
Instead of walking the tree, have your own data object have the IsSelected property (and I recommend the IsExpanded property too). Define a style for the TreeViewItems of the tree using the ItemContainerStyle property on the TreeView that binds those properties from the TreeViewItem to your data objects. Something like this:
<Style x:Key="LibraryTreeViewItemStyle"
TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded"
Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected"
Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight"
Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="FontWeight"
Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
<TreeView ItemsSource="{Binding Path=YourCollection}"
ItemContainerStyle="{StaticResource LibraryTreeViewItemStyle}"
ItemTemplate={StaticResource YourHierarchicalDataTemplate}/>
Just thought I would chime in with the solution I went with, in case this can help anyone. Note that the best way to do this is using a bound property like 'IsSelected' as per kuninl's answer, but in my case it was a legacy application that did not follow MVVM, so I ended up with the below.
private void ChangeSessionSelection()
{
foreach (SessionContainer item in this.treeActiveSessions.Items)
{
var treeviewItem = this.treeActiveSessions.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (item.Session == this.selectedSession.Session)
{
treeviewItem.IsSelected = true;
treeviewItem.IsExpanded = true;
}
else
{
treeviewItem.IsSelected = false;
treeviewItem.IsExpanded = false;
}
}
}
What this does is select and expand the treeview item in the UI that represents the selected dataitem in the code behind. The purpose of this was to have the selection change in the treeview when the users selection changed in an items control in the same window.