How to select an item in a TreeView, clicking in the right button?
Hi,
I want to be able to reproduce the normal behaviour when we click a treeview with the right button, this is, it gets selected and the context menu opens.
What i really don't know how to do it is selecting the item automaticly...
Can somebody give me lights here?
Thx,
Nuno
[326 byte] By [
lpx] at [2008-1-8]
Hi,
You could implement the MouseDown event and check in the MouseButtonEventArgs if the right button was clicked. If that's the case, select the item.
Best regards,
Benny
I'm sorry but i think i didnt understood your tip.
See if the right button was clicked its easy, but.. how can i see if the mousedown catched an element?
I cant see how can i get a possible selected item the way you suggest.
I have seen technics for doing this before, in .net 2.0. It consisted in getting the mouse point and then try to see if that point corresponded to an element in the treeview.
Can you give me a code snippet?
lpx at 2007-10-2 >

Hi,
Yes, I can. A code snippet:
Code Snippet
<Window x:Class="Sample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Sample" WindowState="Maximized" x:Name="window"
>
<Grid>
<TreeView x:Name="treeview">
<TreeViewItem Header="TreeViewItem1"></TreeViewItem>
<TreeViewItem Header="TreeViewItem2">
<TreeViewItem Header="TreeViewItem3"></TreeViewItem>
<TreeViewItem Header="TreeViewItem4">
<TreeViewItem Header="TreeViewItem5"></TreeViewItem>
<TreeViewItem Header="TreeViewItem6"></TreeViewItem>
</TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="TreeViewItem7"></TreeViewItem>
<TreeViewItem Header="TreeViewItem8"></TreeViewItem>
</TreeView>
</Grid>
</Window>
public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
//Attach Mouse Down handler
foreach (TreeViewItem item in treeview.Items)
{
AttachMouseDown(item);
}
}
private void AttachMouseDown(TreeViewItem item)
{
item.MouseDown += new MouseButtonEventHandler(item_MouseDown);
if (item.Items.Count != 0)
{
foreach (TreeViewItem childitem in item.Items)
{
AttachMouseDown(childitem);
}
}
}
void item_MouseDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = e.Source as TreeViewItem;
if (e.RightButton == MouseButtonState.Pressed)
{
item.IsSelected = true;
MessageBox.Show(String.Format("{0} has been right clicked!",item.Header));
}
}
}
Best regards,
Benny
you can just an an event handler on the treeview
void
Window3_Loaded(object sender, RoutedEventArgs e) {
treeview.AddHandler(
TreeViewItem.MouseDownEvent,new MouseButtonEventHandler(tvi_MouseDown)); }
void tvi_MouseDown(object sender, MouseButtonEventArgs e) {
TreeViewItem item = e.Source as TreeViewItem; if (e.RightButton == MouseButtonState.Pressed) {
item.IsSelected =
true; MessageBox.Show(String.Format("{0} has been right clicked!", item.Header)); }
}
This doesnt work.
Now, every time i click in the right button it selects me the base node... 
This is what i have:
Code SnippetIn my window.xaml.cs
tvNetworkExplorer.AddHandler(TreeViewItem.MouseDownEvent, new MouseButtonEventHandler(ne.tvNetworkExplorer_MouseDown));
tvNetworkExplorer.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(ne.tvNetworkExplorer_SelectedItemChanged);
In another file:
public void tvNetworkExplorer_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
TreeViewItem item = e.Source as TreeViewItem;
if (e.RightButton == MouseButtonState.Pressed)
{
item.IsSelected = true;
}
}
Whats wrong?
Nuno
lpx at 2007-10-2 >

Thx for the code snippet. It works, but not on my Tree

I have tried your code stand alone and it works.
I made the same thing in my context and it doesnt work. Really strange.
Any clue?
Thx,
Nuno
lpx at 2007-10-2 >

Hi,
I'm having a problem with this. With the code that Benny provided everything works perfectly, but the Tree is also a perfect tree composed of TreeViewItem's.
My tree is populated thru DataContext, from a class made by me, implementing the ObservableCollection.
The code provided, in this case doesnt work.
Does anyone has a clue why this happens and what i have to do in order to have this working on my custom made tree?
Thx,
Nuno
lpx at 2007-10-2 >

Hi there,
the reason why Benny's code is not working is that Benny added treeviewitems to the treeview directly while you are setting the itemsource and passing a collection of objects that you defined.
When you add treeview items the treeview will push those tree view item objects in its Items collection while if you push your own object the treeview will push those objects in the items collection..
P.S this is since there is this method in the treeview control
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is TreeViewItem;
}
Any way... HOW TO FIX THIS
public Window1()
{
InitializeComponent();
treeview.ItemsSource = new string[]
{
"Hello",
"Hello",
"Hello",
"Hello",
"Hello"
};
this.Loaded += new RoutedEventHandler(Window1_Loaded);
}
void Window1_Loaded(object sender, RoutedEventArgs e)
{
//Attach Mouse Down handler
foreach (object item in treeview.Items)
{
TreeViewItem treeItem = treeview.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
AttachMouseDown(treeItem);
}
}
private void AttachMouseDown(TreeViewItem item)
{
item.MouseDown += new MouseButtonEventHandler(item_MouseDown);
if (item.Items.Count != 0)
{
foreach (object itemObj in item.Items)
{
TreeViewItem treeItem = treeview.ItemContainerGenerator.ContainerFromItem(itemObj) as TreeViewItem;
AttachMouseDown(treeItem);
}
}
}
void item_MouseDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (e.RightButton == MouseButtonState.Pressed)
{
item.IsSelected = true;
MessageBox.Show(String.Format("{0} has been right clicked!", item.Header));
}
}
as you can see I am using Benny's code with the only difference that this code first gets the treeview item (ItemContainerGenerator.ContainerFromItem(itemObj))
I hope this helps... if not let us know 
REGARDS
Hi,
Sorry, i previously marked this as an answer but i havent looked at it until today.
It didnt worked.
I created a project with all the relevant information about this issue:
http://www.imaginando.net/~lpx/AnotherTreeViewTest.zip
The only problem is that the items are not being represented as in my original project, something wrong but i cant find what.
But everything is there and i will specify whats wrong when i found it. Maybe its something so simple that some of you will see it imediatly.
I hope you could help me out as i'm already saturated with this issue.
Many thx,
Best regards,
Nuno
lpx at 2007-10-2 >

I had the same problem. Here is the code you need (I'm also populating my tree via setting the ItemsSource property):
Code Snippet
public Object FindParentControlOfType(object childObject, Type type)
{
FrameworkElement childElement = childObject as FrameworkElement;
if ((childElement != null) && childElement.GetType() == type)
return childElement;
if (childElement == null)
return null;
FrameworkElement parentElement = VisualTreeHelper.GetParent(childElement) as FrameworkElement;
if (parentElement == null)
return null;
if (parentElement.GetType() == type)
return parentElement;
return FindParentControlOfType(parentElement, type);
}
public YourTreeViewClass()
{
InitializeComponent();
YourTreeViewClass.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(YourTreeViewClass_MouseRightButtonDown);
}
void YourTreeViewClass_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//on right click, select the item so that if someone chooses an operation from the context menu, we know which
//item to operate on.
TreeViewItem item = FindParentControlOfType(e.OriginalSource, typeof(TreeViewItem)) as TreeViewItem;
if (item != null)
{
item.IsSelected = true;
}
}
Hi,
My main problem as finally been solved! Thx a lot! That was messing my mind up.
But now i have another problem which is somekind related.
I want to expand a node and its children by the time its created (to avoid that boring thing of expanding them by and.
I have created an event handler for the collection changed event on my items source.
And the i was doing the following:
Code Snippet
void networkExplorer_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (object obj in e.NewItems)
{
TreeViewItem item = FindParentControlOfType(obj, typeof(TreeViewItem)) as TreeViewItem;
ExpandNodeAndItsChildren(item);
}
}
Where ExpandNodeAndItsChildren is:
Code Snippet
private void ExpandNodeAndItsChildren(TreeViewItem item)
{
item.IsExpanded = true;
foreach (TreeViewItem childItem in item.Items)
{
ExpandNodeAndItsChildren(childItem);
}
}
But i cant get the TreeViewItem.
I think i can understand why. When i'm clicking in a treeview, what i'm clicking is in a visual element, so that mut be translated into a TReeViewItem.
In this case i really have an item of my type and i want to get the TreeViewItem that contains it.
Well... can someone give me a tip here?
Many thx,
Nuno
lpx at 2007-10-2 >

You need to add an observer for the ItemContainerGenerator:
Code Snippet
private void SomeMethodYouCallAfterPopulatingYourTree(TreeViewItem yourTreeViewItem)
{
if (yourTreeViewItem.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
// items aren't generated, let us know when they are
yourTreeViewItem.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
}
else
{
yourTreeViewItem.IsSelected = true;
}
}
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
// a selection is pending, try to select the procedure
ItemContainerGenerator items = sender as ItemContainerGenerator;
if (items != null && items.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
TreeViewItem tvi = items.ContainerFromIndex(0) as TreeViewItem;
if (tvi != null)
tvi.IsSelected = true;
}
}
}
There are ways of handling this so that can set IsSelected on TreeViewItem for right click.
Strategy 1: In the lowest VisualTree object (typically the application object of interest that the tree items are used for) you can add a reference to the TreeViewItem as a member. This would need to be done as you populate the tree. This associates the TreeViewItem with the object so that you don't need to search up the VisualTree.
Strategy 2: Search up the VisualTree for object of TreeViewItem type. This thread has example. Recursively use VisualTreeHelper to get Parent until TreeViewItem object found.
Strategy 3: This is the most elegant. Use a HierarchicalDataTemplate. Bind the Tag of lowest VisualTree object (typically the application object of interest that the tree items are used for) to RelativeSource with FindAncestor Mode and Ancestor Type of TreeViewItem. This works for sure as I have implemented it for app. Then when select item, it's Tag is the associated TreeViewItem. This is similar to Strategy 1 but the template does it automatically for you.