Las aplicaciones GUI a veces ofrecen una forma para que los usuarios configuren las teclas de acceso rápido, generalmente utilizando un cuadro de texto que registra una combinación de teclas presionadas dentro de él. Tal control no sale de la caja en WPF, pero podemos implementarlo nosotros mismos.
Clase de sotos
WPF tiene dos enumeraciones útiles para esta tarea – System.Windows.Input.Key
y System.Windows.Input.ModifierKeys
. Hagamos una clase que encapsulemos los valores de esos enums y la llame Hotkey
.
public class Hotkey
{
public Key Key { get; }
public ModifierKeys Modifiers { get; }
public Hotkey(Key key, ModifierKeys modifiers)
{
Key = key;
Modifiers = modifiers;
}
public override string ToString()
{
var str = new StringBuilder();
if (Modifiers.HasFlag(ModifierKeys.Control))
str.Append("Ctrl + ");
if (Modifiers.HasFlag(ModifierKeys.Shift))
str.Append("Shift + ");
if (Modifiers.HasFlag(ModifierKeys.Alt))
str.Append("Alt + ");
if (Modifiers.HasFlag(ModifierKeys.Windows))
str.Append("Win + ");
str.Append(Key);
return str.ToString();
}
}
Se crea una instancia de esta clase especificando una clave junto con una combinación de modificadores (si los hay) que deben presionarse para ejecutar un atajo.
ToString()
WPF llamará al método para mostrar una instancia de la clase dentro de un cuadro de texto si no hay un conjunto de convertidores. También es utilizado por Visual Studio al depurar, lo que lo hace más conveniente. Este método generará una cadena que represente la tecla de acceso rápido actual, por ejemplo Ctrl + Alt + K
.
Control de usuario de WPF
Para hacer el control real de WPF, puede derivar de TextBox
o envuélvalo en tu cuenta UserControl
. Elegí el último, principalmente por dos razones:
- Es posible ocultar todas las propiedades inherentes del cuadro de texto que no son aplicables para mi control
- Hay menos limitaciones en caso de que necesite reemplazar el cuadro de texto con un control diferente o agregar algo encima.
<UserControl x:Class="Your.Namespace.HotkeyEditorControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="UserControl"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<TextBox x:Name="HotkeyTextBox"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
IsReadOnly="True"
IsReadOnlyCaretVisible="False"
IsUndoEnabled="False"
PreviewKeyDown="HotkeyTextBox_PreviewKeyDown"
Text="{Binding Hotkey, ElementName=UserControl, Mode=OneWay, TargetNullValue=< not set >}">
<TextBox.ContextMenu>
<ContextMenu Visibility="Collapsed" />
</TextBox.ContextMenu>
</TextBox>
</UserControl>
Hay algunas cosas importantes que debemos configurar en nuestra interna TextBox
. Primero, no debería permitir la entrada de texto manual, así que configuré IsReadOnly
a true
.
En segundo lugar, sería mejor eliminar el careto, ya que no es útil de ninguna manera. Configuración IsReadOnlyCaretVisible
a false
se encarga de eso.
Tampoco queremos que mantenga el historial de deshacer/rehacer, así que vamos a desactivar IsUndoEnabled
también.
Finalmente, los cuadros de texto WPF tienen un menú contextual predeterminado con botones como copiar, cortar, pegar, etc. que tampoco necesitamos. Podemos deshabilitarlo estableciendo la visibilidad del menú en Collapsed
.
La propiedad de texto está vinculada al Hotkey
propiedad utilizando el OneWay
modo. Este último es importante porque estamos estableciendo el valor de Hotkey
de código-behind. Este enlace solo se usa para actualizar el texto dentro del cuadro de texto.
En cuanto a la detección del código, se ve así:
public partial class HotkeyEditorControl
{
public static readonly DependencyProperty HotkeyProperty =
DependencyProperty.Register(
nameof(Hotkey),
typeof(Hotkey),
typeof(HotkeyEditorControl),
new FrameworkPropertyMetadata(
default(Hotkey),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
)
);
public Hotkey Hotkey
{
get => (Hotkey) GetValue(HotkeyProperty);
set => SetValue(HotkeyProperty, value);
}
public HotkeyEditorControl()
{
InitializeComponent();
}
private void HotkeyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
// Don't let the event pass further because we don't want
// standard textbox shortcuts to work.
e.Handled = true;
// Get modifiers and key data
var modifiers = Keyboard.Modifiers;
var key = e.Key;
// When Alt is pressed, SystemKey is used instead
if (key == Key.System)
{
key = e.SystemKey;
}
// Pressing delete, backspace or escape without modifiers clears the current value
if (modifiers == ModifierKeys.None &&
(key == Key.Delete || key == Key.Back || key == Key.Escape))
{
Hotkey = null;
return;
}
// If no actual key was pressed - return
if (key == Key.LeftCtrl ||
key == Key.RightCtrl ||
key == Key.LeftAlt ||
key == Key.RightAlt ||
key == Key.LeftShift ||
key == Key.RightShift ||
key == Key.LWin ||
key == Key.RWin ||
key == Key.Clear ||
key == Key.OemClear ||
key == Key.Apps))
{
return;
}
// Update the value
Hotkey = new Hotkey(key, modifiers);
}
}
Para capturar pulsaciones de teclas, estamos procesando el PreviewKeyDown
Evento porque también nos permite deshabilitar los atajos de cuadro de texto estándar, como copiar, cortar, pegar, etc.
- Se establece
e.Handled
atrue
para que los eventos no pasen más abajo en la cadena - Extrae información sobre la tecla que se presionó
- Verifica si se elimina, el espacio de retroceso o el escape se presionaron y borra la entrada si es así
Finalmente, así es como se ve el control en mi aplicación, Bombilla:

Luis es un experto en Inteligência Empresarial, Redes de Computadores, Gestão de Dados e Desenvolvimento de Software. Con amplia experiencia en tecnología, su objetivo es compartir conocimientos prácticos para ayudar a los lectores a entender y aprovechar estas áreas digitales clave.