Geeks With Blogs

News Locations of visitors to this page
Brian Genisio's House of Bilz

Shout it kick it on DotNetKicks.com

Continuing in my series of “Adventures in MVVM”, I want to talk about a few different approaches to working with List Boxes with the MVVM pattern.  What I am writing here is generally true of all controls that derive from Selector, including ListBox and ComboBox.  This example was developed in Silverlight, but the same concepts also apply to WPF.

The Problem

You have a list box in your view, and you want your ViewModel to do something when an item in the ListBox is selected. You want to do this without any code-behind, using the MVVM pattern.  There are three methods that I have come up with, and I will outline them here.  In this post, I will be using a VERY simple data class in my ListBox called Person with a First and Last name.  It is so simple, in fact, that I have chosen not to include the source for this class.

Method 1: Quick and Dirty SelectedItem binding

This method sets up a SelectedPerson property in the view model and does something when the property is changed. 

public class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Person> People { get; private set; }

    private Person _selectedPerson = null;
    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            _selectedPerson = value;
            OnPropertyChanged("SelectedPerson");    
            DoSomething(value);
        }
    }
    // ... rest of ViewModel
}
<ListBox ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" />

Pros: This method is quick and simple to get going
Cons: You are introducing side effects in your property code.  If you are OK with this, then read no further.  If this bothers you the way it does for me, then lets look at our next option.

Method 2: Button Command

There are plenty of commanding libraries out there to choose from.  I will take advantage of the Prism commanding system (Microsoft.Practices.Composite.Presentation.Commands).  They have implemented bindable commands for ButtonBase.  The only problem: ListBox is not a ButtonBase.  To get around this, replace the ItemTemplate with a Button that has a template of textblock.

public class ViewModel : INotifyPropertyChanged
{
    public ViewModel()
    {
        PersonSelected = new DelegateCommand<Person>(DoSomething);
        // ... rest of constructor
    }

    public ObservableCollection<Person> People { get; private set; }
    public ICommand PersonSelected { get; private set; }

    // ... rest of ViewModel    
}
<ListBox ItemsSource="{Binding People}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Button Commands:Click.Command="{Binding PersonSelected, Source={StaticResource ViewModel}}" Commands:Click.CommandParameter="{Binding}" >
                <Button.Template>
                    <ControlTemplate>
                        <TextBlock Text="{Binding}" />
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Pros: The ViewModel is much more simple with no side effects. 
Cons: The XAML is ugly as sin.  It also changes the behavior of the ListBox in a subtle way.  Every time you select an item, the command fires, not just when it changes.  This is my LEAST favorite approach.  We can do better

Method 3: Bind Commands to the ListBox

The final mechanism is my favorite.  Even though Prism doesn’t give us the ability to bind commands to ListBoxes, we can extend their attached behavior infrastructure such that all ListBoxes and ComboBoxes (or anything that derives from Selector) can take advantage of it.  The ViewModel doesn’t change from “Method 2”, but the XAML does:

<ListBox ItemsSource="{Binding People}" Commands:Selected.Command="{Binding PersonSelected}" />

Pros: Best of both worlds.  Simple ViewModel.  Simple XAML
Cons: You have to write some extensions to the Prism infrastructure.  This code is boilerplate.  I have written some generics that can reduce the boilerplate code somewhat, but not completely, due to the static properties.

The Winner Is….

I like “Method 3” the best.  With a bit of some infrastructure code that you can tuck away, you get to bind the selected items to a command in any case.  It plays well, and it is easy to follow.

But wait… you want the Prism extensions?  Here they are:

public class SelectorSelectedCommandBehavior : CommandBehaviorBase<Selector>
{
    public SelectorSelectedCommandBehavior(Selector selectableObject)
        : base(selectableObject)
    {
        selectableObject.SelectionChanged += OnSelectionChanged;
    }

    void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        CommandParameter = TargetObject.SelectedItem;
        ExecuteCommand();
    }
}
public static class Selected
{
    private static readonly DependencyProperty SelectedCommandBehaviorProperty = DependencyProperty.RegisterAttached(
        "SelectedCommandBehavior",
        typeof(SelectorSelectedCommandBehavior),
        typeof(Selected),
        null);

    public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached(
        "Command",
        typeof(ICommand),
        typeof(Selected),
        new PropertyMetadata(OnSetCommandCallback));

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Only works for selector")]
    public static void SetCommand(Selector selector, ICommand command)
    {
        selector.SetValue(CommandProperty, command);
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Only works for selector")]
    public static ICommand GetCommand(Selector selector)
    {
        return selector.GetValue(CommandProperty) as ICommand;
    }

    private static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var selector = dependencyObject as Selector;
        if (selector != null)
        {
            GetOrCreateBehavior(selector).Command = e.NewValue as ICommand;
        }
    }

    private static SelectorSelectedCommandBehavior GetOrCreateBehavior(Selector selector)
    {
        var behavior = selector.GetValue(SelectedCommandBehaviorProperty) as SelectorSelectedCommandBehavior;
        if (behavior == null)
        {
            behavior = new SelectorSelectedCommandBehavior(selector);
            selector.SetValue(SelectedCommandBehaviorProperty, behavior);
        }

        return behavior;
    }
}
Posted on Friday, May 29, 2009 11:27 PM | Back to top


Comments on this post: Adventures in MVVM – Commanding with List Boxes

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Why not simply using CollectionViewSource?

Items = CollectionViewSource.GetDefaultView(BacklogItems);
Items.CurrentChanged += OnCurrentBacklogItemChanged;
Left by Laurent Kempé on May 30, 2009 6:13 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Laurent,

I think your question is more about MVVM architecture philosophy. In my opinion, CollectionViewSource is is purely a View construct, thus the ViewModel never knows anything about the CollectionViewSource.

As far as I am concerned, if a class derives from DependencyObject, then it lives in the View, not the ViewModel.

Because of this, you can't use the code you suggested.
Left by Brian Genisio on May 30, 2009 8:21 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
I'm with you Brian :)
SelectionChanged always looked like a command to me. Even if CollectionViewSource solves that issue in another way.

But Laurent does have a point, your ViewModel should give the View data in the form most usable for it. If it's a CollectionViewSource, than it's a CollectionViewSource.

-- Justin
Left by Justin Angel on Jun 24, 2009 10:16 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Hi Brian,

One question, is it possible to use one of those three solutions to a ListView control?
Left by George on Aug 27, 2009 8:17 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
How can we get Multiple selected items(Multi select list box) in view model using method 1 or method 3

Thanks
Left by Abdul on Sep 16, 2009 8:21 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
@Abdul: This is a problem that the SelectedItems property of ListBox is not a DependencyProperty, so you can't bind directly in XAML. I have, however, figured out how to do it using method 3 :)

I answered someone's question on StackOverflow with the solution: http://stackoverflow.com/questions/1297643/sync-selecteditems-in-a-muliselect-listbox-with-a-collection-in-viewmodel/1299544#1299544

I plan to formalize it in a blog post soon.
Left by Brian Genisio on Sep 16, 2009 8:41 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
"Because of this, you can't use the code you suggested. "

OH really? Cause I use CollectionViewSource all the time in the ViewModel and it works great. It achieves your goal of simple clean XAML and code. It even achieves your dubious goal of "zero tolerance for code-behind".

I find your statement that I cannot use something based on DependencyObject in my ViewModel to be frustrating. This sounds like zealotry to me.

Compare my solution to your "solution" #2, which is so tortured and bizarre that I would dread working on a codebase filled with such hacks just so we in our ivory tower could look down from on high and brag about our pure MVVM achitecture. Meanwhile your devs doing maintenance on your spaghetti xaml are looking for other jobs.

Sure you have pure MVVM - what a victory for you... a pyrrhic victory...
Left by El Guapo on Oct 23, 2009 12:34 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
El Guapo,

Actually, I failed to articulate in my statement about not being able to use something that derives from DependencyObject in a ViewModel. My objection to it is much more grounded in practicalities.

In my case, I use NUnit to write my unit tests which do not run in the browser. The Silverlight engine never gets instantiated. Anything that derives from DependencyObject fails in the base constructor with an exception. I have found no way around this and I have not seen a better unit testing strategy that fits all of my needs. This is not a problem in WPF.

Anyways, I hear your point. Pure MVVM is really an exercise. In my real-world, large-scale application, I make heavy use of MVVM. It is in no way pure.

Lately, I have been striving for more expressive code with less plumbing. I think any code that achieves this AND is testable is a win in my book.

Finally, in fairness to me, I did refer to the XAML in "solution #2" as being "ugly as sin". I continued to say that we can do better than that. I am trying to document my thought process. That was a solution in the thought process which I chose to dismiss.
Left by Brian Genisio on Oct 23, 2009 12:53 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Sorry, I was having a really bad day. Your points are well taken. Sorry for going on a rant there. When I read it again I realized I was out of line.
Left by El Guapo on Oct 23, 2009 1:00 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
El Guapo,

At the same time, I was extremely inarticulate by saying "Because of this, you can't use the code you suggested."

I deserved some crap for that... and I owe it to anyone reading this post to elaborate more. Thanks for getting me to do that.
Left by Brian Genisio on Oct 23, 2009 1:07 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
I've used your behaviour in an example of how to do commanding with the listbox/combobox in Silverlight and Prism.

http://www.g7x.com/Blog/post/2009/11/04/Combobox-Listbox-commanding-with-Silverlight-Prism.aspx
Left by Flexman on Nov 03, 2009 11:50 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
how can I get the control in selected command if I need it?
Similar if we write the code in code behind of xaml , we get sender object.
Left by SP on Mar 24, 2010 7:16 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
If you need to get the sender control, specifically, then you are talking about view-specific code. In the Model-View-ViewModel triad, then that code is part of the View, and belongs in the code-behind.

In most cases, though, the behavior is not view-specific. When that is the case, the behavior belongs in the ViewModel.

MVVM is all about separating the View code from the View Behavior. So, if you need access to the control itself from the listbox, by all means, use code-behind.
Left by Brian Genisio on Mar 24, 2010 9:15 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
The preference would be #1 versus having to a) install yet another third party library, b) having to extend what should really be part of the library. Whey you see an discussion on how to solve a focused issue that depends on an elaborate third party library, it's only of use to those willing to commit to that library.
Left by Rick O'Shay on Apr 02, 2010 12:58 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
You say: "You are introducing side effects in your property code. If you are OK with this, then read no further. If this bothers you the way it does for me, then lets look at our next option."

What side effects would that be?
Left by Rob on Apr 20, 2010 4:44 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Inside of a setter, if you do something other than set the value, that something is a side effect. It violates the idea that a method should only do one thing... in this case, the setter does more than one thing... it sets the value and it executes your code.

Practices like this encourage spaghetti code and lead to maintainability issues in real-world applications. I tend to avoid side affects like this wherever possible.
Left by Brian Genisio on Apr 20, 2010 4:47 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Just a question basically I'm seeing on the net that combobox does not support commands, but in silverlight there is no interface for ICommandSource. So what can we do?
Left by dave on Apr 27, 2010 3:05 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Dave,

The "attached behavior" method shown (#3) works really well for combo boxes as well. You don't need ICommandSource to get it working.
Left by Brian on Apr 27, 2010 5:46 AM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Thank you for explanation!
Left by Niki on Jan 18, 2011 7:49 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Isn't assigning an eventhandler to PropertyChanged a better idea? WPF relies on that event, we can do the same!

That would mean option A without the side-effect you refer to.
Left by Christiaan Stoffer on Mar 16, 2011 12:36 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
@Christiaan: Sure, you could do that. I prefer the "Attached Behavior" mechanism still, because we can continue to use the "command" metaphor. It is also a one-time framework piece you can add and it becomes reusable everywhere else. It avoids plumbing every time. It also decouples the command from being directly tied to the selected item. If the view decides to implement it such that the user selects an item and THEN clicks on a button which calls the command, then we are not telling the view specifically how to exist.
Left by Brian Genisio on Mar 16, 2011 1:16 PM

# re: Adventures in MVVM – Commanding with List Boxes
Requesting Gravatar...
Hi Brian,

Nice to see such a quick response!

The decoupling is indeed very nice but your example of a button that does the work after the select is a different scenario :D (Although SO valid... damn does interaction designers)
Left by Christiaan Stoffer on Mar 17, 2011 9:49 AM

Your comment:
 (will show your gravatar)


Copyright © Brian Genisio's House Of Bilz | Powered by: GeeksWithBlogs.net | Join free