在我的Windows Phone 8应用程序中,我的文件MainViewModel.cs中有一个LoadData()方法。
此方法使用实体框架从WCF服务加载数据...
然后,在我的页面中,我调用LoadData()
LoadData()方法:
public void LoadData()
{
client.GetMoviesCompleted += new EventHandler<ServiceReference1.GetMoviesCompletedEventArgs>(client_GetMoviesCompleted);
client.GetMoviesAsync();
client.GetTheatersCompleted += new EventHandler<ServiceReference1.GetTheatersCompletedEventArgs>(client_GetTheatersCompleted);
client.GetTheatersAsync();
this.IsDataLoaded = true;
}
使用方法:
private void client_GetMoviesCompleted(object sender, ServiceReference1.GetMoviesCompletedEventArgs e)
{
Movies = e.Result;
}
private void client_GetTheatersCompleted(object sender, ServiceReference1.GetTheatersCompletedEventArgs e)
{
Theaters = e.Result;
}
然后在我的页面中:
App.ViewModel.LoadData();
问题是它不会等到数据加载完毕。
你能帮我使用Async / Await LoadData()方法等到加载数据吗?
由于
答案 0 :(得分:4)
因此,我们将从这两种方法开始,将现有方法从基于事件的模型转换为基于任务的模型。您需要稍微修改它们以与您的类型对齐,因为我没有足够的信息来完全复制它们,但剩下的更改应该很小:
public static Task<Movie[]> WhenGetMovies(MyClient client)
{
var tcs = new TaskCompletionSource<Movie[]>();
Action<object, Movie[]> handler = null;
handler = (obj, args) =>
{
tcs.SetResult(args.Result);
client.GetMoviesCompleted -= handler;
};
client.GetMoviesCompleted += handler;
client.GetMoviesAsync();
return tcs.Task;
}
public static Task<Theater[]> WhenGetMovies(MyClient client)
{
var tcs = new TaskCompletionSource<Theater[]>();
Action<object, Theater[]> handler = null;
handler = (obj, args) =>
{
tcs.SetResult(args.Result);
client.GetTheatersCompleted -= handler;
};
client.GetTheatersCompleted += handler;
client.GetTheatersAsync();
return tcs.Task;
}
既然我们可以获得代表完成这些异步操作的任务,那么加载数据很容易:
public async Task LoadData()
{
var moviesTask = WhenGetMovies(client);
var theatersTask = WhenGetTheaters(client);
var movies = await moviesTask;
var theaters = await theatersTask;
}
答案 1 :(得分:0)
问题是,当您执行LoadData()方法时,运行时不会等待继续执行您的方法。 你可以这么想:
private bool _moviesLoaded;
private bool _theatersLoaded;
private void client_GetMoviesCompleted(object sender, ServiceReference1.GetMoviesCompletedEventArgs e)
{
Movies = e.Result;
_moviesLoaded = true;
TrySetDataIsLoaded();
}
private void client_GetTheatersCompleted(object sender, ServiceReference1.GetTheatersCompletedEventArgs e)
{
Theaters = e.Result;
_theatersLoaded = true;
TrySetDataIsLoaded();
}
private void TrySetDataIsLoaded()
{
if(_moviesLoaded && _theatersLoaded) this.IsDataLoaded = true;
}
如果您想使用async和await,可以尝试使用TaskCompletionSource
答案 2 :(得分:0)
最重要的是,您需要为您的应用程序设计并实现“加载”状态。无论您使用基于事件的异步编程(如当前代码)还是async
/ await
,都是如此。在加载完成之前,您应该不同步阻止UI。
就个人而言,我喜欢(同步)将所有内容初始化为“加载”状态,并且当异步加载完成时,让它更新视图模型上的数据绑定项。然后,View通过数据绑定转换为“就绪”状态。
答案 3 :(得分:0)
将上面两个变量(private bool _moviesLoaded; private bool _theatersLoaded;)作为属性并在完成的事件处理程序中设置它们。直到该集合被称为使用加载器并且当调用set时禁用此加载器,现在您可以将此数据用于您的工作..