后台加载在MVVM和构造器注入 [英] Background loading in MVVM and Constructor Injection

查看:148
本文介绍了后台加载在MVVM和构造器注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于如何以及在哪里在WPF .NET 4.0加载大量与视图模型数据的问题(所以没有异步/的await:/)。

I have a question about how and where to load a large amount of data with ViewModel in WPF .NET 4.0 (so no async/await :/ ).

下面是我的视图模型:

public class PersonsViewModel : ViewModelBase
{
    private readonly IRepository<Person> _personRepository;

    private IEnumerable<Person> _persons;
    public IEnumerable<Person> Persons
    {
        get { return _persons; }
        private set { _persons = value; OnPropertyChanged("Persons"); }
    }

    public PersonsViewModel(IRepository<Person> personRepository)
    {
        if (personRepository == null)
            throw new ArgumentNullException("personRepository");

        _personRepository = personRepository;
    }
}

此视图模型是在一个窗口中使用,我需要的窗口打开时加载所有的人。我认为许多解决方案,但我想不出这是最好的(或者有更好的方式来做到这一点)。我有两个约束上:
     - 所有的数据必须在另一个线程加载,因为它可以载入时间为秒(数据库中的数据量巨大),我不想冻结用户界面。
     - 视图模型必须是可检验的。

This ViewModel is used in a Window and I need to load all the persons when the Window opens. I thought of many solutions but I can't figure which is the best (or maybe there's a better way to do this). I have two contraints: - all the data must be loaded in another thread because it can take seconds to load (huge amount of data in the database) and I don't want to freeze the UI. - the ViewModel must be testable.

- = [解决方案一:延迟加载] = -

--=[ First solution: Lazy loading ]=--

public class PersonsViewModel : ViewModelBase
{
    private IEnumerable<Person> _persons;
    public IEnumerable<Person> Persons
    {
        get
        {
            if (_persons == null)
                _persons = _personRepository.GetAll();
            return _persons;
        }
    }
}

因为数据是在主线程加载的,我不喜欢这个解决方案。

I don't like this solution because the data is loaded in the main thread.

- = [解决方法二:加载事件] = -

--=[ Second solution: Loaded event ]=--

public class PersonsViewModel : ViewModelBase
{
    // ...

    private Boolean _isDataLoaded;
    public Boolean IsDataLoaded
    {
        get { return _isDataLoaded; }
        private set { _isDataLoaded = value; OnPropertyChanged("IsDataLoaded"); }
    }

    public void LoadDataAsync()
    {
        if(this.IsDataLoaded)
            return;

        var bwLoadData = new BackgroundWorker();
        bwLoadData.DoWork +=
            (sender, e) => e.Result = _personRepository.GetAll();
        bwLoadData.RunWorkerCompleted +=
            (sender, e) => 
            {
                this.Persons = (IEnumerable<Person>)e.Result;
                this.IsDataLoaded = true;
            };
        bwLoadData.RunWorkerAsync();
    }
}

public class PersonWindow : Window
{
    private readonly PersonsViewModel _personsViewModel;

    public PersonWindow(IRepository<Person> personRepository)
    {
        _personsViewModel = new PersonsViewModel(personRepository);

        this.Loaded += PersonWindow_Loaded;
    }

    private void PersonWindow_Loaded(Object sender, RoutedEventArgs e)
    {
        this.Loaded -= PersonWindow_Loaded;

        _personsViewModel.LoadDataAsync();
    }
}

我真的不喜欢这个解决方案,因为它迫使视图模型的用户呼叫LoadDataAsync方法。

I don't really like this solution because it forces the user of the ViewModel to call the LoadDataAsync method.

- = [解决方案三:在视图模型构造函数加载数据] = -

--=[ Third solution: load data in the ViewModel constructor ]=--

public class PersonsViewModel : ViewModelBase
{
    // ...

    public PersonsViewModel(IRepository<Person> personRepository)
    {
        if (personRepository == null)
            throw new ArgumentNullException("personRepository");

        _personRepository = personRepository;

        this.LoadDataAsync();
    }   

    private Boolean _isDataLoaded;
    public Boolean IsDataLoaded
    {
        get { return _isDataLoaded; }
        private set { _isDataLoaded = value; OnPropertyChanged("IsDataLoaded"); }
    }

    public void LoadDataAsync()
    {
        if(this.IsDataLoaded)
            return;

        var bwLoadData = new BackgroundWorker();
        bwLoadData.DoWork +=
            (sender, e) => e.Result = _personRepository.GetAll();
        bwLoadData.RunWorkerCompleted +=
            (sender, e) => 
            {
                this.Persons = (IEnumerable<Person>)e.Result;
                this.IsDataLoaded = true;
            };
        bwLoadData.RunWorkerAsync();
    }
}

在此方案中,视图模型的用户不需要调用额外的方法来加载数据,但它违反了单Responsability原则马克西曼说,在他的著作依赖注入:保持构造无任何逻辑。SRP的暗示成员应只做一件事,现在我们使用的构造函数来注入依赖,我们应该preFER以保持其自由的其他问题。

In this solution, the user of the ViewModel don't need to call an extra method to load data, but it violates the Single Responsability Principle as Mark Seeman says in his book "Dependency Injection" : "Keep the constructor free of any logic. The SRP implies that members should do only one thing, and now that we use the constructor to inject DEPENDENCIES, we should prefer to keep it free of other concerns".

任何想法,以适当的方式来解决这个问题呢?

Any ideas to resolve this problem in a proper way?

推荐答案

很难给出一个准确的答案不知道如何配合你的ViewModels你的意见。

Difficult to give an accurate answer without knowing how you tie your ViewModels to your Views.

一个做法是有一个导航意识到视图模型(一个ViewModel它实现了一个特定的接口如 INavigationAware ,让您的导航服务调用此方法时,它实例化视图模型/查看和一起配合他们。这是棱镜的FrameNavigationService如何运作的方式。

One practice is to have a "navigation aware" ViewModel (a ViewModel which implements a certain interface like INavigationAware and have your navigation service call this method when it instantiates the ViewModel/View and tie them together. It's the way how Prism's FrameNavigationService works.

即。

public interface INavigationAware
{
    Task NavigatedTo(object param);
    Task NavigatedFrom(...)
}

public class PersonWindow : ViewModelBase, INavigationAware 
{

}

和内 NavigatedTo 实现你的初始化code这将在导航服务调用,如果视图模型工具 INavigationAware

and implement your initialization code within NavigatedTo which would be called from the navigation service, if the ViewModel implements INavigationAware.

棱镜的Windows商店应用参考:

Prism for Windows Store Apps References:

  • INavigationAware
  • FrameNavigationService => Look at the NavigateToCurrentViewModel Method

这篇关于后台加载在MVVM和构造器注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆