0

I'm developing a Windows Phone Universal App using MVVM Light (I'm new to MVVM pattern). My problem is to make it work like that:

  1. Application is launched (or the user navigates to different view),
  2. then we see the basic UI,
  3. and then we wait for the data to be loaded, while the application stays responsive.

So far I have tested many different approaches like:

and in each case my application was showing splash screen (or was blocking before navigating to another page) unless the data was loaded. The methods return data properly, views display it well.

So my question is, what is the proper way to load data asynchronously in Universal App? I will be grateful for your help.

This is how my code looks like for now:

MainViewModel.cs

    public MainViewModel()
    {
        this._navigationService = ServiceLocator.Current.GetInstance<INavigationService>();

        _newsService = ServiceLocator.Current.GetInstance<INewsService>();

        LoadMainPageCommand =
            new RelayCommand(async() => await LoadMainPageData());
    }

    public RelayCommand LoadMainPageCommand { get; set; }

    private async Task LoadMainPageData()
    {
        // to make it work a bit longer
        for (int i = Int32.MaxValue; i > 20000; i--) ;

        NewsCategories= await _newsService.GetNewsCategoriesAsync();
        RaisePropertyChanged("NewsCategories");
    }

HubPage.xaml

<Page
x:Class="xxx.HubPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:xxx"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:data="using:xxx.Data"
mc:Ignorable="d">
<i:Interaction.Behaviors>
    <core:EventTriggerBehavior EventName="Loaded">
        <core:InvokeCommandAction Command="{Binding LoadMainPageCommand}"/>
    </core:EventTriggerBehavior>
</i:Interaction.Behaviors>
...

INewsService.cs

public interface INewsService
{
    Task<ObservableCollection<NewsCategory>> GetNewsCategoriesAsync();
}
Community
  • 1
  • 1
K.A.
  • 69
  • 5
  • Why not just fire away `LoadMainPageData()` Task in your constructor, without `await`ing? Binding to command and triggering it on Page's `Loaded` event is unnecessary. – Mikko Viitala Aug 05 '15 at 15:23
  • I've already tried it (with changing `async Task` to `async void`) and it still do the LoadMainPageData() function during loading the application and the user can only see the splash screen. – K.A. Aug 05 '15 at 15:46
  • Keep it as Task and Task.Run(LoadData). – Mikko Viitala Aug 05 '15 at 15:54

1 Answers1

0

Your problem is in your "test" code:

private async Task LoadMainPageData()
{
  // to make it work a bit longer
  for (int i = Int32.MaxValue; i > 20000; i--) ;

  NewsCategories= await _newsService.GetNewsCategoriesAsync();
  RaisePropertyChanged("NewsCategories");
}

This is a method with an asynchronous signature that is doing synchronous work. If you want to stick in a delay, then do it asynchronously:

private async Task LoadMainPageData()
{
  // to make it work a bit longer
  await Task.Delay(TimeSpan.FromSeconds(3));

  NewsCategories= await _newsService.GetNewsCategoriesAsync();
  RaisePropertyChanged("NewsCategories");
}

Then any of the approaches should work.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810