gpt4 book ai didi

mvvm - 是否应该通过构造函数、属性或方法调用来初始化 ViewModel

转载 作者:行者123 更新时间:2023-12-04 02:21:36 25 4
gpt4 key购买 nike

我在 MVVM 的上下文中讨论了一些不同的设计概念,这些概念主要源于何时初始化 ViewModel 的问题。更具体地说,在“初始化”方面,我指的是加载值,例如选择值、安全上下文和其他在某些情况下可能会导致几秒钟延迟的东西。

可能的策略:

  • 将参数传递给 ViewModel 构造函数并在构造函数中加载。
  • 仅支持 ViewModel 上的无参数构造函数,而支持带参数和加载的初始化方法。
  • 选项 1 和 2 的组合,其中参数传递给 ViewModel 构造函数,但加载被推迟到调用 Initialize 方法。
  • 选项 3 的变体,其中参数不是传递给 ViewModel 构造函数,而是直接在属性上设置。

  • 对 ViewModel 属性 getter 和 setter 的影响

    在延迟初始化的情况下,需要知道 ViewModel 是否处于被认为可用的状态,IsBusy 属性通常像其他异步和耗时操作一样用于该状态。这也意味着,由于 ViewModel 上的大多数属性公开了从模型对象检索的值,因此我们必须不断编写以下类型的管道以确保模型可用。
    public string Name
    {
    get
    {
    if (_customerModel == null) // Check model availability
    {
    return string.Empty;
    }

    _customerModel.Name;
    }
    }

    尽管检查很简单,但它只是增加了 INPC 的管道和其他类型的必需品,使 ViewModel 的编写和维护变得有些麻烦。在某些情况下,它变得更加成问题,因为可能并不总是从属性 getter 返回合理的默认值,例如 bool 属性 IsCommercialAccount 的情况,如果没有可用的模型,则返回 true 或false 引发了一系列其他设计问题,例如可空性。在上面的选项 1 的情况下,我们将所有内容传递给构造函数并加载它,然后我们只需要关注来自 View 的 NULL ViewModel,当 ViewModel 不为 null 时,它保证被初始化。

    支持延迟初始化

    使用选项 4 也可以依赖 ISupportInitialize它可以在 ViewModel 的基类中实现,以提供一致的方式来通知 ViewModel 是否已初始化,并通过标准方法开始初始化 BeginInit .这也可以用于选项 2 和 3 的情况,但如果所有初始化参数都设置在一个原子事务中,则意义不大。至少这样,上面显示的条件可能会变成类似

    设计如何影响 IoC

    在 IoC 方面,我理解选项 1 和选项 3 可以使用构造函数注入(inject)来完成,这通常是首选,选项 2 和选项 4 可以分别使用方法和属性注入(inject)来完成。然而,我关心的不是 IoC 或如何传递这些参数,而是整体设计以及它如何影响 ViewModel 实现和它的公共(public)接口(interface),尽管我想成为一个好公民,如果有必要的话,让 IoC 更容易一些 future 。

    可测试性

    所有三个选项似乎都同样支持可测试性的概念,这对在这些选项之间做出决定没有多大帮助,尽管有争议的是,选项 4 可能需要更广泛的测试集来确保属性的正确行为,其中该行为取决于初始化状态.

    指挥能力

    选项 2、3 和 4 都有副作用,需要 View 中的代码调用 ViewModel 上的初始化方法,但是如果需要,这些可以作为命令公开。在大多数情况下,人们可能会在构造之后直接加载调用这些方法,如下所示。
    var viewModel = new MyViewModel();
    this.DataContext = viewModel;
    // Wrap in an async call if necessary
    Task.Factory.StartNew(() => viewModel.InitializeWithAccountNumber(accountNumber));

    其他一些想法

    由于我一直在使用 MVVM 设计模式,因此我尝试了这些策略的变体,但尚未得出最佳实践的结论。我很想听听社区的想法,并尝试就初始化 ViewModel 或以其他方式处理其处于不可用状态时的属性的最佳方法达成合理的共识。

    理想的情况可能是使用状态模式,其中 ViewModel 本身被替换为代表不同状态的不同 ViewModel 对象。因此,我们可以有一个通用的 BusyViewModel 实现来表示忙碌状态,它消除了 ViewModel 上 IsBusy 属性的需求之一,然后当下一个 ViewModel 准备就绪时,它会在 View 上换出,允许 ViewModel 遵循概述的状态在选项 1 中,它在构造过程中完全初始化。这留下了一些关于谁负责管理状态转换的问题,例如,可能是 BusyViewModel 负责抽象类似于 BackgroundWorker 或正在执行初始化的 Task 的东西,并在准备好时呈现内部 ViewModel。另一方面,在 View 上交换 DataContext 可能需要处理 View 中的事件,或者将 View 的 DataContext 属性的有限访问权限授予 BusyViewModel,以便可以在传统的状态模式意义上对其进行设置。如果人们正在沿着这些路线做类似的事情,我肯定想知道,因为我的谷歌搜索还没有出现太多。

    最佳答案

    我的面向对象设计的一般方法,无论是创建 View 模型还是其他类型的类;所有可以传递给构造函数的东西,都应该传递给构造函数。这减少了对某种 IsInitialized 的需求。状态并使您的对象不那么复杂。有时某些框架很难遵循这种方法,例如 IoC 容器(尽管它们应该允许构造函数注入(inject)),但我仍然遵守它作为一般规则。

    关于mvvm - 是否应该通过构造函数、属性或方法调用来初始化 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11596744/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com