c# - WinForms MVP 是否有另一种方法可以将数据绑定(bind)到 View 而无需 Presenter 访问 View 控件?

标签 c# winforms data-binding mvp

我有一个 WinForms 应用程序设置来使用模型 View 演示器。为了避免 View 了解模型,我正在考虑让演示者使用 View 的实例来访问 View 文本框,并将它们数据绑定(bind)到演示者也具有的模型的实例。采用这种方法有什么问题?

我考虑过的另一个选择是让 View 拥有模型的实例。模型属性将具有 INotifyPropertyChanged 设置。在这种情况下,我可以让 View 将数据绑定(bind)设置到它具有的文本框和它也具有的模型实例。这样做有什么问题吗?

我考虑过的另一个选项是将模型属性复制到演示器中并使用 INotifyPropertyChanged 进行设置。然后,当 View 具有演示器的实例时,我可以让 View 将其文本框数据绑定(bind)到演示器中的匹配属性。通过此设置,当演示者进行数据访问调用时,它将为其本身的属性设置值,这将自动更新与演示者属性数据绑定(bind)的 View 文本框。

如果我不使用数据绑定(bind),我只需在 View 中添加 getter 和 setter,以便演示者访问 View 文本框值。演示者将使用 View getter 和 setter 来执行数据访问调用。在从数据访问调用接收数据后,演示者还将使用 setter 来设置 View 文本框值。

我正在考虑的这些选项基于我看过的文章,但也许​​还有另一种方法可以在我没有见过的 WinForms MVP 实现中管理数据。请提供反馈,说明推荐的方法用于管理从 View 到演示者或模型的来回数据,或者可能需要在此处添加另一层(例如某种服务)? 提前致谢。

==================================== 更新 04/10/2018

我能够设置我的应用程序,以便 View 和模型没有对演示者的引用,同时允许演示者引用 View 和模型。当我发现如何从 Presenter 中绑定(bind)到 View 控件所需的数据时,这成为可能。这不需要让 Presenter 直接访问属于 View 的可视控件。

DepartmentPresenter 字段:

 public class DepartmentPresenter : IDepartmentPresenter
 {
  private IDepartmentView departmentView;
  private IDepartmentModel departmentModel;
  private IDepartmentRepository departmentRepository;
  ....
}

这是演示者的实例化:

  void OnDisplayDepartmenSelectedRaised(object sender, DisplayDepartmentSelectedEventArgs e)
  {
   //Get current selected data row from Presenters BindingSource which used by the View to bind 
   //to its DataGridView. The view only knew it wasw a BindingSource and never had to know it
   //was a collectino of DepartmentModel Data Transfer Objects (DTOs) 
   selectedDepartmentModel = (DepartmentModel)departmentModelBindingSource.Current;

  DepartmentPresenter aDepartmentPresenter = new DepartmentPresenter(departmentView,
                                                                     departmentRepository,
                                                                     selectedDepartmentModel.DepartmentId);
  }

演示者构造函数:

  public DepartmentPresenter(IDepartmentView departmentView,
                             IDepartmentRepository departmentRepository,
                             int selectedDepartmentId)
  {
   this.departmentRepository = departmentRepository;
   departmentModel = departmentRepository.GetById(selectedDepartmentId);
   this.departmentView = departmentView;

   //Subscribe to View's save request from save button so Presenter can perform work to be done on a save
   this.departmentView.SaveDepartmentRaised += new EventHandler(OnSaveDepartmentRaised);

   //Create bindings for data the View will use on its textBoxes
   Binding departmentNameBinding = new Binding("Text", DepartmentModel, "DepartmentName", true, DataSourceUpdateMode.OnPropertyChanged);
   Binding cityLocationBinding = new Binding("Text", departmentModel, "CityLocation", true, DataSourceUpdateMode.OnPropertyChanged);
   Binding stateLocationBinding = new Binding("Text", departmentModel, "StateLocation", true, DataSourceUpdateMode.OnPropertyChanged);

   //Store bindings into a dictionary for the View to access for its textBoxes
   Dictionary<string, Binding> bindingDictionary = new Dictionary<string, Binding>();
   bindingDictionary.Add("DepartmentName", departmentNameBinding);
   bindingDictionary.Add("CityLocation", cityLocationBinding);
   bindingDictionary.Add("StateLocation", stateLocationBinding);

   //Use passed in reference to View to tell view to bind its textBoxes using the passed in Dictionary of bindings
   this.departmentView.BindDisplayData(bindingDictionary);

   this.departmentView.ShowView();
  }

以下是 View 如何绑定(bind)到其文本框控件以响应演示者告诉它这样做的方式:

  public void BindDisplayData(Dictionary<string, Binding> bindingDictinary)
  {
   textBoxName.DataBindings.Add(bindingDictinary["DepartmentName"]);
   textBoxCity.DataBindings.Add(bindingDictinary["CityLocation"]);
   textBoxState.DataBindings.Add(bindingDictinary["StateLocation"]);
  }

这是 View 的接口(interface)定义:

 public interface IDepartmentView
 {
  event EventHandler SaveDepartmentRaised;
  void ShowView();
  void BindDisplayData(Dictionary<string, Binding> bindingDictinary);
 }

希望这能帮助那些尝试从模型 View 演示器项目中的演示器绑定(bind)到 View 的人,同时尝试避免使 View 具有演示器的实例。

最佳答案

创建一个接口(interface),您的 View 将实现该接口(interface)并可以引用演示者:

public interface IView<T> where T : class
{
    T Presenter { get; set; }
}

以及 View :

public class TheView : Form, IView<ThePresenter>
{
    public ThePresenter Presenter { get; set; }
}

现在您可以注入(inject)演示者,并且 View 可以使用“Presenter”属性来创建绑定(bind)。

关于c# - WinForms MVP 是否有另一种方法可以将数据绑定(bind)到 View 而无需 Presenter 访问 View 控件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49595161/

相关文章:

c# - C#-不允许发送数据请求,因为未连接套接字

c# - 为什么线程 IsAlive 即使在线程内执行最后一个命令后仍返回 false

c# - 如何在运行时查找窗体中的所有控件

sqlite - 如何防止Sqlite未绑定(bind)参数解释为NULL

c# - 搜索所有组合

c# - linq to sql动态数据在插入和更新之前修改对象

vb.net - 在vb.net中的datagridview中添加行号

c# - 使组件根据大小变化填充最大空白

apache-flex - 弹性 4。将数据从主应用程序传递到自定义组件

C# ASP.NET 通过通用方法绑定(bind)控件