我正在尝试实现MVVM,在ViewModel中我正在做一些异步提取数据。为此,我试图在构造函数中加载数据:
MyModel Model { get; set; }
public MyViewModel()
{
Model = new MyModel();
Model.Foo = await LoadDataFromIsolatedStorage();
但这不是有效的,因为你不能将异步附加到构造函数。所以我尝试了一个公共静态加载函数:
MyModel Model { get; set; }
public MyViewModel()
{
Model = new MyModel();
}
async public static void Load()
{
Model.Foo = await LoadDataFromIsolatedStorage();
但是WP8抱怨它Cannot await void
。因为您将设置ViewModel并将其绑定到视图后面的代码中的View。无聊。
最后一个修复是使Load函数返回一个ViewModel,这样你在视图后面的代码可以做类似的事情:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MyViewModel viewModel = await MyViewModel.Load();
使用以下代码加载:
MyModel Model { get; set; }
public MyViewModel()
{
Model = new MyModel();
}
async public static Task<MyViewModel> Load()
{
MyViewModel viewModel = new MyViewModel();
viewModel.Model.Foo = await LoadDataFromIsolatedStorage();
return viewModel;
现在,问题在于如果加载的数据应该强制应用程序导航到另一个页面,我无法控制。让我们说MyViewModel从隔离存储中加载一个变量,然后应该让应用程序导航到另一个页面?
我已经将eventlistener设置为MyViewModel以使应用程序导航,但是当我启动它时我无法做到这一点。
不适用于事件:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MyViewModel viewModel = await MyViewModel.Load();
viewModel.NavigationAction += viewmodel_NavigationAction;
}
void viewmodel_NavigationAction(sender, args)
{
NavigationService.Navigate(...)
}
会工作,但我“不能等待无效”:
async protected override void OnNavigatedTo(NavigationEventArgs e)
{
MyViewModel viewModel = new MyViewModel();
viewModel.NavigationAction += viewmodel_NavigationAction;
await viewModel.Load(); // given the Load only is a async void and not Task<T>
}
void viewmodel_NavigationAction(sender, args)
{
NavigationService.Navigate(...)
}
答案 0 :(得分:1)
我认为此代码块“不起作用”,因为在加载数据后事件设置得太晚了:
MyViewModel viewModel = await MyViewModel.Load();
viewModel.NavigationAction += viewmodel_NavigationAction;
在这种情况下,修复上一个代码块非常简单:让Load
返回Task
并且它会起作用。 Task
是async
相当于void
;除非您正在编写事件处理程序,否则不应使用async void
。有关详细信息,请参阅我的best practices文章。
但是,即使你开始工作,你也会得到一个空视图,直到VM加载为止;如果您的负载可能需要很长时间(或者错误输出,例如,如果没有网络连接),这可能是糟糕的用户体验。
您可能需要考虑使用NotifyTaskCompletion
from my AsyncEx library,我describe on my blog。该模式允许您(立即)创建处于“加载”状态的VM,该状态将(通过INotifyPropertyChanged
)转换为“加载”或“加载错误”状态。这种模式提供了更好的用户体验,IMO。
答案 1 :(得分:-1)
roliu编写的内容非常有意义,因为async / await模式的整个概念基于Tasks。在编写异步方法时,您总是需要返回一个任务以确保以下await可以正常工作。通常编译器会在后台进行一些特殊的替换,所以你不必关心它。
由于异步操作,你永远不会得到一个bool - 而是一个通用的bool类型的任务!确保您理解MSDN所述的模式。
然后你可以创建这样的东西。它不是Win8应用程序。为简单起见,我选择它作为控制台应用程序。
class Program
{
static void Main(string[] args)
{
DoWork();
}
static async void DoWork()
{
await YourVoidMethod();
}
static Task YourVoidMethod()
{
Task task = Task.Run(() =>
{
// Your payload code
}
);
return task;
}
}
正如提示:使用GUI时,您还需要与调度程序一起工作。更改UI线程的数据时,否则可能会生成跨线程异常。