2009-11-06 15 views

Respuesta

3

He adjuntado ICommand objetos a la propiedad Tag de Button y MenuItem objetos antes.

Entonces, acabo de ver si puedo fundido y ejecutarlo si puedo, ejemplo:

private void button1_Click(object sender, EventArgs e) 
{ 
    ICommand command = ((Control)(sender)).Tag as ICommand; 

    if (command != null) 
    { 
     command.Execute(); 
    } 
} 

Porque incluso una vida más fácil, tratar de crear subclases de los controles (por ejemplo Button, MenuItem)

0

No creo que pueda hacerlo directamente, pero ¿qué tal si utiliza el controlador de clics del botón para invocar el comando? No es tan limpio como WPF pero aún así obtienes tu separación.

+0

Sí, en realidad eso es lo que estoy haciendo ahora, solo me preguntaba si había una forma razonable de hacerlo con el enlace. –

0

Recomiendo implementar INotifyPropertyChanged, puede usarlo tanto en WinForms como en WPF. Consulte here para una introducción y here para obtener más información.

0

Usted podría encontrar el WAF Windows Forms Adapter interesante. Muestra cómo aplicar el patrón Model-View-ViewModel (MVVM) en una aplicación Windows Forms. La implementación del adaptador proporciona una solución para el soporte que falta en Windows Forms.

13

Me preguntaba si lo mismo se podría hacer y terminó escribiendo un Administrador de comandos simple que consulta los comandos registrados (en el caso Application.Idle) y utiliza el enlace de datos para cambiar el estado Habilitado del control

Esto es el código que estoy usando en este momento:

public class CommandManager: Component 
{ 
    private IList<ICommand> Commands { get; set; } 
    private IList<ICommandBinder> Binders { get; set; } 

    public CommandManager() 
    { 
     Commands = new List<ICommand>(); 

     Binders = new List<ICommandBinder> 
         { 
          new ControlBinder(), 
          new MenuItemCommandBinder() 
         }; 

     Application.Idle += UpdateCommandState; 
    } 

    private void UpdateCommandState(object sender, EventArgs e) 
    { 
     Commands.Do(c => c.Enabled); 
    } 

    public CommandManager Bind(ICommand command, IComponent component) 
    { 
     if (!Commands.Contains(command)) 
      Commands.Add(command); 

     FindBinder(component).Bind(command, component); 
     return this; 
    } 

    protected ICommandBinder FindBinder(IComponent component) 
    { 
     var binder = GetBinderFor(component); 

     if (binder == null) 
      throw new Exception(string.Format("No binding found for component of type {0}", component.GetType().Name)); 

     return binder; 
    } 

    private ICommandBinder GetBinderFor(IComponent component) 
    { 
     var type = component.GetType(); 
     while (type != null) 
     { 
      var binder = Binders.FirstOrDefault(x => x.SourceType == type); 
      if (binder != null) 
       return binder; 

      type = type.BaseType; 
     } 

     return null; 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
      Application.Idle -= UpdateCommandState; 

     base.Dispose(disposing); 
    } 
} 

public static class Extensions 
{ 
    public static void Do<T>(this IEnumerable<T> @this, Func<T, object> lambda) 
    { 
     foreach (var item in @this) 
      lambda(item); 
    } 
} 
public abstract class CommandBinder<T> : ICommandBinder where T: IComponent 
{ 
    public Type SourceType 
    { 
     get { return typeof (T); } 
    } 

    public void Bind(ICommand command, object source) 
    { 
     Bind(command, (T) source); 
    } 

    protected abstract void Bind(ICommand command, T source); 
} 

public class ControlBinder: CommandBinder<Control> 
{ 
    protected override void Bind(ICommand command, Control source) 
    { 
     source.DataBindings.Add("Enabled", command, "Enabled"); 
     source.DataBindings.Add("Text", command, "Name"); 
     source.Click += (o, e) => command.Execute(); 
    } 
} 

public class MenuItemCommandBinder : CommandBinder<ToolStripItem> 
{ 
    protected override void Bind(ICommand command, ToolStripItem source) 
    { 
     source.Text = command.Name; 
     source.Enabled = command.Enabled; 
     source.Click += (o, e) => command.Execute(); 

     command.PropertyChanged += (o, e) => source.Enabled = command.Enabled; 
    } 
} 

y esto es un exmaple de cómo usarlo:

public partial class Form1 : Form 
{ 
    private CommandManager commandManager; 

    public ICommand CommandA { get; set; } 
    public ICommand CommandB { get; set; } 

    public bool condition; 

    public Form1() 
    { 
     InitializeComponent(); 

     commandManager = new CommandManager(); 

     CommandA = new DelegateCommand("Command 1", OnTrue, OnExecute); 
     CommandB = new DelegateCommand("Command 2", OnFalse, OnExecute); 

     commandManager.Bind(CommandA, button1); 
     commandManager.Bind(CommandB, button2); 

     commandManager.Bind(CommandA, command1ToolStripMenuItem); 
     commandManager.Bind(CommandB, command2ToolStripMenuItem); 
    } 

    private bool OnFalse() 
    { 
     return !condition; 
    } 

    private bool OnTrue() 
    { 
     return condition; 
    } 

    private void OnExecute() 
    { 
     condition = !condition; 
    } 
} 

Además, si necesita el código, que blogg ed about it here

+0

su solución funciona realmente bien y hace que mis componentes de diálogo sean mucho más fáciles y comprensibles :-). ¡muchas gracias! – rhe1980

+0

me alegra que funcione bien y te gusta! –

+0

¿Podría explicar por qué usa el evento 'Application.Idle' en lugar de usar' DataSourceUpdateMode' en el método 'DataBindings.Add (..)'? –

5

Puede crear una clase de enlace de comando genérica que permita vincular un comando a cualquier clase que herede de ButtonBase.

public class CommandBinding<T> where T : ButtonBase 
{ 
    private T _invoker; 
    private ICommand _command; 

    public CommandBinding(T invoker, ICommand command) 
    { 
     _invoker = invoker; 
     _command = command; 

     _invoker.Enabled = _command.CanExecute(null); 
     _invoker.Click += delegate { _command.Execute(null); }; 
     _command.CanExecuteChanged += delegate { _invoker.Enabled = _command.CanExecute(null); }; 
    } 
} 

La unión luego se pueden configurar utilizando el siguiente código de comando:

CommandBinding<Button> cmdBinding = 
    new CommandBinding<Button>(btnCut, CutCommand); 

esto es sólo el esqueleto de mi aplicación para darle un comienzo tan naturalmente hay algunas salvedades:

  • El ejemplo asume el uso de la interfaz WPF ICommand, por lo que puede tener que modificarse si tiene su propia implementación del patrón de comando.
  • Los parámetros que se pasan deben revisarse para obtener referencias nulas.
  • Una implementación más concreta debería tener algún método para eliminar los controladores de eventos para evitar pérdidas de memoria.

La restricción genérica también se puede cambiar a Control que expone el evento Click y la propiedad Enabled que significa comandos se pueden unir a casi cualquier control.

1
button1.Click += (s, e) => new MyCommand().Execute(); 
0

Si desea enlazar el comando para el control mediante el diseñador, marque esta aplicación de demostración donde muestro cómo usar MVVM en Windows Forms:

https://bitbucket.org/lbras/mvvmforms

El único código que tiene escribir en el código subyacente es la creación de la instancia del modelo de vista.

Cuestiones relacionadas