WPF默认TextBox ContextMenu样式

时间:2015-06-19 14:40:22

标签: wpf xaml

摘要:我的全局“ContextMenu”样式未应用于文本框和其他控件的默认上下文菜单。

细节:我的应用程序中有一些没有显式ContextMenu的TextBox。因此,当您右键单击它们时,您会看到剪切,复制和粘贴的标准上下文菜单选项。但是,该上下文菜单最终不会使用我在Generic.xaml中设置的全局“ContextMenu”样式。 TextBox上的默认上下文菜单实际上不是ContextMenu吗?

如果我显式设置了Textbox的ContextMenu,那么菜单将使用我的全局ContextMenu样式。例如,这很好用:

<Style TargetType="{x:Type TextBox}">
    <Setter Property="ContextMenu" Value="{StaticResource StandardContextMenu}"/>
</Style>

<ContextMenu x:Key="StandardContextMenu">
    <MenuItem Header="Cut" Command="ApplicationCommands.Cut"/>
    <MenuItem Header="Copy" Command="ApplicationCommands.Copy"/>
    <MenuItem Header="Paste" Command="ApplicationCommands.Paste"/>
</ContextMenu>

但我真的不想创建这个完全冗余的ContextMenu只是为了让WPF应用正确的样式。另外,除了TextBox之外还有其他控件在单击时显示ContextMenus,而且这些控件也不会获取全局ContextMenu样式。

那么,当我右键单击没有明确定义ContectMenu的TextBox时,实际显示的内容是什么?那不是ContextMenu吗?为什么不使用全局ContextMenu样式?

修改: 使用Snoop进一步研究,我发现当我明确添加一个ContextMenu时,它在可视化树中显示为ContextMenu。但是显示的默认ContextMenu在可视化树中显示为EditorContextMenu。接下来的问题是如何在全局范围内设置EditorContextMenu的样式。

Context Menus

2 个答案:

答案 0 :(得分:1)

你很难创建自定义上下文菜单,因为它的样式确实不受支持,据我所知,这是不可能的。但是,我建议你只定义每个项目的命令和没有明确的标题文本:

<ContextMenu x:Key="TextBoxContextMenu">
    <MenuItem Command="Cut"/>
    <MenuItem Command="Copy"/>
    <MenuItem Command="Paste"/>
</ContextMenu>

仅定义命令将自动设置用户系统语言的标题文本和快捷键。

另外,不要忘记在PasswordBox,ComboBox和其他文本编辑控件上应用此上下文菜单。祝你好运!

答案 1 :(得分:0)

您知道,我们无法直接在ResourceDictionary xaml中将任何样式重新定义为内部或私有类,但是我们可以从后面的代码中完成。

因此,我们只需要通过反射找到类型,并使用默认的ContextMenu和MenuItem样式BasedOn创建新样式。

var presentationFrameworkAssembly = typeof(Application).Assembly;
var contextMenuStyle = FindResource(typeof(ContextMenu)) as Style;
var editorContextMenuType = Type.GetType("System.Windows.Documents.TextEditorContextMenu+EditorContextMenu, " + presentationFrameworkAssembly);

if (editorContextMenuType != null)
{
  var editorContextMenuStyle = new Style(editorContextMenuType, contextMenuStyle);
  Application.Current.Resources.Add(editorContextMenuType, editorContextMenuStyle);
}

var menuItemStyle = Application.Current.FindResource(typeof(MenuItem)) as Style;
var editorMenuItemType = Type.GetType("System.Windows.Documents.TextEditorContextMenu+EditorMenuItem, " + presentationFrameworkAssembly);

if (editorMenuItemType != null)
{
  var editorContextMenuStyle = new Style(editorMenuItemType, menuItemStyle);
  Application.Current.Resources.Add(editorMenuItemType, editorContextMenuStyle);
}

此外,我们可以生成自定义ResourceDictionary来重新定义默认的隐藏样式,并生成一个虚拟的DefaultHiddenStyle.xaml以允许其与其他版本一样包含在MergedDictionaries中。

<local:DefaultHiddenStyleResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:Styles">

  <!-- No entries are required -->

</local:DefaultHiddenStyleResourceDictionary>

namespace Styles
{
  public class DefaultHiddenStyleResourceDictionary : ResourceDictionary
  {
    public DefaultHiddenStyleResourceDictionary()
    {
      // Run OnResourceDictionaryLoaded asynchronously to ensure other ResourceDictionary are already loaded before adding new entries
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(OnResourceDictionaryLoaded));
    }

    private void OnResourceDictionaryLoaded()
    {
      var presentationFrameworkAssembly = typeof(Application).Assembly;

      AddEditorContextMenuDefaultStyle(presentationFrameworkAssembly);
      AddEditorMenuItemDefaultStyle(presentationFrameworkAssembly);
    }

    private void AddEditorContextMenuDefaultStyle()
    {
      var presentationFrameworkAssembly = typeof(Application).Assembly;
      var contextMenuStyle = Application.Current.FindResource(typeof(ContextMenu)) as Style;
      var editorContextMenuType = Type.GetType("System.Windows.Documents.TextEditorContextMenu+EditorContextMenu, " + presentationFrameworkAssembly);

      if (editorContextMenuType != null)
      {
        var editorContextMenuStyle = new Style(editorContextMenuType, contextMenuStyle);
        Add(editorContextMenuType, editorContextMenuStyle);
      }
    }

    private void AddEditorMenuItemDefaultStyle(Assembly presentationFrameworkAssembly)
    {
      var menuItemStyle = Application.Current.FindResource(typeof(MenuItem)) as Style;
      var editorMenuItemType = Type.GetType("System.Windows.Documents.TextEditorContextMenu+EditorMenuItem, " + presentationFrameworkAssembly);

      if (editorMenuItemType != null)
      {
        var editorContextMenuStyle = new Style(editorMenuItemType, menuItemStyle);
        Add(editorMenuItemType, editorContextMenuStyle);
      }
    }
  }
}