Добавить заголовок к Combobox

Есть комбобокс:

    <ComboBox
        Name="subsystemCombobox"
        Height="30"
        IsReadOnly="True"
        IsEditable="False"
        VerticalAlignment="Bottom"
        HorizontalAlignment="Left">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                    <CheckBox
                        IsChecked="{Binding IsChecked}"
                        Width="120"
                        Content="{Binding SubSystemName}"
                        Checked="CheckBox_Checked"
                    />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

Как сделать в нем заголовок?


Ответы (1 шт):

Автор решения: vitidev

ComboBox просто выводит текущий пункт как он есть, поэтому свой контрол. Вот вам заготовка.

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

xaml:

<UserControl
    x:Class="WpfAppCombo.MyDropDown"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Name="Root"
    d:DesignHeight="30"
    d:DesignWidth="100"
    mc:Ignorable="d">
    <Grid>
        <ToggleButton Name="OpenPopup" Content="{Binding Header, ElementName=Root, Mode=OneWay}">
            <ToggleButton.Template>
                <ControlTemplate TargetType="ToggleButton">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition Width="20" />
                        </Grid.ColumnDefinitions>
                        <Border
                            x:Name="Border"
                            Grid.ColumnSpan="2"
                            Background="#FFEFEFEF"
                            BorderBrush="#C0C0C0"
                            BorderThickness="1"
                            SnapsToDevicePixels="True" />
                        <ContentPresenter
                            Grid.Column="0"
                            Margin="3,0,3,0"
                            VerticalAlignment="Center" />
                        <Path
                            x:Name="Arrow"
                            Grid.Column="1"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Data="M 0 0 L 4 4 L 8 0 Z"
                            Fill="DimGray" />
                    </Grid>
                </ControlTemplate>
            </ToggleButton.Template>
        </ToggleButton>
        <Popup
            Width="{Binding ActualWidth, ElementName=OpenPopup}"
            AllowsTransparency="True"
            IsOpen="{Binding IsChecked, ElementName=OpenPopup}"
            StaysOpen="False">
            <Border
                Padding="5"
                Background="White"
                BorderBrush="#C0C0C0"
                BorderThickness="1"
                SnapsToDevicePixels="True">
                <ItemsControl ItemTemplate="{Binding ItemTemplate, ElementName=Root, Mode=OneWay}" ItemsSource="{Binding ItemsSource, ElementName=Root, Mode=OneWay}">
                    <ItemsControl.ItemContainerStyle>
                        <Style TargetType="ContentPresenter">
                            <Setter Property="Height" Value="{Binding RowHeight, ElementName=Root, Mode=OneTime}" />
                        </Style>
                    </ItemsControl.ItemContainerStyle>
                </ItemsControl>
            </Border>
        </Popup>

    </Grid>
</UserControl>

code-behind:

public partial class MyDropDown : UserControl
{
    public MyDropDown()
    {
        InitializeComponent();
    }

    public double RowHeight { get; set; } = 23;

    public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
        "ItemTemplate", typeof(DataTemplate), typeof(MyDropDown), new PropertyMetadata(default(DataTemplate)));

    public DataTemplate ItemTemplate
    {
        get => (DataTemplate)GetValue(ItemTemplateProperty);
        set => SetValue(ItemTemplateProperty, value);
    }

    public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
        "Header", typeof(string), typeof(MyDropDown), new PropertyMetadata(default(string)));

    public string Header
    {
        get => (string)GetValue(HeaderProperty);
        set => SetValue(HeaderProperty, value);
    }

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
        "ItemsSource", typeof(IEnumerable), typeof(MyDropDown), new PropertyMetadata(default(IEnumerable)));

    public IEnumerable ItemsSource
    {
        get => (IEnumerable)GetValue(ItemsSourceProperty);
        set => SetValue(ItemsSourceProperty, value);
    }
}

использование:

<c:MyDropDown
    Width="150"
    Height="30"
    RowHeight="30"
    Header="{Binding Header, Mode=OneWay}"
    ItemsSource="{Binding Items, Mode=OneWay}">
    <wpfAppCombo:MyDropDown.ItemTemplate>
        <DataTemplate>
            <CheckBox                    
                VerticalAlignment="Center"
                Click="CheckBox_OnClick"
                Content="{Binding SubSystemName, Mode=OneWay}"
                IsChecked="{Binding IsChecked, Mode=TwoWay}" />
        </DataTemplate>
    </wpfAppCombo:MyDropDown.ItemTemplate>
</c:MyDropDown>

Где в CheckBox_OnClick обновлять Header (хотя конечно лучше использовать не события, а команды, но mvvm уже выходит за рамки вопроса)

Замечания

  1. Контрол сделан на коленке, поэтому в нем нет полной стилизации под настоящий комбокбокс, только минимально переопределен шаблон с вшитыми цветами. Также хидер выводит строку, хотя мог бы что угодно
  2. При огромном количестве пунктов вместо списка можно использовать UniformGrid - будет многоколоночный список
  3. Событие Checked у CheckBox срабатывает только в одну сторону, поэтому лучше ловить Click
→ Ссылка