2008-08-12 9 views
34

He hecho algo de programación de WPF y una cosa que nunca obtuve fue el patrón de comando. Todos los ejemplos parecen estar integrados, editar, cortar, pegar. ¿Alguien tiene un ejemplo o sugerencia de las mejores prácticas para los comandos personalizados?Ejemplo de patrón de comando de WPF personalizado

Respuesta

38

¡Ah, ja! Una pregunta que puedo responder! En primer lugar, debo mencionar que personalmente he encontrado que es más fácil definir y conectar comandos en código que en XAML. Me permite conectar los manejadores para los comandos un poco más flexiblemente de lo que lo hace un enfoque XAML.

Debe averiguar qué comandos desea tener y con qué se relacionan. En mi aplicación, actualmente tengo una clase para definir los comandos de aplicaciones importantes, así:

public static class CommandBank 
{ 
    /// Command definition for Closing a window 
    public static RoutedUICommand CloseWindow { get; private set; } 

    /// Static private constructor, sets up all application wide commands. 
    static CommandBank() 
    { 
    CloseWindow = new RoutedUICommand(); 
    CloseWindow.InputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt)); 
    // ... 
    } 

Ahora, porque quería mantener el código todos juntos, usando un código único enfoque de Comandos me permite poner los métodos siguientes en la clase anterior:

/// Closes the window provided as a parameter 
public static void CloseWindowExecute(object sender, ExecutedRoutedEventArgs e) 
{ 
    ((Window)e.Parameter).Close(); 
} 

/// Allows a Command to execute if the CommandParameter is not a null value 
public static void CanExecuteIfParameterIsNotNull(object sender, CanExecuteRoutedEventArgs e) 
{ 
    e.CanExecute = e.Parameter != null; 
    e.Handled = true; 
} 

el segundo método allí incluso se pueden compartir con otros comandos sin tener que repetir todo el lugar.

Una vez que haya definido los comandos de esta manera, puede agregarlos a cualquier pieza de la interfaz de usuario. A continuación, una vez que la ventana se ha cargado, agrego enlaces de comandos tanto a la ventana como a MenuItem y luego agrego un enlace de entrada a la ventana usando un bucle para hacer esto para todos los enlaces de comando. El parámetro que se pasa es la Ventana en sí misma, por lo que el código anterior sabe qué Ventana probar y cerrar.

public partial class SimpleWindow : Window 
{ 
    private void WindowLoaded(object sender, RoutedEventArgs e) 
    { 
    // ... 
    this.CommandBindings.Add(
     new CommandBinding(
     CommandBank.CloseWindow, 
     CommandBank.CloseWindowExecute, 
     CommandBank.CanExecuteIfParameterIsNotNull)); 

    foreach (CommandBinding binding in this.CommandBindings) 
    { 
     RoutedCommand command = (RoutedCommand)binding.Command; 
     if (command.InputGestures.Count > 0) 
     { 
     foreach (InputGesture gesture in command.InputGestures) 
     { 
      var iBind = new InputBinding(command, gesture); 
      iBind.CommandParameter = this; 
      this.InputBindings.Add(iBind); 
     } 
     } 
    } 

    // menuItemExit is defined in XAML 
    menuItemExit.Command = CommandBank.CloseWindow; 
    menuItemExit.CommandParameter = this; 
    // ... 
    } 

    // .... 
} 

que entonces también más adelante con controladores de eventos para los eventos windowClosing y windowClosed, yo recomiendo que haga la aplicación real de los comandos como pequeñas y genéricos como sea posible. Como en este caso, no intenté poner un código que intente detener el cierre de la ventana si hay datos no guardados, guardé ese código firmemente dentro del evento WindowClosing.

Deseo saber si tiene alguna pregunta de seguimiento. :)

+2

Su CanExecuteIfParameterIsNotNull contiene una de mis molestias para mascotas. ¿Por qué no simplemente e.CanExecute = e.Parameter! = Null; – Ray

+0

@Ray ¡Eso no era algo que sabía que podía hacer! Gracias por la edición de Drew. :) – Nidonocu

3

Lo que pasa con XAML es que está bien para programas 'simples', pero lamentablemente, no funciona bien cuando quieres hacer cosas como compartir funciones. Digamos que tiene varias clases y todas las UI tienen comandos que nunca fueron deshabilitados, ¡tendría que escribir un método 'CanAlwaysExecute' para cada ventana o UserControl! Eso no es muy SECO.

Después de haber leído varios blogs y haber intentado varias cosas, he tomado la decisión de hacer XAML puramente sobre apariencia, estilos, animación y factores desencadenantes. Toda mi conexión de manejadores de eventos y comando ahora está en el código subyacente. :)

Otro punto a tener en cuenta es el enlace de entrada, para que puedan capturarse, el foco debe estar en el objeto que contiene los enlaces de entrada. Por ejemplo, para tener un atajo que puede usar en cualquier momento (por ejemplo, F1 para abrir la ayuda), ese enlace de entrada debe establecerse en el objeto Ventana, ya que siempre tiene foco cuando su aplicación está Activa. Usar el método de código debería facilitar eso, incluso cuando comiences a utilizar UserControls que podrían querer agregar enlaces de entrada a su ventana principal.

7
+2

http://blogs.vertigo.com/personal/alanl/Blog/archive/2007/05/31/commands-in-wpf.aspx este enlace está muerto :( – Drahakar

Cuestiones relacionadas