如何防止 WPF 按钮在单击后保持突出显示状态

本文关键字:显示 状态 WPF 何防止 按钮 单击 | 更新日期: 2023-09-27 17:56:13

单击标准 WPF 按钮时,该按钮将以蓝色突出显示(可能使用设置的任何 Windows 主题中的蓝色),并且它会一直突出显示,直到您与任何其他控件交互。对于我的应用程序,这让用户感到困惑。

有没有一种简单的方法关闭它并使按钮恢复正常样式?我正在使用.NET 4。

如何防止 WPF 按钮在单击后保持突出显示状态

发生的情况是,按钮在单击后接受输入焦点,就像单击它时的任何其他控件一样。

Windows 指示控件具有输入焦点(至少在 Aero 主题下)的方式带有微妙的蓝色突出显示。

特别是对于按钮控件,当它具有输入焦点时,只需按 Enter 键即可"按下"该按钮。这就是为什么保持突出显示非常重要的原因,以便用户知道会发生什么。

更好的解决方案是在用户单击按钮后立即将焦点设置为窗口中的其他控件。这样,当用户按 Enter 键时,它将不再自动突出显示,也不会自动触发任何操作。(这是你试图解决的真正可用性问题,即使你还不知道。没有什么比当用户实际尝试键入内容时无意中单击按钮更令人困惑的了。

您可以通过将其 Focusable 属性设置为 false 来阻止按钮完全获得焦点,但我强烈建议不要这样做。完成此操作后,用户将无法仅使用键盘"按下"按钮。设计良好的应用程序应始终可供不想使用鼠标或无法使用鼠标的用户访问。

尝试将Focusable设置为 false。该按钮将可单击,但不会保持焦点。

这是

Aero 按钮具有焦点时的默认外观。您可以设置Focusable="False"或使用自定义样式,当按钮具有焦点时,它不会以不同的方式呈现。像这样:

xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
<Style x:Key="BaseButtonStyle" TargetType="{x:Type ButtonBase}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ButtonBase}">
                <theme:ButtonChrome Name="Chrome" Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding Button.IsDefaulted}"
                        RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"
                        SnapsToDevicePixels="true">
                    <ContentPresenter Margin="{TemplateBinding Padding}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                </theme:ButtonChrome>
                <ControlTemplate.Triggers>
                    <!--
                    Do not show blue when focused
                    <Trigger Property="IsKeyboardFocused" Value="true">
                        <Setter TargetName="Chrome" Property="RenderDefaulted" Value="true" />
                    </Trigger>-->
                    <Trigger Property="ToggleButton.IsChecked" Value="true">
                        <Setter TargetName="Chrome" Property="RenderPressed" Value="true" />
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="#ADADAD" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}" TargetType="{x:Type ToggleButton}" />
<Style x:Key="{x:Type RepeatButton}" BasedOn="{StaticResource BaseButtonStyle}" TargetType="{x:Type RepeatButton}" />
<Style x:Key="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}" TargetType="{x:Type Button}" />

您需要添加对 PresentationFramework.Aero 的引用.dll

这只是焦点状态。要关闭它,您必须更改焦点状态。使用混合最简单。

我不建议将 Focusable 设置为 false,因为它会干扰使用键盘

<Style x:Key="TouchButton" TargetType="{x:Type Button}">
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="ClickMode" Value="Press"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border x:Name="Border" CornerRadius="2" BorderThickness="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
                        <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Button.IsMouseOver" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="Red"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

我需要做类似的事情,但在运行时的代码中,它看起来像这样

//You can get this XAML by using System.Windows.Markup.XamlWriter.Save(yourButton.Template)";
             const string controlXaml = "<ControlTemplate TargetType='"ButtonBase'" " +
                                    "xmlns='"http://schemas.microsoft.com/winfx/2006/xaml/presentation'" " +
                                    "xmlns:s='"clr-namespace:System;assembly=mscorlib'" " +
                                    "xmlns:mwt='"clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero'">" +
                                    "<mwt:ButtonChrome Background='"{TemplateBinding Panel.Background}'" " +
                                    "BorderBrush='"{TemplateBinding Border.BorderBrush}'" " +
                                    "RenderDefaulted='"{TemplateBinding Button.IsDefaulted}'" " +
                                    //"RenderMouseOver='"{TemplateBinding UIElement.IsMouseOver}'" " +
                                    "RenderPressed='"{TemplateBinding ButtonBase.IsPressed}'" Name='"Chrome'" SnapsToDevicePixels='"True'">" +
                                    "<ContentPresenter RecognizesAccessKey='"True'" " +
                                    "Content='"{TemplateBinding ContentControl.Content}'" " +
                                    "ContentTemplate='"{TemplateBinding ContentControl.ContentTemplate}'" " +
                                    "ContentStringFormat='"{TemplateBinding ContentControl.ContentStringFormat}'" " +
                                    "Margin='"{TemplateBinding Control.Padding}'" " +
                                    "HorizontalAlignment='"{TemplateBinding Control.HorizontalContentAlignment}'" " +
                                    "VerticalAlignment='"{TemplateBinding Control.VerticalContentAlignment}'" " +
                                    "SnapsToDevicePixels='"{TemplateBinding UIElement.SnapsToDevicePixels}'" /></mwt:ButtonChrome>" +
                                    "<ControlTemplate.Triggers>" +
                                    "<Trigger Property='"UIElement.IsKeyboardFocused'">" +
                                    "<Setter Property='"mwt:ButtonChrome.RenderDefaulted'" TargetName='"Chrome'"><Setter.Value><s:Boolean>True</s:Boolean></Setter.Value></Setter>" +
                                    "<Trigger.Value><s:Boolean>True</s:Boolean></Trigger.Value></Trigger>" +
                                    "<Trigger Property='"ToggleButton.IsChecked'">" +
                                    "<Setter Property='"mwt:ButtonChrome.RenderPressed'" TargetName='"Chrome'"><Setter.Value><s:Boolean>True</s:Boolean></Setter.Value></Setter>" +
                                    "<Trigger.Value><s:Boolean>True</s:Boolean></Trigger.Value></Trigger>" +
                                    "<Trigger Property='"UIElement.IsEnabled'"><Setter Property='"TextElement.Foreground'"><Setter.Value><SolidColorBrush>#FFADADAD</SolidColorBrush></Setter.Value></Setter>" +
                                    "<Trigger.Value><s:Boolean>False</s:Boolean></Trigger.Value></Trigger></ControlTemplate.Triggers>" +
                                    "</ControlTemplate>";
        var xamlStream = new MemoryStream(System.Text.Encoding.Default.GetBytes(controlXaml));
        var _buttonControlTemplate = (ControlTemplate)System.Windows.Markup.XamlReader.Load(xamlStream);
        var yourButton = new Button() { Template = _buttonControlTemplate };

你可以看到我评论"渲染鼠标悬停"行

我的第一个希望是使用FrameworkElementFactory,但我需要创建所有默认模板。全部手工完成!
;)用

System.Windows.Markup.XamlWriter.Save(myButton.Template)

它给了我想要的模板,然后删除渲染部分很容易。

我找到了 2 步解决方案。解决方案有点好笑,但有效.我的推荐帖子是;

如何将全局焦点视觉样式删除到所有控件?

和C# WPF 应用程序 .NET 4.5 设置鼠标位置

必须导入一个DLL,因为WPF不直接支持鼠标光标移动。

  1. 将 System.Runtime.InteropServices 添加到命名空间
  2. 将两行添加到主窗口或任何窗口代码

[DllImport("User32.dll")] private static extern bool SetCursorPos(int X, int Y);

  1. 将这 2 行添加到您的点击事件中。 SetCursorPos(0, 0); ButtonName.FocusVisualStyle = null;

它对我有用.

就我而言,我已经通过使用 MultiTrigger 解决了这种情况,并像这样设置状态:

<MultiTrigger.Conditions>
   <Condition Property="IsFocused" Value="True"/>
   <Condition Property="IsPressed" Value="False"/>
</MultiTrigger.Conditions>

有关更多信息,请参阅此链接。