MVVM毫无意义吗?

时间:2010-05-09 17:08:06

标签: .net wpf mvvm

正统的MVVM实现是否毫无意义?我正在创建一个新的应用程序,我考虑了Windows窗体和WPF。我之所以选择WPF,是因为它具有前瞻性,并提供了很大的灵活性。使用XAML的代码更少,更容易对UI进行重大更改。

由于WPF的选择是显而易见的,我认为我可以使用MVVM作为我的应用程序架构,因为它提供了可混合性,分离问题和单元可测试性。从理论上讲,它看起来很像UI编程的圣杯。这个简短的冒险;然而,已经变成了一个真正的头痛。 正如在实践中所预期的那样,我发现我已将一个问题换成了另一个问题。我倾向于成为一个强迫性的程序员,因为我想以正确的方式做事,这样我才能获得正确的结果,并可能成为更好的程序员。 MVVM模式刚刚结束了我对生产力的测试,刚刚变成了一个令人讨厌的大黑客!

明显的例子是添加对模态对话框的支持。正确的方法是建立一个对话框并将其绑定到视图模型。让这个工作很难。为了从MVVM模式中受益,您必须在应用程序的各个层中的多个位置分发代码。您还必须使用深奥的编程结构,如模板和lamba表达式。让你盯着屏幕挠挠头的东西。正如我最近发现的那样,这使得维护和调试成为一场噩梦。我有一个关于盒子的工作正常,直到我第二次调用它时出现异常,说它一旦关闭就无法再显示对话框。我必须为对话框窗口添加一个关闭功能的事件处理程序,在IDialogView实现中添加另一个,最后在IDialogViewModel中添加另一个。我以为MVVM会让我们免于这种奢侈的骚扰!

有几个人在这个问题上有竞争解决方案,他们都是黑客,并没有提供一个干净,易于重复使用的优雅解决方案。大多数MVVM工具包都会掩盖对话框,当它们确实解决它们时,它们只是不需要自定义接口或视图模型的警报框。

我打算放弃MVVM视图模式,至少是它的正统实现。你怎么看?如果你有任何问题,是否值得为你带来麻烦?我只是一个不称职的程序员,还是MVVM而不是它被宣传的内容?

8 个答案:

答案 0 :(得分:59)

很抱歉,如果我的答案变得有点长,但不要怪我!你的问题也很冗长。

总之,MVVM并非毫无意义。

  

明显的例子是增加   支持模态对话框。该   正确的方法是建立一个对话框   并将其绑定到视图模型。入门   这项工作很难。

是的,确实如此 但是,MVVM为您提供了一种将UI外观与逻辑分离的方法。没有人强迫你到处使用它,没有人拿着枪对着你的额头,让你为一切创建一个单独的ViewModel。

以下是我对此特定示例的解决方案:
UI如何处理某个输入不是ViewModel的业务。我会将代码添加到View的.xaml.cs文件中,该文件实例化对话框并将相同的ViewModel实例(或其他东西,如果需要)设置为其DataContext。

  

为了从MVVM模式中受益,您必须在应用程序的各个层中的多个位置分发代码。您还必须使用深奥的编程结构,如模板和lamba表达式。

好吧,你不必在几个地方使用它。这就是我要解决的问题:

  • 将XAML添加到视图中,并且.xaml.cs中没有任何内容
  • 在ViewModel
  • 中编写每个应用程序逻辑(除了可以直接使用UI元素操作的内容)
  • 应该由UI完成但与业务逻辑无关的所有代码都会进入.xaml.cs文件

我认为MVVM的目的主要是分离应用程序的逻辑和具体的UI,从而实现UI的轻松修改(或完全替换)。 我使用以下原则:View可以从ViewModel知道并假设它想要的任何内容,但ViewModel可以知道关于视图的任何内容。
WPF提供了一个很好的绑定模型,您可以使用它来实现这一目标。

(顺便说一句,如果使用得当,模板和lambda表达式并不深奥。但如果你不想这样做,请不要使用它们。)

  

让你盯着屏幕挠挠头的东西。

是的,我知道这种感觉。正是我第一次看到MVVM时的感受。但是一旦掌握了它,就不会再感觉不好了。

  

我的盒子工作得很好......

为什么要将ViewModel放在about box后面?没有意义。

  

大多数MVVM工具包都会掩盖对话框,当它们确实解决它们时,它们只是不需要自定义界面或视图模型的警告框。

是的,因为UI元素位于同一个窗口或另一个窗口,或者目前正在围绕火星运行的事实不是ViewModels关注的问题。
Separation of Concerns

修改

这是一个非常好的视频,其标题是Build your own MVVM framework。值得一看。

答案 1 :(得分:8)

  

让这个工作变得困难。在   为了从MVVM中受益   模式,你必须分发代码   在整个地方的几个地方   你的申请层。你也是   必须使用深奥的编程   构造像模板和lamba   表达式。

对于普通的模态对话框?你肯定在那里做错了 - MVVM实现不一定非常复杂。

考虑到你对MVVM和WPF都不熟悉,很可能你到处都使用次优解决方案并且不必要地使事情变得复杂 - 至少我在第一次使用WPF时这样做了。放弃之前,确保问题确实是MVVM,而不是你的实现。

MVVM,MVC,Document-View等是一个古老的模式家族。有一些缺点,但没有你所描述的致命缺陷。

答案 2 :(得分:5)

我通过作弊处理对话问题。我的MainWindow实现了一个IWindowServices接口,该接口公开了所有特定于应用程序的对话框。然后我的其他ViewModel可以导入服务接口(我使用MEF,但您可以轻松地通过构造函数手动传递接口)并使用它来完成必要的操作。例如,以下是我的一个小实用程序应用程序的界面:

//Wrapper interface for dialog functionality to allow for mocking during tests
public interface IWindowServices
{
    bool ExecuteNewProject(NewProjectViewModel model);

    bool ExecuteImportSymbols(ImportSymbolsViewModel model);

    bool ExecuteOpenDialog(OpenFileDialog dialog);

    bool ExecuteSaveDialog(SaveFileDialog dialog);

    bool ExecuteWarningConfirmation(string text, string caption);

    void ExitApplication();
}

这会将所有Dialog执行放在一个位置,并且可以很容易地将其删除以进行单元测试。我遵循对话框的客户端必须创建适当的ViewModel的模式,然后他们可以根据需要进行配置。执行调用块,然后客户端可以查看ViewModel的内容以查看Dialog结果。

更“纯粹”的MVVM设计对于大型应用程序可能很重要,在这种应用程序中,您需要更清洁的绝缘和更复杂的组合,但对于中小型应用程序,我认为这是一种实用的方法,通过适当的服务来暴露所需的钩子,已经足够了。

答案 3 :(得分:5)

我正在使用PRISM进行相当复杂的MVVM开发,因此我已经不得不应对这种担忧。

我的个人结论:

MVVM vs MVC / PopUps&共

  • MVVM确实是一个很好的模式,在大多数情况下,由于WPF中强大的数据绑定,它完全取代了MVC
  • 在大多数情况下,直接从演示者调用服务层是合法的实现
  • 由于{Binding Path = /}语法
  • ,即使是非常复杂的List / Detail场景也可以由纯MVVM实现
  • 尽管如此,当需要实现多个视图之间的复杂协调时,必须使用控制器
  • 可以使用事件;暗示在控制器中存储IView(或AbstractObserver)实例的旧模式已过时
  • 可以通过IOC容器在每个Presenter中注入控制器
  • Prism的IEventAggregator服务是另一种可能的解决方案,如果控制器的唯一用途是事件调度(在这种情况下它可以完全取代控制器)
  • 如果要动态创建视图,这是一个非常适合控制器的工作(在棱镜中,控制器将被注入(IOC)一个IRegionManager)
  • 模式对话框在现代复合应用程序中大部分都是过时的,除了强制确认之类的真正阻塞操作;在这些情况下,模态激活可以被抽象为在控制器内部调用的服务,并由专门的类实现,这也允许高级表示级单元测试。例如,控制器将调用IConfirmationService.RequestConfirmation(“你确定”),它将在运行时触发模态对话框显示,并且可以在单元测试期间轻松模拟

答案 4 :(得分:5)

设计模式可以帮助您,而不是阻碍。成为优秀开发人员的一小部分是知道何时“违反规则”。如果MVVM对于任务来说很麻烦,并且您已确定未来的值不值得付出努力,那么请不要使用该模式。例如,正如其他海报所评论的那样,为什么要通过所有开销来实现一个简单的框?

设计模式从未被教条化。

答案 5 :(得分:1)

由于模式本身MVVM很棒。但WPF的控件库附带的.NET 4.0数据绑定支持是非常有限的,它比WinForm好很多,但对于可绑定的MVVM来说仍然不够,我想它的功率大约是可绑定MVVM所需的30%。登记/> 可绑定MVVM:它是ViewModel仅使用数据绑定与View连接的UI MVVM模式是关于ViewState的对象表示,它没有描述如何维护View和ViewModel之间的同步,在WPF中它的数据绑定却可以是任何东西。实际上你可以在支持事件\回调的任何UI工具包中使用MVVM模式,你可以在WinForms的纯WinAPI中使用它(我做过,而且事件\回调没有太多工作),你甚至可以在文本中使用它控制台,就像使用MVVM模式重写DoS的Norton Commander一样。

简而言之:MVVM并非毫无意义,它很棒。 NET 4.0 WPF的控件库是垃圾。

以下是ViewModel的简单概念证明,您无法使用WPF以纯MVVM方式进行数据绑定。

public class PersonsViewModel
{
    public IList<Person> PersonList;
    public IList<ColumnDescription> TableColumns;
    public IList<Person> SelectedPersons;
    public Person ActivePerson;
    public ColumnDescription SortedColumn;
}

你不能数据绑定WPF的DataGrid列标题,你不能数据绑定选定的行等等,你要么以代码简单的方式做,要么为这5行写一个200行的XAML黑客代码最简单的ViewModel。你只能想象复杂的ViewModel会让事情变得更糟 所以答案是简单的,除非您正在编写Hello World应用程序,在WPF中使用可绑定MVVM是没有意义的。您将花费大部分时间考虑hack绑定ViewModel。数据绑定很不错,但准备回退到事件的70%时间。

答案 6 :(得分:0)

不,这并非毫无意义,但即使模式本身非常简单,也难以包裹。那里有大量的错误信息和各种群体以正确的方式进行斗争。我认为使用WPF和Silverlight你应该使用MVVM,否则你将过度编码并尝试在新模型中解决问题,“旧”胜利形成的方法只会让你陷入困境。在Silverlight中更是如此,因为一切都需要是异步的(围绕这个是可能的,但你应该选择另一个平台)。

我建议您阅读这篇文章Simplifying the WPF TreeView by Using the ViewModel Pattern  仔细了解MVVM如何很好地实现,并允许您将获胜形式的心态转变为MVVM中的新思维方式。简而言之,当您想要完成某些事情时,首先将逻辑应用于ViewModel而不是View。你想选择一个项目?换一个图标?不要迭代UI元素,只需更新模型属性,让数据绑定完成细节。

答案 7 :(得分:-1)

在(模态)对话框中,我已经看到了很多MVVM实现的相同问题。当我查看MVVM模式的参与者时,我感觉缺少一些东西来构建一个连贯的应用程序。

  • 查看包含特定的GUI控件并定义用户界面的外观。
  • ViewModel 表示演示文稿的状态和行为。
  • 模型可以是域图层中的业务对象,也可以是提供必要数据的服务。

但遗漏的是:

  • 谁创建了ViewModels?
  • 谁负责申请工作流程?
  • 当ViewModel需要彼此通信时,谁在它们之间进行调解?

我的方法是引入一个(用例)控制器,它负责缺失点。如何在 WPF Application Framework (WAF) 示例应用程序中看到它的工作原理。