Click here to Skip to main content
Email Password   helpLost your password?
CustomCheckedListBox

Introduction

Due to the fact that .NET CheckedListBox does not have out of the box binding facilities, this article implements an extension of the CheckedListBox which can be bindable. Moreover, it implements the DisplayMember and ValueMember properties in order to get an array of IDs containing the respective checked items.

Approach

We have to implement four extra properties:

You already know the use of the first three but the last one is a List<int>. I chose int because we need the ID and most of the times in the lookup table, this ID is a number. I chose a List because the user can check more than one item, hence we need a list.

Using the Code

To use this code, you have to create an object whose type is cCheckedListBox and add it to your form:

cCheckedListBox cbGenreList = new cCheckedListBox();
cbGenreList.Location = new Point(8, 20);
cbGenreList.Size = new Size(130, 180);
this.grpGenres.Controls.Add(cbGenreList);

// Let's bind it to data from a Database
var GenreList = from c in databasebObjectContext.Genres orderby c.gnDescription select c;
cbGenreList.DataSource = GenreList.ToArray();
cbGenreList.DisplayMember = "gnDescription";
cbGenreList.ValueMember = "gnNumber";

To retrieve the values of the checked items :

List <int> selectedValues;
selectedValues= cbGenreList.ValueList;

To check some items by ID:

List<int> myValues = new List<int>(); 
myValues.Add(44);
myValues.Add(45);
myValues.Add(46);
cbGenreList.ValueList = myValues;

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalwhat is the database schema look like.
macupryk
18:01 11 Jan '10  
There is no db schema table.
GeneralSmall Mod
Roger Willcocks
17:51 22 Apr '09  
As described in this article, if you assign the DisplayMember BEFORE you assign the DataSource, the DisplayMember is wiped (ValueMember is not, go figure). Make this change to preserve it.

EDIT: point to note, this is a behaviour of the base ListControl, not of CheckedListBox
        [DefaultValue("")]
[AttributeProvider(typeof(IListSource))]
[RefreshProperties(RefreshProperties.All)]
[Browsable(true)]
public new object DataSource
{
get
{
return base.DataSource;
}
set
{
string dm = this.DisplayMember;
((ListBox)this).DataSource = value;
if (dm != this.DisplayMember)
{
this.DisplayMember = dm;
}
}
}


Roger Willcocks
Software Engineer
MCP, MCSD .NET
http://www.l-space-design.com/

GeneralGenerics Are Wonderful :)
Roger Willcocks
17:12 22 Apr '09  
This can be generalised to a CheckListBox<KeyType>

or even

CheckedListbox<KeyType,DataItemType>

and add a SelectedItemList method

Roger Willcocks
Software Engineer
MCP, MCSD .NET
http://www.l-space-design.com/

GeneralInitialization error
Penko Mitev
7:16 18 Mar '09  
Hi, the idea looks very good and this is an agile approach which is not developed in the standard control. However, this error appears when trying to change the name of the object I have inserted to the form:

"Code generation for property 'ValueList' failed. Error was: 'Property accessor 'ValueList' on object 'cbxListSelectedOperations' threw the following exception:'Object reference not set to an instance of an object.''"

Any ideas?
AnswerRe: Initialization error
Radu Martin
5:00 31 Mar '09  
Hi, i have the same error. I solved it un this way:


    [Bindable(true), Browsable(true)]
public List<object> ValueList
{
get {
List<object> retArray = new List<object>();
PropertyDescriptor prop = null;
PropertyDescriptorCollection propList = this.DataManager.GetItemProperties();
prop = propList.Find(this.ValueMember, false);
object checkedItem;
if (prop != null)
{
for (int i = 0; i < this.Items.Count; i++)
{
if (this.GetItemChecked(i))
{
checkedItem = this.DataManager.List[i];
retArray.Add(prop.GetValue(checkedItem));
}
}
}
return retArray;
}
}

public void SetValueList(List<object> Value)
{
if (this.DataManager != null)
{
List<object> myList = Value;
PropertyDescriptor prop = null;
PropertyDescriptorCollection propList = this.DataManager.GetItemProperties();
prop = propList.Find(this.ValueMember, false);
object checkedItem;
object valItem;
if (prop != null)
{
for (int i = 0; i < this.Items.Count; i++)
{
checkedItem = this.DataManager.List[i];
valItem = prop.GetValue(checkedItem);
if ((from c in myList where ValueType.Equals(c, valItem) select c).Count() == 1)
this.SetItemCheckState(i, CheckState.Checked);
else this.SetItemCheckState(i, CheckState.Unchecked);
}
}
}
}

This solution solve another problem: binding values to not integer type, like Guid.
GeneralRe: Initialization error
Pinx
3:21 1 Oct '09  
Adding the attribute "ReadOnly(True)" also solves the problem.
In this way, the code generator no longers makes a line in InitializeComponent that sets the property.
QuestionBinding the list
Monir Sabbagh
3:50 5 Feb '09  
Thank you for the great article.
I failed to bind the ValueList member to a int list in data, I got the folowing runtime exception:

"Runtime error //Cannot bind to the property or column RoleReports on the DataSource. Parameter name: dataMember"

Here are my whole code, can you help me please?

public class Report
{
public int ReportID { get; set; }
public string ReportName { get; set; }
}

public class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
public List<int> RoleReports = new List<int>();
}

public List<Report> ReportList = new List<Report>();
public BindingList<Role> RoleList = new BindingList<Role>();


public Form1()
{
InitializeComponent();
cCheckedListBox1.Location = new Point(12, 113);
cCheckedListBox1.Size = new Size(184, 109);
this.Controls.Add(cCheckedListBox1);

ReportList.Add(new Report { ReportID = 1, ReportName = "MCSE" });
ReportList.Add(new Report { ReportID = 2, ReportName = "English" });
ReportList.Add(new Report { ReportID = 3, ReportName = "CCNA" });
ReportList.Add(new Report { ReportID = 4, ReportName = "MCSD" });

RoleList.Add(new Role { RoleID = 1, RoleName = "Administrator", RoleReports = new List<int>() { 1, 2, 3, 4 } });
RoleList.Add(new Role { RoleID = 2, RoleName = "Manager", RoleReports = new List<int>() { 1, 2,3 } });
RoleList.Add(new Role { RoleID = 3, RoleName = "Salse", RoleReports = new List<int>() { 2, 4 } });
RoleList.Add(new Role { RoleID = 4, RoleName = "Student", RoleReports = new List<int>() { 3 } });

}

private void Form1_Load(object sender, EventArgs e)
{
L_RoleID.DataBindings.Add("Text", RoleList, "RoleID", true);
TB_RoleName.DataBindings.Add("Text", RoleList, "RoleName", true);

cCheckedListBox1.DataSource = ReportList;
cCheckedListBox1.DisplayMember = "ReportName";
cCheckedListBox1.ValueMember = "ReportID";
//cCheckedListBox1.ValueList = new List<int>() { 2,4}; // worked
cCheckedListBox1.DataBindings.Add("ValueList", RoleList, "RoleReports", true); // run time error //Cannot bind to the property or column RoleReports on the DataSource. Parameter name: dataMember
}
AnswerRe: Binding the list
Monir Sabbagh
6:31 7 Feb '09  
I am answering my question! Big Grin I changed the class role to this and it worked:

public class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
public List<int> RoleReports { get; set; }

}

Thank you again for the goot article
GeneralThanks
Thomas Wells
10:26 17 Jan '09  
Just what I needed. Though I can't really say I understand why exposing the DataSource and related properties just makes it work I'm glad it does.
GeneralList
José Filipe Néis
4:11 5 Jun '08  
Ricardo, nice job!

I'll use your code and adapt it to use an array of object instead of int, because my ID columns sometimes have strings on it.

Kind regards.

José Filipe


Last Updated 17 Jan 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010