如何将按钮绑定到视图模型中的命令,如使用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