使用async / await和void方法

时间:2013-06-27 13:42:48

标签: c# wcf asynchronous windows-phone-8

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

由于

4 个答案:

答案 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时禁用此加载器,现在您可以将此数据用于您的工作..