I have a WPF application that loads data from a data source.
Until some data is loaded there is nothing to display.
My question is do I:
- Create both V and VM before any data is available; set the data in the VM once available
- Create only V at the start; wait until data available then create the VM injecting the data
- Create both V and VM only once data available
I say Create both V and VM before any data is available; set the data in the VM once available.
Show an IsLoading indicator before the data is loaded and load the data on a separate thread. Otherwise if the data takes a while to load you will get the dreaded wpf black screen.
It feels better if the view loads immediately even if you have to wait for the data to load, it is perceived as quicker.
What I do is create my VM and View immediately, and display the View.
As in many apps, most of my Model takes time to start up, except for a 'startup state' enum, which is available immediately, updated continuously during startup, sent to the VM, and then onto a progress bar in my View.
My VM subscribes to events in the Model, which are pushed to the VM as they occur. In the View XAML I databind to the VM for each VM property.
In this way, the user is kept informed.
I've adopted what Josh Smith does in his article on MSDN here... Scroll down to the part were he talks about applying a View to a ViewModel. In doing this, the View is created when the ViewModel is rendered. There is no need to manually create the view and then assign the DataContext to your ViewModel anymore. This does that automatically for you.
"You can easily tell WPF how to render a ViewModel object by using typed DataTemplates. A typed DataTemplate does not have an x:Key value assigned to it, but it does have its DataType property set to an instance of the Type class. If WPF tries to render one of your ViewModel objects, it will check to see if the resource system has a typed DataTemplate in scope whose DataType is the same as (or a base class of) the type of your ViewModel object. If it finds one, it uses that template to render the ViewModel object referenced by the tab item's Content property."
In other words, you would create your ViewModel like so:
MyViewModel viewModel = new MyViewModel();
// Add the view model to the content of some control (TabItem, Grid, Window, etc.)
// NOTE: You wouldn't actually make this call... instead you would add the
// ViewModel to a collection or a property and the parent would bind
// to it and display it properly
MyContainer.Content = viewModel;
And in your ResourceDictionary you would define this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:DemoApp.ViewModel"
xmlns:vw="clr-namespace:DemoApp.View"
>
<!-- NOTE: The View must be a UserControl (or page) -->
<DataTemplate DataType="{x:Type vm:MyViewModel}">
<vw:MyView />
</DataTemplate>
</ResourceDictionary>
Creating only View with no viewModel is IMO pointless - what about all bound properties from View? They have nothing to be bound to since there is no ViewModel. The fact you don't see any exceptions doesn't mean everything is ok :)
Of course you should instanciate your ViewModels for all Views (of course Views used at the moment :) ) at the very beginning - this is not just advised, but required.