WPF: как настроить SelectionBoxItem в ComboBox - PullRequest
8 голосов
/ 06 февраля 2010

Я хочу отобразить пользовательский шаблон / элемент как выбранный элемент в ComboBox (этот элемент фактически не существует в списке элементов и обновляется по-другому). Это даже не обязательно должен быть элемент, просто будет работать пользовательское представление.

Как я могу сделать это, оставаясь в текущей теме ComboBox (поэтому замена ControlTemplate невозможна)? Насколько я вижу, все свойства SelectionBox * не доступны для редактирования, и внутри ComboBox использует безымянный ContentPresenter.

Ответы [ 4 ]

20 голосов
/ 17 февраля 2010

Я бы сделал это так:

<Window.Resources>

  <DataTemplate x:Key="NormalItemTemplate" ...>
    ...
  </DataTemplate>

  <DataTemplate x:Key="SelectionBoxTemplate" ...>
    ...
  </DataTemplate>

  <DataTemplate x:Key="CombinedTemplate">
    <ContentPresenter x:Name="Presenter"
       Content="{Binding}"
       ContentTemplate="{StaticResource NormalItemTemplate}" />
    <DataTemplate.Triggers>
      <DataTrigger
        Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}"
        Value="{x:Null}">
        <Setter TargetName="Presenter" Property="ContentTemplate"
                Value="{StaticResource SelectionBoxTemplate}" />
      </DataTrigger>
    </DataTemplate.Triggers>
  </DataTemplate>

</Window.Resources>

...

<ComboBox
  ItemTemplate="{StaticResource CombinedTemplate}"
  ItemsSource="..."
  ... />

Причина, по которой это работает, заключается в том, что CombinedTemplate обычно просто использует NormalItemTemplate для представления своих данных, но если предка ComboBoxItem нет, он предполагает, что он находится в поле выбора, поэтому он использует SelectionBoxTemplate.

Обратите внимание, что три DataTemplates могут быть включены в любой уровень ResourceDictionary (не только на уровне Window) или даже непосредственно в ComboBox, в зависимости от ваших предпочтений.

0 голосов
/ 16 февраля 2018

Комментарий Алексея Митева к ответу Рэя Бернса вдохновил меня на написание следующего достаточно короткого служебного класса, который я сейчас использую во всех своих проектах WPF:

public class ComboBoxItemTemplateSelector : DataTemplateSelector
{
    public List<DataTemplate> SelectedItemTemplates { get; } = new List<DataTemplate>();
    public List<DataTemplate> DropDownItemTemplates { get; } = new List<DataTemplate>();

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return GetVisualParent<ComboBoxItem>(container) == null
            ? ChooseFrom(SelectedItemTemplates, item)
            : ChooseFrom(DropDownItemTemplates, item);
    }

    private static DataTemplate ChooseFrom(IEnumerable<DataTemplate> templates, object item)
    {
        if (item == null)
            return null;
        var targetType = item.GetType();
        return templates.FirstOrDefault(t => (t.DataType as Type) == targetType);
    }

    private static T GetVisualParent<T>(DependencyObject child) where T : Visual
    {
        while (child != null && !(child is T))
            child = VisualTreeHelper.GetParent(child);
        return child as T;
    }
}

Имея это в наборе инструментов, можно написать XAML так:

<UserControl.Resources>
     <DataTemplate x:Key="SelectedItemTemplateForInt" DataType="{x:Type system:Int32}">
         <!-- ... -->
     </DataTemplate>

     <DataTemplate x:Key="SelectedItemTemplateForDouble" DataType="{x:Type system:Double}">
         <!-- ... -->
     </DataTemplate>

     <DataTemplate x:Key="DropDownItemTemplateForInt" DataType="{x:Type system:Int32}">
         <!-- ... -->
     </DataTemplate>

     <DataTemplate x:Key="DropDownItemTemplateForDouble" DataType="{x:Type system:Double}">
         <!-- ... -->
     </DataTemplate>
</UserControl.Resources>

<ComboBox>
    <ComboBox.ItemTemplateSelector>
        <local:ComboBoxItemTemplateSelector>
            <local:ComboBoxItemTemplateSelector.SelectedItemTemplates>
                <StaticResource ResourceKey="SelectedItemTemplateForInt" />
                <StaticResource ResourceKey="SelectedItemTemplateForDouble" />
            </local:ComboBoxItemTemplateSelector.SelectedItemTemplates>

            <local:ComboBoxItemTemplateSelector.DropDownItemTemplates>
                <StaticResource ResourceKey="DropDownItemTemplateForInt" />
                <StaticResource ResourceKey="DropDownItemTemplateForDouble" />
            </local:ComboBoxItemTemplateSelector.DropDownItemTemplates>
        </local:ComboBoxItemTemplateSelector>
    </ComboBox.ItemTemplateSelector>
</ComboBox>
0 голосов
/ 16 февраля 2010

Если у меня есть это прямо, вы хотите, чтобы элемент управления отображал что-то произвольное вместе с выпадающей кнопкой, которая отображает список элементов с флажками рядом с ними?

Я бы даже не стал пытаться изменить стиль ComboBox для достижения этой цели. Проблема в том, что ComboBox более специализирован на другом пути, чем вам нужно. Если вы посмотрите на пример ComboBox ControlTemplate , то увидите, что он просто использует элемент управления Popup для отображения списка возможных значений.

Вы можете взять части этого шаблона в качестве руководства для создания UserControl, который будет проще для понимания и лучше обеспечит то, что вы хотите. Вы даже сможете добавить свойство SelectedItems и такое, что ComboBox не предоставит.

Пример того, что я подразумеваю под руководством: Popup имеет свойство IsOpen. В шаблоне управления он установлен на {TemplateBinding IsDropDownOpen}, что означает, что у класса ComboBox есть свойство IsDropDownOpen, которое изменяется, чтобы контролировать развёртывание / свертывание Popup.

0 голосов
/ 16 февраля 2010

Вам нужно изучить Триггеры и Стили . Вы также можете посмотреть некоторые из моих старых вопросов здесь, на StackOverflow, которые помогли мне решить эти проблемы:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...