【问题标题】:WinForms MVP is there another way to databind to View without Presenter accessing View controls?WinForms MVP 是否有另一种方法可以在没有 Presenter 访问 View 控件的情况下将数据绑定到 View?
【发布时间】:2018-09-10 17:15:29
【问题描述】:

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

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

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

如果我不使用数据绑定,我只会在视图中添加 getter 和 setter,以便演示者访问视图文本框的值。演示者将使用视图获取器和设置器来执行数据访问调用。在从数据访问调用接收数据后,演示者还将使用 setter 设置视图文本框的值。

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

================================== 2018 年 4 月 10 日更新

我能够设置我的应用程序,使 View 和 Model 不引用 Presenter,同时允许 Presenter 引用 View 和 Model。这成为可能,因为我发现了如何从 Presenter 中将视图绑定到其控件所需的数据。这样就不需要让 Presenter 直接访问属于 View 的可视控件。

DepartmentPresenter 字段:

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

这是 Presenter 的实例化:

  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);
  }

Presenter 构造函数:

  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 如何绑定到它的 textBox 控件以响应 Presenter 告诉它这样做:

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

View 的接口定义如下:

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

希望这将有助于尝试从模型视图演示器项目中的演示器绑定到视图的人,同时避免使视图具有演示器的实例。

【问题讨论】:

  • 为什么不使用 MVVM?恕我直言,这是比 MVP 更好的模式。

标签: c# winforms data-binding mvp


【解决方案1】:

创建一个接口,您的视图将实现该接口并可以引用演示者:

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

还有观点:

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

现在可以注入presenter,视图可以使用“Presenter”属性来创建绑定。

【讨论】:

  • 现在我将继续使用 View 来引用 Presenter。这是我的问题中列出的选项之一。我希望有别的东西。我在这里提出以下新问题的主题:stackoverflow.com/questions/49618011/…
  • 恕我直言,知道演示者的观点没有任何问题。
  • 我找到了一个不需要 View 来引用 Presenter 的解决方案。我在我的问题中包含了一些代码 sn-ps 来描述我做了什么。
【解决方案2】:

@Robertcode,我几乎同意您的解决方案。通过直接在演示者中使用绑定,您仍然使演示者直接依赖于包含所有视图控件的System.Windows.Forms 程序集。

我认为消除演示者对System.Windows.Forms 程序集的依赖的更好方法是注入一个创建绑定的服务,然后将这些绑定发送到视图中。

绑定服务可以将绑定创建为通用对象。然后视图可以将对象转换为绑定并分配它们。然后将把对System.Windows.Forms 程序集的依赖从presenter 中移出并移到绑定创建服务中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    相关资源
    最近更新 更多