WPF样式未完全应用于上下文菜单。

3
我希望能在WPF/C#应用程序中,在鼠标左键单击时具有上下文菜单。我知道这是一个不寻常的行为,但在这种非常特殊的情况下需要这样做。 以下是XAML文件(仅包含相关部分):
<Window x:Class="_ContextMenuText.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:_ContextMenuText"
    mc:Ignorable="d"
    Title="MainWindow" Height="300" Width="300">
<Window.Resources>
    <ResourceDictionary>
        <Color x:Key="NormalBrushGradient1">#FFAF231E</Color>
        <Color x:Key="NormalBrushGradient2">#FF9F231E</Color>
        <Color x:Key="NormalBrushGradient3">#FF8F231E</Color>
        <Color x:Key="NormalBrushGradient4">#FF601818</Color>

        <Color x:Key="NormalBorderBrushGradient1">#FFBBBBBB</Color>
        <Color x:Key="NormalBorderBrushGradient2">#FF737373</Color>
        <Color x:Key="NormalBorderBrushGradient3">#FF646464</Color>
        <Color x:Key="NormalBorderBrushGradient4">#FF000000</Color>

        <Color x:Key="WindowBackgroundBrushGradient1">#FF8496AA</Color>
        <Color x:Key="WindowBackgroundBrushGradient2">#FF414141</Color>

        <LinearGradientBrush x:Key="NormalBrush"
                   EndPoint="0.5,1"
                   StartPoint="0.5,0">
            <GradientStop Color="{StaticResource NormalBrushGradient1}"
              Offset="0" />
            <GradientStop Color="{StaticResource NormalBrushGradient2}"
              Offset="0.33" />
            <GradientStop Color="{StaticResource NormalBrushGradient3}"
              Offset="0.66" />
            <GradientStop Color="{StaticResource NormalBrushGradient4}"
              Offset="1" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="WindowBackgroundBrush"
                   EndPoint="0.5,1"
                   StartPoint="0.5,0">
            <GradientStop Color="{StaticResource WindowBackgroundBrushGradient1}" />
            <GradientStop Color="{StaticResource WindowBackgroundBrushGradient2}"
              Offset="1" />
        </LinearGradientBrush>
        <Style TargetType="{x:Type ContextMenu}">
            <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}"/>
            <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ContextMenu}">
                        <Grid>
                            <Border Margin="1" x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
                            <StackPanel Background="{TemplateBinding Background}" IsItemsHost="True" ClipToBounds="True" Orientation="Vertical"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
                                <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Foreground" Value="{DynamicResource TextBrush}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type MenuItem}">
                        <ControlTemplate.Resources>
                            <Storyboard x:Key="HighlightedOn">
                                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.Opacity)">
                                    <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="1"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Key="HighlightedOff">
                                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.Opacity)">
                                    <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </ControlTemplate.Resources>
                        <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                            <Grid>

                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition MinWidth="17" Width="Auto" SharedSizeGroup="MenuItemIconColumnGroup"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGTColumnGroup"/>
                                    <ColumnDefinition Width="14"/>
                                </Grid.ColumnDefinitions>

                                <Border Grid.Column="0" Grid.ColumnSpan="4" Background="{DynamicResource NormalBrush}" Opacity="0" x:Name="border"/>

                                <ContentPresenter Margin="4,0,6,0" x:Name="Icon" VerticalAlignment="Center" ContentSource="Icon"/>

                                <Grid Visibility="Hidden" Margin="4,0,6,0" x:Name="GlyphPanel" VerticalAlignment="Center">
                                    <Path x:Name="GlyphPanelpath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,2 L0,4.8 L2.5,7.4 L7.1,2.8 L7.1,0 L2.5,4.6 z" FlowDirection="LeftToRight"/>
                                </Grid>

                                <ContentPresenter Grid.Column="1" Margin="{TemplateBinding Padding}" x:Name="HeaderHost" RecognizesAccessKey="True" ContentSource="Header"/>

                                <Grid Grid.Column="3" Margin="4,0,6,0" x:Name="ArrowPanel" VerticalAlignment="Center">
                                    <Path x:Name="ArrowPanelPath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,0 L0,8 L4,4 z"/>
                                </Grid>

                                <Popup IsOpen="{Binding Path=IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" x:Name="SubMenuPopup" Focusable="false" AllowsTransparency="true" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" VerticalOffset="-3">
                                    <Grid x:Name="SubMenu">
                                        <Border x:Name="SubMenuBorder" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/>

                                        <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
                                    </Grid>
                                </Popup>

                            </Grid>
                        </Border>

                        <ControlTemplate.Triggers>

                            <Trigger Property="Role" Value="TopLevelHeader">
                                <Setter Property="Margin" Value="0,1,0,1"/>
                                <Setter Property="Padding" Value="6,3,6,3"/>
                                <Setter Property="Grid.IsSharedSizeScope" Value="true"/>
                                <Setter Property="Placement" Value="Bottom" TargetName="SubMenuPopup"/>
                                <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
                            </Trigger>

                            <Trigger Property="Role" Value="TopLevelItem">
                                <Setter Property="Margin" Value="0,1,0,1"/>
                                <Setter Property="Padding" Value="6,3,6,3"/>
                                <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
                            </Trigger>

                            <Trigger Property="Role" Value="SubmenuHeader">
                                <Setter Property="DockPanel.Dock" Value="Top"/>
                                <Setter Property="Padding" Value="0,2,0,2"/>
                                <Setter Property="Grid.IsSharedSizeScope" Value="true"/>
                            </Trigger>

                            <Trigger Property="Role" Value="SubmenuItem">
                                <Setter Property="DockPanel.Dock" Value="Top"/>
                                <Setter Property="Padding" Value="0,2,0,2"/>
                                <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
                            </Trigger>
                            <Trigger Property="IsSuspendingPopupAnimation" Value="true">
                                <Setter Property="PopupAnimation" Value="None" TargetName="SubMenuPopup"/>
                            </Trigger>

                            <Trigger Property="Icon" Value="{x:Null}">
                                <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
                            </Trigger>

                            <Trigger Property="IsChecked" Value="true">
                                <Setter Property="Visibility" Value="Visible" TargetName="GlyphPanel"/>
                                <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
                            </Trigger>

                            <Trigger Property="AllowsTransparency" SourceName="SubMenuPopup" Value="true">
                                <Setter Property="Margin" Value="0,0,3,3" TargetName="SubMenu"/>
                                <Setter Property="SnapsToDevicePixels" Value="true" TargetName="SubMenu"/>
                                <Setter Property="BitmapEffect" Value="{DynamicResource PopupDropShadow}" TargetName="SubMenuBorder"/>
                            </Trigger>

                            <Trigger Property="IsHighlighted" Value="true">
                                <Trigger.ExitActions>
                                    <BeginStoryboard Storyboard="{StaticResource HighlightedOff}" x:Name="HighlightedOff_BeginStoryboard"/>
                                </Trigger.ExitActions>
                                <Trigger.EnterActions>
                                    <BeginStoryboard Storyboard="{StaticResource HighlightedOn}"/>
                                </Trigger.EnterActions>
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
</Window.Resources>
<Label 
    Content="Test" 
    Height="30"
    Width="50"
    Name="TestLabel"
    Background="Azure"
    Foreground="Black"
    HorizontalContentAlignment="Center"
    VerticalContentAlignment="Center"
    MouseLeftButtonUp="TestLabel_MouseLeftButtonUp"/>

以下是C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace _ContextMenuText
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        ContextMenu cont = new ContextMenu();
        cont.Style = this.FindResource(typeof(ContextMenu)) as Style;
        MenuItem mni = new MenuItem();
        AddStyleToItem(mni);
        mni.Header = "item1";
        cont.Items.Add(mni);

        MenuItem mni1 = new MenuItem();
        AddStyleToItem(mni);
        mni1.Header = "item2";
        mni.Items.Add(mni1);

        MenuItem mni2 = new MenuItem();
        AddStyleToItem(mni);
        mni2.Header = "item22";
        mni.Items.Add(mni2);

        TestLabel.ContextMenu = cont;
    }
    private void AddStyleToItem(MenuItem item)
    {
        item.Style = this.FindResource(typeof(MenuItem)) as Style;
    }
    private void TestLabel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        TestLabel.ContextMenu.IsOpen = true;
    }
}
}

如果我启动程序并首先用左键单击标签,上下文菜单的样式会不正确:enter image description here 如果通过右键单击打开上下文菜单,则上下文菜单将正确显示:enter image description here 问题在于右键单击打开上下文菜单后,使用左键单击打开上下文菜单时,它也被正确地设计了。似乎当单击鼠标右键时进行了一些初始化。我试图找到模拟右键单击的方法,但失败了。如果我在代码中模拟右键单击,这种类型的初始化就不会执行。上下文菜单将正确显示。我试图在代码中删除样式的分配:
cont.Style = this.FindResource(typeof(ContextMenu)) as Style;

这导致几乎相同的错误行为。只有在首次通过右键单击打开上下文菜单时,第一种设计才不同:

enter image description here

有人能帮我吗?非常感谢!


你的窗口资源被包装在<ResourceDictionary>中,这是不寻常的。尝试将其移除?个人建议将这些样式移动到App.xaml并赋予它们适当的名称。由于ContextMenu显示在另一个窗口中,因此可能无法捕获您窗口的隐式样式。 - ghord
1个回答

2

您需要将ResourceDictionary的内容移动到App.xaml的Application.Resources中,然后它就会开始工作,并且删除窗口资源中的ResourceDictionary。如果可以,请告诉我是否有效。


谢谢。我会尝试这个解决方案并告诉你。 - manton
太好了,这个完美运作!有点奇怪的是,当样式在MainWindow.xaml中时它不起作用,但出于某种原因,只有你的方法才能起作用。 - manton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接