c# wpf xaml combobox

c# - WPF Combobox: plantilla diferente en cuadro de texto y lista desplegable



xaml (5)

Desafortunadamente, el SelectionBoxItemTemplate es una propiedad de solo lectura, así que tenemos que hacer un poco más de trabajo. Al hacer que ItemTemplate sea ​​la forma en que desea que aparezca el elemento cuando se selecciona, puede editar ItemContainerStyle para proporcionar una ControlTemplate que incluya los otros campos que desea mostrar.

<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>

Para la plantilla ComboBoxItem , acabo de modificar la predeterminada, por lo que debería ser completamente funcional.

Este es mi cuadro de combo.

<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>

¿Cómo puedo cambiarlo para que solo aparezca el Nombre completo en la parte del cuadro de texto del cuadro combinado mientras que las tres columnas aún aparecen en la parte desplegable?


En lugar de usar la propiedad SelectionBoxItemTemplate de solo lectura, creé una nueva propiedad (adjunta, escribible) y la utilicé en mi estilo. También agregué un activador a mi estilo para no romper todos los cuadros combinados que no están usando mi nueva propiedad adjunta ...

Úsalo así:

<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>

Solo tienes que añadir esta clase a tu proyecto:

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); } }

y cambie su estilo ComboBox para usar la propiedad adjunta SelectionBoxAltTemplate si está configurada (o porque no pude establecer un activador en "no nulo", lo puse de nuevo en la SelectionBoxItemTemplate predeterminada si la adjunta es nula):

El ContentPresenter dentro del ControlTemplate del estilo ComboBox:

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

Y el activador para proporcionar compatibilidad con versiones anteriores a ComboBoxed sin la propiedad adjunta:

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

Estilo completo:

<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>

Sin embargo, esto podría no funcionar con ItemTemplateSelctors, solo con una sola plantilla, pero podría agregar fácilmente una propiedad adjunta "SelectionBoxAltTemplateSelector" que proporciona el selector y la pasa al estilo.


Hay una respuesta bastante buena a su pregunta aquí si no desea cambiar el estilo de ComboBoxes: https://.com/a/2277488/1070906

Utiliza un Disparador en la Plantilla de datos que se ve si hay un ComboBoxItem en algún lugar arriba en el árbol visual, que no es el caso en el cuadro de selección.


Puede anular el ComboBox y cambiar el SelectionBoxItemTemplate directamente.

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 }

Una vez que definas el control, puedes ponerle estilo.

<controls:SelectionComboBox ItemsSource="{Binding ...}" SelectedItem="{Binding ..., Mode=TwoWay}"> <controls:SelectionComboBox.AltSelectionBoxItemTemplate> <DataTemplate> <!-- My Template Goes Here... --> </DataTemplate> </controls:SelectionComboBox.AltSelectionBoxItemTemplate> </controls:SelectionComboBox>


Si la propiedad IsEditable del ComboBox se establece en Verdadero, puede establecer la propiedad "TextSearch.TextPath" del ComboBox en el nombre de la propiedad que desea mostrar. Así que en tu caso:

<ComboBox IsEditable="True" TextSearch.TextPath="FullName" .../>