WPF :: Стилизация RibbonComboBox иначе, чем RibbonGallery

У меня есть RibbonComboBox, который используется для установки размеров шрифта. Он имеет RibbonGallery, в котором перечислены различные размеры шрифта, отображаемые в соответствующем 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 Вот моя 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>;
        }
     }
  }
}

Все работает, как и ожидалось, но после того, как я выбираю элемент из галереи, он появляется в RibbonComboBox с тем же огромным (или крошечным) FontSize, что и в галерее.

Как я могу «сбросить» FontSize выбранного элемента по умолчанию, когда он отображается в RibbonComboBox?


person Scott Baker    schedule 18.04.2015    source источник
comment
Можете ли вы опубликовать код своей ViewModel, пожалуйста?   -  person Il Vic    schedule 20.04.2015
comment
Размещено по запросу.   -  person Scott Baker    schedule 21.04.2015


Ответы (2)


RibbonComboBox использует ContentPresenter для отображения элемента, выбранного в RibbonGallery. Более того, ContentPresenter принимает тот же ItemTemplate, который вы объявили в RibbonGallery. Это "основная" причина вашей проблемы.

Таким образом, вы можете выбрать одно из двух решений для обхода проблемы.

ПЕРВОЕ РЕШЕНИЕ (самое быстрое)

Вы можете просто установить для свойства IsEditable вашего RibbonComboBox значение «true». Таким образом, RibbonComboBox заменяет ContentPresenter на TextBox без использования ItemTemplate. Тогда шрифт будет иметь нужный размер.

ВТОРОЕ РЕШЕНИЕ (лучшее ИМХО)

Поскольку ItemTemplate используется одновременно как из ContentPresenter RibbonComboBox, так и из RibbonGallery, это тот момент, когда мы можем попытаться решить проблему. Единственное отличие состоит в том, что когда DataTemplate помещается в RibbonGallery, его родителем является RibbonGalleryItem. Поэтому, если его родителем не является RibbonGalleryItem, вы автоматически знаете, что DataTemplate помещен внутри ContentPresenter. Вы можете справиться с этой ситуацией, написав простой DataTrigger. Посмотрим все в коде.

Я написал упрощенную 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;
            }
        }
    }
}

Тогда это мой взгляд:

<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>

Как видите, DataTrigger — это «компонент», который делает «грязную работу».

Теперь вам просто нужно решить, какое решение вы предпочитаете.

person Il Vic    schedule 22.04.2015
comment
Это именно то, что я искал. - person Scott Baker; 22.04.2015

Я бы посоветовал вам использовать библиотеку Fluent.Ribbon вместо лент Microsoft (поскольку они очень глючит, плохо поддерживается и поддерживает только старые стили, действительно поверьте мне, это просто избавит вас от многих проблем).

Тогда вы просто можете использовать этот код:

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

И получить желаемый результат:

введите здесь описание изображения

person Staeff    schedule 21.04.2015
comment
Хотя переход на Fluent.Ribbon может избавить меня от некоторых проблем, получение разрешения на работу со сторонней библиотекой — непростая задача. Это просто не вариант на данном этапе. - person Scott Baker; 22.04.2015
comment
Я уже работаю с лентой Microsoft. Чтобы использовать компонент ленты Fluent, нужно ли менять всю ленту? - person Jonathan Wood; 06.07.2016
comment
Это не совсем просто, и в зависимости от того, до какой степени вы используете, это может занять больше времени, но для нашего приложения с примерно 6 различными лентами это заняло около 3-5 дней, но это также решило многие из ошибок, которые мы связывали на ленту майкрософт - person Staeff; 07.07.2016