【问题标题】:How to update model and view model in MVVM pattern?如何在 MVVM 模式中更新模型和视图模型?
【发布时间】:2015-06-14 21:19:21
【问题描述】:

我正在努力在我当前的项目中实现 MVVM 模式。

“ClassA”不断从远程设备获取所需的数据,并将这些数据存储在它的字段中。这是一个模型,我猜。 ClassA 通过 Update 方法更新所需信息。

“ClassB”不断地从“ClassA”中获取数据,并将其存储在相应的属性中。看起来它是一个视图模型。

View 是一个简单的 MainWindow.xaml,里面有一个 DataGrid。

我有以下问题:

1) 如何更新 ViewModel? ClassB 是否应该有一个 Update 方法,该方法接受 ClassA 的实例并更新相应的字段?

2) 我在哪里存储 ClassA 的实例? ClassA 应该是 ClassB 的一个字段吗?如果应该,那么我如何更新模型? 我想到了类似以下的内容:

public void UpdateB()
{
    ClassA.UpdateA();
    this.FieldOne = ClassA.FieldOne;
    this.FieldTwo = ClassA.FieldTwo;
}

4) 模型是否有它的更新方法或模型只是存储数据?

3) 除了 Windows 初始化之外,我在 MainWindow.cs 中做什么?我在那里更新视图模型(ClassB)吗?

【问题讨论】:

  • 您应该为ClassB(用于视图模型)实现INotifyPropertyChanged 接口,并将ClassB 设置为MainWindow 的DataContext(来自后面的代码或来自xaml)。然后您需要绑定 UI 元素来查看模型字段并填充此字段。您可以找到许多实现 MVVM 模式的简单示例。

标签: c# .net design-patterns mvvm data-binding


【解决方案1】:

我发现最好在每个抽象层中都有一个代表一个项目的对象。这包括存在于磁盘上的数据形式。请记住,在 MVVM 中,唯一真正的目标是促进接口 (User Interface) 和实现 (ViewModel functionality) 之间的松散耦合。

例如,如果我将对象存储在 XML 文件中,我的数据访问层中将有一个对象,该对象仅用于正确管理 XML 数据。我们称之为ObjectXml。此对象仅包含磁盘上数据的本机形式的数据。在这种情况下,所有数据都有一个字符串表示,就像在 XML 文件中一样。

在模型层中,您将以预期的数据类型获得 XML 文件的数据表示。我们称之为Object。属性 getter 和 setter 可以通过在两个方向上执行转换来访问和设置数据的字符串表示。这样,数据就可以持久化到数据源(xml文件、数据库等)了。

ObjectViewModel 中,属性可以访问Object 中的属性。 viewmodel 包含所有用于表示和修改模型的成员。

请注意,ObjectXml 仅在您仅被允许存储字符串信息或不存在适合您的数据类型的架构时才真正有用。

最后,您有一个包含层次结构,如下所示:

public class ObjectXml
{
    [XmlArray("People"), XmlArrayItem("Person")]
    public List<PersonXml> People { get; set; }
    //PersonXml is an xml data model similar to this one

    [XmlElement("Item")]
    public string Items { get; set; }
}

这是 Xml 对象的模型:

public class Object
{
    private ObjectXml _xmlContext;

    public Object(ObjectXml xmlContext)
    {
        this._xmlContext = xmlContext;
    }

    public List<Person> People
    {
        get
        {
            //Person requires a constructor that takes a PersonXml object in order for this to work properly
            return this._xmlContext.People.Select(x => new Person(x)).ToList();
        }
        set
        {
            this._xmlContext.People = value.Select(x => new PersonXml(x)).ToList();
        }
    }

    public double Item
    {
        get { return double.Parse(this._xmlContext.Item); }
        set { this._xmlContext.Item = value.ToString(); }
    }
}

显然,将类命名为 Object 是不明智的,因为它是 C# 中的保留字。希望我已经为您提供了一些关于如何以稳健且可扩展的方式访问和更新数据的想法。

简而言之,您根本不需要更新方法。此外,缺少常量和属性支持字段,在 C# MVVM 中需要直接字段访问的理由很少。

  1. 见下文。不要听人说ViewModelModel需要解耦。该模型的主要目的是一个中间层,用于准备要保存或加载到程序中的数据,并以与数据和程序功能无关的方式存储数据(ViewModel)
  2. 您不需要更新方法。如果需要,请使用访问数据模型并持久保存到数据存储 (xml, database etc.) 的属性。
  3. 您不需要更新方法。
  4. 您不必在ViewModel.cs 内执行任何操作。只有修改视图的代码才应该在代码隐藏中。您应该在视图中访问的唯一ViewModel 是遵循MainWindowViewModel 形式的MainWindowViewModel,它更像是承载其他所需视图模型实例的ApplicationViewModel

最后,不要使用过于复杂的MVVM "framework",因为大多数功能没有用或没有必要。

【讨论】:

  • 看来现在终于明白了。谢谢你。
  • 这很好,除非您拥有除了最微不足道的应用程序之外的任何东西,而且您不仅需要更新持久化的 XML 文件,还需要更新应用程序中依赖于该持久化 XML 的其他视图。跨度>
【解决方案2】:

就像 Yuris 评论中所说的,你不应该使用任何更新方法,而应该实现 INotifyPropertyChanged 接口。顾名思义,当某个属性的值发生变化时,它会通知所有订阅者。

This 是一篇不错的文章,其中包含简约 MVVM 实现的代码。如果您在从头开始实现该模式时遇到问题,请尝试从这个示例开始,并用您自己的一个一个替换现有的类。

至于 MainWindow.cs 中的更新机制 - 如果您在 xaml 代码中指定 DataBinding,就像在上面链接的示例中所做的那样,您不需要任何更新机制。

我希望这可以帮助您入门!

【讨论】:

  • 这篇文章帮助很大。谢谢。
  • 我很高兴听到这个消息 :)
猜你喜欢
  • 2018-06-30
  • 2014-05-27
  • 2020-01-17
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 2013-03-19
相关资源
最近更新 更多