[英]How to data-bind my View's button to the Model, via its interface in the Presenter
为冗长的代码道歉,这就像我能得到它一样浓缩。 下面是一个人为的例子,后面有一个解释:
namespace Contrived.Example
{
internal class Model : INotifyPropertyChanged
{
private bool _isAccountEmpty;
public bool IsAccountEmpty
{
get { return _isAccountEmpty; }
set
{
if (_isAccountEmpty == value) return;
_isAccountEmpty = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
internal interface IView
{
event EventHandler WithdrawalButtonClick;
}
internal class View : IView
{
private Button WithdrawalButton;
private void InitializeComponent()
{
WithdrawalButton = new Button();
WithdrawalButton.Location = new System.Drawing.Point(0, 0);
WithdrawalButton.Size = new System.Drawing.Size(75, 25);
WithdrawalButton.Click += WithdrawalButton_Click;
}
private void WithdrawalButton_Click(object sender, EventArgs e)
{
WithdrawalButtonClick?.Invoke(sender, e);
}
public event EventHandler WithdrawalButtonClick;
}
internal class Presenter
{
private readonly IView _view;
private readonly Model _model;
//private readonly BindingSource bindSource;
public Presenter(IView view)
{
_view = view;
_model = new Model();
view.WithdrawalButtonClick += OnWithDrawalButtonClick;
/* The behavior that follows is what I am after:
* how do I bind my button control to its model counterpart here?
* You can't expose the control directly on the IView interface, can you?
*
* bindSource = new BindingSource {DataSource = typeof(Model)};
* bindSource.Add(_model);
*
* This next line would throw an exception because
* _view isn't actually exposing the button:
* _view.WithdrawalButton
* .DataBindings
* .Add("Enabled", bindSource, "IsAccountEmpty");
*/
}
private void OnWithDrawalButtonClick(object sender, EventArgs e)
{
// Pretend we withdrew too much money
_model.IsAccountEmpty = true;
}
}
}
所以这基本上是我的程序的结构。 我想通过演示者将我的视图按钮绑定到其模型上的属性。 注释代码在没有界面的情况下对我很好,并且在 vb.Net中(控件具有Friend修饰符而不是Private,因此它们对于演示者是可见的)。
现在在C#中按钮是私有的,此外我试图通过将一个接口抛入混合来练习松耦合。 现在我遇到了一个问题,我不能再按照以前的方式将我的按钮绑定到模型了。 任何人都可以告诉我解决这个问题的正确方法是什么? 非常感谢。
PS如果这个设置完全错误,我想也知道,这是我能够自己想出的最好的,没有在学校对这个主题进行任何真正的集中培训。
首先让我告诉你,你的构造并不是完全松耦合的。 如果您查看Presenter,可以找到以下行:
_model = new Model();
如果你想创建松散耦合的程序,可以将新关键字视为邪恶。 因为在这里你被绑定到模型。 不是任何模型,而是完全属于那个模型。 如果你想要UnitTest你的Presenter你将无法模拟一个模型。 所以你应该更好地创建一个进一步的接口IModel并在构造函数中传递它。
public Presenter(IView view, IModel model)
{
this.model = model;
this.view = view;
}
要了解更多关于为什么要这样做以及如何处理这个问题的信息,请阅读...... 关于DependencyInjection 。 完成此步骤后,您可以传递适合您的界面的任何模型。
在此之后我应该回答你的问题;-)。 首先,您可以创建一个处理DataBinding功能的新接口。 然后创建一个新的Button,它可以从Standardbutton开始,并实现新的Interface。 然后你的IView包含一个Property,它包含一个IBindingObject或者你的新接口被调用的任何东西。 这看起来像这样:
public interface IBindingObject
{
ControlBindingsCollection DataBinding {get;}
}
public class MyButton : Button, IBindingObject
{
//Nothing to do here because the Button contains a DataBinding Property by default
}
public interface IView
{
IBindingObject WithdrawalButton {get;}
}
public class View : Form, IView
{
public IBindingObject WithdrawalButton {get {return new MyButton()}}
}
public class Presenter
{
public Presenter(IView view, IModel model)
{
view.WithdrawalButton.DataBindings.Add(//do your binding);
}
}
注意这种方法与ControlBindingCollection耦合,但我认为这种妥协是可以的。 否则你总是必须让你的View访问你的模型,反之亦然。 这会违反模式。 DataBinding和Winforms并不像WPF那样舒服。 所以,如果你有机会使用WPF我会建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.