当使用MVVM时,我应该将数据加载到哪个类中?

9

我目前正在学习C#,最近学习了WPF的MVVM设计模式。我正在编写一个简单的程序来练习这个模式,但是我不确定应该在哪里编写加载数据的方法。

我有一个SalesSheet类,如下所示。它存储我从.xls文件中加载的数据。

class SalesSheet
{
    public List<Row> Rows { get; set; }

    public SalesSheet()
    {
        Rows = new List<Row>();
    }

    public class Row
    {
        public string CallType { get; set; }
        public string HistoryText { get; set; }
    }

}

我的问题是,我应该在哪里编写负责加载数据的方法?

像下面这样编写一个方法是否不好的习惯:

private void LoadData(string filePath)

在模型中,我是否应该调用构造函数?我应该从ViewModel中加载它吗?
5个回答

8
一般来说,一个小的WPF项目应该具有以下大致文件夹结构:
  • ProjectName
    • Converters
    • DataAccess(数据访问)
    • DataTypes(数据类型)
    • Images(图像)
    • ViewModels(视图模型)
    • Views(视图)
DataAccess是您应该存储数据访问类的文件夹。将应用程序的各个方面分开,即视图、视图模型和数据访问类,是一种良好的实践方法。这被称为关注点分离(SoC),是一种良好的做法,因为它使您能够切换层...这意味着您可以稍后添加Web界面(或更改数据库),同时仍保持大部分代码不变,并且也使测试代码更加容易。
您可能只在这个文件夹中拥有一个类,我们称之为DataProvider。在这个DataProvider类中,您将放置所有的数据访问方法。现在,您有了一个数据访问的入口点,并且可以在基础视图模型中添加对它的引用:
protected DataProvider DataProvider
{
    get { return new DataProvider(); }
}

现在您的视图模型都可以访问项目数据源,然后您可以像这样做:
SomeObject someObject = DataProvider.LoadData(filePath);

当然,实现这种模式有许多不同的方法,但是希望现在你已经明白了。

5
在我对MVVM的理解中,你的LoadData方法应该属于模型。然后,视图模型可以通过模型的属性或方法访问已加载的数据。
这里的重要点是,视图模型不知道具体的文件访问逻辑,它是由模型抽象出来的。

1
创建一个视图模型类。 通过在DataContext属性中创建它来在视图的xaml中实例化视图模型类。
实现一个方法来加载视图模型中的数据,例如LoadData。 设置视图,以便在视图加载时调用此方法。 您可以通过在视图的事件处理程序中实现Loaded事件,或者您可以使用交互触发器在视图中链接到视图模型中的方法来完成这个操作。
视图(xaml):
<Window x:Class="MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" 
        xmlns:viewModel="clr-namespace:ViewModels" Loaded="Window_Loaded">
    <Window.DataContext>
        <viewModel:ExampleViewModel/>
    </Window.DataContext>

查看(代码后台):

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ((ExampleViewModel)this.DataContext).LoadData();
    }

如果您不喜欢在代码后台设置 Loaded 事件,您也可以在 xaml 中进行设置(需要引用 "Microsoft.Expression.Interactions" 和 "System.Windows.Interactivity"):
<Window x:Class="MyWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" 
    xmlns:viewModel="clr-namespace:ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"            
    >
<Window.DataContext>
    <viewModel:ExampleViewModel/>
</Window.DataContext>
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/>
    </i:EventTrigger>
</i:Interaction.Triggers>   

在每种情况下,您都需要在ViewModel中调用LoadData方法。 在这里,您应该调用一个单独的类来提供数据。 这个类通常被称为repository。

public class ExampleViewModel
{
    /// <summary>
    /// Constructor.
    /// </summary>
    public ExampleViewModel()
    {
        // Do NOT do complex stuff here
    }


    public void LoadData()
    {
        // Make a call to the repository class here
        // to set properties of your view model
    }

如果存储库中的方法是异步方法,您也可以使 LoadData 方法异步,但并非每种情况都需要。
通常我不会在视图模型的构造函数中加载数据。 在上面的示例中,当设计师显示您的视图时,将调用视图模型的(无参数)构造函数。在此处执行复杂操作可能会导致设计师在显示视图时出现错误(出于相同的原因,我不会在视图构造函数中进行复杂操作)。
在某些情况下,视图模型构造函数中的代码甚至可能在运行时引起问题,当视图模型构造函数执行时,设置绑定到视图元素的视图模型属性,而视图对象尚未完全创建。

0

根据您的项目规格,您有许多选择。

但我发现 DataService 方法简单而灵活。

  1. 在核心(或业务层)中创建一个类,并将其命名为 SalesDataService
  2. 在其构造函数中初始化变量和其他内容(如果有)
  3. 向DataService添加您的方法,例如 GetRows() GetSingleById(int id) ...
  4. 在您的视图模型中添加 protected SalesDataService _salesDataService 字段
  5. 在视图模型的构造函数中实例化 _salesDataService
  6. 必要时调用 GetRows()(如果没有人调用加载数据,则将其放入构造函数中)

0

Window.ContentRendered 是最安全的事件,如果您正在使用数据绑定。在某些情况下,当使用数据绑定时,Window_Loaded 将会太早,对象仍将为空。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接