在搜索 c# winforms 的复选框列表中保留项目的检查状态

Keep checkstate of items in checkboxlist on search c# winforms

所以我正在使用 c# 为 winforms 中选中列表框中的一堆项目开发一个基于文本框的过滤器。

到目前为止我有这个代码:

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);
                }
            }
        }

它工作正常,当我在 TextBox1 中输入文本时,所有不包含输入文本的项目都会消失。 问题涉及每个项目的检查状态。每次 checkedListBox1.Items.Clear();被调用时,检查状态也会被清除。

有没有一种方法可以使过滤器保持工作状态但不清除项目的选中状态?

我已经找了一段时间了,在这方面找不到任何东西,而且我是初学者,无法自己想出解决方案。

非常感谢您的宝贵时间!

请原谅我的英语,这不是我的第一语言:)

CheckListBox.ItemsObjectCollection 类型,这意味着它将接受任何 object 而不仅仅是 string。默认情况下,CheckedListBox 会将 ToString 的结果显示为项目的文本。

这意味着您可以编写一个 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;
    }
}

CheckedListBoxItem.Checked 的行为基于 CheckedListBox.GetItemChecked which treats CheckState.Interetminate as checked, and CheckedListBox.SetItemChecked,后者将 true 视为 CheckState.Checked,将 false 视为 CheckState.Unchecked

在您的 Form 中,您可以将 lstcollection 的类型更改为 List<CheckedListBoxItem> 并将每个项目的 Text 属性 设置为字符串你现在拥有的。

CheckedListBox 没有任何方法来绑定每个项目的 CheckState,所以你必须自己管理它。幸运的是,只要项目的选中状态发生变化,就会触发 CheckedListBox.ItemChecked 事件。因此,您可以使用类似...

的函数来处理事件
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;
}

您的过滤器功能基本保持不变,但是当您将项目添加到 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);
        }
    }
}

编辑

对于这种情况,我不会在设计时将项目添加到 checkedListBox1。我会在运行时将它们添加到 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());
    }
}

如果您真的更喜欢从设计器中填充 checkedListBox1,您也可以这样做。您只需在填充 liscollection 之后和调用 checkedListBox1.Items.AddRange(...)

之前调用 checkedListBox1.Items.Clear()
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());
    }
}

重要的一行是checkedListBox1.Items.AddRange(liscollection.ToArray())。您希望 Items 成为 CheckedListBoxItem 的实例,这样在 ItemCheck 事件中您可以将项目转换为 CheckedListBoxItem 的实例。通过从设计器填充 checkedListBox1,您仅使用 string 填充它,因此当您尝试在 ItemCheck 事件中转换为 CheckedListBoxItem 时,它会失败。这就是为什么你得到 NullReferenceException.