Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
270 views
in Technique[技术] by (71.8m points)

c# - Constructor in ViewModel

Is it possible to have a constructor in the ViewModel, which initializes the data service?

My data service is accessing the web-service of the data storage in a manner similar to this:

    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);
    }

}

I am getting an exception but can only see the following partial description:

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

The binding from View to ViewModel is realized as I've shown in this post: MVVMCross Bindings in Android

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

One of the unusual (opinionated) features of MvvmCross is that by default it uses ViewModel constructor parameters as part of the navigation mechanism.

This is explained with an example in my answer to Passing on variables from ViewModel to another View (MVVMCross)

The basic idea is that when a HomeViewModel requests a navigation using:

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

then this will cause a TwitterViewModel to be constructed with the searchTerm passed into the constructor:

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

At present, this means that every ViewModel must have a public constructor which has either no parameters or which has only string parameters.

So the reason your ViewModel isn't loading is because the MvxDefaultViewModelLocator can't find a suitable constructor for your ViewModel.


For "services", the MvvmCross framework does provide a simple ioc container which can be most easily accessed using the GetService<IServiceType>() extension methods. For example, in the Twitter sample one of the ViewModel contains:

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);
    }

    // ...
}

Similarly, you can see how the conference service data is consumed in the Conference BaseViewModel


If your preference is to use some other IoC container or some other construction mechanism for your ViewModels, then you can override the ViewModel construction within MvvmCross.

Take a look at this question (and answers) for ideas on how to do this - How to replace MvxDefaultViewModelLocator in MVVMCross application

e.g. if you want to, then it should be fairly easy for you to adjust the MyViewModelLocator example in that question to construct your ViewModel with your service.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...