【问题标题】:Multiple item combo box with headers?带有标题的多个项目组合框?
【发布时间】:2011-04-27 17:10:53
【问题描述】:

是否可以在绑定到多个项目的组合框中设置“列标题”?例如,显示人员姓名的组合框。组合框将显示 John Doe。但我想显示列标题:

First   Last
John    Doe
Jane    Doe
Jimmy   Doe

如果不使用数据网格,这可能吗? 包含使用数据网格的简单解决方案怎么样?我找到了一种将数据网格嵌入组合框的解决方案,但它看起来很困难并且需要 MS Blend。

如果我能在下拉列表的第一行中获得一些标题,我会很高兴。

G

这是我的 xaml 代码,其中 HB 尝试产生了 cmets 中提到的编译错误。

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
<ComboBox Name="cboPlaceNames" Grid.IsSharedSizeScope="True" ItemsSource="{DynamicResource items}" Height="22" Width="285" Margin="0,6,165,0" SelectedIndex="0" HorizontalAlignment="Right" VerticalAlignment="Top" SelectionChanged="cboPlaceNames_SelectionChanged">
  <ComboBox.Resources>
    <CompositeCollection x:Key="items">
      <ComboBoxItem IsEnabled="False">
        <Grid TextElement.FontWeight="Bold">
          <Grid.ColumnDefinitions>
            <ColumnDefinition SharedSizeGroup="A"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition SharedSizeGroup="B"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition SharedSizeGroup="C"/>
          </Grid.ColumnDefinitions>
          <Grid.Children>
            <TextBlock Grid.Column="0" Text="Name"/>
            <TextBlock Grid.Column="2" Text="CLLI"/>
            <TextBlock Grid.Column="4" Text="Street"/>
          </Grid.Children>
        </Grid>
      </ComboBoxItem>
      <Separator/>
      <CollectionContainer Collection="{Binding Source={x:Reference cboPlaceNames}, Path=DataContext.Data}"/>
    </CompositeCollection>

    <DataTemplate DataType="x:Type obj:PlaceName">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition SharedSizeGroup="A"/>
          <ColumnDefinition Width="5"/>
          <ColumnDefinition SharedSizeGroup="B"/>
          <ColumnDefinition Width="5"/>
          <ColumnDefinition SharedSizeGroup="C"/>
        </Grid.ColumnDefinitions>
        <Grid.Children>
          <TextBlock Grid.Column="0" Text="{Binding Name}"/>
          <TextBlock Grid.Column="2" Text="{Binding CLLI}"/>
          <TextBlock Grid.Column="4" Text="{Binding Street}"/>
        </Grid.Children>
      </Grid>
    </DataTemplate>
  </ComboBox.Resources>
</ComboBox>      

【问题讨论】:

    标签: wpf xaml combobox header


    【解决方案1】:

    例子:

    <ComboBox Name="cb" Grid.IsSharedSizeScope="True" ItemsSource="{DynamicResource items}">
        <ComboBox.Resources>
            <CompositeCollection x:Key="items">
                <ComboBoxItem IsEnabled="False">
                    <Grid TextElement.FontWeight="Bold">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition SharedSizeGroup="A"/>
                            <ColumnDefinition Width="5"/>
                            <ColumnDefinition SharedSizeGroup="B"/>
                        </Grid.ColumnDefinitions>
                        <Grid.Children>
                            <TextBlock Grid.Column="0" Text="Name"/>
                            <TextBlock Grid.Column="2" Text="Occupation"/>
                        </Grid.Children>
                    </Grid>
                </ComboBoxItem>
                <Separator/>
                <CollectionContainer Collection="{Binding Source={x:Reference cb}, Path=DataContext.Data}"/>
            </CompositeCollection>
    
            <DataTemplate DataType="{x:Type obj:Employee}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition SharedSizeGroup="A"/>
                        <ColumnDefinition Width="5"/>
                        <ColumnDefinition SharedSizeGroup="B"/>
                    </Grid.ColumnDefinitions>
                    <Grid.Children>
                        <TextBlock Grid.Column="0" Text="{Binding Name}"/>
                        <TextBlock Grid.Column="2" Text="{Binding Occupation}"/>
                    </Grid.Children>
                </Grid>
            </DataTemplate>
        </ComboBox.Resources>
    </ComboBox>
    

    请注意,获得Collection绑定权限并不是那么容易,因为既没有DataContext也没有VisualTree可以依赖,ElementNameRelativeSource不起作用,这是因为CompositeCollection只是一个集合,而不是 FrameworkElement。

    除此之外,这样做的方式是通过具有共享大小列的网格。 DataTemplate 通过DataType 自动应用。

    编辑: 将 header-ComboBoxItem 的 IsHitTestVisible 属性设置为 False 是不够的,因为它仍然可以使用键盘进行选择。我现在将其更改为IsEnabled="False",这会使项目稍微淡出。您可能可以重新模板该项目以不这样做。或者,如果您找到另一种方法来禁用它,当然也可以。

    【讨论】:

    • 非常好!在看到这个之前,我不知道 CompositeCollection。如果您还在标题项上设置了 Focusable="False",则它是不可选择的,您不需要 IsEnabled="False"
    • @jschroedl:谢谢;不幸的是,焦点与选择无关,所以这不起作用。
    • HB 这看起来很有希望。您可以发布您使用的参考。我收到有关使用“Collection="{Binding Source={x:Reference"”的错误,谢谢 Greg
    • 什么样的错误? x:Reference 按名称引用 ComboBox。
    • @Khushi: PathBinding 标记扩展的一个属性,我不会解释它,它还有一个广泛的文档以及articles on binding
    【解决方案2】:

    将列标题添加到组合框的最简单方法是在组合框中使用列表视图。 下面的代码给出了解决方案。

                <ComboBox HorizontalAlignment="Center" 
                          IsTextSearchEnabled="False" Width="200"                                            
                          IsEditable="True" Text="{Binding }"> 
                     <ListView ItemsSource="{Binding YOURITEMSOURCE}" 
                            SelectedItem="{Binding Path=SELECTEDITEMSOURCE}"
                             Height="200" ScrollViewer.VerticalScrollBarVisibility="Visible">                  
                               <ListView.View>
                                   <GridView>
                                      <GridViewColumn Width="130"  Header="Name" DisplayMemberBinding="{Binding Name}"   />
                                      <GridViewColumn Width="130" Header="Occupation" DisplayMemberBinding="{Binding Occupation}" />
                                      <GridViewColumn Width="130"  Header="Age" DisplayMemberBinding="{Binding Age}" />
                                      <GridViewColumn Width="130" Header="Salary" DisplayMemberBinding="{Binding Salary}" />
                                   </GridView>
                               </ListView.View>
                      </ListView>
    
                </ComboBox>
    

    【讨论】:

      【解决方案3】:

      我喜欢 Nandha 的回答,因为这是我想要达到的目标。但是,组合框的文本字段将无法正常工作。

      由于我很懒,为了解决这个问题,我创建了一个水平方向的 StackPanel,一个 TextBox 绑定到所选项目的一个字段,以及带有嵌入式 ListView 的 Combo Box。组合框现在的宽度为 20,因此只显示向下箭头(您可以使用宽度和边距来获得正确的外观。这使得文本框看起来像一个组合框,具有 ListView 的所有优点,而且编码更少。

      我希望这会有所帮助。enter image description here

      【讨论】:

        【解决方案4】:

        将以下样式应用于 ComboBox。

        <Style x:Key="ListViewComboBox" TargetType="{x:Type ComboBox}">
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
                                 Color="LightBlue"/>
            </Style.Resources>
            <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="FontFamily" Value="Arial"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="Margin" Value="0"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ComboBox}">
                        <Border Background="{TemplateBinding Background}" 
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}"
                                CornerRadius="3"
                                SnapsToDevicePixels="True">
                            <Grid>
                                <Border x:Name="Border">
                                    <Popup x:Name="PART_Popup" AllowsTransparency="true" IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Focusable="False">
                                        <Border x:Name="Shdw" 
                                                MaxHeight="{TemplateBinding MaxDropDownHeight}" 
                                                MinWidth="{Binding ActualWidth, ElementName=Border}">
                                            <Border x:Name="DropDownBorder" 
                                                    Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" 
                                                    BorderBrush="{TemplateBinding BorderBrush}" 
                                                    BorderThickness="1">
                                                <ListView KeyboardNavigation.DirectionalNavigation="Contained"
                                                          ItemsSource="{TemplateBinding ItemsSource}"
                                                          SelectedItem="{Binding Mode=TwoWay, Path=SelectedItem, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                                          View="{TemplateBinding Tag}"/>
                                            </Border>
                                        </Border>
                                    </Popup>
                                </Border>
                                <DockPanel Margin="2">
                                    <FrameworkElement DockPanel.Dock="Right"
                                                      Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
                                    <Border x:Name="SelectedItemBorder" Margin="{TemplateBinding Padding}">
                                        <Grid>
                                            <ContentPresenter Content="{TemplateBinding SelectionBoxItem}" 
                                                              ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" 
                                                              ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" 
                                                              ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
                                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                                              Margin="1,1,1,1" 
                                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                        </Grid>
                                    </Border>
                                </DockPanel>
                                <ToggleButton x:Name="DropDownToggleButton" 
                                              ClickMode="Press"
                                              Focusable="false" 
                                              Foreground="{TemplateBinding BorderBrush}"
                                              IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                              Margin="2"
                                              MinHeight="0" 
                                              MinWidth="0" 
                                              Width="Auto"/>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelectionBoxHighlighted" Value="true"/>
                                    <Condition Property="IsDropDownOpen" Value="false"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                            </MultiTrigger>
                            <Trigger Property="IsSelectionBoxHighlighted" Value="true">
                                <Setter Property="Background" TargetName="SelectedItemBorder" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="HasItems" Value="false">
                                <Setter Property="MinHeight" TargetName="DropDownBorder" Value="95"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsGrouping" Value="true">
                                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                            </Trigger>
                            <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
                                <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                            </Trigger>
                            <Trigger Property="IsReadOnly" Value="True">
                                <Setter Property="Visibility" TargetName="DropDownToggleButton" Value="Collapsed"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsEditable" Value="true">
                    <Setter Property="IsTabStop" Value="false"/>
                    <Setter Property="Padding" Value="1"/>
                    <Setter Property="Template" Value="{StaticResource ComboBoxEditableTemplate}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        

        将你想要的View应用到ComboBox的Tag属性上

        <ComboBox ItemsSource={Binding Items}>
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <!-- Enter your item template shown as the selected item. -->
                </DataTemplate>
            </ComboBox.ItemTemplate>
            <ComboBox.Tag>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Name}"
                                    Header="Name" 
                                    Width="100"/>
                </GridView>
            </ComboBox.Tag>
        </ComboBox>
        

        这就是所有人。

        【讨论】:

          【解决方案5】:

          我喜欢H.B.'s answer,但不幸的是,当我使用它时,我在标题ComboBoxItemHorizontalContentAlignmentVerticalContentAlignment 属性的输出中看到数据绑定错误:

          找不到与引用“RelativeSource”绑定的源 FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', 祖先级别='1''。 BindingExpression:Path=Horizo​​ntalContentAlignment; 数据项=空;目标元素是'ComboBoxItem'(名称='');目标 属性是“Horizo​​ntalContentAlignment”(类型“Horizo​​ntalAlignment”)

          这些不会使程序崩溃,但它们确实会使输出混乱并在运行调试构建时导致明显的延迟。无论是什么原因导致它们似乎都在ComboBoxComboBoxItem 的内心深处;无论如何,我想不出任何方法来阻止它们(手动设置这些属性或通过Style 没有帮助)。所以我最终选择了一个轻微的变化。这比我喜欢的要长和复杂,但它完成了工作:

          <ComboBox Name="cb" Grid.IsSharedSizeScope="True" ItemsSource="{DynamicResource items}">
           <ComboBox.Resources>
              <!-- We'll use this dummy value to represent the header row. -->
              <!-- The type and value are arbitrary; we just need a unique type -->
              <!-- for DataTemplate selection to work with. -->
              <system:Int32 x:Key="HeaderPlaceholder">-1</system:Int32>
          
              <CompositeCollection x:Key="items">
                <StaticResource ResourceKey="HeaderPlaceholder" />
                <CollectionContainer Collection="{Binding Source={x:Reference cb},
                   Path=DataContext.Data}"/>
              </CompositeCollection>
          
              <!-- DataTemplate for the header item -->
              <DataTemplate DataType="{x:Type system:Int32}">
                <DataTemplate.Resources>
                  <!-- Make the TextBlocks black even though they are disabled -->
                  <Style TargetType="TextBlock">
                    <Style.Triggers>
                      <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="Black" />
                      </Trigger>
                    </Style.Triggers>
                  </Style>
                </DataTemplate.Resources>
          
                <StackPanel>
                  <Grid TextElement.FontWeight="Bold">
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition SharedSizeGroup="A"/>
                      <ColumnDefinition Width="5"/>
                      <ColumnDefinition SharedSizeGroup="B"/>
                    </Grid.ColumnDefinitions>
                    <Grid.Children>
                        <TextBlock Grid.Column="0" Text="Name"/>
                        <TextBlock Grid.Column="2" Text="Occupation"/>
                    </Grid.Children>
                  </Grid>
                  <Separator />
                </StackPanel>
              </DataTemplate>
          
              <!-- DataTemplate for a normal, selectable item -->
              <DataTemplate DataType="{x:Type obj:Employee}">
                <Grid>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition SharedSizeGroup="A"/>
                    <ColumnDefinition Width="5"/>
                    <ColumnDefinition SharedSizeGroup="B"/>
                  </Grid.ColumnDefinitions>
                  <Grid.Children>
                    <TextBlock Grid.Column="0" Text="{Binding Name}"/>
                    <TextBlock Grid.Column="2" Text="{Binding Occupation}"/>
                  </Grid.Children>
                </Grid>
              </DataTemplate>
            </ComboBox.Resources>
          
            <ComboBox.ItemContainerStyle>
              <!-- Make sure the header item is disabled so it can't be selected -->
              <Style TargetType="ComboBoxItem">
                <Style.Triggers>
                  <Trigger Property="DataContext" Value="{StaticResource HeaderPlaceholder}">
                    <Setter Property="IsEnabled" Value="False" />
                  </Trigger>
                </Style.Triggers>
              </Style>
            </ComboBox.ItemContainerStyle>
          </ComboBox>
          

          【讨论】:

          • 1 年后,错误消息又回来了,即使是相同的 XAML。不明白... :(
          猜你喜欢
          • 2011-09-19
          • 1970-01-01
          • 1970-01-01
          • 2010-11-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多