You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF自定义Icon控件:如何关联IconName与PathGeometry的x:Key显示图标

解决方案

你的核心问题是**IconName 属性类型与传入的字符串资源键不匹配**,且缺少从资源键到 PathGeometry 的关联逻辑。下面提供两种可行的实现方式:


方式一:使用值转换器(ValueConverter)

1. 修改 Icon.cs 中的 IconName 属性类型

将 IconName 的类型从 Geometry 改为 string,因为你要传入的是资源键字符串:

public class Icon : Control
{  
    public static readonly DependencyProperty IconNameProperty =
        DependencyProperty.Register("IconName", typeof(string), typeof(Icon),
            new PropertyMetadata(string.Empty));
    public string IconName
    {
        get { return (string)GetValue(IconNameProperty); }
        set { SetValue(IconNameProperty, value); }
    }

    // 保留其他属性和静态构造函数
    public static readonly DependencyProperty IconHeightProperty =
        DependencyProperty.Register("IconHeight", typeof(double), typeof(Icon), new PropertyMetadata(24.0));
    public double IconHeight
    {
        get { return (double)GetValue(IconHeightProperty); }
        set { SetValue(IconHeightProperty, value); }
    }

    public static readonly DependencyProperty IconColorProperty =
        DependencyProperty.Register("IconColor", typeof(Brush), typeof(Icon), new PropertyMetadata(Brushes.Black));
    public Brush IconColor
    {
        get { return (Brush)GetValue(IconColorProperty); }
        set { SetValue(IconColorProperty, value); }
    }

    static Icon()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Icon), 
            new FrameworkPropertyMetadata(typeof(Icon)));
    }
}

2. 创建字符串转 Geometry 的转换器

添加一个实现 IValueConverter 的类,负责根据资源键查找对应的 PathGeometry:

public class StringToGeometryConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string resourceKey && !string.IsNullOrEmpty(resourceKey))
        {
            // 先尝试从应用全局资源查找
            var geometry = Application.Current.TryFindResource(resourceKey) as Geometry;
            return geometry ?? Geometry.Empty;
        }
        return Geometry.Empty;
    }

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

3. 更新 Generic.xaml 中的模板

在资源字典中声明转换器,并在 Path 的 Data 绑定中使用它:

<!-- 声明转换器(确保命名空间 local 指向你的控件库命名空间) -->
<local:StringToGeometryConverter x:Key="StringToGeometryConverter"/>

<!-- 保留你的 PathGeometry 资源 -->
<PathGeometry x:Key="Icon_Close" Figures="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
<PathGeometry x:Key="Icon_WndMinimize" Figures="M19,13H5V11H19V13Z"/>
<PathGeometry x:Key="Icon_WndMaximize" Figures="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z"/>

<Style TargetType="{x:Type local:Icon}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:Icon}">
                <Viewbox Height="{TemplateBinding IconHeight}"
                         Width="Auto">
                    <Canvas Height="24"
                            Width="24">
                        <!-- 使用转换器绑定 IconName 到 Path.Data -->
                        <Path Fill="{TemplateBinding IconColor}"
                              Data="{TemplateBinding IconName, Converter={StaticResource StringToGeometryConverter}}"/>
                    </Canvas>
                </Viewbox>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

方式二:控件内部处理资源查找

如果不想用转换器,可以在控件内部监听 IconName 的变化,自动查找对应的资源:

1. 修改 Icon.cs,添加内部 Geometry 属性和回调

public class Icon : Control
{  
    // 内部 Geometry 属性,用于绑定到 Path.Data
    public static readonly DependencyProperty IconGeometryProperty =
        DependencyProperty.Register("IconGeometry", typeof(Geometry), typeof(Icon), new PropertyMetadata(Geometry.Empty));
    public Geometry IconGeometry
    {
        get { return (Geometry)GetValue(IconGeometryProperty); }
        private set { SetValue(IconGeometryProperty, value); }
    }

    // 修改 IconName 属性,添加变化回调
    public static readonly DependencyProperty IconNameProperty =
        DependencyProperty.Register("IconName", typeof(string), typeof(Icon),
            new PropertyMetadata(string.Empty, OnIconNameChanged));
    public string IconName
    {
        get { return (string)GetValue(IconNameProperty); }
        set { SetValue(IconNameProperty, value); }
    }

    // 其他属性(IconHeight、IconColor)保持不变...

    static Icon()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Icon), 
            new FrameworkPropertyMetadata(typeof(Icon)));
    }

    // IconName 变化时触发,查找对应资源
    private static void OnIconNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var icon = d as Icon;
        if (icon == null) return;

        var resourceKey = e.NewValue as string;
        if (string.IsNullOrEmpty(resourceKey))
        {
            icon.IconGeometry = Geometry.Empty;
            return;
        }

        // 优先从控件自身资源查找,再从全局应用资源查找
        var geometry = icon.TryFindResource(resourceKey) as Geometry;
        if (geometry == null)
        {
            geometry = Application.Current.TryFindResource(resourceKey) as Geometry;
        }

        icon.IconGeometry = geometry ?? Geometry.Empty;
    }
}

2. 更新 Generic.xaml 模板

将 Path.Data 绑定到新的 IconGeometry 属性:

<Path Fill="{TemplateBinding IconColor}"
      Data="{TemplateBinding IconGeometry}"/>

最终使用

两种方式下,MainWindow.xaml 的用法保持不变:

<uiLib:Icon IconHeight="100"
            IconColor="White"
            IconName="Icon_Close"/>

内容的提问来源于stack exchange,提问作者Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:15:49