为什么我的隐式 ContextMenu 样式不会覆盖 TextBox 上下文菜单样式? [英] Why my implicit ContextMenu Style doesn't override the TextBox context menu style?

查看:29
本文介绍了为什么我的隐式 ContextMenu 样式不会覆盖 TextBox 上下文菜单样式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从 本网站:

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?

==更新==

我目前不确定答案,但我认为这里的问题是带有 ContextMenuTextBox 设计中的一些缺陷,我希望有更多知识的人可以证实.使用 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 the TextBox implementation, namely in the method OnContextMenuOpening(ContextMenuEventArgs e). To see it you can override this method in custom TextBox and omit the base. call.
  • Compared to ContextMenu, which is set explicitly, the default ContextMenu is handled different (handled not via ContextMenuService).
  • The default ContextMenu will be created by the TextBox only if the TextBox.ContextMenu property was not set explicitly(XAML or code behind).
  • ContextMenu is not in VisualTree and the only connection to the VisualTree is the property PlacementTarget (if you e.g. do create and open a ContextMenu in code behind and do not set a PlacementTarget the implicit style will not be applied).
  • In TextBox implementation the ContextMenu.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 the OnContextMenuOpening(ContextMenuEventArgs e) for the custom TextBox and before you call the base function do modify the TextBox (e.g. set each time another Margin). The default ContextMenu will not be even opened! If you in place of base call do instantiate and show the ContextMenu by yourself, then Margin modification will not disturb and opened ContextMenu 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>

我说的是错误,因为默认 ContextMenuScrollBar 实现确实正确地应用了隐式样式.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆