我使用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操作?什么是最佳做法?
答案 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();
}