简体   繁体   English

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

[英]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.ItemsObjectCollection类型,这意味着它将接受任何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.CheckedfalseCheckState.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的类型lstcollectionList<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 .您希望ItemsCheckedListBoxItem实例,这样在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM