【问题标题】:What is your experience with abandoning MVVM for UserControl-based WPF architecture?对于基于 UserControl 的 WPF 架构放弃 MVVM 是什么体验?
【发布时间】:2010-12-03 08:40:17
【问题描述】:

我们使用 Infragistics 控件基于 Composite Application LibraryMVVM 构建了一个大型应用程序。

为了节省时间并使应用程序更直接,我们取消了 MVVM 要求。我们现在没有 Presenters 或 ViewModel,我们的 View 已经变成了简单的 UserControl,它们的创建方式如下:

BaseEditor.cs:

using System.Windows.Controls;

namespace App
{
    public class BaseEditor : UserControl
    {
        public string Title { get; set; }
        public BaseEditor()
        {
            Title = "This was defined in the Base Editor.";
            Loaded += new System.Windows.RoutedEventHandler(BaseEditor_Loaded);
        }

        void BaseEditor_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            StackPanel sp = new StackPanel();
            TextBlock tb = new TextBlock();
            tb.Text = Title;
            sp.Children.Add(tb);
            this.Content = sp;
        }
    }
}

CustomerEditor.cs:

namespace App
{
    public class CustomerEditor : BaseEditor
    {
        public CustomerEditor()
        {
            Title = "This was overwritten by the CustomerEditor.";
        }
    }
}

Window1.cs.xaml:

<Window x:Class="App.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:App"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <local:CustomerEditor/>
    </Grid>
</Window>

除了可测试性问题以及像这样执行 WPF“感觉很脏”这一事实之外,我仅从这个决定中体验到了积极的影响,例如:

  • 我们可以互相继承我们的非 XAML 用户控件
  • 我们使用尽可能多的代码隐藏来加快开发速度
  • 将基础架构控件直接附加到来自 Web 服务的模型类可以解决我们在将基础架构绑定到 ObservableCollections 时遇到的几十个小绑定问题
  • 即使在直接的 WPF 中,缺少 ObservableCollections 也会使 not being able to create a simple Menu 等问题消失
  • 我们正在使用 UserControls 和代码背后的直接事件逐一替换 EventAggregator,从而解决了各种事件问题

在 WPF 中做 MVVM 的其他人有类似的经历吗?从长远来看,您是否遇到过任何实际问题?

【问题讨论】:

  • 那么,你把你的业务逻辑放在哪里了?
  • 我们从 ESB 上的服务获取数据,大部分业务逻辑都在那里完成

标签: .net wpf architecture mvvm prism


【解决方案1】:

我们可以相互继承我们的非 XAML 用户控件

我不明白。 MVVM 排除了继承怎么办?

我们使用尽可能多的代码隐藏来加快开发速度

只要是与视图相关的代码,代码隐藏就可以了。 IE。不是您要测试的业务逻辑。关注点和所有的分离。

您仍然可以在使用代码执行所有操作的同时执行 MVVM - 甚至是您的视图。 MVVM 不是零代码。这是关于分离关注点和从中获得的好处。如果您不需要在 Blend 中设计您的视图,那么无论如何您都可以将大部分或全部视图显示为代码。哎呀,即使您确实需要在 Blend 中工作,仍有一定数量的视图仍然可以显示为代码。您只需要评估权衡并做出有意识和明智的决定。

将基础设施控件直接附加到来自 Web 服务的模型类消除了我们在将基础设施控件绑定到 ObservableCollections 时遇到的几十个小绑定问题

Infragistics 控制极差。在那里,我说了算。如果这是一个选项,请不要使用它们。如果这不是一个选项(我也曾担任过这个职位),您通常可以解决附加行为和其他技术的许多问题。是的,这很麻烦,但不要责怪 MVVM - 责怪 Infragistics 生成了一个与 WPF 平台如此不一致的控制集。

即使在直接的 WPF 中,ObservableCollections 的缺乏也会使无法创建简单菜单等问题消失

我完全不明白这一点。 ObservableCollections 是 WPF 的一部分,而不是 MVVM。并且阅读了您的问题(再次 - 在您提交后不久我回复了它)我会说这只是您对 WPF 如何工作的误解 - 与 MVVM 完全无关。

我们正在使用 UserControls 和代码后面的直接事件一一替换 EventAggregator,这清除了事件的各种问题

适合工作的正确工具。如果您能够使用直接事件,那么无论您是否使用 MVVM,您都可以这样做。 MVVM 不以任何方式要求使用事件聚合器模式,因此您的观点也不清楚。事件聚合器模式可用于确保不同的组件可以在运行时协作,而无需任何编译时依赖。通过使用标准 CLR 事件,您可以在组件之间创建强依赖关系。如果您想单独使用它们,那么您将有一次机会。

总而言之,这并不是针对 MVVM 的案例,更多的是缺乏理解。我认为你正在逆流而上,我建议你仔细看看 MVVM。它不是灵丹妙药或一刀切的模式,但如果使用得当,它肯定有助于为您的 WPF/SL 应用程序创建一个极好的基础。

【讨论】:

  • 事件聚合器积分+1。我看到很多关于它的使用的误解......很多人认为在使用 MVVM + Prism 时,您必须使用事件聚合器来引发事件,而这根本不是真的。
  • 我得说,伙计……我已经重读了 10 遍。很好地分解了他的cmets。我没有像你那样仔细阅读OP的帖子......你真的击中了每一点。非常好。
  • 感谢您这么长的回复,非常有用。一旦我们超过了我们的最后期限,我将仔细研究 MVVM,而普通老式的类似 winform 的用户控制编程正在帮助我们实现这一目标。 MVVM 会怎样排除继承?我将 View 理解为带有 XAML 和代码隐藏的 UserControl。如果您有一个 CustomerEditorView 和一个 EmployeeEditorView 并且您意识到它们具有应该从 BaseEditorView 继承的相似功能,那么您不能像上面代码中的纯代码 UserControl 那样继承 XAML。例如,当我们切换时,这对我们来说是一项重大胜利。
  • 我没有提到的另一点是:使用 MVVM,您的 ViewModel 必须具有模型的所有属性,并且在我们没有使用的许多情况下,这似乎是不必要的代码复制INotifyPropertyChanged 功能。当我们将 UserControl 直接连接到模型和验证时,这种情况就消失了,例如我们正在使用 INotifyPropertyChanged,现在我们在需要它的地方使用简单的代码。
  • 为此 +1:“MVVM 不是零代码背后。它是关于分离关注点和从中获得的好处。”
【解决方案2】:

我开始以这样的 FFA(免费)设计模式开发 WPF 应用程序,即使是小型项目,我也不会回头。尽管直接使用源代码、裸机 UI 感觉您的工作效率更高,但我得出的结论是,它更多地是对生产力的感知,因为您会获得即时满足

考虑:TextBlock.Text = "HelloWorld"。无需构建 ViewModel,无需粘合 V 和 VM 或绑定设置。按 F5,我们会看到“HelloWorld”的荣耀。我的问题是多方面的。这是我最大的几个问题:

  • 关注点分离。没有它,代码导航、错误修复、 可扩展性和一般维护 受到严重阻碍。添加一个 应用程序的功能将是 更像一个 选择你自己的冒险书或 比它练习量子物理学 实际上是在做某事。 如果你有一个可预测的方法 构建你的应用程序,你有一个 可预测的工作方式。

    用户界面的灵活性。使用 FFA 模式时,我发现了我的 我的 UI 设计能力 申请几乎是不可能的。 太多次我有一个控制我 无法在 Blend 中设计。它会 只需给一个红色边框 例外。我有一些代码隐藏 使用了其他没有的东西 可用于设计模式导致 问题。神奇地迁移到 MVVM 修复了我所有的 Blend 问题。如果我有 现在 Blend 中有一个红色边框,我知道 这是我的演示文稿的问题 代码。没有别的。

因此,使用 FFA 可能会让您的 V1 快速推出,但 PHB 会想知道为什么 v1.5 会比 v1 花费四倍的时间。我们都去过那里:)

我认为,如果您想做这样的事情,我会使用无外观控件,您可以在其中定义 UI“部分”,使其非常可混合。您可以通过 OnApplyTemplate 获得对 UI 控件的引用。这些控件是完全可样式化和可继承的。这是您的视图,您可以在其中使用这些控件并从绑定中提取数据,并将其传递给您的无外观控件。视图,IMO,应该始终是 VM 绑定到这些类型的控件的粘合剂。

对于您遇到问题的 Infragistics 控件,假设您使用的是 Prism,您应该为其制作自定义区域适配器。这使您可以准确地编写如何将控件添加到 Infragistics 的代码。不涉及绑定。内置视图后,视图注入将像您习惯的那样工作。

我已经看到有些人在 MVVM 中遇到了类似的问题,但我相信这只是将 MVVM 理解为过于字面意思。并非所有事情都由信使引起。我的约 40 个视图(和不断增长的)应用程序有大约 5 个复合事件。我继承了控件,我在甚至不是面板或内容控件的东西上使用视图注入。有时我有代码隐藏处理与演示相关的代码/事件......而且......真的,我提倡 MVVM 并且我没有给出关于测试的@$&% :)

【讨论】:

  • 我希望看到一个使用 MVVM 完成的真实演示应用程序(而不是像 StockTrader 那样做一些简单事情的应用程序),而是一个连接到具有完整 crud 能力的数据库的应用程序,一个使用基础设施的应用程序或 Telerik 或一些真实世界的第三方组件,它们具有某种可扩展性,例如在项目边界上注入控件。当所有这些现实世界的方面进入您的应用程序时,必然会从 MVVM 中退出,最好看看在哪里退出并了解权衡是什么、有限的 UI 测试等。跨度>
【解决方案3】:

我尝试了这个并最终回到 MVVM。您最终会得到与 Windows 窗体中相同的事件驱动的意大利面条式编码混乱。如果我再也不用myLabel.Text = this.MyLabelText 我会很高兴。

不要误会我的意思 - MVVM 更难坚持,您必须了解 WPF 才能成功

但是,如果不使用它,您会失去很多,包括很多使用 Expression Blend 设置控件和 DataTemplate 样式的能力。

【讨论】:

    【解决方案4】:

    我不同意这一点,我曾使用 WPF、MVVM、WCF 和 Telerik 控件开发过一个大型商业应用程序。 一开始,使用 MVVM 有点困难,但一旦我们解决了我们的设计和视图模型框架,它变得非常容易。可重用性非常容易实现,并且开发时间也缩短了。

    此外,完全更改控件非常容易;在某些地方,我们使用了基本的 WPF 控件,后来我们将其替换为 Telerik 控件,反之亦然(因为在某些地方,我们不需要像 GridView 这样的重型 Telerik 控件)。 我可以说,如果需要,我们可以随时轻松地将所有 Telerik 控件替换为其他一些 3 方控件或原生 WPF 控件。

    但是,是的,我们必须在使用 Telerik 控件时实施一些变通方法,并在代码隐藏中编写一些代码来解决一些问题(telerik 中的错误);所有这些代码都是纯粹的表示逻辑。

    【讨论】:

      【解决方案5】:

      嘿,任何对你有用的东西。对这些东西很容易变得虔诚。除非我非常严格地注意关注点分离,否则我的应用程序会滑入意大利面条式代码,但这并不意味着 MVVM 是唯一的出路。如果您有一个可以运行的应用程序,并且您可以在没有一堆级联副作用的情况下进行更改,那么我会说去吧。

      我会恭敬地不同意(不反对)安德森艾姆斯的观点:我不觉得 MVVM 难以坚持;我觉得很容易。对我来说,这是设计 WPF 应用程序的最简单、最自然的方法。我在 Composite WPF (Prism) 框架内使用它,它为复杂应用的分区提供了一个非常健壮的框架。

      我写了一个CodeProject article 在一个真实世界的应用程序中实现 MVVM。希望刚接触 MVVM 的人会发现它很有帮助。

      【讨论】:

      • 如果你来自 WinForms,MVVM 是不自然的,学习曲线更陡峭,这就是我要说的......你必须学习很多关于 WPF 绑定、DataContexts、AttachedProperties 等的知识真的让它为你带来回报。
      • MVVM 总体上很有意义,也许我们只是想用它做太多事情,即从服务创建基于 XML 的动态表单。将 UserControls 绑定到模型后,我们拥有更多控制权。
      • Anderson--是的,我同意来自 WinForms 的 MVVM 可以有一个学习曲线。如果您有模型-视图-控制器模式的 WinForms 经验,MVVM 会更容易学习,这与 MVVM 有许多相似之处。
      • Edward——是的,听起来您可能一直在尝试使用 MVVM 做更多的事情,而不是该模式可以处理的事情。当前的最佳实践似乎是根据需要使用 Prism 将模块加载到 shell 窗口中,而不是创建动态表单,就像您似乎对用户控件所做的那样。 Prism 绝对值得一看,因为它为模块之间的松散耦合通信提供了出色的基础架构。
      【解决方案6】:

      MVVM 的拥护者过度陈述他们的情况。他们声称 MVVM 的替代品必然是意大利面条代码。 Edward 所描述的仍然遵循一种模式,它只是不是 MVVM。视图绑定到模型的事实类似于 MVC。后面的代码可以认为是控制器。

      显然,他认为在开发工作和可维护性方面结果更好。由于后者是设计模式的唯一有效理由,因此反对他的方法的理由并不明确。

      说“你不了解 MVVM”并不是反对他的方法的真正论据。一种更容易理解的模式比一种更容易理解的模式更好。

      【讨论】:

      • 为了记录,我使用 MVVM 并相信这种方法更干净,更易于维护。我承认正确设置比较困难。
      【解决方案7】:

      视图模型很好,因为它使数据绑定更容易。数据绑定并没有涵盖您需要做的所有事情,因此附加到 XAML 的一些代码很方便。

      根据我的经验,混合使用视图模型和附加到事件似乎可以完成工作,直到如果需要可以制定出更纯粹的方法。

      编辑:

      如果您使用事件处理程序将事件转发到视图模型或其他负责对象中的处理程序逻辑,则附加到事件不一定会破坏 MVVM 模型。

      纯数据绑定的优势在于您可以更轻松地制作使用相同视图模型的不同 XAML 外观。一个例子是有一个调试皮肤,它暴露了一些内部工作以帮助开发和一个工作皮肤,它是最终产品。不同的 XAML 视图可以绑定到同一个视图模型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-08
        • 1970-01-01
        • 2016-06-29
        • 2011-05-13
        • 2011-08-14
        • 2013-08-17
        相关资源
        最近更新 更多