2009-11-06 82 views

回答

3

我已将ICommand对象附加到Tag属性ButtonMenuItem之前的对象。

然后,我只是看看我是否能投,如果我可以运行它,例如:

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

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

对于甚至更简单的生活,尝试子类的控件(如ButtonMenuItem

0

我不认为你可以直接做,但如何使用按钮的点击处理程序来调用该命令?它并不像WPF那么干净,但你仍然得到了分离。

+0

是的,其实这就是我现在正在做的 - 我只是想知道是否有一个合理的方式来绑定。 – 2009-11-06 12:09:43

0

你可能会发现有趣的是WAF Windows Forms Adapter。它演示了如何在Windows窗体应用程序中应用Model-View-ViewModel(MVVM)模式。适配器实施为在Windows窗体中支持丢失的命令提供了解决方案。

13

我在想,如果同样的事情可以做,结束编写一个简单的命令管理,查询登记的命令(在Application.Idle事件),并使用数据绑定改变控制的启用状态

这是我现在使用的代码:

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

,这是一个如何使用它的〔实施例:

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

此外,如果你需要的代码,我blogg编辑它here

+0

你的解决方案工作得很好,使我的对话框组件变得更容易和易于理解:-)。非常感谢! – rhe1980 2012-03-16 07:06:37

+0

很高兴它工作正常,你喜欢它! – 2012-03-16 09:28:24

+0

你能解释为什么你在'DataBindings.Add(..)'方法中使用'Application.Idle'事件而不是使用'DataSourceUpdateMode'吗? – 2015-01-05 09:18:03

5

您可以创建一个通用的命令绑定类,允许将命令绑定到从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); }; 
    } 
} 

命令绑定然后可以设置使用下面的代码:

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

这仅仅是我实现的裸露的骨头给你一个开端所以自然有几个注意事项:

  • 该示例假定使用WPF ICommand接口,因此如果您有自己的命令模式实现,则可能必须更改接口。
  • 应检查传入的参数是否为空引用。
  • 更具体的实现应该有一些方法去除事件处理程序以避免内存泄漏。

通用约束也可以改变为Control暴露所述Click事件和Enabled属性,这意味着命令可以绑定到几乎任何控制。

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

如果你想用设计师的命令绑定到控件,请在此演示应用程序,我展示了如何在Windows窗体中使用MVVM:

https://bitbucket.org/lbras/mvvmforms

你唯一代码在代码隐藏中编写视图模型实例的创建。