WPF功能区中的像素化图像/图标?

Pixelated images / icons in in WPF Ribbon?

到目前为止,如果我只想在 XAML 中制作一个带有图像的按钮,我可以这样做:

<Button>
    <Button.Content>
        <Grid>
            <Image Source="myimage.png" Width="45" RenderOptions.EdgeMode="Aliased" RenderOptions.BitmapScalingMode="High Quality"/>
        </Grid>
    </Button.Content>
<Button>

这很有效。现在我正在尝试做 RibbonButtons 和 RibbonApplicationMenuItems,但事情似乎并没有很快变得有意义。

一个 RibbonButton 有一个 LargeImageSource 和一个 SmallImageSource...如果我尝试修改如上所示的内容,两个图像都不会出现。如果我对 Large ImageSources 和 SmallImageSources 使用 48x48 图像,则小图像最终会像素化。什么?我以为我可以指定别名和高质量,并且应用程序应该为我干净地缩放图像。为什么这没有发生?

RibbonApplicationMenuItem 存在类似问题。这个让我指定一个 ImageSource。如果我选择一个大的 PNG,它看起来还不错,但是像素化了(在 Explorer window 中调整大小的相同 PNG 看起来很好),就像它被不正确地拉伸得更小一样。如果我使用嵌入了 16x16、24x24、32x32、48x48 等尺寸的 ICO,它看起来像是使用了 ICO 中最小的图标并且拉伸得更大。

如果我使用与应用程序图标相同的 ICO 文件(它在应用程序顶部看起来不错,因此选择了正确的嵌入式图标),即使使用此 ICO,RibbonApplicationMenuItem 看起来也很差。

显然我在这里遗漏了一些关键的东西。我需要做什么才能让功能区导航上的按钮和项目看起来干净利落?

更多示例代码:

<RibbonApplicationMenuItem Header="Command Text" ImageSource="myimage.png" Command="{Binding MyCommand}" />
<RibbonButton LargeImageSource="myimage.png" Label="Command Text" KeyTip="C" Command="{Binding MyCommand}" />

编辑 2015 年 9 月 24 日:根据 Adeeb Arangodan 的要求,我正在添加更多代码并包含一些图片。

使用的一些原始图像的图片(ICO 和各种尺寸的 PNG):

此外,这里还有更多示例代码。包括整个 window 和多个按钮尝试。如您所见,只有已经正确调整大小的图像 "paste_32.png" 看起来不错。其他所有按钮,无论是使用大于目标尺寸的 ICO 还是 PNG,最终都会变得模糊。

<Window x:Class="RibbonDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:r="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary">
    <Grid>
        <r:Ribbon>
            <r:Ribbon.HelpPaneContent>
                <r:RibbonButton SmallImageSource="pack://application:,,,/RibbonDemo;component/Images/help.ico" />
            </r:Ribbon.HelpPaneContent>

            <r:Ribbon.ApplicationMenu>
                <r:RibbonApplicationMenu >
                    <r:RibbonApplicationMenuItem Header="Error" ImageSource="pack://application:,,,/RibbonDemo;component/Images/error.ico" />
                    <r:RibbonApplicationMenuItem Header="Print" ImageSource="pack://application:,,,/RibbonDemo;component/Images/print.ico" />
                    <r:RibbonApplicationMenuItem Header="Vendor" ImageSource="pack://application:,,,/RibbonDemo;component/Images/batch_logo.png" RenderOptions.EdgeMode="Aliased" RenderOptions.BitmapScalingMode="HighQuality" />
                    <r:RibbonApplicationMenuItem Header="Paste" ImageSource="pack://application:,,,/RibbonDemo;component/Images/paste_32.png" />
                </r:RibbonApplicationMenu>
            </r:Ribbon.ApplicationMenu>

            <r:RibbonTab Header="Home">

                <r:RibbonGroup Header="Home">
                    <r:RibbonMenuButton 
                        LargeImageSource="pack://application:,,,/RibbonDemo;component/Images/error.ico"
                        SmallImageSource="pack://application:,,,/RibbonDemo;component/Images/error.ico" Label="Error">
                    </r:RibbonMenuButton>
                    <r:RibbonButton LargeImageSource="pack://application:,,,/RibbonDemo;component/Images/print.ico" Label="Help"/>
                    <r:RibbonButton LargeImageSource="pack://application:,,,/RibbonDemo;component/Images/batch_logo.png" Label="Vendor" RenderOptions.EdgeMode="Aliased" RenderOptions.BitmapScalingMode="HighQuality"/>
                    <r:RibbonButton LargeImageSource="pack://application:,,,/RibbonDemo;component/Images/paste_32.png" Label="Paste"/>
                </r:RibbonGroup>
            </r:RibbonTab>
        </r:Ribbon>
    </Grid>
</Window>

我是这样做的:

  1. 将您的图片添加到项目中

    SolutionExplorer->Select package->Add->ExistingItem->选择你的镜像文件


  1. 将其设置为内容资源

    Select 解决方案资源管理器中的图像。将 属性 'BuildAction' 设置为 'Content'


  1. 将 xaml 标记中的功能区图像设置为 SmallImageSource 或 LargeImageSource。我的图片是128*128分辨率的png图片

     <RibbonButton Margin="3" LargeImageSource="/Resources/images/Home.png" 
          Label="Home" ToolTip="Show company detials" Command="{Binding ShowHomeCommand}">
    

我不确定这是最好的方法(如果有人在 XAML 中有易于使用的方法,我会把另一个解决方案标记为正确答案),但这对我很有效使用具有 只有 一种图像但尺寸不同的 ICO 时。我根据 Nikolay 的回答创建了一个转换器 here

[ValueConversion(typeof(string), typeof(ImageSource))]
public class IconExtractor32 : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string path = parameter.ToString();
        var decoder = BitmapDecoder.Create(new Uri(path.ToString()), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);

        // It is assumed that if multiple icons of the same size are available,
        // that the first ones encountered are those intended for use.
        var result = decoder.Frames.First(f => f.Width == 32);
        if (result == default(BitmapFrame))
            result = decoder.Frames.OrderBy(f => f.Width).First();
        return result;
    }

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

我为每个标准尺寸(16、24、32 等)创建了一个转换器,每个转换器都可以单独使用。他们只需要传递一个 ICO 文件的路径。

然后我创建了一个可以传递 "path, size" 形式的字符串的父转换器,因此在 XAML 图像中的 Button 可以使用相同的转换器。

[ValueConversion(typeof(string), typeof(ImageSource))]
public class IconExtractor : IValueConverter
{
    private IconExtractor32 extractor32 = new IconExtractor32();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string source = parameter.ToString();
        string[] values = source.Split(',').Select(sValue => sValue.Trim()).ToArray();

        if (2 != values.Count())
        {
            throw new NotImplementedException();
        }
        else
        {
            string path = "pack://application:,,," + values[0];

            switch (values[1])
            {
                case "32":
                    return extractor32.Convert(value, targetType, path, culture);
                default:
                    throw new NotImplementedException();
            }
        }
    }

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

我不认为这很优雅,我不确定它是否有效,它(还)不能处理 PNG 或其他图像格式,对于 ICO,它只能处理那些只适用于一张图像的图像(与不同尺寸的多个不同图像相反)通过选择第一项。但它确实允许:

<Fluent:MenuItem.Icon>
    <Binding Converter="{StaticResource iconExtractor}" ConverterParameter="/myapplication;component/Images/error.ico, 32"/>
</Fluent:MenuItem.Icon>