WPF:如何在ComboBox中自定义SelectionBoxItem

时间:2010-02-06 20:57:18

标签: wpf templates combobox customization

我想在ComboBox中显示自定义模板/项目作为选定项目(此项目实际上不存在于项目列表中,并且更新方式不同)。这甚至不需要是一个项目,只需提供自定义视图即可。

如何在保持当前ComboBox主题的同时执行此操作(因此无法替换ControlTemplate)?据我所知,所有SelectionBox *属性都不可编辑,内部ComboBox使用未命名的ContentPresenter。

4 个答案:

答案 0 :(得分:20)

我会这样做:

<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内,具体取决于您的偏好。

答案 1 :(得分:0)

如果我直截了当,你想要一个随意显示的控件以及一个下拉按钮,它会显示一个带有复选框的项目列表吗?

我甚至不愿意尝试重新设置ComboBox来实现这一目标。问题是ComboBox在不同于您需要的路径上更专业。如果您查看ComboBox ControlTemplate Example,您会看到它只是使用Popup控件来显示可能的值列表。

您可以将该模板的各个部分作为创建UserControl的指导,以便更容易理解并更好地提供您想要的内容。您甚至可以添加SelectedItems属性,ComboBox无法提供。

我的意思是指导的一个例子:Popup有一个IsOpen属性。在控件模板中,它设置为{TemplateBinding IsDropDownOpen},这意味着ComboBox类具有IsDropDownOpen属性,该属性已更改以控制Popup的展开/折叠

答案 2 :(得分:0)

Alexey Mitev对Ray Burns'answer的评论激励我编写以下合理的短实用程序类,我现在在所有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>

答案 3 :(得分:-1)

您需要查看TriggersStyles。您可能还想在StackOverflow上查看我的一些旧问题,这些问题帮助我克服了这些问题: