使用文本框搜索列表视图项目

4
我正在使用C#开发一个简单的应用程序(电话簿),我的项目中有一个填充了联系人的listview。我一直在尝试实现通过文本框自动(即时)搜索listview的可能性,我已经成功了,但不是预期的方式。如果给你一个例子,你会意识到实际的问题。假设我有一个名为Bill Gates的联系人,当我尝试搜索它时,它被找到了,这部分是没问题的。但是,当我尝试搜索另一个联系人时,问题就来了。在这种情况下,我必须在输入另一个名字之前清除文本框,但只能逐个字母地删除。当我开始删除整个名称时,在删除第一个字母后,它会像我刚刚输入名称一样选择该项(并且还聚焦)- 实际上,在它再次找到联系人之前没有时间删除整个名称。我必须先删除第一个字母,然后切换回文本框,再删除另一个字母,以此类推。是否有任何解决方案可以使搜索自动进行 - 就像现在的情况一样,但另一方面,清除(清除文本框)而不选择联系人是可能的。
看看代码:
private void txt_Search_TextChanged(object sender, System.EventArgs e)
    {
        if (txt_Search.Text != "")
        {
            foreach (ListViewItem item in listView1.Items)
            {
                if (item.Text.ToLower().Contains(txt_Search.Text.ToLower()))
                {
                    item.Selected = true;
                }
                else
                {
                    listView1.Items.Remove(item);
                }

            }
            if (listView1.SelectedItems.Count == 1)
            {
                listView1.Focus();
            }
        }
        else 
        { 
            LoadContacts();
            RefreshAll();
        }
    } 
4个回答

9
你的代码存在一些问题,首先,在遍历集合时修改它时,我们不应该使用 foreach 循环,虽然在某些情况下看起来可能有效,但实际上不是的。这样做将来肯定会很奇怪并且会使你感到困惑。相反,我们应该使用 for 循环,并且以倒序方式进行遍历。 第二个问题是你设置了 Selectedtrue,这可能导致你的文本框失去焦点,而选中项却变成了 listView 中的一个项目。解决方案是我们必须使用其他方法来表示项目已被选中,例如使用 BackColor
private void txt_Search_TextChanged(object sender, System.EventArgs e)
{
    if (txt_Search.Text != "") {
        for(int i = listView1.Items.Count - 1; i >= 0; i--) {
            var item = listView1.Items[i];
            if (item.Text.ToLower().Contains(txt_Search.Text.ToLower())) {
                item.BackColor = SystemColors.Highlight;
                item.ForeColor = SystemColors.HighlightText;
            }
            else {
                listView1.Items.Remove(item);
            }
        }
        if (listView1.SelectedItems.Count == 1) {
            listView1.Focus();
        }
    }
    else   
        LoadContacts();
        RefreshAll();
    }
}

同时,当用户聚焦于ListView时,所有的BackColorForeColor应该被重设。我们可以处理ListViewEnter事件:

//Enter event handler for listView1
private void listView1_Enter(object sender, EventArgs e){
  foreach(ListViewItem item in listView1.Items){
    item.BackColor = SystemColors.Window;
    item.ForeColor = SystemColors.WindowText;
  }
}

1
我不知道该说什么,这个程序完美地运行了。非常感谢! - Exinta Enea

1

编辑 最好不要使用Text_Changed,而是尝试以下Key_Down方法

private void txt_Search_KeyDown(object sender, KeyEventArgs e)
{
   if (e.KeyCode == Keys.Enter) //apply your search only when pressing ENTER key
     {
       // you do your search as it was before 
       // i personally don't have suggestions here
       if (!txt_Search.AutoCompleteCustomSource.Contains(txt_Search.Text)) txt_Search.AutoCompleteCustomSource.Add(txt_Search.Text);
       //the line above will save all your searched contacts and display it in a beautiful format
     }
   else if (txt_Search.Text == "")
     {
       LoadContacts();
       RefreshAll();
     }
}

当然,不要忘记设置txt_Search的属性AutoCompleteMode = SuggestAppendAutoCompleteSource = CustomSource

你能否解释一下你的解决方案,因为我不太清楚这个更改会做什么。 - Exinta Enea
好的@Exinta Enea,检查修改后的答案,告诉我你是否遇到问题。 - chouaib

0
这种方法感觉有点像是一个hack,但你可以追踪已输入到文本框中的文本长度,并且只有在文本长度大于上一次调用事件时才执行搜索和聚焦逻辑。这样,如果有人删除了一个字母,搜索和聚焦就不会发生。代码示例如下:
// declare lastSearchLength as a int outside of your TextChanged delegate
if (!String.IsNullOrEmpty(txt_Search.Text) && txt_Search.Text.Length > lastSearchLength)
{
    foreach (ListViewItem item in listView1.Items)
    {
        if (item.Text.ToLower().Contains(txt_Search.Text.ToLower()))
        {
            item.Selected = true;
        }
        else
        {
            listView1.Items.Remove(item);
        }

        }
        if (listView1.SelectedItems.Count == 1)
        {
            listView1.Focus();
        }

        lastSearchLength = txt_Search.Text.Length;
    }
    else 
    { 
        LoadContacts();
        RefreshAll();
    }
}

-1
你正在使用每次键盘按下时都进行回传(postback)的方式。当页面重新加载时,焦点并不会停留在你所期望的位置上。我建议在客户端使用JavaScript实现该功能,或者使用搜索按钮而非TextChanged事件。

你误读了一些内容,这不是一个网络应用程序,而是桌面应用程序。另外,正如我所说,我希望搜索是自动的 - 不需要按任何搜索按钮。 - Exinta Enea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接