WPF ComboBox:如何将焦点设置在其切换按钮上

发布于 2024-09-28 00:24:09 字数 6851 浏览 6 评论 0原文

我正在尝试让 ComboBox 来匹配视觉设计,因此当 ComboBox 获得焦点时,其 ToggleButton 具有蓝色边框。我不知道如何做到这一点,也找不到例子。

ComboBox 获得焦点时,内部的 TextBox 获得虚线焦点视觉效果。如何将 ComboBox 焦点状态传递给 ToggleButton,以便打开它的蓝色边框样式?

这是我的 ComboBox 模板:

<ControlTemplate x:Key="ComboBoxCT" TargetType="{x:Type ComboBox}">
    <Grid x:Name="gLayoutRoot"
        Margin="{TemplateBinding Margin}" 
        HorizontalAlignment="{TemplateBinding HorizontalAlignment}" 
        VerticalAlignment="{TemplateBinding VerticalAlignment}" 
        MinWidth="{TemplateBinding MinWidth}" 
        MinHeight="{TemplateBinding MinHeight}" 
        MaxWidth="{TemplateBinding MaxWidth}" 
        MaxHeight="{TemplateBinding MaxHeight}" 
        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
        <ToggleButton x:Name="ToggleButton" 
            Grid.Column="2" 
            Focusable="false"
            IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
            ClickMode="Press" 
            Style="{DynamicResource ComboBoxToggleStyle}" 
            />
        <AccessText x:Name="ContentSite" 
            Style="{StaticResource ComboBoxAccessTextStyle}" 
            Text="{TemplateBinding SelectionBoxItem}" 
            Foreground="{TemplateBinding Foreground}"/>
        <TextBox x:Name="PART_EditableTextBox"
            Style="{x:Null}" 
            HorizontalAlignment="{TemplateBinding HorizontalAlignment}" 
            VerticalAlignment="{TemplateBinding VerticalAlignment}" 
            Margin="2,3,17,2"
            Focusable="True" 
            Background="{DynamicResource InnerBgLight}"
            Visibility="Hidden"
            IsReadOnly="{TemplateBinding IsReadOnly}">
            <TextBox.Template>
                <ControlTemplate TargetType="TextBox">
                    <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
                </ControlTemplate>
            </TextBox.Template>
        </TextBox>
        <Popup x:Name="Popup"
            Placement="Bottom"
            IsOpen="{TemplateBinding IsDropDownOpen}"
            AllowsTransparency="True" 
            Focusable="False"
            PopupAnimation="Slide">
                <Grid x:Name="DropDown"
                    SnapsToDevicePixels="True"                
                    MinWidth="{TemplateBinding ActualWidth}"
                    MaxHeight="{TemplateBinding MaxDropDownHeight}">
                        <Border x:Name="OuterBorder"
                            Style="{DynamicResource OuterBorderBottomRestStyle}"
                            Background="{DynamicResource InnerBorder}">
                            <Border x:Name="InnerBorder" 
                                Style="{DynamicResource InnerBottomBorderStyle}">
                                <ScrollViewer x:Name="scvCbxItems" SnapsToDevicePixels="True">
                                    <StackPanel x:Name="spCbxItemsPanel" IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                                </ScrollViewer>
                            </Border>
                        </Border>
                </Grid>
            </Popup>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="HasItems" Value="false">
                <Setter TargetName="InnerBorder" Property="MinHeight" Value="95"/>
            </Trigger>
            <Trigger Property="IsGrouping" Value="true">
                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
            </Trigger>
            <Trigger Property="IsEditable" Value="true">
                <Setter Property="IsTabStop" Value="false"/>
                <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
                <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
            </Trigger>
            <Trigger Property="IsEnabled" Value="false">
                <Setter Property="Foreground" Value="{DynamicResource FgDisabledBrush}"/>
                <Setter Property="OpacityMask" TargetName="OuterBorder" Value="{DynamicResource OuterBgDisabledOpacityMask}"/>
            </Trigger>  
        </ControlTemplate.Triggers>
    </ControlTemplate>

这是我的 ToggleButton 模板:

    <ControlTemplate x:Key="ComboBoxToggleCT" TargetType="{x:Type ToggleButton}">
    <Border x:Name="OuterBorder" 
        Style="{DynamicResource OuterBorderTopRestStyle}">
        <Border x:Name="InnerBorder" 
            Style="{DynamicResource InnerTopBorderStyle}">
                <Path x:Name="Arrow" 
                    HorizontalAlignment="Right" VerticalAlignment="Center"
                    Margin="5"
                    Fill="{DynamicResource FgBrush}"
                    Data="{DynamicResource DownArrowGeometry}"/>
        </Border>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderTopSelectStyle}"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="OpacityMask" TargetName="OuterBorder" Value="{DynamicResource OuterBgDisabledOpacityMask}"/>
            <Setter Property="Fill" TargetName="Arrow" Value="{DynamicResource FgDisabledBrush}"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderTopSelectStyle}"/>
            <Setter Property="Style" TargetName="InnerBorder" Value="{DynamicResource InnerBorderTopFocusStyle}"/>
        </Trigger>
        <!--<Trigger Property="IsKeyboardFocused" Value="True">-->
        <Trigger Property="IsKeyboardFocused" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsFocused}">
            <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderBottomFocusStyle}"/>
            <Setter Property="Style" TargetName="InnerBorder" Value="{DynamicResource InnerBorderTopFocusStyle}"/>
        </Trigger>
    </ControlTemplate.Triggers>

</ControlTemplate>

如您所见,我尝试绑定到 ComboBox 的焦点状态,但是这在触发器内部不起作用。

任何帮助表示赞赏。抱歉这个菜鸟问题。谢谢!

I'm trying to get a ComboBox to match a visual design, so its ToggleButton has a blue border when the ComboBox has focus. I can't figure out how to do this and can't find an example.

When the ComboBox gets focus, the TextBox inside gets the dashed focus visual. How do I pass the ComboBox focus state down to the ToggleButton, so that it's blue border style is turned on?

Here is my ComboBox template:

<ControlTemplate x:Key="ComboBoxCT" TargetType="{x:Type ComboBox}">
    <Grid x:Name="gLayoutRoot"
        Margin="{TemplateBinding Margin}" 
        HorizontalAlignment="{TemplateBinding HorizontalAlignment}" 
        VerticalAlignment="{TemplateBinding VerticalAlignment}" 
        MinWidth="{TemplateBinding MinWidth}" 
        MinHeight="{TemplateBinding MinHeight}" 
        MaxWidth="{TemplateBinding MaxWidth}" 
        MaxHeight="{TemplateBinding MaxHeight}" 
        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
        <ToggleButton x:Name="ToggleButton" 
            Grid.Column="2" 
            Focusable="false"
            IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
            ClickMode="Press" 
            Style="{DynamicResource ComboBoxToggleStyle}" 
            />
        <AccessText x:Name="ContentSite" 
            Style="{StaticResource ComboBoxAccessTextStyle}" 
            Text="{TemplateBinding SelectionBoxItem}" 
            Foreground="{TemplateBinding Foreground}"/>
        <TextBox x:Name="PART_EditableTextBox"
            Style="{x:Null}" 
            HorizontalAlignment="{TemplateBinding HorizontalAlignment}" 
            VerticalAlignment="{TemplateBinding VerticalAlignment}" 
            Margin="2,3,17,2"
            Focusable="True" 
            Background="{DynamicResource InnerBgLight}"
            Visibility="Hidden"
            IsReadOnly="{TemplateBinding IsReadOnly}">
            <TextBox.Template>
                <ControlTemplate TargetType="TextBox">
                    <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
                </ControlTemplate>
            </TextBox.Template>
        </TextBox>
        <Popup x:Name="Popup"
            Placement="Bottom"
            IsOpen="{TemplateBinding IsDropDownOpen}"
            AllowsTransparency="True" 
            Focusable="False"
            PopupAnimation="Slide">
                <Grid x:Name="DropDown"
                    SnapsToDevicePixels="True"                
                    MinWidth="{TemplateBinding ActualWidth}"
                    MaxHeight="{TemplateBinding MaxDropDownHeight}">
                        <Border x:Name="OuterBorder"
                            Style="{DynamicResource OuterBorderBottomRestStyle}"
                            Background="{DynamicResource InnerBorder}">
                            <Border x:Name="InnerBorder" 
                                Style="{DynamicResource InnerBottomBorderStyle}">
                                <ScrollViewer x:Name="scvCbxItems" SnapsToDevicePixels="True">
                                    <StackPanel x:Name="spCbxItemsPanel" IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                                </ScrollViewer>
                            </Border>
                        </Border>
                </Grid>
            </Popup>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="HasItems" Value="false">
                <Setter TargetName="InnerBorder" Property="MinHeight" Value="95"/>
            </Trigger>
            <Trigger Property="IsGrouping" Value="true">
                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
            </Trigger>
            <Trigger Property="IsEditable" Value="true">
                <Setter Property="IsTabStop" Value="false"/>
                <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
                <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
            </Trigger>
            <Trigger Property="IsEnabled" Value="false">
                <Setter Property="Foreground" Value="{DynamicResource FgDisabledBrush}"/>
                <Setter Property="OpacityMask" TargetName="OuterBorder" Value="{DynamicResource OuterBgDisabledOpacityMask}"/>
            </Trigger>  
        </ControlTemplate.Triggers>
    </ControlTemplate>

And here's my ToggleButton template:

    <ControlTemplate x:Key="ComboBoxToggleCT" TargetType="{x:Type ToggleButton}">
    <Border x:Name="OuterBorder" 
        Style="{DynamicResource OuterBorderTopRestStyle}">
        <Border x:Name="InnerBorder" 
            Style="{DynamicResource InnerTopBorderStyle}">
                <Path x:Name="Arrow" 
                    HorizontalAlignment="Right" VerticalAlignment="Center"
                    Margin="5"
                    Fill="{DynamicResource FgBrush}"
                    Data="{DynamicResource DownArrowGeometry}"/>
        </Border>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderTopSelectStyle}"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="OpacityMask" TargetName="OuterBorder" Value="{DynamicResource OuterBgDisabledOpacityMask}"/>
            <Setter Property="Fill" TargetName="Arrow" Value="{DynamicResource FgDisabledBrush}"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderTopSelectStyle}"/>
            <Setter Property="Style" TargetName="InnerBorder" Value="{DynamicResource InnerBorderTopFocusStyle}"/>
        </Trigger>
        <!--<Trigger Property="IsKeyboardFocused" Value="True">-->
        <Trigger Property="IsKeyboardFocused" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsFocused}">
            <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderBottomFocusStyle}"/>
            <Setter Property="Style" TargetName="InnerBorder" Value="{DynamicResource InnerBorderTopFocusStyle}"/>
        </Trigger>
    </ControlTemplate.Triggers>

</ControlTemplate>

As you can see I try to bind to the ComboBox's focus state, but that doesn't work inside the Trigger.

Any help appreciated. Sorry for the noob question. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

童话里做英雄 2024-10-05 00:24:09

最简单的方法是绑定到模板父项的 IsFocused。注意:Mode=OneWay 很重要,因为 IsFocused 是只读的。你可以这样做:

<DataTrigger Binding="{Binding IsFocused, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" Value="True">
   <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderBottomFocusStyle}"/>
   <Setter Property="Style" TargetName="InnerBorder" Value="{DynamicResource InnerBorderTopFocusStyle}"/>
</DataTrigger >

The easiest way to do this is to have a binding to the Templated Parent's IsFocused. Note: Mode=OneWay is important since IsFocused is read only. You could do something like this:

<DataTrigger Binding="{Binding IsFocused, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" Value="True">
   <Setter Property="Style" TargetName="OuterBorder" Value="{DynamicResource OuterBorderBottomFocusStyle}"/>
   <Setter Property="Style" TargetName="InnerBorder" Value="{DynamicResource InnerBorderTopFocusStyle}"/>
</DataTrigger >
恋竹姑娘 2024-10-05 00:24:09

您想要自定义或选择 FocusVisualStyle:
参见这里:
MSDN:控件中焦点的样式和 FocusVisualStyle

我认为蓝色的您想要的是来自一些原始的 Windows 主题,也许它包含在此下载中 默认 WPF 主题,来自 Microsoft WPF 示例

You want to customize or chose a FocusVisualStyle:
See here:
MSDN: Styling for Focus in Controls, and FocusVisualStyle

I think the blue one you want to have is from some original windows theme, maybe it's contained in this download Default WPF Themes from Microsoft WPF Samples.

梦年海沫深 2024-10-05 00:24:09

您已在 ControlTemplate 中为 ToggleButton 设置了 Focusable=False,因此当它收到焦点时,会将焦点传递给下一个内部可聚焦 UIElement。
如果删除它,您的 ToggleButton 应该获得焦点,而不是 TextBox。

You have set Focusable=False for your ToggleButton in the ControlTemplate, so when it receives the focus, it passes it down to the next inner focusable UIElement.
If you remove that, your ToggleButton should get the focus instead of the TextBox.

守望孤独 2024-10-05 00:24:09

当您将 ComboBox.IsEditable 属性设置为 True 时,绑定到模板化父项的 IsFocused 属性不起作用。相反,您可以使用 IsKeyboardFocusWithin,检查以下内容:

<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" Value="True">
    <Setter Property="Background" TargetName="Border" Value="{DynamicResource MainColorLight}" />
    <Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource MainColorLight}" />
    <Setter Property="BorderBrush" TargetName="Border2" Value="{DynamicResource MainColorLight}" />
    <Setter Property="Fill" TargetName="Arrow" Value="White" />
</DataTrigger >

Binding to the templated parent's IsFocused prperty do not work when you set the ComboBox.IsEditable property to True. Instead you can use IsKeyboardFocusWithin, check the following:

<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" Value="True">
    <Setter Property="Background" TargetName="Border" Value="{DynamicResource MainColorLight}" />
    <Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource MainColorLight}" />
    <Setter Property="BorderBrush" TargetName="Border2" Value="{DynamicResource MainColorLight}" />
    <Setter Property="Fill" TargetName="Arrow" Value="White" />
</DataTrigger >
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文