2009-06-21 7 views
27

Estoy usando el RelayCommand en mi aplicación. Es genial para poner el código en el modelo de vista, pero ¿cómo puedo vincular las teclas a mi comando?Teclear un RelayCommand

RoutedUICommand tiene su propiedad InputGestures, que hace que el comando se invoque automáticamente cuando presiono la tecla. (Como una ventaja adicional, incluso hace que la pantalla de teclas se muestre en MenuItem.) Lamentablemente, no hay una interfaz reutilizable para las propiedades adicionales de RoutedUICommand, por lo que no puedo crear un RelayUICommand que obtenga la misma magia.

ya he intentado usar InputBindings:

<Window.InputBindings> 
    <KeyBinding Key="PageUp" Command="{Binding SelectPreviousLayerCommand}"/> 
</Window.InputBindings> 

Pero eso me consigue una excepción de tiempo de ejecución, porque KeyBinding.Command no es una propiedad de dependencia. (En realidad, de lo que se queja es de que KeyBinding ni siquiera es DependencyObject). Y dado que mi RelayCommand es una propiedad de mi ViewModel (a diferencia del campo estático para el que está diseñado RoutedUICommand), la única forma que conozco es de enlace de datos. para referenciarlo desde XAML.

¿Cómo han solucionado esto? ¿Cuál es la mejor manera de vincular una pulsación de tecla a un RelayCommand?

Respuesta

14

La propiedad Comando de la clase KeyBinding no soporta el enlace de datos. Este problema se resolverá en .NET 4.0 y debería poder verlo en la próxima versión .NET 4.0 Beta 2.

+10

La vinculación de la propiedad Command de la clase KeyBinding en .NET 4.0 se describe en un artículo en http://tomlev2.wordpress.com/2009/10/26/vs2010-binding-support-in-inputbindings/ –

+1

El enlace anterior se ha movido a http://www.thomaslevesque.com/2009/10/26/vs2010-binding-support-in-inputbindings/ – avenmore

17

No creo que pueda hacer esto desde XAML, exactamente por las razones que describe.

Terminé haciéndolo en el código subyacente. Aunque es código, es solo una línea de código, y aún bastante declarativa, así que puedo vivir con eso. Sin embargo, realmente espero que esto se resuelva en la próxima versión de WPF.

He aquí una línea de ejemplo de código de uno de mis proyectos:

this.InputBindings.Add(new KeyBinding(
    ((MedicContext)this.DataContext).SynchronizeCommand, 
    new KeyGesture(Key.F9))); 

SynchronizeCommand en este caso es un ejemplo de RelayCommand, y (obviamente) F9 lo activa.

-1

Suponiendo sus RoutedCommands se definen de forma estática:

#region DeleteSelection 

    /// <summary> 
    /// The DeleteSelection command .... 
    /// </summary> 
    public static RoutedUICommand DeleteSelection 
     = new RoutedUICommand("Delete selection", "DeleteSelection", typeof(ChemCommands)); 

    #endregion 

de enlace en XAML así:

<Canvas.InputBindings> 
    <KeyBinding Key="Delete" Command="{x:Static Controls:ChemCommands.DeleteSelection}" /> 
</Canvas.InputBindings> 

Saludos,

Tim Haughton

+0

La pregunta sobre los Comandos de Relevo en un ViewModel y no sobre los RoutedCommands. –

0

creo una asociación de teclas en mi opinión modelo que vincula el comando y la clave al igual que

 this.KeyBinding = new KeyBinding(); 
     //set the properties 
     this.KeyBinding.Command = this.Command; 
     this.KeyBinding.Key = this.Key; 
     //modifier keys may or may not be set 
     this.KeyBinding.Modifiers = this.ModifierKeys; 

Luego de crear una colección de artículos InputBinding en mi raíz Ver modelo y añadirlos a la InputBindings ventanas de código de mi ventana detrás

 foreach (var item in applicationViewModel.InputBindingCollection) { 
     this.InputBindings.Add(item); 
    } 

su forma mala de hacer las cosas en el código detrás de lo que sé , pero todavía no sé cómo hacer la encuadernación, sin embargo sigo trabajando en ello. :) Lo único que esto me da es una lista de modificadores de comandos de teclas en el menú, pero eso está por venir.

10

Puede crear una subclase de KeyBinding, agregar una propiedad de dependencia CommandBinding que establezca la propiedad Command y luego agregarla a XAML como cualquier otro enlace de entrada.

public class RelayKeyBinding : KeyBinding 
{ 
    public static readonly DependencyProperty CommandBindingProperty = 
     DependencyProperty.Register("CommandBinding", typeof(ICommand), 
     typeof(RelayKeyBinding), 
     new FrameworkPropertyMetadata(OnCommandBindingChanged)); 
    public ICommand CommandBinding 
    { 
     get { return (ICommand)GetValue(CommandBindingProperty); } 
     set { SetValue(CommandBindingProperty, value); } 
    } 

    private static void OnCommandBindingChanged(
     DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var keyBinding = (RelayKeyBinding)d; 
     keyBinding.Command = (ICommand)e.NewValue; 
    } 
} 

XAML:

<Window.InputBindings> 
    <RelayKeyBinding 
     Key="PageUp" 
     CommandBinding="{Binding SelectPreviousLayerCommand}" /> 
</Window.InputBindings> 
+1

'keyBinding.Command = e.NewValue;' necesita un molde por lo que debe ser como 'keyBinding.Command = (ICommand) e.NewValue;' ¿Correcto? – Ankesh

2

Puede usar la clase CommandReference.

Código muy elegante y funciona como un encanto.

Tome un vistazo a: How do I associate a keypress with a DelegateCommand in Composite WPF?

Funciona de la misma con RelayCommands, pero no va a actualizar sus CanExecutes ya que el CommandReference no utiliza llamar CommandManager.RequerySuggested Todo lo que necesita hacer para lograr automática CanExecute reevaluación es hacer el siguiente cambio dentro de la clase CommandReference

public event EventHandler CanExecuteChanged 
{ 
    add { CommandManager.RequerySuggested += value; } 
    remove { CommandManager.RequerySuggested -= value; } 
} 
Cuestiones relacionadas