(based on @Nikolay great answer and follow-up comment about binding)
You probably will be better off creating a Converter
instead of a MarkupExtension
so that you can leverage Binding
. Using the same logic as provided by @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();
}
You must then create a resource from your converter class somewhere in a ResourceDictionary as usual:
<localConverters:IcoFileSizeSelectorConverter x:Key="IcoFileSizeSelector" />
And then you can use Binding
:
<Image Source="{Binding Path=IconResource, Converter={StaticResource IcoFileSizeSelector}, ConverterParameter=16}" />
PS: in the converter code, we accept all inputs for parameter, even missing or invalid ones. That behaviour is more convenient if like me you like to play with live XAML edit.