Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

MVVM ListBox Grouping

0.00/5 (No votes)
18 Jan 2012 1  
This is an example to show the use of MVVM in creating a grouping listbox.

This is an example to show the use of MVVM in creating a grouping listbox. The example shows a list of employees with their job title, name and grade. I’ve defaulted to grouping by Job Title and supplied to buttons on the window to allow you to toggle the grouping between job title and grade. This is to demonstrate the dynamic behaviour of the grouping in the view model.

First let’s start with the EmployeeViewModel:

C#
public class EmployeeViewModel
{
    public string Name
    {
        get;
        set;
    }
    public string JobTitle
    {
        get;
        set;
    }
    public string Grade
    {
        get;
        set;
    }
}

Nothing to strenuous here, just a POCO.

Followed by the MainViewModel:

C#
public class MainViewModel
{
    private ObservableCollection employees = new ObservableCollection();
    private ObservableCollection groupingColumns = new ObservableCollection();
    public MainViewModel()
    {
        var view = CollectionViewSource.GetDefaultView(Employees);
        GroupByJobTitleCommand = new GroupByCommand(GroupingColumns, "JobTitle");
        GroupByGradeCommand = new GroupByCommand(GroupingColumns, "Grade");
        GroupingColumns.CollectionChanged += (s, e) =>
        {
            view.GroupDescriptions.Clear();
            foreach (var groupName in GroupingColumns)
            {
                view.GroupDescriptions.Add(new PropertyGroupDescription(groupName));
            }
        };
    }
    public ObservableCollectionEmployees
    {
        get { return this.employees; }
    }
    public ObservableCollectionGroupingColumns
    {
        get { return this.groupingColumns; }
    }
    public ICommand GroupByJobTitleCommand
    {
        get;
        private set;
    }
    public ICommand GroupByGradeCommand
    {
        get;
        private set;
    }
}

And the GroupByCommand that will allow us to switch the grouping field:

C#
public class GroupByCommand : ICommand
{
    private ObservableCollection groupingColumns;
    private string groupName;
    public GroupByCommand(ObservableCollectiongroupingColumns, string groupName)
    {
        this.groupingColumns = groupingColumns;
        this.groupName = groupName;
    }
    public bool CanExecute(object parameter)
    {
        return true;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        this.groupingColumns.Clear();
        this.groupingColumns.Add(this.groupName);
    }
}

Followed by the XAML:

XML
<Grid Grid.IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource=’{Binding Employees}’>
<ListBox.GroupStyle>
<x:Static Member=’GroupStyle.Default’ />
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="col1" Width="200"/>
<ColumnDefinition SharedSizeGroup="col2" Width="200"/>
<ColumnDefinition SharedSizeGroup="col3" Width="200"/>
</Grid.ColumnDefinitions>
<TextBlock Text=’{Binding Name}’/>
<TextBlock Text=’{Binding JobTitle}’ Grid.Column="1"/>
<TextBlock Text=’{Binding Grade}’ Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<Button Command="{Binding GroupByJobTitleCommand}">Group By Job Title</Button>
<Button Command="{Binding GroupByGradeCommand}">Group By Job Grade</Button>
</StackPanel>
</Grid>

The XAML here is pretty straightforward, but a couple of points:

  1. We’ve used ListBox.GroupStyle to tell the list box we want group styling.
  2. The IsSharedSizeScope on the out Grid and SharedSizeGroup on the column definitions have been used to make each row line up and give us the appearance of a more traditional grid with the data in columns.

And finally, the code behind (dirty words I know, but it’s just setting up the DataContext):

C#
public MainWindow()
{
    InitializeComponent();
    var mainViewModel = new MainViewModel();
    mainViewModel.Employees.Add(new EmployeeViewModel() { 
      Name = "Blogs, Fred", JobTitle = "Programmer", Grade = "1" });
    mainViewModel.Employees.Add(new EmployeeViewModel() { 
      Name = "Gates, Bill", JobTitle = "Project Manager", Grade = "1" });
    mainViewModel.Employees.Add(new EmployeeViewModel() { 
      Name = "Jobs, Steve", JobTitle = "Analyst", Grade = "2" });
    mainViewModel.Employees.Add(new EmployeeViewModel() { 
      Name = "Smith, John", JobTitle = "Programmer", Grade = "2" });
    mainViewModel.Employees.Add(new EmployeeViewModel() { 
      Name = "Davis, Mavis", JobTitle = "Project Manager", Grade = "3" });
    this.DataContext = mainViewModel;
}

So we’ve basically set up a list of employees in the MainViewModel and attached an instance of it as our DataContext. In this view model, we have a couple of commands for actually doing the grouping. By default we have a normal list of employees and then selecting either of the buttons will group them by that property.

I believe this is a more MVVM approach to doing grouping in a list box (or anything that support grouping) and keeps the logic in the view model. I’ve seen other examples, but most of them use the XAML to control the grouping and usually have fixed data sets in XAML declared as static resources.

The styling of this leaves a lot to be desired and you can’t expand or collapse the groups. To see how this is done, I suggest you look at Karl Shifflett’s example for some inspiration.

You can download the code from this article here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here