如何避免从构造函数调用long操作

时间:2015-04-15 08:22:35

标签: c# constructor

我使用MVVM,我必须创建一个ViewModel类,在打开View时应该加载大量数据。

基本上,当我创建viewmodel时,它应该使用数据库并获取数据。

我首先使用这种方法:

public class MainViewModel
{
 public MainViewModel()
 {
   //set some properties
   Title="Main view";
   //collect the data
   StartLongOperation();
 }

 private void StartLongOperation()
 {
   Thread t=new Thread(...);
   t.start();
 }
}

它可以在不阻塞UI线程的情况下加载数据。

后来我发现this guideline关于如何使用构造函数,并且不建议从构造函数开始长操作。

  

√在构造函数中做最少的工作。

     

除了捕获之外,构造函数不应该做很多工作   构造函数参数。任何其他处理的成本应该是   延迟到需要。

就我而言,打开视图时需要数据。

我的第一个想法是使用事件

我应该如何避免从construcor调用long操作?什么是最佳做法?

5 个答案:

答案 0 :(得分:3)

Miguel Castro在他的一篇伟大的Pluralsight课程中谈到了这个解决方案。他绑定到一个名为ViewLoaded的视图模型中的属性,当视图加载时,该属性显然会被绑定,这反过来会调用你的长时间运行方法。

所以这在视图中(或者是所有视图的基类以帮助重用):

    public ViewBase()
    {
        // Programmatically bind the view-model's ViewLoaded property to the view's ViewLoaded property.
        BindingOperations.SetBinding(this, ViewLoadedProperty, new Binding("ViewLoaded"));
    }

    public static readonly DependencyProperty ViewLoadedProperty =
        DependencyProperty.Register("ViewLoaded", typeof(object), typeof(UserControlViewBase),
        new PropertyMetadata(null));

这是ViewModel基类代码:

public object ViewLoaded
{
    get
    {
        OnViewLoaded();
        return null;
    }
}

protected virtual void OnViewLoaded() { }

只需覆盖ViewModel中的OnViewLoaded()方法,然后从那里调用长时间运行的方法。

答案 1 :(得分:1)

也许使用工厂模式来避免MainViewModel周围但没有填充。

    public class VMFactory
    {
        public async Task<MainViewModel> GetVM()
        {
            MainViewModel vm = new MainViewModel();
            await vm.LongOperation();
            return vm;
        }
    }

    public class MainViewModel
    {
        public MainViewModel()
        {
            //set some properties
            Title = "Main view";
        }

        public async Task LongOperation()
        {
            (...)
        }
    }

或者更好。将长时间运行的方法从MainViewModel移到存储库或服务

    public class VMRepository
    {
        public async Task LongOperation()
        {
            (...)
        }

        public async Task<MainViewModel> GetVM()
        {
            MainViewModel vm = new MainViewModel();
            vm.DataWhichTakesAlongTime  = await LongOperation();
            return vm;
        }
    }

    public class MainViewModel
    {
        public MainViewModel()
        {
            //set some properties
            Title = "Main view";
        }

        public object DataWhichTakesAlongTime { get; set; }
    }

说实话,虽然从这个问题的对话中听起来你只是使用构造函数作为“LoadDataNow”的方便触发器。命令,实际上你应该添加一个ICommand,将它绑定到视图中的某些内容(已加载)添加加载微调器和已完成的事件等等

有争议的我还建议您添加一个Controller类来实例化存储库视图和vm并调用&#39; LoadData&#39;视图上的方法。我不知道MVVM,但基本上做了你的IoC容器所做的事情,而不必跳过配置的箍

答案 2 :(得分:0)

避免调用它很简单,只需将其拆分为2个方法;打开视图时或设置数据上下文后调用的构造函数和GetData方法。

为什么只是管理期望。如果您还没有编写代码并为其他人的视图模型编写新视图,您是否希望构造函数开始访问数据库?或者你希望它只是构建一个视图模型,你需要再次调用才能开始获取数据?

答案 3 :(得分:0)

我不知道也许它错了,但有时候我会做(如果我需要重新参数)

public class MainViewModel
    {
        public MainViewModel()
        {
            //set some properties
            Title = "Main view";
        }
        public static string GetMainViewModelString()
        {
            var mainViewModel = new MainViewModel();
            return mainViewModel.GetString();
        }
        public string GetString()
        {
            /*your code*/
        }
    }

然后致电

var stringData = MainViewModel.GetMainViewModelString();

但是当它需要我从构造函数

调用一些操作时

答案 4 :(得分:0)

使用视图生命周期来执行此方法。您可以使用Tasks来简化执行,并且可以绑定到其他属性以显示进度。使用Windows应用商店应用视图显示的示例。

视图模型:

public class MainViewModel
{
    public MainViewModel()
    {
        this.Title = "Main view";
    }

    public async Task StartLongOperationAsync()
    {
        this.IsLoading = true;

        await Task.Run(() =>
        {
            //do work here
        });

        this.IsLoading = false;
    }
}

在视图上:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    await ((MainViewModel)this.DataContext).StartLongOperationAsync();
}