Silverlight ICommand Behaviors

I've always been a fan of Commands way back when they were called Actions in the old Delphi days. With .NET, WPF, and Silverlight we have so many new tools available to us. One I’ve been having fun with is behaviors. If you're unfamiliar with these little jewels then check them out here and here. I almost immediately recognized a way to combine my old love of commands with my new love of behaviors. Let’s say we want to attach a generic command to refresh our server to any UI element using a behavior. To start with I came up with a base class to contain my command with a virtual DoCommand() that will be implemented in a descended class but that will take care of the base behavior hookups.

namespace Falafel.Behaviors { public class BaseCommandBehavior : BehaviorDependencyObject> { public BaseCommandBehavior() { IsEnabled = true; } bool _IsEnabled; public bool IsEnabled { get { return _IsEnabled; } set { _IsEnabled = value; if (_IsEnabled) { if (this.Command == null) this.Command = new ActionCommand(this.DoCommand); } else this.Command = null; } } public ICommand Command { get; private set; } public virtual void DoCommand() { } } }

This class gives us the framework for an ICommand and an IsEnabled property for the ICommand. To use this class we only need to override the DoCommand() in a new class. Let’s say our new behavior will refresh a server that we are dealing with.

namespace Falafel.Behaviors { public class RefreshServerBehavior : BaseCommandBehavior { public override void DoCommand() { base.DoCommand(); ServerProxy.Proxy.Refresh(); } } }
So now we just need to attach to a UI element. The easiest way to do this is of course within Blend. What you end up with is some XAML that looks like this.
Rectangle x:Name="rectangle" Fill="#FF6CFF00" Stroke="Black" Width="164"> i:Interaction.Behaviors> FalafelBehaviors:RefreshServerBehavior> i:Interaction.Triggers> i:EventTrigger SourceName="rectangle" EventName="MouseLeftButtonDown"> i:InvokeCommandAction CommandName="Command"/> i:EventTrigger> i:Interaction.Triggers> FalafelBehaviors:RefreshServerBehavior> i:Interaction.Behaviors> Rectangle>
In this case notice that we are attaching this behavior to a rectangle and tying it to the MouseLeftButtonDown event. One of the cool things with behaviors is that you can attach them to any UI element and use almost any events to trigger them.

To add another command behavior is very easy. Let’s say we want to add a server reset command behavior. We just need a new class to override our base DoCommand().

namespace Falafel.Behaviors { public class ResetServerBehavior : BaseCommandBehavior { public override void DoCommand() { base.DoCommand(); ServerProxy.Proxy.Reset(); } } }
This pattern gives us an easy way to quickly add any number of command behaviors, but what about adding these behaviors in code behind? One of my rules to writing behaviors is to always include a static procedure to add your behavior to any UI element. This is not always straight forward. What I normally do is start off by adding my behavior within blend (just like we did above) to get the needed XAML. Inspecting the behavior XAML makes it easy to see what elements are going to be required in your static method. Normally just a static class within your behavior class would be necessary, but in this case a generic class is needed.
public static class AttachCommandBehaviorT> where T : BaseCommandBehavior, new() { public static T AttachBehavior(DependencyObject target, string eventTriggerName) { T behavior = new T(); InvokeCommandAction ica = new InvokeCommandAction() { CommandName = "Command" }; System.Windows.Interactivity.EventTrigger etrigger =
new System.Windows.Interactivity.EventTrigger(eventTriggerName); etrigger.Actions.Add(ica); System.Windows.Interactivity.Interaction.GetTriggers(behavior).Add(etrigger); System.Windows.Interactivity.Interaction.GetBehaviors(target).Add(behavior); return behavior; } }

If you look at the structure of the XAML used to attach the command behavior, you can follow the C# code here a little easier. Now that we have our static add method, to add any of our command behaviors in code behind is just a one liner.

void MainPage_Loaded(object sender, RoutedEventArgs e) { AttachCommandBehaviorResetServerBehavior>.AttachBehavior(buttonReset, "Click"); }

Behaviors are a very important part of WPF and Silverlight that can simplify your application design. If you’re not familiar with them yet, you need to be. Comments are always welcome. For those who have a Google Wave account, I’ve added a Google Wave for this blog that you can find with this wave search – “with:public Silverlight Behavior ICommand Falafel”.

comments powered by Disqus