Sometimes we need to implement this function in the TreeView:
Right-click the TreeView and select the TreeViewItem from the shortcut menu. Then we can process the selected data.
However, the TreeView of WPF does not provide the right-click function. We need to implement it ourselves.
The most basic idea is that when a right-click event in a TreeView occurs, we traverse all its items, including sub-items, and obtain the Rect of the TreeViewItem control corresponding to the Item, then, call the Rect Contains method to determine whether the mouse is in this range. (For a simpler method, see the supplement below)
It should be noted that TreeViewItem is an ItemsControl. When we select a subitem of it, its Rect also contains the mouse, as shown in. Therefore, we need to keep searching, until the last TreeViewItem contains the mouse. Obviously, this is a recursive process.
When Level_3_1 is selected, Rect of Root, Level_1_1, and Level_2_1 are considered to contain the mouse position.
The code is simple:Code
Foreach (object item in source. Items)
TreeViewItem currentItem = source. ItemContainerGenerator. ContainerFromItem (item) as TreeViewItem;
Point mousePosition = Mouse. GetPosition (currentItem );
Rect itemRect = VisualTreeHelper. GetDescendantBounds (currentItem );
// It may be the selected item or the parent node of the selected item
If (itemRect. Contains (mousePosition ))
// Check whether the child is selected. Otherwise, the child is selected.
If (currentItem. IsExpanded)
// Only determine the expanded items
TreeViewItem selectedItem = SelectItemByRightClick (currentItem );
If (selectedItem! = Null)
SelectedItem. IsSelected = true;
CurrentItem. IsSelected = true;
For ease of use, I also defined an AttachedProperty so that you can enable the right-click selection function by using a simple xaml statement. For example:Code
When you use AttachedProperty to enable the right-click selection function, pay special attention to the event processing sequence.
First, the PreviewMouseRightButtonDown event occurs in the TreeView, and the code in the TreeViewHelper starts to process the event, followed by the MouseRightButtonDown event. The reason for this phenomenon is that in the TreeViewHelper I wrote, it is handled by listening to PreviewMouseRightButtonDown. During control initialization, we first add our own PreviewMouseRightButtonDown event processing method, then we set the value of the additional attribute, so that we can process the custom event before the TreeViewHelper event is processed.
Therefore, if it is enabled through the additional property, it is best to write other code in the MouseRightButtonDown processing method. If you want to process in PreviewMouseRightButtonDown, do not use additional properties, but manually call TreeViewHelper. SelectItemByRightClick (treeView ). Then write other processing logic. This is illustrated in my sample code.
Code download http://files.cnblogs.com/RMay/TreeViewRightClick/TreeViewRightClick.rar
Another small problem is that you must note the following when calling the Message. Show () method in WPF:
If you call this method in a non-UI thread, you must use Dispatcher. invoke (). Otherwise, the dialog box will block this non-UI thread rather than the UI thread, resulting in a dialog box that looks "non-modal.
Last night I remembered that some features of RoutedEvent can be used to easily implement the right-click selection of TreeView.
We know that in WPF, we can listen to the event of this element on the element's Parent, such:
<TreeView TreeViewItem. PreviewMouseRightButtonDown = "TreeViewItem_PreviewMouseRightButtonDown "...... />
In this way, when the PreviewMouseRightButtonDown event occurs in the TreeViewItem, the event will be intercepted by the TreeView and handled by the event processing method we have defined.
However, unlike normal event registration
Private void TreeViewItem_PreviewMouseRightButtonDown (object sender, MouseButtonEventArgs e)
The sender is not a TreeViewItem, but a TreeView. To get the TreeViewItem, we need to use the OriginalSource attribute in e.
However, if we directly write TreeViewItem item = e. OriginalSource as TreeViewItem, we cannot get it. We can find that e. OriginalSource is a TextBlock. Isn't it TreeView or TreeViewItem? How can I run a TextBlock inexplicably? In fact, this TextBlock is the stuff in the ItemTemplate of the default TreeView provided by WPF. Therefore, we only need to find the TreeViewItem along its TemplatedParent.
The sample code is as follows:
Private static T GetTemplatedAncestor <T> (FrameworkElement) where T: FrameworkElement
If (element is T)
Return element as T;
FrameworkElement templatedParent = element. TemplatedParent as FrameworkElement;
If (templatedParent! = Null)
Return GetTemplatedAncestor <T> (templatedParent );
For ease of use, I still think it is more appropriate to implement AttachedProperty. What if I want TreeView to listen to the events of TreeViewItem in the code? In fact, it is also very simple:
When using it, you can describe it in xaml:
In addition, there is no conflict with the TreeView event at this time. We can rest assured that we can write the logic we want to write in the TreeView PreviewMouseRightButtonDown.