2009-11-06 45 views

Trả lời

3

Tôi đã đính kèm ICommand đối tượng vào tài sản Tag của các đối tượng ButtonMenuItem trước đây.

Sau đó, tôi chỉ thấy nếu tôi có thể đúc và chạy nó nếu tôi có thể, ví dụ:

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

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

Đối thậm chí là một cuộc sống dễ dàng hơn, hãy thử subclassing các điều khiển (ví dụ Button, MenuItem)

0

Tôi không nghĩ bạn có thể làm điều đó trực tiếp nhưng cách sử dụng trình xử lý nhấp chuột của nút để gọi lệnh? Nó không sạch như WPF nhưng bạn vẫn nhận được sự tách biệt của bạn.

+0

Yea, thực sự đó là những gì tôi đang làm bây giờ - Tôi đã chỉ tự hỏi nếu có một cách hợp lý để làm điều đó với ràng buộc. –

0

Tôi khuyên bạn nên triển khai INotifyPropertyChanged bạn có thể sử dụng trong WinForms cũng như WPF. Xem here để biết giới thiệu và here để biết thêm thông tin.

0

Bạn có thể tìm thấy WAF Windows Forms Adapter thú vị. Nó cho thấy cách áp dụng Mẫu Model-View-ViewModel (MVVM) trong một ứng dụng Windows Forms. Việc triển khai Bộ điều hợp cung cấp giải pháp cho thiếu Lệnh hỗ trợ trong Windows Forms.

13

Tôi đã tự hỏi nếu điều tương tự có thể được thực hiện và kết thúc viết một CommandManager đơn giản mà truy vấn các lệnh đăng ký (trên các sự kiện Application.Idle) và sử dụng liên kết dữ liệu để thay đổi trạng thái bật của kiểm soát

Đây là mã tôi đang sử dụng ngay bây giờ:

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

và đây là một exmaple làm thế nào để sử dụng nó:

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

Ngoài ra nếu bạn cần mã, tôi blogg ed về nó here

+0

giải pháp của bạn hoạt động thực sự tốt và làm cho các thành phần hộp thoại của tôi dễ dàng hơn và dễ hiểu hơn :-). cảm ơn rất nhiều! – rhe1980

+0

vui vì nó hoạt động tốt và bạn thích nó! –

+0

Bạn có thể giải thích tại sao bạn sử dụng sự kiện 'Application.Idle' thay vì sử dụng' DataSourceUpdateMode' trong phương thức 'DataBindings.Add (..)'? –

5

Bạn có thể tạo một lớp ràng buộc lệnh chung cho phép lệnh được liên kết với bất kỳ lớp nào được kế thừa từ 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); }; 
    } 
} 

Các ràng buộc sau đó có thể được thiết lập bằng cách sử dụng đoạn mã sau lệnh: chỉ

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

Đây là xương trần thực hiện của tôi để cung cấp cho bạn một sự khởi đầu rất tự nhiên có một vài hãy cẩn thận:

  • Ví dụ giả định việc sử dụng giao diện WPF ICommand do đó có thể phải được thay đổi nếu bạn có triển khai thực hiện mẫu lệnh.
  • Các tham số được truyền vào phải được kiểm tra cho các tham chiếu null.
  • Triển khai cụ thể hơn sẽ có một số phương pháp loại bỏ trình xử lý sự kiện để tránh rò rỉ bộ nhớ.

Ràng buộc chung cũng có thể được thay đổi để Control đó cho thấy nhiều sự kiện ClickEnabled tài sản có nghĩa là các lệnh có thể được liên kết với hầu hết các Control.

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

Nếu bạn muốn để ràng buộc các lệnh để điều khiển bằng cách sử dụng thiết kế, kiểm tra ứng dụng demo này mà tôi thấy làm thế nào để sử dụng MVVM trong Windows Forms:

https://bitbucket.org/lbras/mvvmforms

Mã duy nhất bạn có để viết trong mã-đằng sau là việc tạo ra thể hiện mô hình khung nhìn.

Các vấn đề liên quan