Reputation: 31
in my Windows Phone 8 application, I have a LoadData() method in my file MainViewModel.cs.
This method load data from a WCF service with entity framework...
Then, in my pages, I call LoadData()
The LoadData() method :
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;
}
With the methods :
private void client_GetMoviesCompleted(object sender, ServiceReference1.GetMoviesCompletedEventArgs e)
{
Movies = e.Result;
}
private void client_GetTheatersCompleted(object sender, ServiceReference1.GetTheatersCompletedEventArgs e)
{
Theaters = e.Result;
}
Then in my pages :
App.ViewModel.LoadData();
The problem is that it doesn't wait until the data is loaded.
Can you help me to use Async/Await the LoadData() method to wait until the data is loaded ?
Thanks
Upvotes: 1
Views: 5322
Reputation: 203842
So we'll start with these two methods that convert your existing methods from an event-based model into a task based model. You'll need to modify them slightly to line up with your types as I don't quite have enough information to replicate them completely, but the remaining change should be small:
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;
}
Now that we can get tasks that represent the completion of these async operations loading the data is easy:
public async Task LoadData()
{
var moviesTask = WhenGetMovies(client);
var theatersTask = WhenGetTheaters(client);
var movies = await moviesTask;
var theaters = await theatersTask;
}
Upvotes: 4
Reputation: 9242
make above two variables (private bool _moviesLoaded;private bool _theatersLoaded;) as properties and set them in completed eventhandlers . and till the set is called use loader and when set is called disable this loader and now you can use this data for your work..
Upvotes: 0
Reputation: 456587
The bottom line is that you'll need to design and implement a "loading" state for your application. This is true whether you use event-based asynchronous programming (like your current code) or async
/await
. You should not synchronously block the UI until the loading is complete.
Personally, I like to (synchronously) initialize everything into the "loading" state, and when the asynchronous loading completes, have it update data-bound items on the View Model. The View then transitions to a "ready" state via data binding.
Upvotes: 0
Reputation: 6499
The problem is, when you execute your LoadData() method, the runtime don't wait to continue the execution of your method. You can simply do a think like this :
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;
}
If you want to use async and await, you can try to work with TaskCompletionSource
Upvotes: 0