I'm new to WPF and MVVM. I think this is a simple question. My ViewModel is performing an asynch call to obtain data for a DataGrid which is bound to an ObservableCollection in the ViewModel. When the data is loaded, I set the proper ViewModel property and the DataGrid displays the data with no problem. However, I want to introduce a visual cue for the user that the data is loading. So, using Blend, I added this to my markup:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LoadingStateGroup">
<VisualState x:Name="HistoryLoading">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="HistoryGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="HistoryLoaded">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="WorkingStackPanel">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I think I know how to change the state in my code-behind (something similar to this):
VisualStateManager.GoToElementState(LayoutRoot, "HistoryLoaded", true);
However, the place where I want to do this is in the I/O completion method of my ViewModel which does not have a reference to it's corresponding View. How would I accomplish this using the MVVM pattern?
What I've done in the past is to declare an event in my VM to which the View subscribes. Then, when I want to indicate that the busy indicator should disappear, I raise the event inside the VM.
The standard way of doing this is normally to have a property in your viewmodel (either dependency property or one participating in INotifyPropertyChanged) that would signify that data is loading - perhaps
bool IsLoadingData
or similar. You set it to true when you start loading, and set it to false when you are done.Then you would bind a trigger or visual state to this property in the view, and use the view to describe how to present to the user that the data is loading.
This approach maintains the separation where the viewmodel is the logical representation the user's view, and does not need to participate in the actual display - or have knowledge of animations, visual states, etc.
To use a DataStateBehavior to change visual states based on a binding in Silverlight:
You can do something like this :
XAML
Code:
----------------------- Updated code -----------------------
XAML
Template
Custom Element