¿Cómo evito que los botones WPF permanezcan resaltados después de hacer clic?

Cuando se hace clic en un botón estándar de WPF, se resalta en azul (probablemente usando el color azul de cualquier tema de Windows configurado) y permanece resaltado hasta que interactúa con cualquier otro control. Para mi aplicación, es confuso para el usuario.

¿Existe una forma sencilla de apagar esto y hacer que el botón vuelva a su estilo normal? Estoy usando .NET 4.

preguntado el 10 de mayo de 11 a las 12:05

Por cierto, el problema es grave en una pantalla táctil para un botón que "alterna". Considere un botón que está activado, también lo está el color de resaltado. El usuario ahora lo toca para apagarlo: ya no está resaltado PERO tiene el foco, por lo que todavía le parece al usuario que es ese color de resaltado (desde el foco). Muy confuso. (Y demuestra que es un error fundamental usar un estilo con un color de enfoque similar al color de resaltado. Es mejor usar la solución tradicional de indicar el enfoque con un solo contorno).

7 Respuestas

Lo que pasa es que el botón acepta la enfoque de entrada después de hacer clic en él, al igual que lo hace cualquier otro control cuando hace clic en él.

Y la forma en que Windows indica que un control tiene el foco de entrada (al menos bajo el tema Aero) es con un sutil resaltado azul.

Para un control de botón en particular, cuando tiene el foco de entrada, simplemente presionando el Entrar La tecla "empujará" ese botón. Es por eso que mantener el resaltado es muy importante, para que el usuario sepa qué esperar.

La mejor solución es establecer el foco en un control diferente en su ventana inmediatamente después de que el usuario haya hecho clic en el botón. De esa manera, ya no se resaltará automáticamente y no se activará ninguna acción automáticamente cuando el usuario presione el botón Entrar clave. (Este es el reales. problema de usabilidad que está tratando de resolver, incluso si aún no lo sabe. No hay nada más confuso que hacer clic en un botón sin darse cuenta cuando el usuario está tratando de escribir algo).

Usted podría evitar que el botón obtenga el enfoque por completo configurando su Focusable propiedad a falso, pero lo recomendaría mucho en contra de esto. Una vez que haya hecho esto, no habrá forma de que el usuario "presione" el botón usando solo el teclado. Las aplicaciones bien diseñadas deben Siempre hay ser accesible para los usuarios que prefieren no hacerlo o que no pueden usar el mouse.

contestado el 10 de mayo de 11 a las 17:05

Gracias por la explicación detallada. Creo que establecer el enfoque en un control oculto o algo sería el camino a seguir. Probablemente otro botón con una altura y un ancho de cero, ya que no quisiera que este botón ocupara ningún espacio. Visibilidad = ninguno no debería funcionar ya que el foco no se puede establecer en algo que no está dibujado. Además, ¿hay alguna forma de que no tenga que establecer el enfoque para cada botón en el evento de clic? Hay demasiados botones en mi aplicación. y muchos de ellos solo tienen enlaces de comando ... sin eventos ... ¡el MVVM! - aprendiz

@learner: O al control con el que es más probable que interactúe el usuario. No estoy seguro de cómo está distribuida su ventana, pero a menos que lo único que contenga sea un botón, probablemente haya una opción más natural para que un control tenga el foco en lugar de uno oculto fuera de la pantalla. - Cody Grey ♦

@learner: Hmm, si realmente quieres hacer mucho esto, deberías reconsiderar seriamente si los botones son el diseño adecuado para tu aplicación. Por lo general, el comportamiento predeterminado es el que desea (también es lo que es más probable que espere el usuario, dado que todas sus otras aplicaciones funcionan de la misma manera). Ser diferente por el simple hecho de ser diferente rara vez es una buena idea, incluso si parece que sería "mejor" en ese momento. Si los botones no deberían comportarse como otros botones, ¡quizás no deberían ser botones en absoluto! - Cody Grey ♦

Correcto en realidad. Miré VS2010 y hace lo mismo. No resalta la acción realizada en el botón. Pero sí, parece que no hay forma de usar la pestaña del teclado para cambiar el enfoque. - aprendiz

Vale la pena señalar que para un sistema POS, con acceso solo a pantalla táctil (sin teclado ni mouse), la mejor solución aquí es Focusable = false. El problema real para mí fue que cuando se escanea un token RFID, escribe (virtualmente) un número de 10 dígitos, seguido de Enter; resultando en botones que se hacen clic aleatoriamente. - Danny Beckett

Intenta configurar Focusable a falso. Se podrá hacer clic en el botón, pero no permanecerá enfocado.

contestado el 10 de mayo de 11 a las 16:05

Esto interfiere con la capacidad del usuario para interactuar con la aplicación utilizando solo el teclado. El sello distintivo de una aplicación mal diseñada es aquella que es inaccesible sin usar el mouse. - Cody Grey ♦

@CodyGray A menos que se muestre, por ejemplo, en una pantalla táctil en una tienda. En tal caso, el enfoque es definitivamente no deseado y la entrada del teclado o del mouse no importa en absoluto. - Spook

@CodyGray O hay atajos de teclado claramente especificados para cada acción, y aún más si la barra espaciadora es uno de ellos. - Krzysztof Bociurko

Ese es simplemente el estado enfocado. Para apagarlo tendrás que cambiar el estado enfocado. Es más fácil usando Blend.

No recomiendo configurar Focusable en falso porque interfiere con el uso del teclado

contestado el 10 de mayo de 11 a las 17:05

Este es el aspecto predeterminado de los botones Aero cuando tienen el foco. Puede configurar Focusable="False" o use un estilo personalizado, que no lo represente de manera diferente cuando el botón tiene el foco. Algo como:

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

Debería agregar una referencia a PresentationFramework.Aero.dll

contestado el 10 de mayo de 11 a las 17:05

Debe tener en cuenta que cambiar el estilo solamente cambiar cómo se dibuja el botón cuando tiene el foco. No cambiará el hecho de que el botón tiene el foco. Esto es importante, porque un botón enfocado es "especial". Interpreta cualquier pulsación de la tecla Intro como "hacer clic" en el botón, lo que provoca una acción potencialmente inesperada si el usuario no puede saber de un vistazo qué control tiene el foco. Por lo tanto, no se recomienda simplemente cambiar el estilo. - Cody Grey ♦

Gracias hombre. La solución de estilo podría ser muy útil, pero me temo que mis usuarios se quejarán del problema mencionado por "Cody Gray" - aprendiz

MEJOR sería cambiar el estilo para que se pueda ver el enfoque, pero se ve diferente al aspecto resaltado. Por ejemplo, borde de "contorno", pero color no resaltado. Esto aborda el punto que plantea Cody. - ToolmakerSteve

Necesitaba hacer algo similar, pero en el código en tiempo de ejecución, se veía así

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

Puedes ver que comento la línea "" RenderMouseOver "

Mi primera esperanza fue usar FrameworkElementFactory, pero necesitaba crear toda la plantilla predeterminada ... ¡TODO A MANO! ;)
Usar

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

Me dio la plantilla que quería y luego quitar la sección Render fue fácil.

respondido 14 nov., 12:01

Encontré una solución de 2 pasos. La solución es un poco divertida pero funciona. Mis puestos de referencia son;

¿Cómo eliminar FocusVisualStyle global a todos los controles?

y Aplicación C # WPF .NET 4.5 Establecer la posición del mouse

Se debe importar una DLL, porque WPF no admite directamente el movimiento del cursor del mouse.

  1. agregar System.Runtime.InteropServices al espacio de nombres
  2. Agregue dos líneas a MainWindow o cualquier código de su ventana

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

  1. Agregue estas 2 líneas a su evento de clic. SetCursorPos(0, 0); ButtonName.FocusVisualStyle = null;

Esto funciona para mi .

respondido 19 mar '19, 23:03

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

Respondido 19 Jul 20, 11:07

Por favor, explique su respuesta con un poco más de detalle, ayuda a otros a entender cuál es su sugerencia de solución. - CobyC

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.