Làm thế nào một nút có thể được liên kết với một lệnh trong một mô hình khung nhìn như trong WPF với MVVM?Ràng buộc với các lệnh trong WinForms
Trả lời
Tôi đã đính kèm ICommand
đối tượng vào tài sản Tag
của các đối tượng Button
và MenuItem
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
)
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.
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.
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.
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
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
vui vì nó hoạt động tốt và bạn thích nó! –
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 (..)'? –
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 Click
và Enabled
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.
button1.Click += (s, e) => new MyCommand().Execute();
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.
- 1. OneWay ràng buộc trên WinForms?
- 2. Ràng buộc dữ liệu WinForms
- 3. WinForms ComboBox dữ liệu ràng buộc Gotcha
- 4. Truy cập mục bị ràng buộc với hàng DataGridView (WinForms)
- 5. Ràng buộc dữ liệu WinForms - Liên kết với các đối tượng trong danh sách
- 6. Lệnh ràng buộc bên trong DataGridTemplateColumn
- 7. Ràng buộc với một lệnh trong một DataGrid
- 8. WPF: Ràng buộc các lệnh trong mã phía sau
- 9. Lệnh ràng buộc MVVM đối với mục contextmenu
- 10. MarkupExtension với các tham số ràng buộc
- 11. HaiWay ràng buộc với các mụcControl
- 12. Sự kiện giao diện người dùng ràng buộc WPF với các lệnh trong ViewModel
- 13. Ràng buộc các Procs
- 14. Hiển thị các ràng buộc trên bảng lệnh
- 15. Mẫu ràng buộc với ràng buộc là gì?
- 16. Winforms: Làm thế nào để ràng buộc mục Checkbox của CheckedListBox với databinding
- 17. Ràng buộc khóa trong Eclipse cho lệnh gói Maven
- 18. ràng buộc NSTextField với NSNumber
- 19. Ràng buộc ListBox với ViewModel trong WPF
- 20. MVVM ràng buộc với InkCanvas
- 21. Để ràng buộc rõ ràng với^l trong Bash
- 22. Hoàn tác trong các ràng buộc WPF
- 23. Các ràng buộc duy nhất trong couchdb
- 24. Ràng buộc Qt với LLVM
- 25. WPF ràng buộc với Grid.ColumnSpan
- 26. Ràng buộc với UserControl DependencyProperty
- 27. Thêm các ràng buộc trong phpMyAdmin
- 28. std :: ràng buộc một hàm ràng buộc
- 29. Buộc ràng buộc duy nhất trong GAE
- 30. Câu lệnh DELETE xung đột với ràng buộc REFERENCE trong ASP.NET Dynamic Data
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. –