Click here to Skip to main content
15,881,881 members
Articles / Desktop Programming / XAML
Tip/Trick

Checkbox Inside ListBox to Select Multiple Items in Silverlight Using MVVM

Rate me:
Please Sign up or sign in to vote.
4.67/5 (2 votes)
21 Jun 2012CPOL2 min read 40.4K   1.1K   1   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.

Image 1

Course Class

I have a class Course with the properties below:

  • CourseName
  • CourseId
  • NoOfStudents
Class.cs:
C#
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
C#
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.

C#
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:

XML
<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:

XML
<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.

C#
this.DataContext = LayoutRoot.DataContext;

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

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

This is my complete code behind code.

C#
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)


Written By
Technical Lead EF (Education First)
India India
I graduated as Production Engineer and started my career as Software Developer then worked as tester for a while before moving into Windows application development using Microsoft Technologies. But for the last few years i am working on javascript, React, Node, AWS, Azure Chatbots

Comments and Discussions

 
QuestionCorrection Pin
ghous9225-Oct-12 0:11
ghous9225-Oct-12 0:11 

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

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