如何将手动创建的WPF菜单项转换为模板/样式资源/控件模板

4
我手动创建了一个菜单项。现在我希望将其作为模板/样式资源/控件模板 - 无论哪种方式对于这个任务最好。
我的菜单项看起来像这样(我知道代码很短):
<MenuItem
x:Name="Quit"                           << OUTSIDE TEMPLATE
Command="{Binding ShutdownCommand}">    << OUTSIDE TEMPLATE
<MenuItem.Header>
    <StackPanel 
        Orientation="Horizontal">
        <TextBlock 
            Width="150" 
            Text="Quit ERD Builder"/>   << OUTSIDE TEMPLATE
        <TextBlock 
            Width="80" 
            Margin="0,2,0,0" 
            TextAlignment="Right">
            <Border 
                Padding="4,0,4,0" 
                BorderBrush="#B0B0B0" 
                Background="#fff" 
                BorderThickness="1" 
                CornerRadius="6">
                <TextBlock 
                    Width="Auto" 
                    Text="Alt+F4"       << OUTSIDE TEMPLATE
                    FontSize="10" 
                    Foreground="#555" />
            </Border>
        </TextBlock>
    </StackPanel>
</MenuItem.Header>
<MenuItem.Icon>
    <Image 
        Width="16" 
        Height="16" 
        Margin="0,0,5,0" 
        HorizontalAlignment="Center" 
        VerticalAlignment="Center" 
        RenderOptions.BitmapScalingMode="HighQuality" 
        SnapsToDevicePixels="True">
        <Image.Source>
            <BitmapImage 
                UriSource="/ERDBuilder;component/icons/bw/102-walk.png" />  << OUTSIDE TEMPLATE
        </Image.Source>
    </Image>
</MenuItem.Icon>

我使用<< OUTSIDE TEMPLATE声明的行是我想要在菜单项中声明而不是在Template中声明的行。
我已经尝试过一些样式,但例如"Background"由于某种原因无法工作。我能够更改"FontSize",但无法更改"Background"颜色:
<Style 
x:Key="TopTaskBarMenuitem" 
TargetType="MenuItem">
<Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
        <Setter Property="Background" Value="#ffff00" />    << DONT WORK
        <Setter Property="FontSize" Value="20" />           << WORKS
    </Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="#000" />               << WORKS
<Setter Property="BorderThickness" Value="1" />             << WORKS
<Setter Property="Width" Value="150"/>                      << WORKS

这是手动创建XAML菜单的样子: 手动创建的菜单项(我不能在这里上传图片?!)
这是具有静态样式资源的菜单项: 具有样式资源的菜单项 可以看到,“背景”颜色不会影响菜单项。
如果我能许个愿望,最终我想要的是“菜单项”这一侧的东西:
<MenuItem
Style="{StaticResource TopTaskBarMenuitem}"                     << TEMPLATE / STYLE BINDING
x:Name="Quit"                                                   << OUTSIDE TEMPLATE
Command="{Binding ShutdownCommand}"                             << OUTSIDE TEMPLATE
MyHeaderText="Quit ERD Builder"/>                               << OUTSIDE TEMPLATE
MyShortcutText="Alt+F4"                                         << OUTSIDE TEMPLATE
MyUriSource="/ERDBuilder;component/icons/bw/102-walk.png" />    << OUTSIDE TEMPLATE

非常感谢所有能够提供帮助的人!

附注:这里的三个代码发布中都缺少最后一行代码。我不知道为什么,也无法修复。

Dirk

2个回答

2
要实现这一点,您需要创建一个派生自 MenuItem 的自定义控件。
您所需做的就是创建控件类,并使用 DependencyProperties 以利用其所有优势。欲了解更多信息,请阅读 this
namespace MyControls
{
    class MyMenuItem : MenuItem
    {
        public string MyHeaderText
        {
            get { return (string)GetValue(MyHeaderTextProperty); }
            set { SetValue(MyHeaderTextProperty, value); }
        }
        public static readonly DependencyProperty MyHeaderTextProperty = DependencyProperty.Register("MyHeaderText", typeof(string), typeof(MyMenuItem));

        public string MyShortcutText
        {
            get { return (string)GetValue(MyShortcutTextProperty); }
            set { SetValue(MyShortcutTextProperty, value); }
        }
        public static readonly DependencyProperty MyShortcutTextProperty = DependencyProperty.Register("MyShortcutText", typeof(string), typeof(MyMenuItem));

        public string MyUriSource
        {
            get { return (string)GetValue(MyUriSourceProperty); }
            set { SetValue(MyUriSourceProperty, value); }
        }
        public static readonly DependencyProperty MyUriSourceProperty = DependencyProperty.Register("MyUriSource", typeof(string), typeof(MyMenuItem));
    }
}

现在您可以实例化控件,但仍需要“重新模板化”它:
<mc:MyMenuItem MyHeaderText="Quit ERD Builder" MyShortcutText="Alt+F4" MyUriSource="/ERDBuilder;component/icons/bw/102-walk.png">
    <mc:MyMenuItem.Style>
        <Style TargetType="mc:MyMenuItem">
            <Style.Setters>
                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Width="150" Text="{Binding Mode=TwoWay, Path=MyHeaderText, RelativeSource={RelativeSource FindAncestor, AncestorType=mc:MyMenuItem}}"/>
                                <TextBlock Width="80" Margin="0,2,0,0" TextAlignment="Right">
                                    <Border Padding="4,0,4,0" BorderBrush="#B0B0B0" Background="#fff" BorderThickness="1" CornerRadius="6">
                                        <TextBlock Width="Auto" Text="{Binding Mode=TwoWay, Path=MyShortcutText, RelativeSource={RelativeSource FindAncestor, AncestorType=mc:MyMenuItem}}" FontSize="10" Foreground="#555" />
                                    </Border>
                                </TextBlock>
                            </StackPanel>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
                <Setter Property="Icon">
                    <Setter.Value>
                        <Image Width="16" Height="16" Margin="0,0,5,0" HorizontalAlignment="Center" VerticalAlignment="Center" RenderOptions.BitmapScalingMode="HighQuality" SnapsToDevicePixels="True" Source="{Binding Mode=OneWay, Path=MyUriSource, RelativeSource={RelativeSource FindAncestor, AncestorType=mc:MyMenuItem}}" />
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>
    </mc:MyMenuItem.Style>
</mc:MyMenuItem>

不要忘记在窗口(或无论您放置此控件的位置)标记中引用此新控件的命名空间:
xmlns:mc="clr-namespace:MyControls"

可以将这种样式插入到资源字典中,这样每次使用该控件时就不需要引用它了。
<Style TargetType="mc:MyMenuItem">
    <!-- Style comes here -->
</Style>

然后,您可以获得您所要求的内容:
<mc:MyMenuItem MyHeaderText="Quit ERD Builder" MyShortcutText="Alt+F4" MyUriSource="/ERDBuilder;component/icons/bw/102-walk.png" />

我希望它能帮助你!

嗨Wiley。我试过了,我觉得它运行得很好。但是图标的URI不起作用。编译后我遇到了错误:XmlParseException: System.Windows.Media.Imaging.BitmapImage引发了异常。 - Dirk Schiller

0

CoreStyle.xaml

来自模板/样式的部分:

<Setter Property="Icon">
  <Setter.Value>
    <ctrl:Bitmap>
      <ctrl:Bitmap.Source>
        <!-- This doesnt work: --> <BitmapImage UriSource="{Binding Mode=OneWay, Path=MenuIcon, RelativeSource={RelativeSource FindAncestor, AncestorType=ctrl:MainMenuItem}}" />
        <!-- This Still works fine: <BitmapImage UriSource="../Resources/Icons/16/page_add.png" />-->
      </ctrl:Bitmap.Source>
    </ctrl:Bitmap>
  </Setter.Value>
</Setter>

MainMenuItem.cs

从 MenuItem 派生的自定义控件类:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ErdBuilder.Shell.Controls
{
class MainMenuItem : MenuItem
{
    public ICommand MenuCommand
    {
        get { return (ICommand) GetValue(MenuCommandProperty); }
        set { SetValue(MenuCommandProperty, value); }
    }

    public static readonly DependencyProperty MenuCommandProperty = DependencyProperty.Register("MenuCommand", typeof(ICommand), typeof(MainMenuItem));

    public string MenuText
    {
        get { return (string)GetValue(MenuTextProperty); }
        set { SetValue(MenuTextProperty, value); }
    }

    public static readonly DependencyProperty MenuTextProperty = DependencyProperty.Register("MenuText", typeof(string), typeof(MainMenuItem));

    public string MenuShortcut
    {
        get { return (string)GetValue(MenuShortcutProperty); }
        set { SetValue(MenuShortcutProperty, value); }
    }

    public static readonly DependencyProperty MenuShortcutProperty = DependencyProperty.Register("MenuShortcut", typeof(string), typeof(MainMenuItem));

    public string MenuIcon
    {
        get { return (string)GetValue(MenuIconProperty); }
        set { SetValue(MenuIconProperty, value); }
    }

    public static readonly DependencyProperty MenuIconProperty = DependencyProperty.Register("MenuIcon", typeof(string), typeof(MainMenuItem));

}

}

我也尝试过这个:

public BitmapImage MenuIcon
    {
        get { return new BitmapImage(new Uri((string)GetValue(MenuIconProperty))); }
        set { SetValue(MenuIconProperty, value); }
    }

    public static readonly DependencyProperty MenuIconProperty =     DependencyProperty.Register("MenuIcon", typeof(BitmapImage), typeof(MainMenuItem));

Shell.xaml

最后是我尝试使用新控件的部分:

<ctrl:MainMenuItem x:Name="TestMenu"
  MenuCommand="{x:Static ApplicationCommands.New}"
  MenuText="New..."
  MenuShortcut="Ctr+N"
  MenuIcon="../Resources/Icons/16/page_add.png"/>

MenuCommand属性也不起作用。我可以设置它,没有错误,但它不能识别我的菜单命令值设置。 - Dirk Schiller

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