It's simpler.
Http://www.cnblogs.com/anqincmt/archive/2008/10/23/1318001.html
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.
[Idea]
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)
[Special Points]
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.
[Implementation]
The code is simple:
Code
Public static TreeViewItem SelectItemByRightClick (ItemsControl source)
{
//////////////////////////////////////// /////////////////////////////////////
//
// Note: For TreeViewItem, if it is selected, it must be that its parent node is also selected.
//
//////////////////////////////////////// /////////////////////////////////////
If (! (Source is TreeView )&&! (Source is TreeViewItem ))
{
Throw new ArgumentException ("only TreeView or TreeViewItem", "source ");
}
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;
Return selectedItem;
}
}
CurrentItem. IsSelected = true;
Return currentItem;
}
}
Return null;
}
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
<TreeView x: Name = "DemoTreeView"
Local: TreeViewHelper. EnableRightClickSelection = "True"
[Note]
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
[Appendix]
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.
Example: http://files.cnblogs.com/RMay/TreeViewRightClick/MessageBoxTricks.rar
[Supplement]
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:
Code
Private static void TreeViewItem_PreviewMouseRightButtonDown (object sender, MouseButtonEventArgs e)
{
// Note that the sender here is TreeView
// We Need To Get The TreeViewItem from e. OriginalSource.
TreeViewItem item = GetTemplatedAncestor <TreeViewItem> (e. OriginalSource as FrameworkElement );
Item. IsSelected = true;
}
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 );
}
Return null;
}
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:
Code
Private static void OnEnableRightClickSelectionChanged (DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
TreeView treeView = sender as TreeView;
If (treeView! = Null)
{
// Use the RoutedEvent feature to enable the TreeView to process the PreviewMouseRightButtonDown event of the TreeViewItem
If (bool) e. NewValue)
{
TreeView. AddHandler (
TreeViewItem. PreviewMouseRightButtonDownEvent,
New MouseButtonEventHandler (TreeViewItem_PreviewMouseRightButtonDown ));
}
Else
{
TreeView. RemoveHandler (
TreeViewItem. PreviewMouseRightButtonDownEvent,
New MouseButtonEventHandler (TreeViewItem_PreviewMouseRightButtonDown ));
}
}
}
When using it, you can describe it in xaml:
Code
<TreeView x: Name = "DemoTreeView"
Local: TreeViewHelper2.EnableRightClickSelection = "True"
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.
Download Code:
Http://files.cnblogs.com/RMay/TreeViewRightClick/TreeViewRightClick2.rar