我想在附加到FlowDocument中的超链接的ContextMenu中显示多个操作。其中一些操作取决于Hyperlink对象的NavigateUri属性的值。如何获取用户右键单击的超链接的引用?
不幸的是,它并不像使用PlacementTarget属性那么简单。正如MSDN论坛中的这个(未答复的)问题所指出的,ContextMenu的PlacementTarget并不指向Hyperlink元素,而是指向整个FlowDocumentScrollViewer: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/3ab90017-dea8-497c-a937-87a403cb24e0
所以我需要另一种方法来确定用户点击的超链接。
请注意,我的上下文菜单被定义为包含我的FlowDocumentScrollViewer的UserControl中的资源,并使用样式属性设置器附加到每个超链接,如下所示:
<UserControl.Resources>
<ContextMenu x:Key="contextMenu">
<MenuItem Name="mnuOpen" Header="_Open Link" Click="mnuOpen_Click" />
<MenuItem Name="mnuView" Header="_View Properties" Click="mnuView_Click" />
</ContextMenu>
<Style TargetType="Hyperlink">
<Setter Property="ContextMenu" Value="{DynamicResource contextMenu}" />
</Style>
</UserControl.Resources>
任何提示都将不胜感激!
答案 0 :(得分:3)
框架实际上在PopupControlService.Owner属性中跟踪该值,但它是一个内部类。如果您愿意使用未记录的功能,您可以迭代ContextMenu上的属性并将其拉出来:
private static object GetOwner(ContextMenu menu)
{
var prop = menu.GetLocalValueEnumerator();
while (prop.MoveNext())
{
if (prop.Current.Property.Name == "Owner" &&
prop.Current.Property.OwnerType.Name == "PopupControlService")
{
return prop.Current.Value;
}
}
return null;
}
另一种方法是由超级链接引发ContextMenuService.ContextMenuOpeningEvent,因此您可以使用sender参数并将其放入您自己的附加属性中。像这样:
public class ContextMenuOwnerTracker
{
private static bool isInitialized;
public static void Initialize()
{
if (!isInitialized)
{
isInitialized = true;
EventManager.RegisterClassHandler(typeof(ContentElement),
ContextMenuService.ContextMenuOpeningEvent,
new ContextMenuEventHandler(OnContextMenuOpening));
EventManager.RegisterClassHandler(typeof(ContentElement),
ContextMenuService.ContextMenuClosingEvent,
new ContextMenuEventHandler(OnContextMenuClosing));
}
}
private static void OnContextMenuOpening
(object sender, ContextMenuEventArgs args)
{
var menu = ContextMenuService.GetContextMenu((DependencyObject)sender);
if (menu != null)
{
SetOwner(menu, sender);
}
}
private static void OnContextMenuClosing
(object sender, ContextMenuEventArgs args)
{
var menu = ContextMenuService.GetContextMenu((DependencyObject)sender);
if (menu != null)
{
ClearOwner(menu);
}
}
private static readonly DependencyPropertyKey OwnerKey =
DependencyProperty.RegisterAttachedReadOnly(
"Owner",
typeof(object),
typeof(ContextMenuOwnerTracker),
new PropertyMetadata(null));
public static readonly DependencyProperty OwnerProperty =
OwnerKey.DependencyProperty;
public static object GetOwner(ContextMenu element)
{
return element.GetValue(OwnerProperty);
}
private static void SetOwner(ContextMenu element, object value)
{
element.SetValue(OwnerKey, value);
}
private static void ClearOwner(ContextMenu element)
{
element.ClearValue(OwnerKey);
}
}
请注意,可能有多个具有ContextMenu属性的ContentElements,这实际上会在所有这些属性上设置所有者,即使它只对实际显示的那个有用。
要获取特定MenuItem的值,您必须向上走树或使用{RelativeSource AncestorType=ContextMenu}
绑定。您还可以标记继承的Owner属性,使其自动传播到MenuItems。
如果您将上下文菜单附加到超级链接的更高级别,则可以使用OriginalSource而不是发件人,但这通常会为您提供运行,因此您必须走上树以查找超链接。