【问题标题】:C# WPF MVVM Window OnLoad BindingC# WPF MVVM 窗口 OnLoad 绑定
【发布时间】:2013-12-20 05:29:46
【问题描述】:

我的代码如下...

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

我的 ViewModel 看起来像这样...

class MainWindowViewModel : INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        bool flag = Application.Current.MainWindow.IsInitialized;

        if (flag)
        {
            // Do something...
        }

    }

我想我的问题是....这符合 MVVM 设计模式吗?唯一的其他方法是How to fire a Command when a window is loaded in wpf

我不知道为什么,但我不想使用 mvvm-light 或任何其他样板代码..

【问题讨论】:

  • 一切都好。别担心:)
  • 您发布的链接不使用 MVVM Light - 使用 System.Windows.Interactivity 是您在使用 MVVM 时最终需要的东西 - 它解决了许多这些问题。
  • 如果你打算使用 Blend,那么 @ReedCopsey 给出了很好的建议。还要查看 Prism/MEF 中的 CompositePresentationEvent 类或代理应用级消息的类似事物。您无需借助完整的 Prism 范例即可使用它们。
  • @RobPerkins 我推荐使用System.Windows.Interactivity.dll,即使你没有使用 Blend :) 它有很多有用的 MVVM 工具(行为等)

标签: c# wpf mvvm


【解决方案1】:

从 ViewModel 访问 UI 组件违反了 MVVM 模式。

Application.Current.MainWindow.IsInitialized 打破了这种模式。

自定义行为更符合 MVVM。因此,我建议采用您在问题中作为链接提到的方法。


访问 UI 组件会破坏 ViewModel 的可测试性。您将如何为您的 ViewModel 类编写测试用例?当您尝试通过单元测试对其进行测试时,Application.Current 将变为null,它将引发空引用异常。

MVVM 的主要动机之一是将 UI 逻辑与业务分离 逻辑,以便业务逻辑可以单独测试而无需担心 关于它的消费者是视图。

【讨论】:

    【解决方案2】:

    在没有样板代码的 MVVM 中,没有“纯粹”的方法可以做到这一点。一般来说,您不需要响应 VM 中的 VIew 进行工作 - 只是这个概念违反了 MVVM,因为您的 ViewModel 试图做一些事情来响应 View,而事情应该总是以另一种方式流动.

    在实际场景中,ViewModel 根本不应该关心 View 的状态 - 它应该只为 View 提供数据绑定数据。

    大多数时候,人们尝试这样做是为了避免预先加载数据。这通常通过推送数据加载并在 ViewModel 内直接在后台线程 上启动它,然后在完成时更新 VM 内的属性来更好地处理。 C# 5 的async/await 语言特性可以用来简化这一点。

    【讨论】:

    • 感谢大家对此提出的意见。 MVVM 只是一种设计模式,但考虑到它在业务应用程序中的广泛使用,它肯定希望它更多。我使用 INotifyPropertyChanged 和 ICommand 绑定数据没有问题,但是这样的事情有很大的解释空间......
    • @DavidRussell 归根结底,几乎每个人都同意虚拟机不应该知道任何关于 View 的事实——即:reedcopsey.com/blog/wp-content/uploads/2010/01/MVVM.png 你如何将其余部分结合在一起,并且不同的框架都有自己的想法。一旦您了解了基础知识,框架确实会大有帮助(即使您自己编写),但像 EventToCommand、行为和其他事件触发器之类的东西对于“真实”应用程序不违反 MVVM 至关重要
    【解决方案3】:

    虽然通常认为有一些加载/卸载逻辑是违反模式的,但有一组用例是必要的。例如。视图模型可能需要订阅某些事件。如果卸载时没有取消订阅,则可能不会被垃圾回收,具体取决于订阅的性质。

    会打破模式的是从视图模型中访问视图状态,例如操纵控制。视图模型的作用是将数据暴露给视图,管理加载/卸载行为是该契约的一部分。知道何时加载视图模型意味着知道何时公开该数据。

    虽然视图模型确实不应该关心视图的状态,但它必须知道如何准备数据以在视图中呈现。更重要的是,视图模型是模型和视图之间的一层,使 它们 分开。换句话说:既然“模型”意味着逻辑,那么“视图模型”意味着获取数据以显示的逻辑。这也是关于知道何时获取它/使其可用/等。

    您可能想看看this blog post,它提供了一种让视图模型意识到正在加载的便捷方法。就 MVVM 纯度而言,它并不是 100% 正确,因为它将FrameworkElement 传递回视图模型,但假设我们忽略了这个参数。

    下面的示例代码基于上面的博客文章,但具有更纯粹的签名。你可以在你的类上实现IViewModel 接口:

    public interface IViewModel : INotifyPropertyChanged
    {
        void Load();
        void Unload();
    }
    

    然后使用附加属性指示视图在加载或卸载时调用适当的方法:

    ViewModelBehavior.LoadUnload="True"
    

    请注意,最后一行在 XAML 中占有一席之地 - 视图是强制执行某种行为的视图,反之亦然。

    【讨论】:

      【解决方案4】:

      您当前所做的事情是正确的,这就是在幕后使用其他框架的方式。

      既然你提到了MVVM-Light,我建议你可以看看caliburn micro。它具有非常好的框架来符合 MVVM 模式。 Caliburn micro 可以轻松地将绑定与控件上的事件挂钩。只需查看它的文档,它仍然被视为 MVVMy..

      【讨论】:

      • 我对 MVVM 还是比较陌生。太糟糕了,每个人都使用背后的代码来教 WPF,但实际上应该只使用 mvvm 来教。这基本上是我在窗口加载时触发某些东西的作弊。
      • 也许我想成为一个最纯粹的人,但如果它可以帮助它,我不喜欢我的代码中的任何 3rd 方框架。我将与 Caliburn Micro 一起玩...看看它是否可以转换我...谢谢
      • @DavidRussell 至于“教 WPF”——你可能想看看我的系列文章reedcopsey.com/series/windows-forms-to-mvvm
      • 我不同意你的说法,即这是“正确的”——这样做确实是直接违反 MVVM...
      • @ReedCopsey 第一个源代码是我的意思,它是正确的而不是第二个。我完全不同意您从 ViewModel 访问 Application.Current。
      【解决方案5】:

      特别是因为 MVVM 主要用于保证易于维护和可测试的代码,你应该记住,如果你在 UnitTests 中使用MainViewModel,Application.Current 将为空。因此,此代码将在您的测试中以 NullPointerException 结尾。

      如果你想确保某些东西已经初始化,你应该考虑使用Initialized 事件。但是你在调用InitializeComponent 之后创建了ViewModel - 我只会离开结帐。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-27
        • 2019-01-24
        • 2013-03-19
        • 2016-03-23
        • 2011-07-19
        相关资源
        最近更新 更多