【问题标题】:WPF Combobox: Different template in textbox and drop-downlistWPF Combobox:文本框和下拉列表中的不同模板
【发布时间】:2010-09-08 21:18:44
【问题描述】:

这是我的组合框。

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

如何更改它,以便只有 FullName 出现在组合框的文本框部分,而所有三列仍然出现在下拉部分中?

【问题讨论】:

    标签: c# wpf xaml combobox


    【解决方案1】:

    不幸的是,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模板,我只是修改了默认的,所以它应该是功能齐全的。

    【讨论】:

    • 我要花很长时间才能完全理解你做了什么,但它确实像宣传的那样有效。
    • 已经有几年了,但这个答案对我很有用。 +1
    【解决方案2】:

    如果 ComboBox 的 IsEditable 属性设置为 True,则可以将 ComboBox 的“TextSearch.TextPath”属性设置为要显示的属性名称。所以在你的情况下:

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

    【讨论】:

    • “破坏”TextSearch 是什么意思?
    【解决方案3】:

    我没有使用只读的 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):

    ComboBox 样式的 ControlTemplate 内的 ContentPresenter:

    <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”,该属性提供选择器并将该属性传递给样式。

    【讨论】:

      【解决方案4】:

      如果您不想更改 ComboBoxes 样式,这里有一个很好的回答您的问题:https://stackoverflow.com/a/2277488/1070906

      它在 DataTemplate 中使用了一个触发器,用于查看可视树上方某处是否有 ComboBoxItem,而选择框中的情况并非如此。

      【讨论】:

        【解决方案5】:

        您可以覆盖 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
        
        }
        

        一旦定义了控件,就可以设置它的样式。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-04
          相关资源
          最近更新 更多