Как сделать поиск по слову по listbox?

355
03 декабря 2017, 10:31

Как сделать поиск по listbox, по слову или части слова? Например: в textbox1 пишем слово "man" и нажимаем на кнопку "Search" и нужно, чтоб нашло слово или часть слова, в listbox1 и перешло на строку с этим словом. И чтоб по нажатию кнопки "Search" еще раз, чтоб нашлась следующая строка содержащая это слово. И если дальше в списке нету строки с этим словом, тогда нужно чтоб поиск шел по кругу и переходил на первую строку с этим словом в listbox. То есть, чтоб поиск происходил по кругу в listbox, по нажатию кнопки "Search". (Если можно, объясните как для новичка). В общем нужна такая же функция как в кнопке "Найти далее" в блокноте.
Сделал вот так, но работает неправильно, проходит по всем вариантам которые есть в listbox и останавливается на последнем:

private void buttonFindNext_Click(object sender, EventArgs e)
    {
        Form1 main = this.Owner as Form1;
        if (main != null)
            for (int i = 0; i < main.listBox1.Items.Count; i++)
        {
            if (main.listBox1.Items[i].ToString().ToLower().Contains(textBoxSearch.Text))
            {
                main.listBox1.SetSelected(i, true);
            }
        }
    }

Как сделать чтоб находил только один вариант, а по нажатию кнопки "найти далее" переходил на следующий найденный текст, который ввели в textBoxSearch?

Answer 1

Для поиска с продолжением, вам необходимо запоминать последнее найденное положение. В вашем случае это будет индекс элемента ListBox. Для того, чтобы значение сохранялось между кликами по кнопке, нужно завести отдельное поле в классе формы. Для простоты, пусть все элементы размещены на одной форме, тогда решение может выглядеть так:

private int lastFoundIndex = -1;
private void buttonFindNext_Click(object sender, EventArgs e)
{
    int i;
    for (i = lastFoundIndex + 1; i < listBox1.Items.Count; i++)
    {
        var currVal = listBox1.Items[i].ToString();
        if(currVal.IndexOf(textBoxSearch.Text, StringComparison.OrdinalIgnoreCase) > -1)
        {
            listBox1.SetSelected(i, true);
            lastlastFoundIndex = i;
            break;//прерываем цикл
        }
    }
    if(lastFoundIndex > -1 && i == listBox1.Items.Count)
    {
        for (i = 0; i <= lastFoundIndex; i++)
        {
            var currVal = listBox1.Items[i].ToString();
            if(currVal.IndexOf(textBoxSearch.Text, StringComparison.OrdinalIgnoreCase) > -1)
            {
                listBox1.SetSelected(i, true);
                lastlastFoundIndex = i;
                break;//прерываем цикл
            }
        }
    }
}

Теперь немного расшифрую "магию"

Начальное значение lastFoundIndex выбрано -1, т.к. индексы коллекций и перечислений начинаются с 0, а значит такого значения среди индексов быть не может, что и будет означать, что поиск не дал результатов.

Случай первый: элементов нет. В этом случае первый цикл пройдет по всем элементам до конца, значение lastFoundIndex не изменится, второй цикл выполнен не будет согласно условию.

Случай второй: есть один и более искомых элементов. При первом поиске, первый цикл выполнится до первого найденного значения, изменит состояние lastFoundIndex и прервет цикл. Следующий цикл не выполнится, т.к. первый еще не дошел до конца. Допустим мы нашли последний или единственный элемент. При следующем поиске первый цикл начнется со значения lastFoundIndex + 1, т.е. следующего за предыдущим найденным, дойдет до конца, и начнет выполнятся второй цикл с 0, до последнего найденного индекса. Если элемент был всего один, то мы вернемся на то же место, если нет, то на первый найденный с начала списка элемент.

Если текст для поиска изменился, необходимо выставить значение lastFoundIndex обратно в -1.

Вместо приведения к нижнему регистру, при котором будет создана еще одна строка, я воспользовался перегрузкой метода String.IndexOf(String.IndexOf (String, StringComparison), во втором параметре которого указывается одно из возможных правил поиска, в данном случае игнорировать регистр.

Answer 2

@rdorn: Спасибо большое. Код немного подправил, не знаю или все правильно сделано, но код работает как надо.

private int lastFoundIndex = -1;
    private void buttonFindNext_Click(object sender, EventArgs e)
    {
        Form1 main = this.Owner as Form1;
        if (main != null)
        {
            int i;
            for (i = lastFoundIndex + 1; i < main.listBox1.Items.Count; i++)
            {
                var currVal = main.listBox1.Items[i].ToString();
                if (currVal.ToLower().Contains(textBoxSearch.Text.ToLower()))
                {
                    main.listBox1.SetSelected(i, true);
                    lastFoundIndex = i;
                    break;//прерываем цикл
                }
            }
            if (lastFoundIndex > -1 && i == main.listBox1.Items.Count)
            {
                for (int s = 0; s <= lastFoundIndex; s++)
                {
                    var currVal = main.listBox1.Items[s].ToString();
                    if (currVal.ToLower().Contains(textBoxSearch.Text.ToLower()))
                    {
                        main.listBox1.SetSelected(s, true);
                        lastFoundIndex = s;
                        break;//прерываем цикл
                    }
                }
            }
        }
    }
READ ALSO
Неподвижные объекты

Неподвижные объекты

Есть 2 объекта левый без Rigidbody а правый с Rigidbody(is Kinematic= false) через левый можно проходить насквозь а правый можно отодвигатьКак сделать так чтобы...

294
.Net Core приложение с embedded базой данных

.Net Core приложение с embedded базой данных

Как-то вот не разобрался, можно ли добавить в проект, допустим - консольного приложения, базу данных и задеплоить это всё хозяйство одним dll? Если...

272
Как выставить уровень UAC на максимум?

Как выставить уровень UAC на максимум?

Подскажите, есть ли возможность по кнопке или чекбоксу (в приложении C#) установить уровень UAC на максимум?

275
Как можно сохранить ссылку на созданный обьект, чтобы изменить его после добавления в коллекцию?

Как можно сохранить ссылку на созданный обьект, чтобы изменить его после добавления в коллекцию?

Надо сломать HashSet, для чего тредуется добавить в него объект, после этого изменить его (извне коллекции)Есть следующий класс:

314