Previously I wrote about replacing an attached behaviour that was used to execute a view model action, with a Blend behavior that executes a view model command. The advantage of this approach is that you use what’s provided by the Blend SDK, rather than having to write your own attached behaviour, which may introduce errors, and associated unit tests.
Following a conversation with a colleague, I realised that while the app works, my use of the InvokeCommandAction was incorrect. This blog post will correct this.
Implementation
A Blend behaviour and a Blend action are used to execute a view model command when the ItemClick event fires on the GridView.
<GridView Grid.Row="1"
IsItemClickEnabled="True"
ItemsSource="{Binding Photos}"
Margin="140,0,0,0"
SelectionMode="None">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ItemClick">
<core:InvokeCommandAction Command="{Binding PhotoNavigationCommand}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
...
</GridView>
An EventTriggerBehavior is used which handles the ItemClick event. The InvokeCommandAction specifies the view model command that will be invoked when the event fires. Please note that it is not necessary to specify a CommandParameter to pass to the view model command. This is because the EventTriggerBehavior passes the associated EventArgs to the embedded action. The overall effect is that when the ItemClick event fires on the GridView, the PhotoNavigationCommand in the MainPageViewModel class is invoked, with the PhotoNavigationCommand receiving the ItemClickEventArgs of the GridView as a parameter.
public DelegateCommand<object> PhotoNavigationCommand { get; private set; }
public MainPageViewModel(IRepository repository, INavigationService navigationService)
{
_repository = repository;
_navigationService = navigationService;
PhotoNavigationCommand = new DelegateCommand<object>(NavigateToPhoto);
}
private void NavigateToPhoto(object parameter)
{
var photo = ((ItemClickEventArgs)parameter).ClickedItem as FileInformation;
if (photo != null)
{
_navigationService.Navigate("Photo", photo.Path);
}
}
In the MainPageViewModel class the PhotoNavigationCommand is a generic DelegateCommand of type object. This is an attempt to eliminate the dependency on ItemClickEventArgs in the view model. In the MainPageViewModel constructor the PhotoNavigationCommand is initialiased to a new DelegateCommand that will execute the NavigateToPhoto method. This method gets the photo that was clicked on and uses the NavigationService to navigate to the PhotoPage where the clicked on photo will be displayed. However, the problem remains that the MainPageViewModel class still has one final dependency on ItemClickEventArgs, which is a UI specific concept. From a purist point of view for MVVM, this is unacceptable.
Summary
In this blog post I’ve updated my use of InvokeCommandAction to execute a view model command. There’s still a problem in that the MainPageViewModel class has a dependency on the ItemClickEventArgs type, which is a UI specific concept. From a purist point of view for MVVM, this is unacceptable. I’ll address this issue in a future blog post.
The sample app can be downloaded here.