我在WinForms中涉足了MVP,还有很多问题需要解决。大多数问题来自于你在VS中的事实,并且能够使用Forms设计器轻松设计表单是很好的。
我试用了一个由广泛使用的WebForms MVP项目开发的WinForms MVP API,但由于表单使用泛型的文件背后的代码(例如public class TheForm:UserControl),您将失去设计窗体的能力,因为设计师知道如何处理泛型。
我结束了与核心接口,IPresenter,IView,IViewModel去。即使我没有添加任何额外的属性,我总是为特定的实现创建了一个中间接口,主要是因为稍后当我想要额外添加时,容易进行更改。IPresenter采用类型为IView的同变种generice类型所以在继承链中,我可以制作特定子视图类型的演示者。最终创建一个对话框实例化一个演示,并调用显示完成:
ISomePresenter<ISomeView> somePresenter = new SomeFactory.GetSomePresenter();
somePresenter.Show();
我的观点持有IViewModel的副本:
public void Show()
{
ISomeView theView = new V();
theView.ViewModel = new SomePresenterViewModel();
.
.
.
}
没有回到原来的问题... 的SampleView无法了解ISampleViewModel,因此无法将ViewModel进行标准数据绑定而无需在其他位置投射。这在我开发所有这些东西的项目中失控,人们在事件处理程序以及BindingSource向导中遍布各处。 MVP的全部内容都丢失了。
因此,现在我已经非常严格地处理事件,并将控件设置为属性中的公共属性(以及附带的ISampleView属性),以便演示者可以看到它们或者简单地创建重复事件以重新启动该活动将由主持人提起我一直在思考整个Databinding难题。真的,做到这一点的唯一方法是没有设计人员的支持,并完成设计人员在Presenter的代码中所做的一切。也许可以使用Designer在.designer.cs文件中获取自动生成的代码,但将所有代码剪切到Presenter中。也许这样做只是为了获得语法等,然后打开一些锅炉板代码或创建一个基于生成的代码片段。您仍然需要访问视图上的实际控件以指定绑定,因此还需要将属性添加到返回控件实例的ISampleView。另外,我建议将BindingSource实例放入Presenter中,或者至少让Presenter拥有实例的其他类。
我喜欢尽可能地使用设计师,但有时您需要休息一下。 正如我所说的CodePlex上的WinForms MVP项目很棒,但所有的表单设计都是在代码中完成的。在我的场景中,只有DataBinding需要在代码中完成,而这实际上并不是一个可视化的东西,因此处理起来更容易。
此外,作为一个附注,用户NotifyPropertyWeaver(IL编织)支持完整的数据绑定。这很棒,因为您可以在视图模型中创建自动属性,这使得您的代码变得简洁并且更具可读性,而无需在每个属性上调用NotifyPropertyChanging等。 IL Fitting with Fody在最终构建输出步骤之前完成所有后期编译。非常方便。
无论如何,我希望围绕这个问题的这个大脑转储概念对某个人有价值。我花了很长时间把它整理出来,但对我来说它工作得很好。
史蒂夫
编辑2014年4月23日
你知道吗,.NET数据绑定是流浪汉一个巨大的痛苦。最近在一个项目中,我们刚刚结束了自己的数据绑定代码的特定控制,因为它们都很难处理。
重新思考我最初的答复还有更近的经验,核心模型应该保持完全独立。我倾向于创建我称之为ViewModel的ViewModel,它与数据库进行交谈,并且是DataBindable并由View查看。数据绑定让我非常悲伤,尤其是在处理控件事件时,比如DateTimePicker的ValueChanged。在一种情况下,我有一个开始和结束日期选择器以及一个复选框,以便将结束日期设置为开始日期后一天以及我需要考虑的其他范围规则。在根据某些规则更改值时,将数据绑定配置给虚拟机,事件再次触发并最终取得我所做的最重要的选择。我最终不得不放置bool值来帮助了解事件处理程序是否应该继续,然后有潜在的竞争条件或不知道事件处理程序(在另一个线程中)是否应该等待。非常迅速得到混乱。因此,我现在的做法是创建一个大型的MODEL,触及数据库,并且可以根据捕获的数据进行验证规则检查,但是我会创建一个小而轻的版本,它只保存数据绑定的属性。与真实模型的分离仍然存在,并且Presenter/Controller响应的任何事件都可以在表单数据验证/数据持久化时间从VM复制到主模型。如果我对事件做出响应,然后将vm值绑定到一个更轻的虚拟机,我可以创建一个全新的虚拟机实例并重新分配验证结果,然后将此新的虚拟机实例设置为.DataSource当我准备好时,视图上的BindingSource避免了事件处理器的混乱。
主模型可以响应NotifyPropertyChanged事件更新自己的更改或更好的只是让主持人在适当的时间做到这一点。
顺便说一句,似乎Visual Studio 2012和2013现在处理非常酷的设计师的通用控件。
作为一个方面说明,我一直在iOS开发最近涉足。有一件事让我印象深刻,就是他们在MVC中作为过程的一部分被烘焙的方式,与.NET不同的是,它允许我们采用各种方式来实现它。我从中吸取了一些教训,并将它们应用于.NET,并发现我的大脑并没有突破这么多。我特别喜欢的一件事是列表控件的工作方式,它非常类似于Qt(C++框架)MVC控件。具有单体后端对象列表的能力,但视图只能保持它在可见区域需要的东西比.NET控件的默认行为好得多。
无论如何,祝你好运与.NET数据绑定。我个人建议任何新来者......不要使用它,只需让控制器在适当的时候明确地分配所有的值。但是,如果你感到舒服并且能够理解烦人的细微差别,我希望我所说的某些东西能够传达给某个人。
为什么在视图中引用模型将是一个坏主意?我只是向我的演示者添加一个方法,将模型绑定到IView。 –
@WiktorZychla:我在演示者中封装了视图和模型。目的是让演示者以外的任何对象都不应该混淆它的观点 - 包括模型。否则,在其他对象接管视图控制的情况下可能发生函数蠕变。 – IAbstract
然后让您的演示者使用视图模型,即吸收演示者中的模型并将视图绑定到演示者,因为它将是视图模型。这将是一个推荐的方法。 –