49

When a standard WPF button is clicked, it gets highlighted in blue (probably using the blue color from whatever Windows theme is set), and it stays highlighted until you interact with any other control. For my application, it is confusing for the user.

Is there a simple way turn this off and get the button back to its normal style? I am using .NET 4.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
learner
  • 565
  • 1
  • 6
  • 14
  • 2
    BTW, the problem is severe on a touchscreen for a button that "toggles". Consider a button that is toggled on, so is the highlight color. User now touches it to turn it off: it is no longer highlighted BUT it has focus, so it still looks to user like it is that highlight color (from focus). Very confusing. (And demonstrates that it is a fundamental error to use a style with focus color similar to highlight color. Better to use traditional solution of indicating focus with an outline only.) – ToolmakerSteve Aug 02 '17 at 11:01

8 Answers8

60

What happens is that the button accepts the input focus after it has been clicked, just like any other control does when you click on it.

And the way that Windows indicates that a control has the input focus (at least under the Aero theme) is with a subtle blue highlight.

For a button control in particular, when it has the input focus, simply pressing the Enter key will "push" that button. That's why maintaining the highlight is very important, so that the user knows what to expect.

The better solution is to set the focus to a different control in your window immediately after the user has clicked on the button. That way, it will no longer be automatically highlighted and no action will be automatically triggered when the user presses the Enter key. (This is the real usability problem that you're trying to solve, even if you don't know it yet. Nothing is more confusing than a button inadvertently getting clicked when the user is actually trying to type something.)

You could prevent the button from ever getting the focus altogether by setting its Focusable property to false, but I would very much recommend against this. Once you've done this, there will be no way for the user to "press" the button using only the keyboard. Well-designed applications should always be accessible to users who either prefer not to or who are unable to use the mouse.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Thank you for the detailed explanation. I think setting the focus to hidden control or something would be the way to go. Probably another button with a height and width of zero as I would not want this button to take up any space. Visibility=none should not work as focus cant be set to something that isnt drawn. Also is there a way i dont have to set the focus for each button in the click event? There are too many buttons in my app. and many of them only have command bindings.. no events.. the MVVM! – learner May 10 '11 at 13:32
  • @learner: Or to the control that the user is most likely to interact with. I'm not sure how your window is laid out, but unless the only thing it contains is a button, there's probably a more natural choice for a control to have the focus rather than one hidden off the screen. – Cody Gray - on strike May 10 '11 at 13:35
  • @learner: Hmm, if you really find yourself wanting to do this a lot, you should seriously reconsider whether buttons are the right design for your app. Generally, the default behavior is what you want (it's also what the user is most likely to expect, given all their other apps work the same way). Being different just for the sake of being different is rarely a good idea, even if it seems like it would be "better" at the time. If the buttons shouldn't behave like other buttons, then perhaps they shouldn't be buttons at all! – Cody Gray - on strike May 10 '11 at 13:37
  • Correct actually. I looked at VS2010 and it does the same. No highlight for the action done on the button. But yes, seems like there is no way to use keyboard tab to change focus. – learner May 10 '11 at 13:44
  • 2
    It's worth noting that for a POS system, with touchscreen access only (no keyboard or mouse), the best solution here is `Focusable = false`. The real issue for me was that when an RFID token is scanned, it types (virtually) a 10-digit number, followed by Enter; resulting in buttons getting randomly clicked. – Danny Beckett Oct 26 '14 at 16:05
19

Try to set Focusable to false. The button will be clickable but will not remain focused.

HCL
  • 36,053
  • 27
  • 163
  • 213
  • 1
    This interferes with the user's ability to interact with the application using only the keyboard. The hallmark of a poorly-designed app is one that is inaccessible without using the mouse. – Cody Gray - on strike May 10 '11 at 13:01
  • 12
    @CodyGray Unless it is displayed - for example - on a touchscreen in a shop. In such case focus is definitely unwanted and keyboard or mouse input does not matter at all. – Spook May 23 '14 at 11:31
  • @CodyGray Or there are clearly specified keyboard shortcuts for each action - and even more if space bar is one of them. – Krzysztof Bociurko May 09 '18 at 10:16
3

This is the default look for Aero buttons when they have focus. You can either set Focusable="False" or use a custom Style, that doesn't render it differently when the button has focus. Something like:

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}" />

You'd need to add a reference to PresentationFramework.Aero.dll

H.B.
  • 166,899
  • 29
  • 327
  • 400
CodeNaked
  • 40,753
  • 6
  • 122
  • 148
  • 2
    You should be aware that changing the style will *only* change how the button is drawn when it has the focus. It will not change the fact that the button *has* the focus. This is important, because a focused button is "special". It interprets any press of the Enter key as "clicking" the button, causing potentially unexpected action if the user can't tell at a glance which control has the focus. Merely changing the style is therefore not recommended. – Cody Gray - on strike May 10 '11 at 13:05
  • Thanks man. The style solution could be very usefull but i fear my users will complain the problem mentioned by "Cody Gray" – learner May 10 '11 at 13:37
  • BETTER would be to change the style **so that focus can be seen, but looks different than the highlighted look**. For example, "outline" border, but non-highlighted color. This addresses the point Cody raises. – ToolmakerSteve Aug 02 '17 at 10:47
2

That is simply the focussed state. To turn it off you will have to change the focussed state. It's easiest by using Blend.

I do not recommend setting Focusable to false because it interferes with using the keyboard

Emond
  • 50,210
  • 11
  • 84
  • 115
1
<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>
  • 1
    please explain your answer in a bit more detail, it helps others understand what you suggest the solution is. – CobyC Jul 19 '20 at 09:06
0

I needed to do something similar, but in code at runtime, it looked like this

//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 };

You can see that i comment the ""RenderMouseOver" line

My first hope was using FrameworkElementFactory but i needed to create all the default template.... ALL BY HAND! ;)
Using

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

It give me the template i wanted and then removing the Render section was easy.

Guish
  • 4,968
  • 1
  • 37
  • 39
0

I found 2 steps solution. The solution is little funny but working . My referance posts are;

How to remove global FocusVisualStyle to all the Controls?

and C# WPF application .NET 4.5 Set Mouse Position

One DLL must be imported , because WPF is not directly supporting mouse cursor move.

  1. add System.Runtime.InteropServices to namespace
  2. Add two line to the MainWindow or whatever your window's code

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

  1. Add these 2 lines to your click event . SetCursorPos(0, 0); ButtonName.FocusVisualStyle = null;

It works for me .

0

I've resolved this situation, in my case, by using MultiTrigger, and to set the states like this:

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

TO more information see this link.