CheckListBox.Items is of type ObjectCollection, which means that it will accept any object and not just string. By default, CheckedListBox will display the results of ToString as the item's text.
What this means is that you could write a class to represent the items stored in the CheckedListBox that track their own CheckedState property, then override the ToString method so that it displays the text that you want.
// CheckedListBoxItem.cs
public class CheckedListBoxItem
{
/// <summary>
/// The item's text - what will be displayed in the CheckedListBox.
/// </summary>
public string Text { get; set; }
/// <summary>
/// The item's check state.
/// </summary>
public CheckState CheckState { get; set; } = CheckState.Unchecked;
/// <summary>
/// Whether the item is checked or not.
/// </summary>
public bool Checked
{
get
{
return (CheckState == CheckState.Checked || CheckState == CheckState.Indeterminate);
}
set
{
if (value)
{
CheckState = CheckState.Checked;
}
else
{
CheckState = CheckState.Unchecked;
}
}
}
public bool Contains(string str, StringComparison comparison)
{
return Text.IndexOf(str, comparison) >= 0;
}
public override string ToString()
{
return Text;
}
}
The behavior of CheckedListBoxItem.Checked is based on CheckedListBox.GetItemChecked which treats CheckState.Interetminate as checked, and CheckedListBox.SetItemChecked which treats true as CheckState.Checked and false as CheckState.Unchecked.
In your Form, you would then change the type of lstcollection to List<CheckedListBoxItem> and set the Text property of each item to the string that you have now.
CheckedListBox doesn't have any way to bind the CheckState of each item, so you'll have to manage that yourself. Fortunately, there is the CheckedListBox.ItemChecked event that will fire whenever the checked state of an item changes. So, you can handle the event with a function like...
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
// Since each item in the CheckedListBox is of type CheckedListBoxItem, we can
// just cast to that type...
CheckedListBoxItem item = checkedListBox1.Items[e.Index] as CheckedListBoxItem;
// Then set the checked state to the new value.
item.CheckState = e.NewValue;
}
Your filter function remains largely unchanged, but when you're adding the items to the CheckedListBox you have to pass the CheckedState as well...
private List<CheckedListBoxItem> liscollection;
private void textBox1_TextChanged(object sender, EventArgs e)
{
checkedListBox1.Items.Clear();
if (string.IsNullOrEmpty(textBox1.Text) == false)
{
foreach (var item in liscollection)
{
if (item.Contains(textBox1.Text, StringComparison.OrdinalIgnoreCase))
{
checkedListBox1.Items.Add(item, item.CheckState);
}
}
}
else
{
foreach (var item in liscollection)
{
checkedListBox1.Items.Add(item, item.CheckState);
}
}
}
EDIT
For a case like this, I wouldn't add the items to checkedListBox1 at design time. I'd add them to liscollection at runtime, then add liscollection to checkedListBox1.Items.
public class YourForm : Form
{
public YourForm()
{
InitializeComponent();
// You would add one item to liscollection for each item that you have in the checkedListBox1's designer and set the Text to whatever the item is now...
liscollection = new List<CheckedListBoxItem>
{
new CheckedListBoxItem { Text = "The" },
new CheckedListBoxItem { Text = "needs" },
new CheckedListBoxItem { Text = "of" },
new CheckedListBoxItem { Text = "the" },
new CheckedListBoxItem { Text = "many" },
new CheckedListBoxItem { Text = "outweigh" },
new CheckedListBoxItem { Text = "the" },
new CheckedListBoxItem { Text = "needs" },
new CheckedListBoxItem { Text = "of" },
new CheckedListBoxItem { Text = "the" },
new CheckedListBoxItem { Text = "few" },
};
checkedListBox1.Items.AddRange(liscollection.ToArray());
}
}
If you really prefer to populate checkedListBox1 from the designer, you can do that too. You just have to call checkedListBox1.Items.Clear() after populating liscollection and before calling checkedListBox1.Items.AddRange(...)
public class YourForm : Form
{
public YourForm()
{
InitializeComponent();
liscollection = new List<CheckedListBoxItem>();
foreach(string str in checkedListBox1.Items)
{
liscollection.Add(new CheckedListBoxItem { Text = str });
}
checkedListBox1.Items.Clear();
checkedListBox1.Items.AddRange(liscollection.ToArray());
}
}
The important line there is checkedListBox1.Items.AddRange(liscollection.ToArray()). You want the Items to be instances of CheckedListBoxItem, that way in the ItemCheck event you can cast the item to an instance of CheckedListBoxItem. By populating checkedListBox1 from the designer, you're populating it with strings only, so when you try to cast to a CheckedListBoxItem in the ItemCheck event it fails. That's why you're getting that NullReferenceException.