WPF :: Styling the RibbonComboBox Differently Than The RibbonGallery
Asked Answered
S

2

8

I have a RibbonComboBox that is used to set font sizes. It has a RibbonGallery that lists the various font sizes, displayed in the appropriate FontSize:

<r:RibbonComboBox DataContext="{x:Static vm:RibbonDataModel.FontSizeComboBoxData}"
                  SelectionBoxWidth="30">
   <r:RibbonGallery MaxColumnCount="1"
                    Command="{Binding Command}"
                    CommandParameter="{Binding SelectedItem}">
      <r:RibbonGallery.GalleryItemTemplate>
         <DataTemplate>
            <Grid>
               <TextBlock Text="{Binding}"
                          FontSize="{Binding}" />
            </Grid>
         </DataTemplate>
      </r:RibbonGallery.GalleryItemTemplate>
   </r:RibbonGallery>
</r:RibbonComboBox>

EDIT Here is my ViewModel:

public static RibbonDataModel
{
  public static GalleryData<object> FontSizeComboBoxData
  {
     get
     {
        lock (LockObject)
        {
           const string key = "Font Size";
           if (!DataCollection.ContainsKey(key))
           {
              var value = new GalleryData<object>
              {
                 Command = HtmlDocumentCommands.ChangeFontSize,
                 Label = "Change Font Size",
                 ToolTipDescription = "Set the font to a specific size.",
                 ToolTipTitle = "Change Font Size",
              };

              var fontSizes = new GalleryCategoryData<object>();
              var i = 9.0;
              while (i <= 30)
              {
                 fontSizes.GalleryItemDataCollection.Add(i);
                 i += 0.75;
              }
              value.CategoryDataCollection.Add(fontSizes);
              DataCollection[key] = value;
           }
           return DataCollection[key] as GalleryData<object>;
        }
     }
  }
}

Everything works as expected, but after I select an item from the gallery, it shows up in the RibbonComboBox with the same huge (or tiny) FontSize as it uses in the gallery.

How can I "reset" the FontSize of the selected item to the default when it's displayed in the RibbonComboBox?

Screamer answered 18/4, 2015 at 18:37 Comment(2)
Can you post your ViewModel's code, please?Cadenza
Posted as requested.Screamer
C
5

The RibbonComboBox uses a ContentPresenter to show the item you select in the RibbonGallery. Moreover the ContentPresenter adopts the same ItemTemplate that you declared in the RibbonGallery. This is the "core" reason of your problem.

So you can choose between two solutions to workaround the problem.

FIRST SOLUTION (the fastest one)

You can simply set the IsEditable property of your RibbonComboBox to "true". In this way the RibbonComboBox replaces the ContentPresenter with a TextBox, without using any ItemTemplate. Then the font will have the right size.

SECOND SOLUTION (the best one IMHO)

Since the ItemTemplate is used at the same from both the RibbonComboBox's ContentPresenter and the RibbonGallery, it is the point where we can try to solve the problem. The olny difference is that when the DataTemplate is placed inside the RibbonGallery, its parent is a RibbonGalleryItem. So if its parent is not a RibbonGalleryItem, you automatically know that the DataTemplate is placed inside the ContentPresenter. You can handle this situation by writing a simple DataTrigger. Let's see all in the code.

I wrote a simplified ViewModel:

namespace WpfApplication1
{
    public class FontSizes
    {
        private static FontSizes instance = new FontSizes();
        private List<double> values = new List<double>();

        public FontSizes()
        {
            double i = 9.0;
            while (i <= 30)
            {
                values.Add(i);
                i += 0.75;
            }
        }

        public IList<double> Values
        {
            get
            {
                return values;
            }
        }

        public static FontSizes Instance
        {
            get
            {
                return instance;
            }
        }
    }
}

Then this is my View:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ribbon="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
        xmlns:vm="clr-namespace:WpfApplication1"
        Title="Window1" Height="300" Width="300">
    <Window.Resources />

    <DockPanel>
        <ribbon:RibbonComboBox Label="Select a font size:"
                  SelectionBoxWidth="62"
                  VerticalAlignment="Center">

        <ribbon:RibbonGallery MaxColumnCount="1">
                <ribbon:RibbonGalleryCategory DataContext="{x:Static vm:FontSizes.Instance}" ItemsSource="{Binding Path=Values, Mode=OneWay}">
                    <ribbon:RibbonGalleryCategory.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <TextBlock Name="tb" Text="{Binding}" FontSize="{Binding}" />
                            </Grid>

                            <DataTemplate.Triggers>
                                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ribbon:RibbonGalleryItem, AncestorLevel=1}}"
                                             Value="{x:Null}">
                                    <Setter TargetName="tb" Property="FontSize" Value="12" />
                                </DataTrigger>
                            </DataTemplate.Triggers>
                        </DataTemplate>
                    </ribbon:RibbonGalleryCategory.ItemTemplate>
                </ribbon:RibbonGalleryCategory>
            </ribbon:RibbonGallery>
        </ribbon:RibbonComboBox>
    </DockPanel>
</Window>

As you can see the DataTrigger is the "component" which makes the "dirty job".

Now you just need to make you your mind about which solution you prefer.

Cadenza answered 22/4, 2015 at 8:21 Comment(0)
S
2

I would advise you to use the Fluent.Ribbon library instead of the Microsoft Ribbons (as they are very buggy, not well maintained and only support old styles, really trust me on this one it will just save you much trouble).

Then you simply can use this code:

<fluent:ComboBox Header="Font Size" ItemsSource="{Binding FontSizes}">
    <fluent:ComboBox.ItemTemplate>
        <ItemContainerTemplate>
            <TextBlock FontSize="{Binding }" Text="{Binding }" />
        </ItemContainerTemplate>
    </fluent:ComboBox.ItemTemplate>
</fluent:ComboBox>

And get the desired result:

enter image description here

Surcease answered 21/4, 2015 at 14:56 Comment(3)
While switching to Fluent.Ribbon might save me some troubles, getting approval to work with a third party library is no simple task. This is simply not an option at this juncture.Screamer
I'm already working with Microsoft's ribbon. To use the Fluent ribbon component, do I need to swap out the entire ribbon?Teepee
It's not entirely easy, and depending on what to what extend you are using it can take a longer time, but for our application with about 6 different ribbons it took about 3-5 days, but it also solved many of the bugs we had related to microsoft's ribbonSurcease

© 2022 - 2024 — McMap. All rights reserved.