WPF Combobox: другой шаблон в текстовом поле и раскрывающемся списке - PullRequest
16 голосов
/ 09 сентября 2010

Это мое поле со списком.

    <ComboBox Height="45" HorizontalAlignment="Left" Margin="184,66,0,0" Name="ComboBox1" VerticalAlignment="Top" Width="216">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Label Content="{Binding FullName}" Width="150" />
                    <Label Content="{Binding Title}" Width="100"/>
                    <Label Content="{Binding BranchName}" />
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

Как я могу изменить его так, чтобы в текстовом поле комбинированного списка отображалось только полное имя, а все три столбца все еще присутствовали в раскрывающемся списке?

Ответы [ 5 ]

30 голосов
/ 09 сентября 2010

К сожалению, SelectionBoxItemTemplate является свойством только для чтения, поэтому нам нужно проделать немного больше работы.Используя ItemTemplate так, как вы хотите, чтобы элемент отображался при выборе, вы можете отредактировать ItemContainerStyle для предоставления ControlTemplate, включающего другие поля, которые вы хотите отобразить.

<ComboBox Height="45" HorizontalAlignment="Left" Margin="184,66,0,0" Name="ComboBox1" VerticalAlignment="Top" Width="216">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Label Content="{Binding FullName}" Width="150" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
    <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                        <Border x:Name="Bd"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}">
                            <StackPanel Orientation="Horizontal">
                                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                                <Label Content="{Binding Title}" Width="100"/>
                                <Label Content="{Binding BranchName}" />
                            </StackPanel>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsHighlighted" Value="True">
                                <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

Для шаблона ComboBoxItem я только что изменил шаблон по умолчанию, поэтому он должен быть полностью функциональным.

7 голосов
/ 09 сентября 2010

Если для свойства ComEBox IsEditable задано значение True, для свойства ComboBox «TextSearch.TextPath» можно задать имя свойства, которое вы хотите отобразить.Итак, в вашем случае:

<ComboBox IsEditable="True" TextSearch.TextPath="FullName" .../>
2 голосов
/ 08 января 2016

Вместо использования свойства SelectionBoxItemTemplate, доступного только для чтения, я создал новое (прикрепленное, доступное для записи) свойство и использовал его в своем стиле.Я также добавил триггер к своему стилю, чтобы не нарушать все выпадающие списки, которые не используют мое новое прикрепленное свойство ...

Используйте его так:

<ComboBox ItemsSource="{Binding ...}" SelectedItem="{Binding ..., Mode=TwoWay}">
    <controls:ComboBoxSelectionBoxAltTemplateBehaviour.SelectionBoxAltTemplate>
        <DataTemplate DataType="{x:Type ...}">
            ... Template for the selection box ...
        </DataTemplate>
    </controls:ComboBoxSelectionBoxAltTemplateBehaviour.SelectionBoxAltTemplate>
    <ComboBox.ItemTemplate>
        <DataTemplate DataType="{x:Type ...}">
            ... Template for the popup ...
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Вам просто нужно добавитьэтот класс для вашего проекта:

public class ComboBoxSelectionBoxAltTemplateBehaviour
{
    public static readonly DependencyProperty SelectionBoxAltTemplateProperty = DependencyProperty.RegisterAttached(
        "SelectionBoxAltTemplate", typeof (DataTemplate), typeof (ComboBoxSelectionBoxAltTemplateBehaviour), new PropertyMetadata(default(DataTemplate)));

    public static void SetSelectionBoxAltTemplate(DependencyObject element, DataTemplate value)
    {
        element.SetValue(SelectionBoxAltTemplateProperty, value);
    }

    public static DataTemplate GetSelectionBoxAltTemplate(DependencyObject element)
    {
        return (DataTemplate) element.GetValue(SelectionBoxAltTemplateProperty);
    }

}

и измените стиль ComboBox, чтобы использовать вложенное свойство SelectionBoxAltTemplate, если оно установлено (или потому что я не смог установить триггер на «не ноль», я установил его обратно по умолчаниюSelectionBoxItemTemplate, если прикрепленный является нулевым):

ContentPresenter внутри ControlTemplate стиля ComboBox:

<ContentPresenter Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding controls:ComboBoxSelectionBoxAltTemplateBehaviour.SelectionBoxAltTemplate}" />

И триггер для обеспечения обратной совместимости с ComboBoxed без присоединенного свойства:

<ControlTemplate.Triggers>
    <Trigger Property="controls:ComboBoxSelectionBoxAltTemplateBehaviour.SelectionBoxAltTemplate" Value="{x:Null}">
        <Setter Property="ContentTemplate" Value="{Binding SelectionBoxItemTemplate, RelativeSource={RelativeSource TemplatedParent}}" TargetName="ContentSite" />
    </Trigger>
    ...
</ControlTemplate.Triggers>

Полный стиль:

<Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="FontSize" Value="12" />
    <Setter Property="Background" Value="{StaticResource ComboBoxBackground}"/>
    <Setter Property="BorderBrush" Value="{StaticResource ComboBoxBorder}"/>
    <Setter Property="Margin" Value="6"/>
    <Setter Property="Padding" Value="3,3,5,3"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBox}">
                <Grid>
                    <Grid.ColumnDefinitions>                    
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Border Name="Border" Grid.ColumnSpan="2" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
                    <ToggleButton Name="ToggleButton2" Focusable="False" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" Grid.ColumnSpan="2" Background="Transparent"/>
                    <!-- Allows clicking anywhere on the combobox, not only the visible button on the right -->
                    <ToggleButton Focusable="false" Grid.Column="1" x:Name="ToggleButton" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" Style="{StaticResource ComboBoxToggleButton}"/>
                    <ContentPresenter HorizontalAlignment="Left" Margin="{TemplateBinding Control.Padding}" x:Name="ContentSite" VerticalAlignment="Center" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding controls:ComboBoxSelectionBoxAltTemplateBehaviour.SelectionBoxAltTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" IsHitTestVisible="False" />

                    <TextBox Visibility="Hidden"  HorizontalAlignment="Left" Margin="{TemplateBinding Control.Padding}" x:Name="PART_EditableTextBox" Style="{x:Null}" VerticalAlignment="Center" Focusable="True" Background="Transparent"  />

                    <Popup IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" x:Name="Popup" Focusable="False" AllowsTransparency="True" PopupAnimation="Slide">
                        <Grid MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}" x:Name="DropDown" SnapsToDevicePixels="True">
                            <Border x:Name="DropDownBorder" Background="{StaticResource ComboBoxBackground}" BorderBrush="{StaticResource ComboBoxBorder}" BorderThickness="1" Padding="0,4">
                                <ScrollViewer SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="True" Style="{x:Null}" >
                                    <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
                                </ScrollViewer>
                            </Border>
                        </Grid>
                    </Popup>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="controls:ComboBoxSelectionBoxAltTemplateBehaviour.SelectionBoxAltTemplate" Value="{x:Null}">
                        <Setter Property="ContentTemplate" Value="{Binding SelectionBoxItemTemplate, RelativeSource={RelativeSource TemplatedParent}}" TargetName="ContentSite" />
                    </Trigger>
                    <Trigger Property="HasItems" Value="false">
                        <Setter Property="MinHeight" Value="95" TargetName="DropDownBorder" />
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
                    </Trigger>
                    <Trigger Property="IsEditable" Value="true">
                        <Setter Property="IsTabStop" Value="false" />
                        <Setter Property="Visibility" Value="Visible" TargetName="PART_EditableTextBox" />
                        <Setter Property="Visibility" Value="Hidden" TargetName="ContentSite" />
                    </Trigger>

                    <Trigger Property="IsMouseOver" Value="true" SourceName="ToggleButton2">
                        <Setter Property="Background" Value="{StaticResource ComboBoxMouseOver}" />
                    </Trigger>
                    <Trigger Property="HasItems" Value="False">
                        <Setter Property="IsEnabled" Value="False"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Однако это может не работать с ItemTemplateSelctors, только с одним единственным шаблоном - но вы можете легко добавить присоединенное свойство «SelectionBoxAltTemplateSelector», которое предоставляет селектор и передаетчто в стиле.

1 голос
/ 08 января 2016

Если вы не хотите менять стиль ComboBoxes, здесь есть довольно хороший ответ на ваш вопрос: https://stackoverflow.com/a/2277488/1070906

Он использует триггер в DataTemplate, который проверяет, есть ли ComboBoxItem где-то выше в визуальном дереве, чего нет в поле выбора.

0 голосов
/ 31 декабря 2018

Вы можете переопределить ComboBox и напрямую изменить шаблон SelectionBoxItemTemplate.

public class SelectionComboBox : ComboBox
{
    #region Properties

    #region Dependency Properties
    public DataTemplate AltSelectionBoxItemTemplate
    {
        get { return (DataTemplate)GetValue(AltSelectionBoxItemTemplateProperty); }
        set { SetValue(AltSelectionBoxItemTemplateProperty, value); }
    }

    public static readonly DependencyProperty AltSelectionBoxItemTemplateProperty =
        DependencyProperty.Register("AltSelectionBoxItemTemplate", typeof(DataTemplate), typeof(SelectionComboBox), new UIPropertyMetadata(null, (s, e) =>
        {
            // For new changes...
            if ((s is SelectionComboBox) && ((SelectionComboBox)s).Presenter != null && (e.NewValue is DataTemplate))
                ((SelectionComboBox)s).Presenter.ContentTemplate = (DataTemplate)e.NewValue;

            // Set the new value
            ((SelectionComboBox)s).AltSelectionBoxItemTemplate = (DataTemplate)e.NewValue;
        }));
    #endregion

    #region Internals

    #region Elements
    ContentPresenter Presenter { get; set; }
    #endregion

    #endregion

    #endregion

    #region Constructors
    #endregion

    #region Methods

    #region Overrides
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        Presenter = this.GetTemplateChild("contentPresenter") as ContentPresenter;

        // Directly Set the selected item template
        if (AltSelectionBoxItemTemplate != null) Presenter.ContentTemplate = AltSelectionBoxItemTemplate;
    }
    #endregion

    #endregion

}

Как только вы определите элемент управления, вы сможете его стилизовать.

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