You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键修改说明:

  1. 修复控件显示:在ControlTemplate中添加了PART_EditableTextBox(显示选中项)和PART_ToggleButton(触发下拉),这两个是ComboBox模板必须的命名部件,缺失会导致控件无渲染。
  2. 实现横向项布局:将Popup内的StackPanel设置为Orientation="Horizontal",让项横向排列。
  3. 上方中心弹出:设置Popup的PlacementTarget为下拉按钮,Placement="Top",并通过HorizontalOffset调整偏移量,使弹窗中心与按钮中心对齐。
  4. 固定项大小:在ItemContainerStyle中设置Width="30"和Height="30",并调整内容对齐方式,确保方块填满容器。
  5. 保留关闭逻辑:添加了默认触发逻辑,点击外部区域或按Esc键会自动关闭弹窗,选中项时ComboBox也会自动关闭弹窗(内置行为)。
  6. 适配DataGrid场景:弹窗从按钮上方弹出,不会向下扩展影响DataGrid的列宽;项数量少无需滚动,移除了原代码中的ScrollViewer。

内容的提问来源于stack exchange,提问作者Boppity Bop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 16:20:41