Click here to Skip to main content
Click here to Skip to main content

Checkbox Inside ListBox to Select Multiple Items in Silverlight Using MVVM

, 21 Jun 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Santhosh Kumar Jayaraman
Software Developer Education First
India India
Started my career with Infosys in 2009 and currently working with Education First. I have great passion towards Microsoft technologies. I have experience in Microsoft technologies like WPF, WCF, ASPNET, WinForms,Silverlight, VB.NET, C-Sharp, Entity framework,SSRS, LINQ, Extension methods and SQL server.

Comments and Discussions

 
QuestionCorrection Pinmemberghous9225-Oct-12 0:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141015.1 | Last Updated 21 Jun 2012
Article Copyright 2012 by Santhosh Kumar Jayaraman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid