我曾经创建了一个样式来修复WPF中菜单项被窃听的外观。它主要是关于菜单文本不对齐的。它在左上角太远,没有使用适当的间距。
我发现它确实在窗口菜单中工作,但是在我现在测试的的上下文菜单中,不是。所以问题是,为什么文本框中的上下文菜单不考虑这种样式?
更新:我发现TextBox使用自己的菜单项类、私有嵌套类TextEditorContextMenu.EditorContextMenu和自己的菜单项--嵌套类EditorMenuItem。两者都来自于ContextMenu和MenuItem,resp。那么,如果它们是我所设计的类的子类,那么为什么我的风格也不适用于它们呢?
我唯一能做的就是复制
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=SubmenuItemTemplateKey}" TargetType="{x:Type MenuItem}">从PresentationFramework.Aero的资源到我的样式文件。但是,这使得我的菜单看起来很像Windows 7,这在Windows 8或10 (或XP)上可能不是预期的。但是重新定义样式键至少会影响EditorMenuItem的外观。为什么?
如果EditorMenuItem没有自己的样式(我找不到它),为什么它不使用我为基类提供的任何样式?它怎么知道不使用我的样式,而只使用默认的样式,而默认的样式是被替换的,对于其他每个上下文菜单都是不可访问的?
下面是XAML代码,它存储在MenuStyles.xaml中,并包含在来自App.xaml的ResourceDictionary中。
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Expression Blend 4 created this (and a lot more) from some system theme on Windows 7 -->
<Style TargetType="{x:Type MenuItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=SubmenuItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
<Style.Triggers>
<Trigger Property="Role" Value="TopLevelHeader">
<Setter Property="Padding" Value="7,2,8,3"/>
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=TopLevelHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
</Trigger>
<Trigger Property="Role" Value="TopLevelItem">
<Setter Property="Padding" Value="7,2,8,3"/>
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=TopLevelItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
</Trigger>
<Trigger Property="Role" Value="SubmenuHeader">
<Setter Property="Padding" Value="5,4,2,3"/>
<!-- Changed from 2,3,2,3 -->
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=SubmenuHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
</Trigger>
<Trigger Property="Role" Value="SubmenuItem">
<Setter Property="Padding" Value="5,4,2,3"/>
<!-- Changed from 2,3,2,3 -->
</Trigger>
</Style.Triggers>
</Style>
<!-- Expression Blend 4 created this from some system theme on Windows 7 -->
<!-- Edited like in: http://devlicio.us/blogs/christopher_bennage/archive/2008/06/19/styling-separators-in-wpf.aspx -->
<!-- Decreased in height to be more platform standard -->
<Style x:Key="{x:Static MenuItem.SeparatorStyleKey}" TargetType="{x:Type Separator}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Separator}">
<Grid Margin="0,3,0,2" SnapsToDevicePixels="true">
<!-- Changed from 0,6,0,4 -->
<Rectangle Fill="#E0E0E0" Height="1" Margin="30,0,1,1"/>
<Rectangle Fill="White" Height="1" Margin="30,1,1,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>发布于 2016-01-24 11:12:14
您的问题在于不清楚地了解WPF中的样式是如何工作的。有两种类型的样式处理方式不同。
第一种类型是主题风格。每个FrameworkElement和FrameworkContentElement在初始化时使用DefaultStyleKey属性解析自己的Style。带有主题资源的资源字典的位置由ThemeInfoAttribute指定。
第二种类型是非主题风格。可以通过指定元素的Style属性显式设置此样式。或者也可以在初始化时隐式地解析它。非主题样式的Setter优先于主题样式的Setter。
当您通过将非主题Style添加到应用程序或没有键的元素的ResourceDictionary中时,它将隐式地使用,并且只有没有显式设置Style属性的目标类型的实例才会受到影响,而不是派生类型。此行为在FrameworkElement.GetRawValue方法(第1887行)中定义:
internal void GetRawValue(DependencyProperty dp, PropertyMetadata metadata, ref EffectiveValueEntry entry)
{
// ...
if (dp != StyleProperty)
{
if (StyleHelper.GetValueFromStyleOrTemplate(new FrameworkObject(this, null), dp, ref entry))
{
return;
}
}
else
{
object source;
object implicitValue = FrameworkElement.FindImplicitStyleResource(this, this.GetType(), out source);
if (implicitValue != DependencyProperty.UnsetValue)
{
// This style has been fetched from resources
HasImplicitStyleFromResources = true;
entry.BaseValueSourceInternal = BaseValueSourceInternal.ImplicitReference;
entry.Value = implicitValue;
return;
}
}
// ...
}因此,您的Style没有应用,因为它只为MenuItem类设计,因为它不是主题Style。您有两种方法来更改Style的TextBox's ContextMenu中的项,它们都有缺点。
第一种方法是为所有的Style es添加一个TextBox,并在其中设置ContextMenu。但是,如果分别使用和拼写检查,则将释放重转换和拼写MenuItems。
<Style TargetType="{x:Type TextBox}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Copy" />
<MenuItem Command="ApplicationCommands.Cut" />
<MenuItem Command="ApplicationCommands.Paste" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>第二种方法是在启动时使用反射为TextEditorContextMenu.EditorMenuItem类创建一个TextEditorContextMenu.EditorMenuItem。但是,只有在使用拼写检查和文本服务框架时,才应该使用此方法。
// Inside the Application.OnStartup method
Style menuItemStyle = TryFindResource(typeof(MenuItem)) as Style;
if (menuItemStyle != null)
{
Assembly menuItemAssembly = typeof(MenuItem).Assembly;
Type editorMenuType = menuItemAssembly.GetType("System.Windows.Documents.TextEditorContextMenu+EditorMenuItem", false);
if (editorMenuType != null)
{
Resources.Add(editorMenuType, menuItemStyle);
}
Type reconversionMenuType = menuItemAssembly.GetType("System.Windows.Documents.TextEditorContextMenu+ReconversionMenuItem", false);
if (reconversionMenuType != null)
{
Resources.Add(reconversionMenuType, menuItemStyle);
}
}https://stackoverflow.com/questions/34920125
复制相似问题