SIGN UP MEMBER LOGIN:    
ARTICLE

Checkbox Inside Listbox to Select Multiple Items in Silverlight Using MVVM

Posted by Santhosh Kumar Articles | Silverlight with C# February 01, 2012
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 found a way to do it. In the following article, I will explain how we did that.
Reader Level:

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 found a way to do it. In the following article, I will explain how we did that.

In a UI, the user will have an option to select a list of courses in a listbox and the selected courses will be listed in the gridview like in the following figure.

ChkSIl1.gif

Course Class

I have a class Course with the following properties.

  1. CourseName
  2. CourseId
  3. 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 one BaseViewModel and a viewmodel for a 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 2 properties in the viewmodel. One is for a list of courses and the other is for a 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 added 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 a checkbox and binding a CourseName with checkbox content. Also, in the green highlighted code, there 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 another problem for us. Since we can't bind a SelectedItems property in XAML, we have to bind that in code behind. Wiring up a viewmodel in a view is not a violattion of MVVM, sometimes we can use that. So in the code behind, in the constructor, I added the following 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 listbox, I added the following code to add selecteditems to the 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 the application now.

Login to add your contents and source code to this article
share this article :
post comment
 

Thanks

Posted by Santhosh Kumar Feb 03, 2012

Great what an article. I will surely try to implement this.

Posted by Daisy Krause Feb 02, 2012

Very useful article. Thanks for sharing.

Posted by Alok Pandey Feb 01, 2012

Really your article is considerately.Thanks

Posted by Arjun Panwar Feb 01, 2012
Nevron Gauge for SharePoint
Become a Sponsor
PREMIUM SPONSORS
  • The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
    Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor