在WPF中创建带弹窗的横向项控件/ComboBox:修复失效代码
修复并实现需求的WPF ComboBox代码
原代码无效的核心原因是ControlTemplate中缺少了ComboBox的主视觉组件(选择输入区域、下拉触发按钮),同时未按需求配置弹出层的位置和项布局。以下是修复并满足所有需求的完整代码:
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" IsDropDownOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource Self}}"> <!-- 模拟30×30的方块项 --> <ComboBox.Items> <ComboBoxItem Background="Red"/> <ComboBoxItem Background="Green"/> <ComboBoxItem Background="Blue"/> <ComboBoxItem Background="Yellow"/> </ComboBox.Items> <!-- 设置项的固定大小和对齐 --> <ComboBox.ItemContainerStyle> <Style TargetType="{x:Type ComboBoxItem}"> <Setter Property="Width" Value="30"/> <Setter Property="Height" Value="30"/> <Setter Property="Margin" Value="2"/> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <!-- 移除默认选中高亮,避免影响方块显示 --> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBoxItem}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <ContentPresenter/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="BorderBrush" Value="Black"/> <Setter Property="BorderThickness" Value="1"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ComboBox.ItemContainerStyle> <!-- 自定义ControlTemplate:修复显示问题 + 实现上方弹出 --> <ComboBox.Template> <ControlTemplate TargetType="{x:Type ComboBox}"> <Grid x:Name="MainGrid"> <!-- 主选择区域:显示选中项 + 下拉按钮 --> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <!-- 显示选中项的文本框(只读) --> <TextBox x:Name="PART_EditableTextBox" IsReadOnly="True" Text="{TemplateBinding SelectionBoxItem}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="5"/> <!-- 下拉触发按钮 --> <ToggleButton x:Name="PART_ToggleButton" Grid.Column="1" IsChecked="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0 0 1 1"> <Path Width="8" Height="8" Fill="Black" Data="M0,0 L4,4 L8,0 Z"/> </ToggleButton> <!-- 弹出层:从按钮中心上方弹出 + 横向排列项 --> <Popup x:Name="PART_Popup" AllowsTransparency="True" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PlacementTarget="{Binding ElementName=PART_ToggleButton}" Placement="Top" HorizontalOffset="-15" <!-- 偏移使弹窗中心对齐按钮中心 --> VerticalOffset="-5"> <!-- 调整与按钮的间距 --> <Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Padding="2"> <!-- 横向排列项,无需滚动 --> <StackPanel IsItemsHost="True" Orientation="Horizontal"/> </Border> </Popup> </Grid> <!-- 保留默认触发逻辑:点击外部/按Esc关闭弹窗 --> <ControlTemplate.Triggers> <Trigger Property="IsKeyboardFocusWithin" Value="False"> <Setter Property="IsDropDownOpen" Value="False"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </ComboBox.Template> </ComboBox>
关键修改说明:
- 修复控件显示:在ControlTemplate中添加了
PART_EditableTextBox(显示选中项)和PART_ToggleButton(触发下拉),这两个是ComboBox模板必须的命名部件,缺失会导致控件无渲染。 - 实现横向项布局:将Popup内的StackPanel设置为
Orientation="Horizontal",让项横向排列。 - 上方中心弹出:设置Popup的
PlacementTarget为下拉按钮,Placement="Top",并通过HorizontalOffset调整偏移量,使弹窗中心与按钮中心对齐。 - 固定项大小:在ItemContainerStyle中设置
Width="30"和Height="30",并调整内容对齐方式,确保方块填满容器。 - 保留关闭逻辑:添加了默认触发逻辑,点击外部区域或按Esc键会自动关闭弹窗,选中项时ComboBox也会自动关闭弹窗(内置行为)。
- 适配DataGrid场景:弹窗从按钮上方弹出,不会向下扩展影响DataGrid的列宽;项数量少无需滚动,移除了原代码中的ScrollViewer。
内容的提问来源于stack exchange,提问作者Boppity Bop
相关产品推荐
相关产品推荐

