Brian Genisio's House of Bilz

  Home  |   Contact  |   Syndication    |   Login
  62 Posts | 0 Stories | 118 Comments | 0 Trackbacks

News

Locations of visitors to this page

Archives

Post Categories

Who am I?

Adventures in MVVM Shout it kick it on DotNetKicks.com

EDIT:

One of the things that I enjoy most about working with MVVM in Silverlight is how new it is.  When I say “new”, I mean that Silverlight doesn’t support the pattern very well out of the box, so the development community needs to step up and solve these problems.  Some solutions are better than others.  In this article, I solved a problem the best way I knew how.  I urge you to read Ward Bell’s comments to this article, and my responses.  After reflecting on it more, I concede that this is not the best way to implement a lightweight bindable command in SIlverlight.

Instead, I should have just read the Prism 2 source code to see how they implemented commands via attached behaviors.  I would have learned that that I learned attached behaviors wrong in the first place.  In Julian Dominguez’s blog post on the topic, he walks you through the thought process for attaching commands via behaviors.  Although this is not the final code that made it into Prism, it is very close.  I recommend reading it.

That being said, I will keep my original text in place.  I think that the thought process for how I got there is very useful for learning… at least I find it useful.  Then, be sure to read the comments, visit Julian’s blog and browse the Prism (CAL) source code.

One of the most important aspects of implementing the MVVM pattern in WPF and SIlverlight is the ability for the UI layer to bind directly to commands in the ViewModel.  The only problem with this:  commands were never implemented in Silverlight.  Even though I (and many others) have ranted about this, our voice has not been heard.  Even with the release of the Silverlight 3 beta, it seems as if we are still pining for commanding in Silverlight.

Many libraries have implemented commands in Silverlight, usually with some sort of static lookup table, mapping buttons to commands.  They include Prism, Caliburn, SilverlightFX and the MVVM toolkit.  It can feel like overkill to bring in these libraries just to get commanding.  There are plenty of good reasons to use these libraries – don’t get me wrong – but if you are just looking for bindable commands, there is an easier way.

This article will walk you through the process of creating a button with command properties.  This technique can be translated easily to any other control in order to achieve bindable commanding in Silverlight.

ICommand

The ICommand interface was the only thing that was included from the WPF commanding infrastructure within Silverlight.  The interface is extremely simple:

interface ICommand
{
    void Execute(object parameter);
    bool CanExecute(object parameter);
    event EventHandler CanExecuteChanged;
}

The requirements of any control that deals with ICommand are:

  1. Call Execute() when a trigger is hit
  2. Only call Execute() if CanExecute() returns true
  3. Allow a bindable parameter to be passed into Execute() and CanExecute()
  4. Disable the control when CanExecute() is false
  5. Refresh the enable/disable state of the control when the CanExecuteChanged event is raised

Implementing CommandButton

Lets start with requirements 1 and 2:

public class CommandButton : Button
{
    public CommandButton()
    {
        Click += (sender, e) =>
        {
            if (Command != null && Command.CanExecute(null))
                Command.Execute(null);
        };
    }

    public static DependencyProperty CommandProperty =
        DependencyProperty.Register("Command",
                                    typeof(ICommand), typeof(CommandButton),
                                    new PropertyMetadata(null));

    public ICommand Command
    {
        get { return GetValue(CommandProperty) as ICommand; }
        set { SetValue(CommandProperty, value); }
    }
}

With this, you can bind a command in the ViewModel to the view:

public class ViewModel : INotifyPropertyChanged
{
    public ViewModel()
    {
        MyCommand = new DelegateCommand<object>(DoSomething);
    }

    private void DoSomething(object obj)
    {
        // Do what you want
    }

    public ICommand MyCommand { get; private set; }

   // The rest of your ViewModel
}

This XAML creates a CommandButton in place of a Button:

<local:CommandButton Content="Click Me" Command="{Binding MyCommand}" />

Adding Parameters

Implementing feature 3 is trivial. Add the CommandParameter property and pass it in to Execute() and CanExecute()

public class CommandButton : Button
{
    public CommandButton()
    {
        Click += (sender, e) =>
        {
            if (Command != null && Command.CanExecute(CommandParameter))
                Command.Execute(CommandParameter);
        };
    }

    // Everything else from initial Implementation
	
    public static DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter",
                                    typeof(object), typeof(CommandButton),
                                    new PropertyMetadata(null));

    public object CommandParameter
    {
        get { return GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }
}

With that, you can add parameters to the XAML:

<local:CommandButton Content="Click Me" Command="{Binding MyCommand}" CommandParameter="MyParameter" />

Hooking IsEnabled to CanExecute()

Things get a bit more complicated when implementing requirements 4 and 5, but it is still pretty straight-forward.  I start by registering an event handler for when the Command property changes (CommandChanged).  This event handler hooks the CanExecuteChanged event and handles the event by setting the IsEnabled flag to the value of CanExecute().  It then proceeds to initialize the value of IsEnabled since we know the answer at this time.

The final class:

public class CommandButton : Button
{
    public CommandButton()
    {
        Click += (sender, e) =>
        {
            if (Command != null && Command.CanExecute(CommandParameter))
                Command.Execute(CommandParameter);
        };
    }

    public static DependencyProperty CommandProperty =
        DependencyProperty.Register("Command",
                                    typeof(ICommand), typeof(CommandButton),
                                    new PropertyMetadata(null, CommandChanged));

    private static void CommandChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
    {
        var button = source as CommandButton;
        if (button == null) return;

        button.RegisterCommand(args.OldValue as ICommand, args.NewValue as ICommand);            
    }

    private void RegisterCommand(ICommand oldCommand, ICommand newCommand)
    {
        if (oldCommand != null)
            oldCommand.CanExecuteChanged -= HandleCanExecuteChanged;

        if (newCommand != null)
            newCommand.CanExecuteChanged += HandleCanExecuteChanged;

        HandleCanExecuteChanged(newCommand, EventArgs.Empty);
    }

    private void HandleCanExecuteChanged(object sender, EventArgs args)
    {
        if (Command != null)
            IsEnabled = Command.CanExecute(CommandParameter);
    }

    public ICommand Command
    {
        get { return GetValue(CommandProperty) as ICommand; }
        set { SetValue(CommandProperty, value); }
    }

    public static DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter",
                                    typeof(object), typeof(CommandButton),
                                    new PropertyMetadata(null));

    public object CommandParameter
    {
        get { return GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }
}

Summary

This method for hooking commands to buttons has one drawback in my opinion:  It requires you to put a CommandButton in your XAML instead of a vanilla Button.  This, of course, means that other controls that inherit from Button such as Checkbox and RadioButton do not get this behavior (you have to implement this pattern for them).  Still, this approach makes it very easy to add commands to any control you wish; even in WPF.  In a future post, I will discuss a similar approach for binding a command to a ComboBox (or ListBox) selection changed event.

posted on Friday, May 22, 2009 8:53 PM

Feedback

# re: Adventures in MVVM – Commands in Silverlight 5/24/2009 11:58 AM Ward
No doubt you have tapped into an important issue. And I admire your honesty in drawing attention to the "drawback" in that your apporach works only for Button; not any of its derived classes nor anything else clickable nor any other control (e.g., ComboBox) that could use a Command.

IMHO, this is not a "drawback"; it's fatal. You've written miles of code (perfectly acceptable code) to support a single control. You've also obliged everyone who would use your technique to swap out their button for your button.

Is there some reason that you have choosen this approach rather than the attached behavior alternatives widely available elsewhere?

Have you looked into Commanding in Prism (http://www.codeplex.com/Prism) from Microsoft Patterns and Practices?

I strongly suggest readers investigate Prism ... both because it addresses this problem well and because it is an emerging "standard" with the potential for wide adoption. Moreover, it tackles many other issues that arise with MVVM and WPF/Silverlight application development in general.


# re: Adventures in MVVM – Commands in Silverlight 5/24/2009 12:20 PM Brian Genisio
Ward,

Thanks for the feedback. I also strongly suggest that readers investigate Prism. I am a big fan of the framework, and I think it has great potential. I linked it in the beginning of my article.

Why have I chosen this approach rather than other alternatives? The answer is simple: This is a lightweight approach to adding a command to the most common commanding case: the button.

If thats all you need, then this approach works. In the top of my article, I state that: "if you are just looking for bindable commands", this is an easy way to get commands.

Although I really like the idea of bringing in third party libraries to give me commanding, I work for a VERY large company. Using any third party library (no matter who owns it) such as Prism, Caliburn or MVVM Toolkit, I have to go through a troublesome vetting process... crappy, I know, but it is the reality of what I am working with. I know several other people in this situation.

It turns out that in my commercial project, I am using a static dictionary to map commands to the controls they bind to. It is a more heavyweight approach than this, but it is much more versatile.

So, in short, I consider this to be a "lightweight" approach to solving the bindable comands issue in Silverlight.

Thanks,
Brian


# re: Adventures in MVVM – Commands in Silverlight 5/24/2009 12:50 PM Brian Genisio
So, Ward's feedback got me thinking further...

I think that I was confused about how to implement an attached behavior. In the case of commands, I have been implementing attached behavior commands by storing the command and the control in a static dictionary. Not only do I dislike the idea of having this monster static dictionary, the code is complex and has a lot of potential for memory leaks.

So, it got me to thinking... is there a better way to implement a lightweight bindable commands via attached behaviors that was less ugly than the static dictionary method I know so well?

Then I read Julian Dominguez's blog, and realized that he was storing the behavior in the element itself! (SetValue) Of course! Why didn't I think of that? (Because I am a bit slower than the geniuses in this field)

So, to summarize, there IS a better way to achieve lightweight bindable commands than the method I described in this article. I will be making some edits to this article very soon, but until then, Check out Julian's blog post on the topic:

http://blogs.southworks.net/jdominguez/2008/08/icommand-for-silverlight-with-attached-behaviors/

# re: Adventures in MVVM – Commands in Silverlight 5/25/2009 12:47 AM Ward Bell
Good stuff, Brian. Your big-employer problem is all too familiar. Sometimes I get it; most of the time I do not. So what ... it's our reality.

I regret that I skipped right over your original intro in which you mentioned Prism, Caliburn, SilverlightFx and MVVM Toolkit; my bad! These frameworks all have something to offer.

I appreciate too your readiness to keep exploring and the courage it takes to expose your code for public comment. This is no small matter. The journey counts ... and sharing yours with us is well worth it. Keep on truckin'

# re: Adventures in MVVM – Commands in Silverlight 5/25/2009 6:33 AM Rishi
Just wanted to add that it is at best self-limiting to think ICommands are only useful against a Button’s click. You can ICommands in respone to both simple (like MouseOver) and complex (like say a Second tap) behaviours – in fact I very often use ICommands with a Control’s load event and equally often when selecting an item in a ListBox. Have a look at:

http://www.orkpad.com/Blog/post/2009/04/03/nRoute-Comes-complete-with-a-full-set-of-behavioural-teeth.aspx

It shows a range “simple” events you can use ICommands to in SL (but with a library).

# re: Adventures in MVVM – Commands in Silverlight 11/1/2009 4:13 PM Lavanya
Hi

I am creating a prism2 Application mainly it contains 2 modules. A LiTTLE BIT URGENT

In module one i am going to place Images(around 10) using ListBox and in Module 2 I Place an Image Control.

when i select a image in module one it should be displayed in module 2.

My Problem is am not able to generated a command Event of TabControl and Not able to Execute and publist the event.

Any help is Appreciated with a little sample code to gennerate ListBox Command Event (SilVerlight).



Thanks in advance.

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: