WPF: как настроить SelectionBoxItem в ComboBox
Я хочу отобразить пользовательский шаблон / элемент как выбранный элемент в ComboBox (этот элемент фактически не существует в списке элементов и обновляется по-разному). Это даже не должно быть элементом, просто предоставление пользовательского представления будет работать.
Как я могу это сделать, оставаясь в текущей теме ComboBox (так что замена ControlTemplate невозможна)? Насколько я вижу, все свойства SelectionBox* не редактируются и внутренне ComboBox использует неназванное объект ContentPresenter.
4 ответов
Я бы сделал так:
<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
(не только в
если у меня есть это прямо, вы хотите элемент управления, который имеет что-то произвольное, отображаемое вместе с раскрывающейся кнопкой, которая отображает список элементов с флажками рядом с ними?
я бы даже не стал пытаться перестроить ComboBox
для достижения этой цели. Проблема в том, что ComboBox
более специализирован по другому пути, чем то, что вам нужно. Если вы посмотрите на ComboBox ControlTemplate Пример, вы увидите, что он просто использует Popup
управление для отображения список возможных значений.
вы можете взять кусочки этого шаблона в качестве руководства для создания UserControl
что легче понять и лучше обеспечивает то, что вы хотите. Вы даже сможете добавить SelectedItems
свойство и такое, что ComboBox
не предоставляет.
пример того, что я подразумеваю под руководствам:Popup
есть IsOpen
собственность. В шаблоне элемента управления установлено значение {TemplateBinding IsDropDownOpen}
, что означает ComboBox
классе IsDropDownOpen
свойство, которое изменяется в порядке для управления расширением / сворачиванием Popup
.
комментарий Алексея Митева к Рэю Бернсу ответ вдохновил меня написать следующий достаточно короткий служебный класс, который я теперь использую во всех своих проектах 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>