2

I'd like to load my viewmodel after a page has loaded but I can't seem to figure out how to do this.

Here's the viewModel methods where both methods inside LoadViewModel are long running async methods:

public async Task LoadViewModel()        
{
    await GetAllTiles();
    await UpdateAllScenarioCardsAsync(); 
}

In the view I'm trying something like this:

private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    var viewModel = DataContext as StatsViewModel;
    if (viewModel != null)
    {
        var statsViewModel = viewModel;
        await statsViewModel.LoadViewModel();
    }
}

For some reason the LoadViewModel() method blocks the entire UI even if I remove the awaits for GetAllTiles() and UpdateAllScenarioCardsAsync()... The NavigationHelper_LoadState method is run before the page is loaded so I've tried registering LoadViewModel() to the Loaded event of the page but I can't seem to get it to work.

EDIT Here is my UpdateAllScenarioCardsAsync() class. UpdateTotalTilesAsync() and UpdataTodayTilesAsync() have await statements inside the code as well but it still blocks the UI. I used closedScenario because I thought the issue could be closing over a variable over the wrong scope like answered in this question, but still now luck. I'm tempted to think it has something to do with the foreach loop because I have successfully done this elsewhere in my solution and it doesn't block the UI thread, but that code had no foreach loop.

private async Task UpdateAllScenarioCardsAsync()
{
    IsPending = true;

    try
    {
        // Load all of the scenario cards
        foreach (var scenario in _scenariosList)
        {
            var closedScenario = scenario;
            var data = new ScenarioDataCard(closedScenario);
            await UpdateTotalTiles(data);
            await UpdateTodayTestedTiles(data);
            ScenarioDataCards.Add(data);
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }
    finally
    {
        IsPending = false;
    }
}
Community
  • 1
  • 1
Ebsan
  • 758
  • 1
  • 10
  • 33
  • shouldn't it be - await viewModel.LoadViewModel(); to prevent blocking? – iandayman Mar 01 '15 at 22:23
  • but doesn't that make the NavigationHelper_LoadState() method pause (await) until it's finished. Basically blocking the page from being loaded? I'd like the page UI to load, then have the ViewModel load it's data. – Ebsan Mar 02 '15 at 01:47

1 Answers1

0

You need to add an await inside the LoadState event handler. Otherwise it will simply block whilst waiting for the LoadViewModel() to return. Like this...

private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    var viewModel = DataContext as StatsViewModel;
    if (viewModel != null)
    {
        await viewModel.LoadViewModel();
    }
} 

I also assume that the GetAllTiles and UpdateAllScenarioCardsAsync methods are implemented so that they really do perform work on another thread so that they are not blocking the main user interface thread.

Phil Wright
  • 22,580
  • 14
  • 83
  • 137
  • I tried that but it didn't work. I believe I'm implementing the other async classes correctly as I've put await statements everywhere where async code is run. I updated my question with some more code. – Ebsan Mar 02 '15 at 00:19
  • That is strange. Not sure why it would take a long time. Try removing code from the processing until it start working fast again and that will indicate the code that is the problem. – Phil Wright Mar 02 '15 at 00:30
  • In my other code I'm awaiting a PullAsync() from a MobileServiceSyncTable for Azure Mobile Service, and it has the desired effect. Basically the UI thread doesn't get blocked while waiting for the Pull method to run. But here, it gets blocked until it runs through all the code. Would the code being in the same class cause this issue? Where as in the other code it's calling external methods? – Ebsan Mar 02 '15 at 00:58