【问题标题】:Constructor in ViewModelViewModel 中的构造函数
【发布时间】:2019-08-07 05:12:00
【问题描述】:

是否可以在 ViewModel 中有一个构造函数来初始化数据服务?

我的数据服务正在以类似这样的方式访问数据存储的网络服务:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.ObjectModel;
    using Cirrious.MvvmCross.ViewModels;
    using Cirrious.MvvmCross.Commands;
    using MobSales.Logic.DataService;
    using MobSales.Logic.Base;
    using MobSales.Logic.Model;

    namespace MobSales.Logic.ViewModels
    {
        public class CustomersViewModel:MvxViewModel
        {
            ICustomerService custService;
        public CustomersViewModel(ICustomerService custService)
        {
            this.custService = custService;
            if (custService != null)
            {
                custService.LoadCustomerCompleted += new EventHandler<CustomerLoadedEventArgs>(custService_LoadCustomerCompleted);
            }
            loadCustomerCommand = new MvxRelayCommand(LoadCustomer);
            loadCustomerCommand.Execute();
        }


    private ObservableCollection<Customer> customers;

    public ObservableCollection<Customer> Customers
    {
        get { return customers; }
        set
        {
            customers = value;
            FirePropertyChanged("Customers");
        }
    }


    private CustomerViewModel customer;

    public CustomerViewModel Customer
    {
        get { return customer; }
        set
        {
            customer = value;
            FirePropertyChanged("Customer");
        }
    }


    private MvxRelayCommand loadCustomerCommand;

    public MvxRelayCommand LoadCustomerCommand
    {
        get { return loadCustomerCommand; }
    }

    public void LoadCustomer()
    {
        custService.LoadCustomer();
    }

    void custService_LoadCustomerCompleted(object sender, CustomerLoadedEventArgs e)
    {
        if (e.Error != null)
        {
            return;
        }

        List<Customer> loadedCustomers = new List<Customer>();
        foreach (var cust in e.Customers)
        {
            loadedCustomers.Add(new Customer(cust));
        }

        Customers = new ObservableCollection<Customer>(loadedCustomers);
    }

}

我遇到了异常,但只能看到以下部分描述:

Cirrious.MvvmCross.Exceptions.MvxException: Failed to load ViewModel for type MobSales.Logic.ViewModels.CustomersViewModel from locator MvxDefau…

从 View 到 ViewModel 的绑定是如我在这篇文章中所展示的那样实现的:MVVMCross Bindings in Android

谢谢!

【问题讨论】:

  • 我对 ViewModels 的理解是,它确实与获取数据等无关。
  • 是的,没错,我只会初始化(错误的词...批准会更好)我的数据服务。获取数据会发生在其他地方。你可以看到,我有一个加载完成的事件......
  • 如果在你的 ViewModel 中没有发生,为什么你的 ViewModel 必须有这个数据服务?
  • 仅适用于这个 custService_LoadCustomerCompleted 和这个 LoadCustomer

标签: c# xamarin.android mvvmcross


【解决方案1】:

MvvmCross 的一个不同寻常的(自以为是的)功能是默认情况下它使用 ViewModel 构造函数参数作为导航机制的一部分。

这在我对Passing on variables from ViewModel to another View (MVVMCross)的回答中用一个例子来解释

基本思想是,当 HomeViewModel 请求导航时,使用:

private void DoSearch()
{
    RequestNavigate<TwitterViewModel>(new { searchTerm = SearchText });
}

那么这将导致一个 TwitterViewModel 使用传入构造函数的 searchTerm 构建:

public TwitterViewModel(string searchTerm)
{
    StartSearch(searchTerm);
}

目前,这意味着每个 ViewModel 都必须有一个没有参数或只有字符串参数的公共构造函数

因此,您的 ViewModel 未加载的原因是 MvxDefaultViewModelLocator 无法为您的 ViewModel 找到合适的构造函数。


对于“服务”,MvvmCross 框架确实提供了一个简单的 ioc 容器,可以使用 GetService&lt;IServiceType&gt;() 扩展方法最容易地访问它。例如,在 Twitter sample 之一的 ViewModel 中包含:

public class TwitterViewModel
    : MvxViewModel
    , IMvxServiceConsumer<ITwitterSearchProvider>
{
    public TwitterViewModel(string searchTerm)
    {
        StartSearch(searchTerm);
    }

    private ITwitterSearchProvider TwitterSearchProvider
    {
        get { return this.GetService<ITwitterSearchProvider>(); }
    }

    private void StartSearch(string searchTerm)
    {
        if (IsSearching)
            return;

        IsSearching = true;
        TwitterSearchProvider.StartAsyncSearch(searchTerm, Success, Error);
    }

    // ...
}

同样可以在Conference BaseViewModel看到会议服务数据是如何消费的


如果您的偏好是为您的 ViewModel 使用一些其他 IoC 容器或其他一些构造机制,那么您可以在 MvvmCross 中覆盖 ViewModel 构造。

看看这个问题(和答案),了解如何做到这一点 - How to replace MvxDefaultViewModelLocator in MVVMCross application

例如如果您愿意,那么您应该很容易调整该问题中的 MyViewModelLocator 示例以使用您的服务构建您的 ViewModel。

【讨论】:

  • 好的,明白了(多次阅读后)。所以我不在 MVVM 中使用 ViewModels 的构造函数。如果我做对了,则构造函数用于数据传递目的,因此仅用于字符串。
  • 在 MvvmCross 中是的,这是默认行为 - 但如果您想要不同的行为,则可以轻松覆盖默认行为 - 编写您认为最适合您的应用的代码 :)
  • 不,我不会重写它们,我不想离开约定,以确保它尽可能便携和可重复使用。到目前为止,谢谢。
  • 请问一般来说,在视图模型中编写构造函数方法是不是一个坏主意?我的简单示例是当需要根据传递给它的键在视图模型中填充列表时。我觉得 VM 的构造函数应该执行此任务,而不是单独的控制器执行此任务。 (或者至少它调用存储库以基于密钥获取其数据)。 (这与这个问题有些无关)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-19
  • 2019-10-09
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 2018-07-29
相关资源
最近更新 更多