使用async/await和void方法

本文关键字:void 方法 await async 使用 | 更新日期: 2023-09-27 18:20:04

在我的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()方法等待数据加载吗?

感谢

使用async/await和void方法

因此,我们将从这两个方法开始,它们将现有方法从基于事件的模型转换为基于任务的模型。你需要稍微修改它们以符合你的类型,因为我没有足够的信息来完全复制它们,但剩下的变化应该很小:

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;
}

问题是,当您执行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和wait,可以尝试使用TaskCompletionSource

最重要的是,您需要为应用程序设计和实现一个"加载"状态。无论使用基于事件的异步编程(如当前代码)还是async/await,都是如此。在加载完成之前,不应同步阻止UI。

就我个人而言,我喜欢(同步地)将所有内容初始化为"加载"状态,当异步加载完成时,让它更新视图模型上的数据绑定项。然后,视图通过数据绑定转换到"就绪"状态。

将以上两个变量(private bool_viesLoaded;private bool _theaters Loaded;)作为属性,并在已完成的事件处理程序中设置它们。直到集合被调用,使用加载器,当集合被调用时,禁用这个加载器,现在你可以将这些数据用于你的工作。。