4

我确信其他人找到了一种方法来做到这一点,我很接近但不完全。我使用 StaticResourceConverter 类成功地使用基于资源名称的几何绑定到资源的 Path 对象:

public class StaticResourceConverter: BaseConverter, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(System.Convert.ToString(value).IsNullOrEmpty())
        {
            return null;
        }
        var resource = Application.Current.Resources[value];
        return resource;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}

绑定到 MenuItem 中的 Image 对象需要使用相同的方法创建具有底层 DrawingImage 的 Image 实例:

<Style TargetType="{x:Type MenuItem}">
    <Setter Property="Icon">
        <Setter.Value>
            <Image Style="{StaticResource ResourceKey=SpMenuItemIcon}">
                <Image.Source>
                    <DrawingImage>
                        <DrawingImage.Drawing>
                            <GeometryDrawing
                                Brush="{StaticResource SpIconPath}"
                                Geometry="{Binding IconPath,
                                    Converter={converters:StaticResourceConverter}}"/>
                        </DrawingImage.Drawing>
                    </DrawingImage>
                </Image.Source>
            </Image>
        </Setter.Value>
    </Setter>
</Style>

问题是我怀疑只创建了一个 Image 实例,或者只绑定了 1 个,因为只有菜单中的最后一个图标在正确的几何路径下可见。为什么 WPF 只绑定最后一个 MenuItem 以及如何使其适用于所有菜单项?

更新:

只是为了帮助测试这里有几个示例几何资源绑定到(使用键):

<Geometry x:Key="ExpandIconPath">F1 M 30.25,58L 18,58L 18,45.75L 22,41.75L 22,50.75L 30,42.75L 33.25,46L 25.25,54L 34.25,54L 30.25,58 Z M 58,45.75L 58,58L 45.75,58L 41.75,54L 50.75,54L 42.75,46L 46,42.75L 54,50.75L 54,41.75L 58,45.75 Z M 45.75,18L 58,18L 58,30.25L 54,34.25L 54,25.25L 46,33.25L 42.75,30L 50.75,22L 41.75,22L 45.75,18 Z M 18,30.25L 18,18L 30.25,18L 34.25,22L 25.25,22L 33.25,30L 30,33.25L 22,25.25L 22,34.25L 18,30.25 Z</Geometry>
<Geometry x:Key="CollapseIconPath">F1 M 54.2499,34L 42,34L 42,21.7501L 45.9999,17.7501L 45.9999,26.7501L 53.9999,18.7501L 57.2499,22.0001L 49.2499,30.0001L 58.2499,30.0001L 54.2499,34 Z M 34,21.7501L 34,34L 21.75,34L 17.75,30.0001L 26.75,30.0001L 18.75,22.0001L 22,18.7501L 30,26.7501L 30,17.7501L 34,21.7501 Z M 21.75,42L 34,42L 34,54.25L 30,58.25L 30,49.25L 22,57.25L 18.75,54L 26.75,46L 17.75,46L 21.75,42 Z M 42,54.25L 42,42L 54.2499,42L 58.2499,46L 49.2499,46.0001L 57.2499,54L 53.9999,57.25L 45.9999,49.25L 45.9999,58.25L 42,54.25 Z</Geometry>
<Geometry x:Key="CloseIconPath">F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z</Geometry>
4

2 回答 2

7

与 Clemens 建议的不同,您无需将整体设为Style不共享。问题来自Imagewhich 必须是唯一的MenuItem。因此,您应该Image通过将其放入x:Shared设置为的资源中来使其不共享False

一个独立的工作示例:

主窗口.xaml

<Window x:Class="So19902960WpfMenuItemIconGeometry.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:So19902960WpfMenuItemIconGeometry"
        Title="MainWindow" Height="350" Width="525">
    <Control.Resources>
        <local:StaticResourceConverter x:Key="StaticResourceConverter"/>
        <Geometry x:Key="ExpandIconPath">F1 M 30.25,58L 18,58L 18,45.75L 22,41.75L 22,50.75L 30,42.75L 33.25,46L 25.25,54L 34.25,54L 30.25,58 Z M 58,45.75L 58,58L 45.75,58L 41.75,54L 50.75,54L 42.75,46L 46,42.75L 54,50.75L 54,41.75L 58,45.75 Z M 45.75,18L 58,18L 58,30.25L 54,34.25L 54,25.25L 46,33.25L 42.75,30L 50.75,22L 41.75,22L 45.75,18 Z M 18,30.25L 18,18L 30.25,18L 34.25,22L 25.25,22L 33.25,30L 30,33.25L 22,25.25L 22,34.25L 18,30.25 Z</Geometry>
        <Geometry x:Key="CollapseIconPath">F1 M 54.2499,34L 42,34L 42,21.7501L 45.9999,17.7501L 45.9999,26.7501L 53.9999,18.7501L 57.2499,22.0001L 49.2499,30.0001L 58.2499,30.0001L 54.2499,34 Z M 34,21.7501L 34,34L 21.75,34L 17.75,30.0001L 26.75,30.0001L 18.75,22.0001L 22,18.7501L 30,26.7501L 30,17.7501L 34,21.7501 Z M 21.75,42L 34,42L 34,54.25L 30,58.25L 30,49.25L 22,57.25L 18.75,54L 26.75,46L 17.75,46L 21.75,42 Z M 42,54.25L 42,42L 54.2499,42L 58.2499,46L 49.2499,46.0001L 57.2499,54L 53.9999,57.25L 45.9999,49.25L 45.9999,58.25L 42,54.25 Z</Geometry>
        <Geometry x:Key="CloseIconPath">F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z</Geometry>
        <Image x:Key="MenuItemImage" x:Shared="False" Width="16" Height="16">
            <Image.Source>
                <DrawingImage>
                    <DrawingImage.Drawing>
                        <GeometryDrawing Brush="Blue"
                                Geometry="{Binding Tag,
                                    RelativeSource={RelativeSource AncestorType=MenuItem},
                                    Converter={StaticResource StaticResourceConverter}}"/>
                    </DrawingImage.Drawing>
                </DrawingImage>
            </Image.Source>
        </Image>
        <Style TargetType="MenuItem">
            <Setter Property="Icon" Value="{StaticResource MenuItemImage}"/>
        </Style>
    </Control.Resources>
    <Menu>
        <MenuItem Header="Expand" Tag="ExpandIconPath"/>
        <MenuItem Header="Collapse" Tag="CollapseIconPath"/>
        <MenuItem Header="Close" Tag="CloseIconPath"/>
    </Menu>
</Window>

主窗口.xaml.cs

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace So19902960WpfMenuItemIconGeometry
{
    public partial class MainWindow
    {
        public MainWindow ()
        {
            InitializeComponent();
        }
    }

    public class StaticResourceConverter : IValueConverter
    {
        public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == DependencyProperty.UnsetValue || value == null)
                return DependencyProperty.UnsetValue;
            return Application.Current.MainWindow.Resources[value];
        }

        public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

笔记:

  1. 您应该在方法中抛出NotSupportedException而不是Exception使用自定义消息ConvertBack。它专门用于方法未实现且不会实现的情况。

  2. 你应该DependencyProperty.UnsetValueConvert方法中检查。当绑定失败时,转换器不应使应用程序崩溃。

于 2013-11-20T19:26:45.157 回答
5

x:Shared属性设置为false 以防止 Style 资源因此Image在所有应用 Style 的地方被重用:

<Style TargetType="{x:Type MenuItem}" x:Shared="False">
    <Setter Property="Icon">
        ...
    </Setter>
</Style>
于 2013-11-15T13:45:11.970 回答