Search code examples
c#winformscheckedlistbox

Search in for items in CheckedListBox C#


I have a CheckedListBox and a Text box. Goal here is to make a searchable CheckedListBox. When I type something in TextBox I have to filter items in CheckedListBox. I have written a below code to do so, But every time I enter a text the, CheckedListBox items gets cleared and new filtered items list will appear. The problem with this code is the filtering works fine but the checked items will be reset every time.

public partial class Form1 : Form
{
    string[] elArray = {"Not Applicable" , "Aberdeen - Delivered" , "Belfast - Delivered" , "Birmingham - Delivered" , "Bournemouth - Delivered" , "Bradford - Delivered" , "Bristol - Delivered" , "Cambridge - Delivered" , "Canterbury - Delivered" , "OTHERS TO DE ADDED ..."};
    public Form1()
    {
        InitializeComponent();
        foreach (string elData in elArray)
        {
            resultBoxList.Items.Add(elData);
        }
    }

    private void searchBox_TextChanged(object sender, EventArgs e)
    {
        resultBoxList.Items.Clear();
        string[] resultArray = { };
        foreach (string res in elArray)
        {
            if (res.Contains(searchBox.Text))
            {
                resultBoxList.Items.Add(res);
            }
        }
        foreach (string resData in resultArray)
        {
            resultBoxList.Items.Add(resData);
        }
    }
}

enter image description here enter image description here


Solution

  • You have two problems to resolve, to:

    1. Apply the filter and preserve the list items.
    2. Preserve the checked state of the items.

    You can achieve that by using a DataTable as the data source of the list items and their checked states, and bind it's default DataView to the CheckedListBox.DataSource property.

    Note
    The DataSource, DisplayMember, and ValueMember properties of the CheckedListBox control are hidden. They don't show up in the Properties Window nor in IntelliSense.

    These properties are hidden and especially the DataSource because it delegates the functionalities of the DataManager to the base class, the ListBox which doesn't know about. Hence doesn't handle, the state of the CheckBoxes (i.e., it doesn't override OnDataSourceChanged() method to generate custom or specialized behavior.

    Firstly, create the DataTable, add the items, and populate the control.

    public Form1()
    {
        InitializeComponent();
    
        var elArray = new[]
        {
            "Not Applicable",
            "Aberdeen - Delivered",
            "Belfast - Delivered",
            "Birmingham - Delivered",
            "Bournemouth - Delivered",
            "Bradford - Delivered",
            "Bristol - Delivered",
            "Cambridge - Delivered",
            "Canterbury - Delivered",
            "OTHERS TO DE ADDED ..."
        };
        var dt = new DataTable();
    
        dt.Columns.Add("Item", typeof(string));
        dt.Columns.Add("Checked", typeof(bool));
    
        foreach (var item in elArray) dt.Rows.Add(item, false);
    
        dt.AcceptChanges();
    
        resultBoxList.DataSource = dt.DefaultView;
        resultBoxList.DisplayMember = "Item";
        resultBoxList.ValueMember = "Item";
    
        // If not already done by the designer...
        resultBoxList.ItemCheck += resultBoxList_ItemCheck;
    }
    

    Secondly, handle the ItemCheck event to update the checked state in the data source.

    private void resultBoxList_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        var dv = resultBoxList.DataSource as DataView;
        var drv = dv[e.Index];
        drv["Checked"] = e.NewValue == CheckState.Checked ? true : false;
    }
    

    Lastly, in the TextChanged event, solve the above mentioned problems:

    1. Set the DataView.RowFilter to apply/remove the filter. In your case, you need to use the LIKE operator. See the referred link for more patterns and details.
    2. Restore the checked states from the data source.
    private void searchBox_TextChanged(object sender, EventArgs e)
    {
        var dv = resultBoxList.DataSource as DataView;
        var filter = searchBox.Text.Trim().Length > 0
            ? $"Item LIKE '{searchBox.Text}*'"
            : null;
    
        dv.RowFilter = filter;
    
        for (var i = 0; i < resultBoxList.Items.Count; i++)
        {
            var drv = resultBoxList.Items[i] as DataRowView;
            var chk = Convert.ToBoolean(drv["Checked"]);
            resultBoxList.SetItemChecked(i, chk);
        }
    }
    

    SOQ66080248