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

Checkbox Inside ListBox to Select Multiple Items in Silverlight Using MVVM

0.00/5 (No votes)
21 Jun 2012 1  
Silverlight doesn't have a ListBox control with a checkbox. In this article, I describe how to achieve that functionality in Silverlight using MVVM.

Introduction

When I was working for a project, we had requirements like a List should be displayed in a ListView and the user should be able to select items through a checkbox. Since Silverlight doesn’t have a ListBox control with a checkbox, we tried many ways to achieve this. Finally we got a way to accomplish this. In the below article, I will explain how we did that.

In the UI, the user will have the option to select a list of courses in the ListBox and the selected courses will be listed in a GridView like in the below figure.

Course Class

I have a class Course with the properties below:

  • CourseName
  • CourseId
  • NoOfStudents
Class.cs:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace ListBoxWithCheckBoxSLXAML
{
public class Course
{
    public string CourseName { get; set; }
    public int CourseId { get; set; }
    public int NoOfStudents { get; set; }
}
}

ViewModel

As usual I have a BaseViewModel and a viewmodel for the view which inherits from BaseViewModel.

BaseViewModel.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace ListBoxWithCheckBoxSLXAML
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

ViewModel.cs

I have two properties in the viewmodel. One is for list of courses and the other for the list of selected courses.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace ListBoxWithCheckBoxSLXAML
{
    public class ViewModel : BaseViewModel
    {
        
        private ObservableCollection<Course> _courses;
        private ObservableCollection<Course> _selectedcourses;


        public ObservableCollection<Course> Courses
        {
            get
            {
                return _courses;
            }
            set
            {
                _courses = value;
                NotifyPropertyChanged("Courses");
            }
        }

        public ObservableCollection<Course> SelectedCourses
        {
            get
            {
                return _selectedcourses;
            }
            set
            {
                _selectedcourses = value;
                NotifyPropertyChanged("SelectedCourses");
            }
        }

        public ViewModel()
        {
            Courses = new ObservableCollection<Course>()
            {
                new Course(){CourseId=1,CourseName="JAVA",NoOfStudents=10},
                new Course(){CourseId=2,CourseName=".Net",NoOfStudents=10},
                new Course(){CourseId=3,CourseName="MainFrame",NoOfStudents=10}
            };
            SelectedCourses = new ObservableCollection<Course>();
            SelectedCourses.CollectionChanged += 
              new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
              SelectedCourses_CollectionChanged);

        }

        void SelectedCourses_CollectionChanged(object sender, 
             System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            NotifyPropertyChanged("SelectedCourses");
        }
    }
}

View

MainPage.xaml:

In my XAML file, under usercontrol.resources, I add the following code:

<Style x:Key="CheckBoxList" TargetType="ListBox" >
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Transparent" Margin="{TemplateBinding Padding}">
                                <CheckBox Content="{Binding CourseName}" VerticalContentAlignment="Center"
                            IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

Here within the ListBox, for the ListBox item, I am adding a template as checkbox and binding CourseName with the checkbox content. Also the green highlighted code, I am binding the IsChecked property of the checkbox to the IsSelected property of the ListBox. So whenever a checkbox (ListBoxItem) is checked, that item will be added to the SelectedItems property of the ListBox. Simple, isn’t it?

You can find the complete XAML code below:

<UserControl x:Class="ListBoxWithCheckBoxSLXAML.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:viewmodel="clr-namespace:ListBoxWithCheckBoxSLXAML"
    DataContext="{Binding Path=ViewModel}"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <viewmodel:ViewModel x:Key="ViewModel"/>
        <Style x:Key="CheckBoxList" TargetType="ListBox" >
            <Setter Property="ItemContainerStyle">
                <Setter.Value>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate>
                                    <Border Background="Transparent" Margin="{TemplateBinding Padding}">
                                        <CheckBox Content="{Binding CourseName}" VerticalContentAlignment="Center"
                                          IsChecked="{Binding Path=IsSelected,RelativeSource=
                                                     {RelativeSource TemplatedParent},Mode=TwoWay}"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource ViewModel}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox x:Name="Courses" Grid.Row="0" SelectionMode="Multiple" 
             Style="{StaticResource CheckBoxList}" HorizontalAlignment="Stretch"
             ItemsSource="{Binding Courses}" Height="100" Width="100" 
             SelectionChanged="Courses_SelectionChanged"/>
        <sdk:DataGrid x:Name="gvSelectedCourses" ItemsSource="{Binding SelectedCourses}" 
                   Grid.Row="1" AutoGenerateColumns="False" Width="300">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn Header="Course Name" Binding="{Binding CourseName}" Width="100"/>
                <sdk:DataGridTextColumn Header="Course Id" Binding="{Binding CourseId}"  Width="100"/>
                <sdk:DataGridTextColumn Header="No Of Students" Binding="{Binding NoOfStudents}"  Width="100"/>
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
    </Grid>
</UserControl>

This is not over yet. Here is the problem for us. Since we can’t bind the SelectedItems property in XAML, we have to bind that in the code behind. Wiring up the viewmodel in the view is not violating MVVM, sometimes we can use that. So in the code behind, in the constructor, I add the below code, since I am binding the viewmodel with the grid in XAML and not with the entire view.

this.DataContext = LayoutRoot.DataContext;

In the selection changed event of the ListBox, I add the below code to add SelectedItems to SelectedCourses.

((ViewModel)DataContext).SelectedCourses.Clear();
foreach (Course item in Courses.SelectedItems)
{
    ((ViewModel)DataContext).SelectedCourses.Add(item);
}

This is my complete code behind code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace ListBoxWithCheckBoxSLXAML
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            //since i bound viewmodel to grid, here am binding to entire view.
            this.DataContext = LayoutRoot.DataContext;

        }

        private void Courses_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ((ViewModel)DataContext).SelectedCourses.Clear();
            foreach (Course item in Courses.SelectedItems)
            {
                ((ViewModel)DataContext).SelectedCourses.Add(item);
            }
        }
    }
}

You can play around with the application now.

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