[英]Keep checkstate of items in checkboxlist on search c# winforms
So I'm working on a textbox based filter for a bunch of items in a Checked List Box in winforms using c#.因此,我正在使用 c# 为 winforms 中的选中列表框中的一堆项目开发基于文本框的过滤器。
So far I have this code:到目前为止,我有这个代码:
List<string> liscollection = new List<string>();
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBox1.Text) == false)
{
checkedListBox1.Items.Clear();
foreach (string str in liscollection)
{
if (str.Contains(textBox1.Text, StringComparison.OrdinalIgnoreCase))
{
checkedListBox1.Items.Add(str);
}
}
}
else if (textBox1.Text == "")
{
checkedListBox1.Items.Clear();
foreach (string str in liscollection)
{
checkedListBox1.Items.Add(str);
}
}
}
It works fine, when I enter the text in TextBox1 all items not containing the entered text disappear.它工作正常,当我在 TextBox1 中输入文本时,所有不包含输入文本的项目都会消失。 The problem comes to the checked state on each item.
问题出现在每个项目的选中状态。 Every time checkedListBox1.Items.Clear();
每次checkedListBox1.Items.Clear(); is called, the checked state also gets cleared.
被调用,checked 状态也会被清除。
Is there a method I could use to keep the filter working but to not clear the checked state of the items?有没有一种方法可以让过滤器保持工作但不清除项目的选中状态?
I have been looking for a while now and can't find anything on this and I am a beginner and can't come up with a solution on my own.我一直在寻找一段时间,但在这方面找不到任何东西,而且我是初学者,无法自己提出解决方案。
Thank you so much in advance for your time!非常感谢您抽出宝贵时间!
And excuse my English, it is not my first language :)请原谅我的英语,这不是我的母语 :)
CheckListBox.Items
is of type ObjectCollection
, which means that it will accept any object
and not just string
. CheckListBox.Items
是ObjectCollection
类型,这意味着它将接受任何object
而不仅仅是string
。 By default, CheckedListBox
will display the results of ToString
as the item's text.默认情况下,
CheckedListBox
会将ToString
的结果显示为项目的文本。
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.这意味着您可以编写一个
class
来表示存储在CheckedListBox
中的项目,这些项目跟踪它们自己的CheckedState
属性,然后覆盖ToString
方法,以便它显示您想要的文本。
// 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
.的行为
CheckedListBoxItem.Checked
基于CheckedListBox.GetItemChecked
它把CheckState.Interetminate
作为托运和CheckedListBox.SetItemChecked
它把true
作为CheckState.Checked
和false
的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.在您的
Form
,您将lstcollection
的类型lstcollection
为List<CheckedListBoxItem>
并将每个项目的Text
属性设置为您现在拥有的字符串。
CheckedListBox
doesn't have any way to bind the CheckState
of each item, so you'll have to manage that yourself. CheckedListBox
无法绑定每个项目的CheckState
,因此您必须自己管理它。 Fortunately, there is the CheckedListBox.ItemChecked
event that will fire whenever the checked state of an item changes.幸运的是,
CheckedListBox.ItemChecked
事件会在项目的选中状态发生变化时触发。 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...您的过滤器功能在很大程度上保持不变,但是当您将项目添加到
CheckedListBox
您还必须传递CheckedState
...
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.对于这样的情况,我不会在设计时将项目添加到
checkedListBox1
。 I'd add them to liscollection
at runtime, then add liscollection
to checkedListBox1.Items
.我会在运行时将它们添加到
liscollection
,然后将liscollection
添加到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.如果您真的更喜欢从设计器填充
checkedListBox1
,您也可以这样做。 You just have to call checkedListBox1.Items.Clear()
after populating liscollection
and before calling checkedListBox1.Items.AddRange(...)
你只需要调用
checkedListBox1.Items.Clear()
填充后liscollection
并调用之前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())
.重要的一行是
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
.您希望
Items
是CheckedListBoxItem
实例,这样在ItemCheck
事件中您可以将项目转换为CheckedListBoxItem
的实例。 By populating checkedListBox1
from the designer, you're populating it with string
s only, so when you try to cast to a CheckedListBoxItem
in the ItemCheck
event it fails.通过从设计器填充
checkedListBox1
,您只使用string
s 填充它,因此当您尝试在ItemCheck
事件中转换为CheckedListBoxItem
,它会失败。 That's why you're getting that NullReferenceException
.这就是您收到
NullReferenceException
的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.