如果我有一个多分辨率的图标文件(.ico),如何确保WPF选择正确大小的图标? 设置Image的宽度和高度是否会强制进行选择,还是WPF只是调整ico文件中的第一个图标?
这是我目前使用的方法(虽然有效,但我希望避免调整大小,如果那是发生的事情)。
<MenuItem.Icon>
<Image Source="MyIcons.ico" Width="16" Height="16" />
</MenuItem.Icon>
如果可能的话,我希望在Xaml中声明它,而不必为它编写代码。
我使用简单的标记扩展来实现这个功能:
/// <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}" />
(基于@Nikolay的出色答案和后续评论,关于绑定)
你最好创建一个转换器
而不是标记扩展
,这样你就可以利用绑定
。使用@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 编辑器玩耍,这种行为更加方便。
仅使用Xaml似乎不可能实现。
如果你询问的原因是图标看起来模糊,可以查看这篇非常好的文章,我用它来解决这个问题:http://blogs.msdn.com/dwayneneed/archive/2007/10/05/blurry-bitmaps.aspx
你需要使用自定义控件,不仅要精确调整图标的大小,还要确保它与像素网格完全重合。只有这样才能避免插值和模糊。
正在尝试查找关于图标中图像大小选择的信息...如果找到了会回复...
ListBox
上使用多个图标时,这是否会影响性能?如果能够 缓存 解码后的图标,那么每个图标大小只需要解码一次就可以了。 - JobaDiniz