WPF的ContextMenu沒有類似WinForm里面ContextMenu.SourceControl的概念,但是你可以通過ContextMenuService的GetPlacementTarget方法來獲取類似的效果。
很多時候,我們會希望在WPF的資源文件里面定義一個通用的右鍵彈出菜單,然后將這個菜單通過定義在各個控件的ContextMenu屬性來設置用戶右擊控件時彈出菜單。然而因為WPF的一些設計不足,你不能在右鍵菜單的點擊事件處理函數中獲知右鍵菜單彈出時,鼠標的焦點是在哪個控件上?
例如下面的代碼:
XAML代碼:
<Window.Resources>
<ContextMenux:Key="sampleContextMenu">
<MenuItemHeader="MenuItem1"Click="WhoBringMeOut"/>
ContextMenu>
...
Window.Resources>
<TreeView>
<TreeViewItemHeader="TreeViewItem1"ContextMenu="{StaticResource
sampleContextMenu}"/>
<TreeViewItemHeader="TreeViewItem2"ContextMenu="{StaticResource
sampleContextMenu}"/>
<TreeViewItemHeader="TreeViewItem3"/>
TreeView>
<DockPanelContextMenu="{StaticResource
sampleContextMenu}">
<ImageSource="img1.ico"/>
<TextBlockText="QuicklyAccess"/>
DockPanel>
C#代碼:
public?void?WhoBringMeOut(object?sender,
RoutedEventArgs e)
{
//
sender的值是被點擊的MenuItem,而不是觸發右鍵菜單
//彈出的控件,例如TreeViewItem,或者是DockPanel
}
這種情況下你可以通過ContextMenuService的GetPlacementTarget方法來獲取類似的效果。
然而,看起來WPF在MenuItem.Click事件處理上面有一點bug,就是你不能通過(sender as
MenuItem).ContextMenu
獲取到點擊的右鍵菜單,只好求助于LogicalTreeHelper.GetParent方法了,
使用下面的方法獲取到ContextMenu的Owner:?ContextMenuService.GetPlacementTarget(LogicalTreeHelper.GetParent(sender
as MenuItem))
也就是說上面的C#代碼改成下面的樣子就可以了:
public?void?WhoBringMeOut(object?sender,
RoutedEventArgs e)
{
ContextMenuService.GetPlacementTarget(
LogicalTreeHelper.GetParent(sender?as?MenuItem));
}