Click here to Skip to main content
16,018,797 members
Articles / Programming Languages / C#

Fully data-bound CheckedListBox

Rate me:
Please Sign up or sign in to vote.
4.69/5 (16 votes)
19 Apr 2008CPOL3 min read 81.4K   2K   32   20
BoundCheckedListBox is bindable to three tables representing a many-to-many data relation.

manytomanytest-src

Introduction

Maybe you already know that the .NET CheckedListBox doesn't provide any data binding, though it seems to be eligible in cases where you have a many-to-many data relation with a relation table; e.g., a product can be part of multiple categories, and each category can contain multiple products.

So, my task was to make the CheckedListBox bindable again.

Background

If you search for a bindable CheckedListBox on CodeProject, you will find two or three. I did this too. But when I took a closer look at them, I noticed that they don't implement a new data binding facility, but rather reactivate the listbox data binding to one single table - meaning that the list of items will be data bound. The checkboxes have to be set more or less manually. See Bindable CheckedListBox or A ComboBox with a CheckedListBox as a Dropdown for details.

This is not what I wanted. I wanted the CheckedListBox to be fully data-bindable; e.g., holding a list of categories and automagically setting the checked states according to the data sources (one of them holding the currently selected product), and adding/removing entries of the relation table if the user (un)checks an item. Playing with the sample should make this clear.

So, the next question was how to create my own data binding. I had a basic idea on how this should work, but this article helped me a lot: Implementing Complex Data Binding in Custom Controls.

The BoundCheckedListBox does not bind to only one data source, it binds to three data sources and needs five data members.

Using the code

The sample shows which person loves which fruits.

So, we need:

  • A data source for the parent table, Personen
  • A data source for the child table, Fruechte
  • A data source for the relation table, p_f
  • A data member for the parent ID column, ID (Personen.ID)
  • A data member for the child ID column, ID (Fruechte.ID)
  • A data member for the child display column (holding the items shown in the ListBox), Name (Fruechte.Name)
  • Two data members for the two columns holding the IDs in the relation table

This is how you can set those (or via a property list in Design view):

C#
boundCheckedListBox1.ChildDisplayMember = "Name";
boundCheckedListBox1.ChildValueMember = "fID";
boundCheckedListBox1.ParentValueMember = "pID";
boundCheckedListBox1.ParentIDMember = "ID";
boundCheckedListBox1.ChildIDMember = "ID";
boundCheckedListBox1.ParentDataSource = parentBindingSource;
boundCheckedListBox1.ChildDataSource = childBindingSource;
boundCheckedListBox1.RelationDataSource = relationBindingSource;

where each data source is a binding source, having a dataset as a data source and the corresponding table as the data member. Have a look at the source.

Points of Interest

It is very important that the BoundCheckedListBox gets a currency manager from the data source and not a property manager (as that does not provide a list, an exception will be thrown). I figured out that using a DataSet.Table as the data source only wants to give me the property manager. So, I made use of binding sources.

Set the default values which don't throw exceptions if a new DataRow is created and no values are set. I can only call the currency manager's AddNew method, and the values are set after that.

Make use of the EndEdit functions of the binding sources. I have a button adding a new element to the child table and textboxes setting the name. E.g.:

C#
EventHandler dataChangedHandler = new EventHandler(dataChanged);
....
button_kat_add.Click += dataChangedHandler;
button_kat_del.Click += dataChangedHandler;
....
textBox_kat_name.LostFocus += dataChangedHandler;
....

void dataChanged(object sender, EventArgs e) {
     dataTable1BindingSource.EndEdit();
     ....BindingSource.EndEdit();
     ....BindingSource.EndEdit();
     ....relationBindingSource.EndEdit();
}
......

private void button_kat_add_Click(object sender, EventArgs e) {
    this.....BindingSource.AddNew();
}

private void button_kat_del_Click(object sender, EventArgs e) {
     if (kategorienBindingSource.Current != null)
         this.kategorienBindingSource.RemoveCurrent();
}

If a checkbox is unchecked, the DataRow in the relation table is deleted. So we might end up with several deleted rows with the same IDs. This should be improved by un-deleting rows.

Feel free to make comments and updates!

History

  • 19th April, 2008 - Initial version

License

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


Written By
Systems Engineer
Germany Germany
Student of Systems Engineering and Engineering Cybernetics

Comments and Discussions

 
SuggestionPropogate changes back to database. Pin
Erich Wilgenbus18-Aug-13 0:57
Erich Wilgenbus18-Aug-13 0:57 
GeneralMy vote of 5 Pin
mammad20021-Jan-13 11:43
mammad20021-Jan-13 11:43 
QuestionHow do you commit the delete changes? Pin
mikep19981-Nov-12 17:35
mikep19981-Nov-12 17:35 
AnswerRe: How do you commit the delete changes? Pin
vbar7-Nov-12 21:08
vbar7-Nov-12 21:08 
In principle, this control changes your data source. As far as I remember, I iterated over the changes of the data tables manually and committed the changes to the database then via sql strings. I am not sure this also works automatically via the adapters. If you just want to apply the changes to your (local) data tables, maybe have a look at AcceptChanges().
GeneralMinor bugfix Pin
Member 44444045-Mar-09 17:59
Member 44444045-Mar-09 17:59 
GeneralRe: Minor bugfix Pin
stewart.page9-Aug-09 8:02
stewart.page9-Aug-09 8:02 
GeneralRe: Minor bugfix Pin
vbar10-Aug-09 10:15
vbar10-Aug-09 10:15 
Generalstrange behavior on storing items into database Pin
ai_mueller22-Feb-09 4:30
ai_mueller22-Feb-09 4:30 
GeneralRe: strange behavior on storing items into database Pin
vbar22-Feb-09 6:31
vbar22-Feb-09 6:31 
GeneralRe: strange behavior on storing items into database Pin
ai_mueller22-Feb-09 9:38
ai_mueller22-Feb-09 9:38 
AnswerRe: strange behavior on storing items into database Pin
vbar22-Feb-09 11:11
vbar22-Feb-09 11:11 
QuestionWhat's wrong in my code Pin
Monir Sabbagh12-Feb-09 0:37
Monir Sabbagh12-Feb-09 0:37 
AnswerRe: What's wrong in my code Pin
Monir Sabbagh12-Feb-09 8:54
Monir Sabbagh12-Feb-09 8:54 
AnswerRe: What's wrong in my code Pin
vbar12-Feb-09 11:22
vbar12-Feb-09 11:22 
GeneralRe: What's wrong in my code Pin
vbar12-Feb-09 11:31
vbar12-Feb-09 11:31 
GeneralRe: What's wrong in my code Pin
Monir Sabbagh14-Feb-09 2:14
Monir Sabbagh14-Feb-09 2:14 
GeneralRe: What's wrong in my code Pin
vbar15-Feb-09 8:01
vbar15-Feb-09 8:01 
GeneralAwesome control Pin
Phil Jeffrey10-Jul-08 20:31
Phil Jeffrey10-Jul-08 20:31 
GeneralAdjust database Pin
Michael_Kndt15-May-08 9:25
Michael_Kndt15-May-08 9:25 
GeneralRe: Adjust database Pin
vbar15-May-08 10:58
vbar15-May-08 10:58 

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.