San*_*ndy 7 c# data-binding mvp winforms
我有一个在MVP中实现的WinForms应用程序.我的表单有一个TextBox,我想将其Text属性数据绑定到Model中的属性.我不想在视图中引用模型.
在谷歌搜索后,我发现通过耦合模型和视图进行数据绑定是一个坏主意.我的样品初始化Model,View并且Presenter是如下.
class View : Form, IView
{
public View()
{
InitializeComponent();
new Presenter(this);
}
}
class Presenter
{
public Presenter(IView) : this.Presenter(this, new Model())
{
}
public Presenter(IView view)
{
}
}
class Model : IModel
{
public Model()
{
}
}
Run Code Online (Sandbox Code Playgroud)
目前我已经为每3个项目Model,View和Presenter.View参考Presenter并Presenter参考Model.任何人都可以指导我如何形成数据绑定到控件View到属性Model?
编辑
我知道在Grid中做的事情.我们可以在演示者中将Datasource网格的属性分配给List(或类似的),如:
_view.DataSource = _model.ListOfEmployees;
Run Code Online (Sandbox Code Playgroud)
这将反映ListOfEmployees模型中更改时UI中的值.但是什么TextBox暴露Text财产呢?我怎样才能在MVP架构中绑定它?
IAb*_*act 10
我的建议是将视图和模型封装在Presenter中.这意味着给定视图的专用Presenter(在大多数情况下).在我看来,这很好用,因为大多数模型无论如何都会有所不同.
class Presenter {
readonly IView view;
readonly IModel model;
public Presenter() {
// if view needs ref. to presenter, pass into view ctor
view = new View(this);
model = new Model();
}
// alternatively - with the model injected - my preference
public Presenter(IModel Model) {
// if view needs ref. to presenter, pass into view ctor
view = new View(this);
model = Model;
}
}
Run Code Online (Sandbox Code Playgroud)
在IView中,公开控件或控件的数据源属性:
interface IView {
object GridDataSource { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
添加到您的Presenter的一些方法:
void SetGridDatasource() {
view.GridDatasource = model.SomeBindableData;
}
Run Code Online (Sandbox Code Playgroud)
查看实施:
public object GridDatasource {
get { return myGridView.DataSource; }
set { myGridView.DataSource = value; }
}
Run Code Online (Sandbox Code Playgroud)
注意:
代码段未经测试,建议作为起点.
更新注释:
INotifyPropertyChanged是一种非常有价值的机制,用于更新IView和之间的属性IModel.
大多数控件都具有某种绑定功能.我建议尽可能使用这些DataBinding方法.只需通过IView公开这些属性,然后让Presenter将这些绑定设置为IModel属性.
说明:
如果要将文本框数据绑定到模型的底层属性:
第一:像许多其他状态一样,包含属性的任何内容都必须实现INotifyPropertyChanged接口,以便在更改object属性时触发必要的事件以通知视图更改.在这方面,我将使用viewmodel作为模型的属性来封装您希望将视图数据绑定的特定属性.
第二:您的IView将包含View必须实现的viewmodel属性.
第三:您的View将实现IView属性,viewmodel对象上只有一个set访问器,用于将每个文本框数据绑定到dto属性.请注意,在下面的示例中,我如何在视图加载后再次手动设置文本框.现在,当底层模型的viewmodel属性更改时,将更新textbox.text值.这适用于两种方式(双向数据绑定).使用用户输入编辑文本框将更改基础模型的dto属性值.
第四:您的演示者只会在视图加载时将IView的属性设置为Model的属性一次.
示例:请记住,这是一个非常简化的粗略示例,并且没有像OP正在使用的任何模型抽象,但应该为Winforms MVP中的文本框数据绑定提供一个良好的起点.我将在生产应用程序中更改的另一件事是使Model无状态并将viewmodel(person)移动到演示者中.
//VIEWMODEL
public class Person : INotifyPropertyChanged
{
string _firstName;
string _lastName;
public string FirstName
{
get { return _firstName; }
set
{
if(value != _firstName)
{
_firstName = value;
NotifyPropertyChanged("FirstName");
}
}
}
public string LastName
{
get { return _lastName; }
set
{
if (value != _lastName)
{
_lastName = value;
NotifyPropertyChanged("LastName");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
//MODEL
class Model
{
Person _person;
public Person Person { get { return _person; } }
public Model()
{
//Set default value
_person = new Person(){ FirstName = "Test", LastName = "Subject" };
}
public void ChangePerson()
{
//When presenter calls this method, it will change the underlying source field and will reflect the changes in the View.
_person.FirstName = "Homer";
_person.LastName = "Simpson";
}
}
//PRESENTER
class Presenter
{
readonly View _view;
readonly Model _model;
public Presenter(View view)
{
_view = view;
_model = new Model();
_view.OnViewLoad += Load;
_view.OnChangePerson += ChangePerson;
}
private void Load()
{
_view.Person = _model.Person;
}
private void ChangePerson()
{
_model.ChangePerson();
}
}
//IVIEW
interface IView
{
Person person { set; }
event Action OnViewLoad;
event Action OnChangePerson;
}
//VIEW
public partial class View : IView
{
public View()
{
Presenter presenter = new Presenter(this);
this.Load += (s, e) => OnViewLoad(); //Shorthand event delegate
this.btnChange.Click += (s, e) => OnChangePerson(); //Shorthand event delegate
}
public event Action OnViewLoad;
public event Action OnChangePerson;
public Person person
{ //This is how you set textbox two-way databinding
set
{
//Databinding syntax: property of control, source, source property, enable formatting, when to update datasource, null value
txtFirstName.DataBindings.Add(new Binding("Text", value, "FirstName", true, DataSourceUpdateMode.OnPropertyChanged, string.Empty));
txtLastName.DataBindings.Add(new Binding("Text", value, "LastName", true, DataSourceUpdateMode.OnPropertyChanged, string.Empty));
}
}
}
Run Code Online (Sandbox Code Playgroud)