WPF Commands: Better approach to using ICommandSource


I originally wanted to write a post about using creating Command Source controls using ICommandSource but after looking at it on MSDN, I found quite a number of limitations with this approach…namely,

  • You need to create a custom control for every one that does not support taking a command source natively.
  • You can only bind one command at a time.
  • Your number of custom controls could grow fairly large very quickly, which makes maintenance of the code a horror, and not scalable.
  • The ICommandSource implementation code will be repeated in most of your custom controls, which is not a good option. I have thought about abstracting that out using a base class (that implements ICommandSource), but the problem is that your custom control needs to inherit the original WPF control (e.g. Slider, ListView), and multiple inheritance is not allowed in C#, so there goes my idea.

Better Approach

I pondered to myself….there has to be a better way to do this, and after much searching, I found a great article which suggest an alternate and better approach. I came across the solution in a blog post (WPF Commands Everywhere) by Tomer Shaman. The idea behind it is by using custom-written Command Source Trigger classes and using the WPF Attached Properties mechanism. This allows us to define the Command Source Triggers in XAML, and the author introduces two kinds of triggers, one for Routed Events and one for Property Changed. When a routed event is triggered or property value is changed, the Command that is hooked up will be triggered, essentially emulating the ICommandSource behaviour, but without all the messy/repetitive code. This is a snipplet of the XAML code from Tomer’s blog post.

<ListView x:Name="list"
		  SelectedIndex="-1"
		  DockPanel.Dock="Top"
		  ItemsSource="{Binding Emails}"
		  IsSynchronizedWithCurrentItem="True"
		  Height="100">
	<ts:CommandSource.Trigger>
		<ts:CommandTriggerGroup>
			<ts:EventCommandTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonUp"
									Command="{Binding Path=DownloadEmail}"
									CustomParameter="{Binding ElementName=list, Path=SelectedValue}" />

			<ts:EventCommandTrigger RoutedEvent="UIElement.PreviewMouseRightButtonUp"
									Command="{Binding Path=MarkAsRead}"
									CustomParameter="{Binding ElementName=list, Path=SelectedValue}" />

			<ts:EventCommandTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonDown"
									Command="{Binding Path=OpenEmail}"
									CustomParameter="{Binding ElementName=list, Path=SelectedValue}" />
		</ts:CommandTriggerGroup>
	</ts:CommandSource.Trigger>
</ListView>
....
<Expander IsExpanded="{Binding Path=DummyProperty}" Header="Contact">
	<ts:CommandSource.Trigger>
		<ts:PropertyCommandTrigger Property="Expander.IsExpanded"
					   Value="True"
					   CustomParameter="{Binding}"
					   Command="{Binding Path=DownloadContact, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" />
	</ts:CommandSource.Trigger>
</Expander>

In the code behind, the Commands (DownloadEmail, MarkAsRead, OpenEmail) are instantiated and exposed with public getters for databinding in XAML. I strongly suggest that you go over to Tomer’s blog post and have a read, and download the full code for this implementation. It will start to make sense once you start digging into it.

I personally feel that this implementation is much cleaner, reusable and just brilliant. If you agree, do go over to Tomer’s blog and leave him a ‘thank you’ or comment, I did. 🙂

Share this post:
Advertisements
Posted in WPF. Tags: . Leave a Comment »

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: