Asynchronously loading Blendable sample data in MVVM Light in the view model's constructor

385 views Asked by At

I have a Windows Phone 8.1 MVVM Light project and I am struggling to keep it Blendable.

As I see it I have a few options. I can load different view models depending on whether ViewModelBase.IsInDesignModeStatic is true in the ViewModelLocator constructor, or I can test ViewModelBase.IsInDesignModeStatic in the view model constructor and load data appropriately.

If ViewModelBase.IsInDesignModeStatic is true I need to load data from file. Here's my code:

public async Task<ThingsSampleDataSource> GetSampleDataAsync()
{
    if (_DeserializedThingsSampleDataSource == null)
    {
        var dataUri = new Uri(_SampleDataJSONFile);
        var file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
        var jsonText = await FileIO.ReadTextAsync(file);
        _DeserializedThingsSampleDataSource = JsonConvert.DeserializeObject<ThingsSampleDataSource>(jsonText);
    }
    return _DeserializedThingsSampleDataSource;
}

When I call that method I need to mark the call await and thus the calling method async. But constructors cannot be marked async.

Or I can provide a ContinueWith continuation instead of awaiting return of the asynchronous code. But Blend loads the page before the ContinueWith is complete.

Given that sample data is loaded in the view model or the locator service constructors and it has to load data from a file, an asynchronous activity, how do I do this in MVVM Light so that the sample data is available in Blend?

(N.B. other answers I have found, for example this one, do not use MVVM Light.)

1

There are 1 answers

3
D.Rosado On

Load your data on the page load event, using a Command, so you can take advantage of the await/async stuff. I don't know how this works with blend as I don't use it much.

View:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding PageLoadedCommand}"/>
    </i:EventTrigger>   
</i:Interaction.Triggers>

ViewModel:

public RelayCommand PageLoadedCommand { get; private set; }
public MyConstructor(IService serviceInjected)
{
    PageLoadedCommand = new RelayCommand(async()=>await OnPageLoaded());
....
}

private async Task OnPageLoaded()
{
   if(ViewModelBase.IsInDesignModeStatic)
   {
       var data = await GetSampleDataAsync();
       //Do something..
   }
}