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

A Custom CheckedListBox with Datasource Implementation (Bindable)

By , 16 Jan 2008
 
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:

  • DataSource
  • DisplayMember
  • ValueMember
  • ValueList

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

  • 17th January, 2008: Article posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ricardo Cuello
Software Developer (Junior)
Canada Canada
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionwhat is the database schema look like.membermacupryk11 Jan '10 - 17:01 
There is no db schema table.
GeneralSmall ModmemberRoger Willcocks22 Apr '09 - 16:51 
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 :)memberRoger Willcocks22 Apr '09 - 16:12 
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 errormemberPenko Mitev18 Mar '09 - 6:16 
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 errormemberRadu Martin31 Mar '09 - 4:00 
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 errormemberPinx1 Oct '09 - 2:21 
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 listmemberMonir Sabbagh5 Feb '09 - 2:50 
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 listmemberMonir Sabbagh7 Feb '09 - 5:31 
I am answering my question! Big Grin | :-D 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
GeneralThanksmemberThomas Wells17 Jan '09 - 9:26 
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<int></int>memberJosé Filipe Néis5 Jun '08 - 3:11 
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

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 17 Jan 2008
Article Copyright 2008 by Ricardo Cuello
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid