摘要:我的全局“ContextMenu”样式未应用于文本框和其他控件上的默认上下文菜单。
具体说明:我的应用程序中有一些没有显式上下文菜单的文本框。因此,当您右键单击它们时,您会看到标准的上下文菜单选项“剪切”、“复制”和“粘贴”。但是,该上下文菜单最终并未使用我在 Generic.xaml 中设置的全局“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>
Run Code Online (Sandbox Code Playgroud)
但我真的不想为了让 WPF 应用正确的样式而创建这个完全冗余的 ContextMenu。另外,除了 TextBox 之外,还有其他控件在单击时显示 ContextMenus,并且这些控件也不会采用全局 ContextMenu 样式。
那么,当我右键单击未定义显式 ContectMenu 的 TextBox 时,实际上会显示什么?那东西不是ContextMenu吗?为什么它不使用全局ContextMenu样式?
编辑:使用 Snoop 进一步研究这一点,我发现当我显式添加 ContextMenu 时,它在可视化树中显示为 ContextMenu。但显示的默认 ContextMenu 在可视化树中显示为 EditorContextMenu。那么,下一个问题是如何全局设置 EditorContextMenu 的样式。
如您所知,我们无法直接在 ResourceDictionary xaml 中针对内部或私有类重新定义任何样式,但我们可以从代码隐藏中执行此操作。
因此,我们只需要通过反射找到类型并使用 BasedOn 我们默认的 ContextMenu 和 MenuItem 样式创建新样式。
private void Initialize()
{
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);
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我们还可以生成自定义 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>
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)