2009-11-06 89 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

你唯一代碼在代碼隱藏中編寫視圖模型實例的創建。