如何从WPF中的多分辨率.ico文件中选择正确的大小图标?

时间:2009-06-04 17:44:20

标签: wpf icons

如果我有一个多分辨率图标文件(.ico),我怎样才能确保WPF选择合适尺寸的文件?设置图像的宽度和高度是否会强制它,或者WPF是否只是调整ico文件中的第一个图标?

这就是我目前正在使用的(它有效,但我想避免调整大小,如果这是正在发生的事情)。

<MenuItem.Icon>
    <Image Source="MyIcons.ico" Width="16" Height="16"  />
</MenuItem.Icon>

如果可能的话,我想在Xaml中声明这一点,而无需为其编写代码。

4 个答案:

答案 0 :(得分:29)

我使用简单的标记扩展:

/// <summary>
/// Simple extension for icon, to let you choose icon with specific size.
/// Usage sample:
/// Image Stretch="None" Source="{common:Icon /Controls;component/icons/custom.ico, 16}"
/// Or:
/// Image Source="{common:Icon Source={Binding IconResource}, Size=16}"
/// </summary> 
public class IconExtension : MarkupExtension
{
    private string _source;

    public string Source
    {
        get
        {
            return _source;
        }
        set
        {
            // Have to make full pack URI from short form, so System.Uri recognizes it.
           _source = "pack://application:,,," + value;
        }
    }

    public int Size { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var decoder = BitmapDecoder.Create(new Uri(Source), 
                                           BitmapCreateOptions.DelayCreation,
                                           BitmapCacheOption.OnDemand);

        var result = decoder.Frames.SingleOrDefault(f => f.Width == Size);
        if (result == default(BitmapFrame))
        {
            result = decoder.Frames.OrderBy(f => f.Width).First();
        }

        return result;
    }

    public IconExtension(string source, int size)
    {
        Source = source;
        Size = size;
    }

    public IconExtension() { }
}

Xaml用法:

<Image Stretch="None"
       Source="{common:Icon Source={Binding IconResource},Size=16}"/>

<Image Stretch="None"
       Source="{common:Icon /ControlsTester;component/icons/custom-reports.ico, 16}" />

答案 1 :(得分:4)

似乎只能使用Xaml。

答案 2 :(得分:2)

(基于@Nikolay的出色回答和有关绑定的后续评论)

创建Converter而不是MarkupExtension可能会更好,这样您就可以利用Binding。使用与@Nikolay提供的相同的逻辑

    /// <summary>
    /// Forces the selection of a given size from the ICO file/resource. 
    /// If the exact size does not exists, selects the closest smaller if possible otherwise closest higher resolution.
    /// If no parameter is given, the smallest frame available will be selected
    /// </summary>
    public class IcoFileSizeSelectorConverter : IValueConverter
    {
        public virtual object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var size = string.IsNullOrWhiteSpace(parameter?.ToString()) ? 0 : System.Convert.ToInt32(parameter);

            var uri = value?.ToString()?.Trim();
            if (string.IsNullOrWhiteSpace(uri))
                return null;

            if (!uri.StartsWith("pack:"))
                uri = $"pack://application:,,,{uri}";

            var decoder = BitmapDecoder.Create(new Uri(uri),
                                              BitmapCreateOptions.DelayCreation,
                                              BitmapCacheOption.OnDemand);

            var result = decoder.Frames.Where(f => f.Width <= size).OrderByDescending(f => f.Width).FirstOrDefault()
                ?? decoder.Frames.OrderBy(f => f.Width).FirstOrDefault();

            return result;
        }

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

然后,您必须照常从转换器类的ResourceDictionary中的某个位置创建资源:

<localConverters:IcoFileSizeSelectorConverter x:Key="IcoFileSizeSelector" />

然后您可以使用Binding

<Image Source="{Binding Path=IconResource, Converter={StaticResource IcoFileSizeSelector}, ConverterParameter=16}" />

PS:在转换器代码中,我们接受参数的所有输入,甚至包括缺失或无效的输入。如果像我这样喜欢实时XAML编辑,则这种行为会更方便。

答案 3 :(得分:1)

如果您问的原因是图标看起来很模糊,请查看我用来解决该问题的非常好的文章:http://blogs.msdn.com/dwayneneed/archive/2007/10/05/blurry-bitmaps.aspx

您必须使用自定义控件,不仅可以精确地调整图标大小,还可以确保它与像素网格完全一致。只有这样你才能避免插值,因此会模糊。

尝试在图标中查找有关图像尺寸选择的查询的一些信息...如果找到任何信息,我会回复...