为什么我的隐式 ContextMenu 样式不会覆盖 TextBox 上下文菜单样式? [英] Why my implicit ContextMenu Style doesn't override the TextBox context menu style?
问题描述
我从 本网站:
I have this implicit style for the ContextMenu
that I took from this site:
<Application.Resources>
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<Style TargetType="ContextMenu">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Grid.IsSharedSizeScope" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border
Name="Border"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1" >
<StackPanel IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border" Property="Padding" Value="0,3,0,3"/>
<Setter TargetName="Border" Property="CornerRadius" Value="4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
然后我尝试在这里使用它,以便它同时应用于 TextBox
的默认 ContextMenu
和我为我添加的 ContextMenu
按钮
.
Then I try to use it here so it gest applied both for the default ContextMenu
of the TextBox
and the ContextMenu
I added for my Button
.
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Height="30" Width="200">Test</TextBox>
<Button Grid.Row="1" Width="200" Height="30" Content="Test2">
<Button.ContextMenu>
<ContextMenu>
<MenuItem>Test</MenuItem>
<MenuItem>Test2</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
该样式应用于 Button
,而不应用于 TextBox
.
The style gets applied on the Button
, but not on the TextBox
.
我觉得这应该相当简单明了,为什么我的隐式样式没有应用于 TextBox
的默认 ContextMenu
,我做错了什么?
I feel this should be rather straightforward and simple, why isn't my implicit style getting applied to the default ContextMenu
of the TextBox
, what am I doing wrong?
==更新==
我目前不确定答案,但我认为这里的问题是带有 ContextMenu
的 TextBox
设计中的一些缺陷,我希望有更多知识的人可以证实.使用 Snoop,我可以看到 ContextMenu
不是您期望的对象,而是一个 EditorContextMenu
对象,它是内部的,因此您无法对其进行样式设置.他们为什么使用它?我不知道.
I don't know the answer for sure at the moment, but I think the issue here is some flaw in the Design of the TextBox
with the ContextMenu
, I wish someone more knowledgeable could confirm.
Using Snoop I could see that the ContextMenu
wasn't the object you would expect, but an EditorContextMenu
object, that is internal, so you can't style it. Why do they use that? I don't know.
作为一种变通方法,我创建了一个默认的上下文菜单并使用它.如果您向 TextBox
添加上下文菜单,它会正确地采用隐式样式.由于您知道默认的 ContextMenu
具有的项,并且这些项基本上使用 ApplicationCommands,因此非常简单:
As a work around, I create a default context menu and use it. If you add a context menu to the TextBox
, it correctly takes the implicit styling.
Since you know the items that the default ContextMenu
has, and the items in turn basically use the ApplicationCommands, it is very simple:
<ContextMenu x:Key="DefaultContextMenu">
<MenuItem Command="ApplicationCommands.Copy" />
<MenuItem Command="ApplicationCommands.Cut" />
<MenuItem Command="ApplicationCommands.Paste" />
</ContextMenu>
然后在您的 TextBoxStyle 中执行:
Then in your TextBoxStyle do:
<Style x:Key="MyTextBoxStyle" TargetType="TextBox">
<Setter Property="ContextMenu" Value="{StaticResource DefaultContextMenu}" />
有了这个,您的 TextBox
的默认 ContextMenu
将采用隐式样式.
With this your TextBox
's Default ContextMenu
will take the implicit style.
推荐答案
对我来说,它看起来像是 TextBox
实现中的一个错误,而且特殊之处在于 ContextMenu
不属于到 VisualTree.
It looks like a bug in TextBox
implementation for me and the peculiarity is that ContextMenu
does not belong to the VisualTree.
我会试着解释一下.
- 默认的
ContextMenu
将由TextBox
创建和显示实现,即在方法中OnContextMenuOpening(ContextMenuEventArgs e)
.看到它你可以在自定义TextBox
中覆盖此方法并省略base.
调用. - 与显式设置的
ContextMenu
相比,默认的ContextMenu
是处理不同(不是通过ContextMenuService
处理). - 默认的
ContextMenu
将被TextBox
创建TextBox.ContextMenu
属性未明确设置(XAML 或代码隐藏). ContextMenu
不在 VisualTree 中,它是与VisualTree 是属性PlacementTarget
(如果您例如创建并在后面的代码中打开一个ContextMenu
并且不要设置一个PlacementTarget
将不会应用隐式样式).- 在
TextBox
实现中设置了ContextMenu.PlacementTarget
,但该值来自一些内部缓存/字典.我不能调试它并肯定地说,但我认为缓存的值是错误的这里.
你可以做个小测试,看看缓存的值是否正确.覆盖自定义的OnContextMenuOpening(ContextMenuEventArgs e)
TextBox
并在调用基本函数之前修改TextBox
(例如,每次设置另一个Margin
).默认的ContextMenu
甚至不会打开!如果您代替base
调用,请实例化并显示ContextMenu
自己修改,然后Margin
修改不会打扰并打开ContextMenu
将具有您在资源中设置的隐式样式.
- The default
ContextMenu
will be created and shown by theTextBox
implementation, namely in the methodOnContextMenuOpening(ContextMenuEventArgs e)
. To see it you can override this method in customTextBox
and omit thebase.
call. - Compared to
ContextMenu
, which is set explicitly, the defaultContextMenu
is handled different (handled not viaContextMenuService
). - The default
ContextMenu
will be created by theTextBox
only if theTextBox.ContextMenu
property was not set explicitly(XAML or code behind). ContextMenu
is not in VisualTree and the only connection to the VisualTree is the propertyPlacementTarget
(if you e.g. do create and open aContextMenu
in code behind and do not set aPlacementTarget
the implicit style will not be applied).- In
TextBox
implementation theContextMenu.PlacementTarget
being set, BUT the value comes from some internal cache/dictionary. I could not debug it and say for sure, but I suppose the cached value is wrong here.
You can do small test to see the cached value is correct. Override theOnContextMenuOpening(ContextMenuEventArgs e)
for the customTextBox
and before you call the base function do modify theTextBox
(e.g. set each time anotherMargin
). The defaultContextMenu
will not be even opened! If you in place ofbase
call do instantiate and show theContextMenu
by yourself, thenMargin
modification will not disturb and openedContextMenu
will have implicit style you set in the resources.
要测试的代码段:
public class MyStyledTextBox: TextBox
{
protected override void OnContextMenuOpening(ContextMenuEventArgs e)
{
//this.Margin = new Thickness(0, 20, 0, 0);
var uiScope = e.Source as TextBox;
var ctxm = new ContextMenu();
MenuItem menuItem;
menuItem = new MenuItem();
menuItem.Header = "CutCustom";
menuItem.CommandTarget = this;
menuItem.Command = ApplicationCommands.Cut;
ctxm.Items.Add(menuItem);
ctxm.PlacementTarget = uiScope;
ctxm.IsOpen = true;
//base.OnContextMenuOpening(e);
}
}
<StackPanel>
<StackPanel.Resources>
<Style TargetType="ContextMenu" >
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Grid.IsSharedSizeScope" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border Name="Border_custom" Background="Chocolate" BorderBrush="Coral" BorderThickness="1" >
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border_custom" Property="Padding" Value="0,3,0,3"/>
<Setter TargetName="Border_custom" Property="CornerRadius" Value="4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<local:MyStyledTextBox Height="30" Width="200" Text="Test">
<!--<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Test"/>
<MenuItem Header="Test2"/>
</ContextMenu>
</TextBox.ContextMenu>-->
</local:MyStyledTextBox>
</StackPanel>
我说的是错误,因为默认 ContextMenu
的 ScrollBar
实现确实正确地应用了隐式样式.
I'm saying about bug, because of ScrollBar
implementation of default ContextMenu
does apply an implicit style correctly.
坏消息是,在 TextBox
的当前实现中,您无法访问内部创建的默认 ContextMenu
和未应用的隐式样式.
The bad news is, that in current implementation of TextBox
you can't reach the internally created default ContextMenu
and the implicit style being not applied.
这篇关于为什么我的隐式 ContextMenu 样式不会覆盖 TextBox 上下文菜单样式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!