Search code examples
c#.netwinformsdata-bindingcheckedlistbox

Preserve check state of the items in cascading CheckedListBox


I have 2 Checkedlistbox controls in my C# windows form application program. First Checkedlistbox is for doctors' specialty for example dentist, radiologist and etc. If I check dentist checkbox doctors' specialty Checkedlistbox control, all doctors who are dentist will be shown in the doctors' name Checkedlistbox control.
The problem is that when I check dentist Checkedlistbox and then some dentists from doctors' Checkedlistbox, then if I check radiologist Checkedlistbox, then doctors' name Checkedlistbox will be reset and all my dentist checked checkbox will be de-selected.
What I have tried: Doctors' name Checkedlistbox data source:

DoctorsIDCheckedlistbox.DataSource = _ClinicEntities.Tbl_Doctors
      .Where(w => _SelectedSpecialty.Contains(w.SpecialtyID))
      .Select(s => new DoctorListCheckbox{ Name = s.Name + " " + s.LastName, DoctorID = s.DoctorID })
      .ToList();

DoctorsIDCheckedlistbox.DisplayMember = "Name";
DoctorsIDCheckedlistbox.ValueMember = "DoctorID";

Then I save checked items in ItemCheck event:

private void DoctorsID_ItemCheck(object sender, ItemCheckEventArgs e)
{
    int doctorID = Convert.ToInt32(DoctorsIDCheckedlistbox.SelectedValue);
    if (e.NewValue == CheckState.Checked)
    {
        _SelectedDoctorsChecked.Add(doctorID.ToString());
    }
    else
    {
        _SelectedDoctorsChecked.Remove(doctorID.ToString());
    }
}

Then for doctors' specialty ItemCheck event:

private void SpecialtyTypeID_ItemCheck(object sender, ItemCheckEventArgs e)
{
    for (int i = 0; i < DoctorsIDCheckedlistbox.Items.Count; i++)
    {
         if (_SelectedDoctorsChecked.Contains(DoctorsIDCheckedlistbox.Items[i].ToString()))
         {
             try
             {
                 DoctorsIDCheckedlistbox.SetItemChecked(i, true);
             }
             catch (Exception ex)
             {
                 MessageBox.Show(ex.ToString());
             }
        }
    }
}

I expect code above look through _SelectedDoctorsChecked list which is selected doctors and check them when doctors' specialty checkboxes status changes. But it don't work.

Example:
I check A in doctors' specialty and items 1, 2 and 3 will be shown in doctors' name. I check 1 and 3. When I check B in doctors' specialty, Items 1, 2 and 3 from A and 4, 5 and 6 from B will be shown. I expect number 1 and 3 be checked. But it won't.

Edit:
My Checkedlistbox control data source:

DoctorsIDCheckedlistbox.DataSource = _ClinicEntities.Tbl_Doctors
   .Where(w => _SelectedSpecialty.Contains(w.SpecialtyID))
   .Select(s => new DoctorListCheckbox{ Name = s.Name + " " + s.LastName, DoctorID = s.DoctorID })
   .ToList();

   DoctorsIDCheckedlistbox.DisplayMember = "Name";
   DoctorsIDCheckedlistbox.ValueMember = "DoctorID";

And DoctorListCheckbox class:

 public partial class DoctorListCheckbox
 {
    public int DoctorID { get; set; }
    public string Name { get; set; }
    public CheckState CheckState { get; set; }
    public override string ToString()
    {
        return Name;
    }
 }

I have did it based on Microsoft Example


Solution

  • The basics are same as what I explained in Updates in the DataSource reset CheckedListBox checkboxes.

    You need to define a BindingList<Specialties> as data source of the specialties checked list box and show all specialties.

    For doctors, you need an empty BindingList<CheckedListBoxItem<Doctor>> and set it as data source of doctors checked list box. Then you need to handle the following events:

    • ItemChecked event of specialties checked list box: If the item is checked, then find all doctors with the checked specialty from your repository and them as CheckedListBoxItem<Doctor> to the binding list. Otherwise, find all doctors with unchecked specialty in the binding source and remove them.

    • ItemChecked event of doctors: Sync check state of the binding list item using the check state of checked list box item.

    • ListChanged event of the binding list: Sync the checked list box items check states, using the check state of the binding list items.

    Example

    Here is the full example for a scenario of having 2 checked list box of specialties and doctors and select doctors based on the selected specialties:

    Models

    public class Speciality
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public override string ToString() { return Name; }
    }
    public class Doctor
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int SpecialityId { get; set; }
        public override string ToString() { return Name; }
    }
    public class CheckedListBoxItem<T>
    {
        public CheckedListBoxItem(T item)
        {
            DataBoundItem = item;
        }
        public T DataBoundItem { get; set; }
        public CheckState CheckState { get; set; }
        public override string ToString() { return DataBoundItem.ToString(); }
    }
    

    Sample Data

    public class DB
    {
        public IEnumerable<Speciality> Specialities
        {
            get
            {
                return new List<Speciality>()
                {
                    new Speciality(){ Id= 1, Name ="S1"},
                    new Speciality(){ Id= 2, Name ="S2"},
                    new Speciality(){ Id= 3, Name ="S3"},
                };
            }
        }
        public IEnumerable<Doctor> Doctors
        {
            get
            {
                return new List<Doctor>()
                {
                    new Doctor(){ Id= 1, Name ="D1", SpecialityId = 1},
                    new Doctor(){ Id= 2, Name ="D2", SpecialityId = 2},
                    new Doctor(){ Id= 3, Name ="D3", SpecialityId = 2},
                    new Doctor(){ Id= 4, Name ="D4", SpecialityId = 3},
                    new Doctor(){ Id= 5, Name ="D5", SpecialityId = 3},
                    new Doctor(){ Id= 6, Name ="D6", SpecialityId = 3},
                };
            }
        }
    }
    

    Form Event Handlers

    DB db = new DB();
    BindingList<Speciality> specialities;
    BindingList<CheckedListBoxItem<Doctor>> doctors;
    private void Form10_Load(object sender, System.EventArgs e)
    {
        specialities = new BindingList<Speciality>(db.Specialities.ToList());
        specialitiesCheckedListBox.DataSource = specialities;
        doctors = new BindingList<CheckedListBoxItem<Doctor>>();
        doctorsCheckedListBox.DataSource = doctors;
        doctors.ListChanged += doctors_ListChanged;
    }
    private void doctors_ListChanged(object sender, ListChangedEventArgs e)
    {
        for (var i = 0; i < doctorsCheckedListBox.Items.Count; i++) {
            doctorsCheckedListBox.SetItemCheckState(i,
                ((CheckedListBoxItem<Doctor>)doctorsCheckedListBox.Items[i]).CheckState);
        }
    }
    private void specialitiesCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        var item = (Speciality)specialitiesCheckedListBox.Items[e.Index];
        if (e.NewValue == CheckState.Checked) {
            db.Doctors.Where(x => x.SpecialityId == item.Id)
                .Select(x => new CheckedListBoxItem<Doctor>(x)).ToList()
                .ForEach(x => doctors.Add(x));
        }
        else {
            doctors.Where(x => x.DataBoundItem.SpecialityId == item.Id)
                .ToList().ForEach(x => doctors.Remove(x));
        }
    }
    private void doctorsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        ((CheckedListBoxItem<Doctor>)doctorsCheckedListBox.Items[e.Index])
            .CheckState = e.NewValue;
    }