2
votes

So far, if I've wanted to just make a button with an image in my XAML, I could do something like this:

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

This worked well. Now I'm trying to do RibbonButtons and RibbonApplicationMenuItems, and things don't seem to quickly make sense.

A RibbonButton has a LargeImageSource and a SmallImageSource... If I try modifying the content like as shown above, neither of the images appear. If I use a 48x48 image for both Large and SmallImageSources, the small one ends up pixelated. What? I thought I can specify aliasing and high quality, and that the application is supposed to scale the image cleanly for me. Why doesn't this happen?

Similar issue with the RibbonApplicationMenuItem. This one lets me specify an ImageSource. If I pick a large PNG, it looks okay-ish, but is pixelated (the same PNG resized in an Explorer window looks fine), like it is being improperly stretched smaller. If I use an ICO that has 16x16, 24x24, 32x32, 48x48, etc. embedded, it looks like the smallest icon in the ICO is used and the stretched larger.

If I use the same ICO file that the application icon is using (which looks fine on at the top of the application, so that picked the right embedded icon), even with this ICO the RibbonApplicationMenuItem looks poor.

Obviously I'm missing some key things here. What do I need to do so that my buttons and items on my ribbon navigation look clean and sharp?

More example code:

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

EDIT 9/24/15: Per Adeeb Arangodan's request, I'm adding more code and including some pictures.

Pictures of some of the original images used (ICOs, and PNGs of various sizes):

enter image description here

Also, here is more example code. Included is the entire window, and multiple button attempts. As you can see, only the image "paste_32.png" which is already sized correctly, appears to look nice. Every other button, whether using an ICO or PNG that is larger than the target size, ends up blurry.

<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>
2
Maybe you should also show your code about RibbonButtons and RibbonApplicationMenuItemsIl Vic
I've added some more of my code. One image I have tried using is a 128x128 PNG that according to paint.net has a resolution of 96 pixels/inch. It appears rendered in Button/MenuItem looking jagged.ohioDeveloper

2 Answers

0
votes

This is how I did this:

  1. Add your image to the project

    SolutionExplorer->Select package->Add->ExistingItem->choose your image file


  1. Set it as a content resource

    Select the image in solution explorer. Set the property 'BuildAction' to 'Content'


  1. Set the Ribbon image in xaml markup as SmallImageSource or LargeImageSource. My image is a png image with 128*128 resolution

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

I'm not sure this is the best way (and will mark another solution as the right answer if someone has a method that is easy to use in the XAML), but this was effective for me when using ICOs that have only one type of image, but different sizes. I created a Converter based on Nikolay's answer 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();
    }
}

I created one of these converters for each standard size (16, 24, 32, etc.) that could each be used standalone. They just need to be passed a path to the ICO file.

I then created a parent converter that could be passed a string in the form of "path, size", so that in the XAML image for a Button could use the same converter.

[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();
    }
}

I don't think of this as elegant, I'm not sure it is efficient, it does not (yet) handle PNGs or other image formats, and for ICOs it can only handle those that are for one image (as opposed to multiple different images in various sizes) by picking the First item. But it does allow:

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