如何將按鈕綁定到視圖模型中的命令,如使用MVVM的WPF中一樣?綁定到WinForms中的命令
回答
我已將ICommand
對象附加到Tag
屬性Button
和MenuItem
之前的對象。
然後,我只是看看我是否能投,如果我可以運行它,例如:
private void button1_Click(object sender, EventArgs e)
{
ICommand command = ((Control)(sender)).Tag as ICommand;
if (command != null)
{
command.Execute();
}
}
對於甚至更簡單的生活,嘗試子類的控件(如Button
,MenuItem
)
我不認爲你可以直接做,但如何使用按鈕的點擊處理程序來調用該命令?它並不像WPF那麼幹淨,但你仍然得到了分離。
我建議實施INotifyPropertyChanged你可以在WinForms和WPF中使用它。有關簡介,請參閱here;有關其他信息,請參見here。
你可能會發現有趣的是WAF Windows Forms Adapter。它演示瞭如何在Windows窗體應用程序中應用Model-View-ViewModel(MVVM)模式。適配器實施爲在Windows窗體中支持丟失的命令提供瞭解決方案。
我在想,如果同樣的事情可以做,結束編寫一個簡單的命令管理,查詢登記的命令(在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
你的解決方案工作得很好,使我的對話框組件變得更容易和易於理解:-)。非常感謝! – rhe1980 2012-03-16 07:06:37
很高興它工作正常,你喜歡它! – 2012-03-16 09:28:24
你能解釋爲什麼你在'DataBindings.Add(..)'方法中使用'Application.Idle'事件而不是使用'DataSourceUpdateMode'嗎? – 2015-01-05 09:18:03
您可以創建一個通用的命令綁定類,允許將命令綁定到從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
屬性,這意味着命令可以綁定到幾乎任何控制。
button1.Click += (s, e) => new MyCommand().Execute();
如果你想用設計師的命令綁定到控件,請在此演示應用程序,我展示瞭如何在Windows窗體中使用MVVM:
https://bitbucket.org/lbras/mvvmforms
你唯一代碼在代碼隱藏中編寫視圖模型實例的創建。
- 1. 命令綁定到UserControl
- 2. 綁定命令到MenuItem
- 3. 將命令綁定到WPF中的ComboBoxItem
- 4. 將ComboBoxItem綁定到WPF中的命令?
- 5. DataTemplate中的綁定命令
- 6. DataGridTemplateColumn中的綁定命令
- 7. Bash綁定命令
- 8. 綁定GruntJS命令
- 9. ContextMenu命令綁定
- 10. Reactiveui命令綁定
- 11. MVVM命令綁定
- 12. WPF命令綁定
- 13. 綁定命令MVVM
- 14. WPF綁定命令
- 15. 命令綁定MVVM
- 16. WPF:綁定到來自ControlTemplate的命令
- 17. WPF命令綁定到MVVM的DataItemTemplate
- 18. wpf中的自定義命令綁定
- 19. Winforms綁定到列表框
- 20. 將WinForms DataGridView綁定到MembershipUserCollection
- 21. 如何添加命令綁定到不具有命令綁定屬性
- 22. 無法從菜單項綁定命令,命令綁定
- 23. Silverlight的命令綁定
- 24. ListBoxItem的MVVM命令中的WPF列表框的命令綁定
- 25. WinForms數據綁定 - 綁定到列表中的對象
- 26. CheckedListBox WinForms綁定
- 27. 如何將命令綁定到按鈕
- 28. 未找到綁定命令錯誤
- 29. 命令對象綁定到Domain類
- 30. TextEdit_KeyDown事件綁定到一個命令
是的,其實這就是我現在正在做的 - 我只是想知道是否有一個合理的方式來綁定。 – 2009-11-06 12:09:43