代码之家  ›  专栏  ›  技术社区  ›  dthrasher

在流文档的超链接上使用上下文菜单

  •  1
  • dthrasher  · 技术社区  · 15 年前

    我想在连接到FlowDocument中的超链接的ContextMenu中显示几个操作。其中一些操作取决于超链接对象的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>
    

    1 回复  |  直到 15 年前
        1
  •  3
  •   Quartermeister    15 年前

    这个框架实际上是在PopupControlService.所有者属性,但它是一个内部类。如果您愿意使用未记录的功能,可以迭代上下文菜单上的属性并将其拉出:

    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

    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);
        }
    }
    

    请注意,可能有多个ContentElements具有ContextMenu属性,这实际上会为所有这些属性设置所有者,即使这只对实际显示的一个有影响。

    要获取特定MenuItem的值,必须遍历树或使用绑定 {RelativeSource AncestorType=ContextMenu} . 您还可以标记继承的所有者属性,使其自动传播到MenuItems。

    如果您将上下文菜单附加到比超链接更高的级别,则可以使用OriginalSource而不是sender,但这通常会给您一个运行时间,因此您必须在树上查找超链接。

    推荐文章