Введение в ADO.NET. Источник данных - XML-файл. Отображение данных связанной таблицы, страница 13

Вы заметили, что отображаемые строки можно сортировать самыми разными способами, если последовательно нажимать мышью заголовки всех столбцов элемента DataGridView? Эта внешняя сортировка никак не влияет на то значение, которое дает выражение rows[0][0]. Оно всего лишь выбирает значение, расположенное в нулевом столбце той строки DataTable, индекс которой записан в элементе rows[0]. Нулевой столбец соответствует полю ID и мы узнаем ключ первой из найденных записей. Если строки DataGridView в данный момент отсортированы по этому столбцу, то результат поиска будет показан (маркирован) правильно, если по другому — нет.

В процессе отбора строк из DataTable не учитывается факт внешней сортировки, так как эта структура расположена в памяти и не сортируется при нажатии на заголовки DataGridView. Напомним, что компонент DataGridView лишь отображает объекты. Ниже приводится одно из решений этой проблемы, но оно далеко от оптимального.

void Find()

{

string what = Trim(comboFind.Text);

if (what == "")

  return;

DataRow[] rows = ds.Tables[0].Select("Name LIKE '" + what + "*'");

if (rows.Length == 0)

{

  // Здесь ваш код

// Показываем метку "Not Found"

  return;

}

// Здесь ваш код  Прячем метку "Not Found"

// Запоминаем искомую строку в списке

int i;   // Ищем индекс строки по факту совпадения реальной ячейки с полем найденной строки

for (i = 0; i< studsGrid.Rows.Count; i++)

{

  if (studsGrid.Rows[i].Cells[1].Value.ToString() == rows[0]["Name"].ToString())

    break;

}

studsGrid.CurrentCell = studsGrid.Rows[i].Cells[1]; // Выделяем первую из найденных строк

}

Приведенная версия метода Find пытается учесть факт сортировки на экране. Внимательно рассмотрите выражение: studsGrid.Rows[i].Cells[1].Value.ToString(). Отметьте, что его синтаксис сильно отличается от выраженияrows[0]["Name"].ToString().

¨  Первое возвращает строковое значение того объекта, который в данный момент времени (с учетом сортировки) расположен в ячейке DataGridView с координатами (i,1).

¨  Второе выражение содержит результат поиска и отбора в DataTable, то есть в памяти, а не на экране. Оно не учитывает факт внешней сортировки.

Мы ищем совпадение этих объектов и тем самым учитываем факт сортировки. Характерно, что выражение rows[0]["Name"] имеет тип object, а выражение studsGrid.Rows[i].Cells[1] — ссылка на объект типа DataGridViewTextBoxCell. Поэтому их нельзя сравнивать без предварительного приведения к строковому типу.

Поиск в DataGridView

Анализ поведения приложения в режиме поиска, наводит на мысль о том, что целесообразно производить поиск не в таблице, поддерживаемой классом DataTable, а непосредственно в компоненте DataGridView. Хотелось бы сделать поиск более удобным. Например, продолжить его со строки, следующей за той, которая в данный момент содержит фокус. Процедуру поиска обычно зацикливают так, чтобы при прохождении всего списка можно было повторить ее сначала. Мы сделаем это без назойливого напоминания о том, что очередной цикл поиска закончился. Это можно выполнить, например, так.

¨  Ввести в класс формы вспомогательные переменные:

    DataGridViewCell activeCell, foundCell;

    bool bFindNext; // Надо ли производить сдвиг при продолжении поиска

    string findWhat;

¨  Произвести их инициализацию в конструкторе класса:

    // Здесь ваш код

¨  Изменить алгоритм метода Find и разработать метод FindNext:

  void Find()

  {

    int row = 0, col = 0;

    if (activeCell != null)

    {

      row = activeCell.RowIndex;

      col = activeCell.ColumnIndex;

    }

   string text = Trim(comboFind.Text);   // Искомый текст

    if (findWhat != text)

      findWhat = text;

    if (bFindNext || activeCell == foundCell)

      row++;

    if (FindNext(row, col))

    {

      sNotFound.Visible = false;

      if (!comboFind.Items.Contains(comboFind.Text))

        comboFind.Items.Add(comboFind.Text);

      bFindNext = true;

    }

    else

      sNotFound.Visible = true;