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

        row["Mark"] = DBNull.Value;

        exams.Rows.Add(row);

      }

    }

}

Итак, если пользователь вставил в первую таблицу одну новую запись (строку), то во второй таблице появляются 4 строки (по числу курсов лекций). Для связывания их с родительской строкой первой таблицы необходимо правильно установить значение столбца StudID, которое соответствует ключевому полю ID первой таблицы (см. код инициализации столбца StudID текущей строки).

В нашей версии предполагается, что названия курсов лекций фиксированы и хранятся в массиве текстовых строк courses. Введите его в блок объявлений данных класса.

string[] courses = { "Mathematics", "Physics", "English", ".NET Framework" };

В качестве упражнения измените код так, чтобы поля даты, зачета, оценки, а может быть и наименования курса, заполнялись автоматически (с привлечением объекта Random). Да и количество сданных экзаменов может флуктуировать.

В этот момент следует попытаться отладить приложение и убедиться, что в начальный момент для каждой новой записи, вносимой в первую таблицу, во второй таблице (экзаменов) появляются четыре, связанных с ней записи.

Это действительно так, если строки добавляются в новую, пустую таблицу. Однако, обработчик события дает сбой при попытке вставить новые строки в старую таблицу, то есть ту, которая восстанавливается из файла. В чем же дело? Попробуйте самостоятельно вычислить причину такого поведения и способ его коррекции.

Вы, вероятно, догадались, что перед восстановлением всего набора данных из файла, надо выключить реакцию на событие RowChanged и вновь включить ее после восстановления. Чтобы сделать это оптимальным способом, не порождая новые объекты при каждом чтении из файла (и добавляя тем самым работы сборщику мусора gc — garbage collector), желательно один раз создать делегата с заданием (объект типа DataRowChangeEventHandler), запомнить его, и вынимать-вставлять его в коллекцию делегатов события RowChanged при каждом чтении файла с данными.

¨  Введите в класс формы новый элемент данных — ссылку на объект типа DataRowChangeEventHandler.

    DataRowChangeEventHandler rowChanged;

¨  Создайте его в нужном месте и добавьте в коллекцию делегатов события RowChanged.

    studs.RowChanged += rowChanged = new DataRowChangeEventHandler(studs_RowChanged);

¨  Удалите ссылку на делегата из коллекции события RowChanged главной таблицы ds.Tables[0] перед вызовом метода ReadXml и вновь вставьте ее после этого вызова.

Канонизация имен студентов

Для того, чтобы придать полю Name стандартный формат, давно напрашивается вставка функции Trim, разработанной нами ранее в одном из курсов. Дело в том, что можно ввести два имени: "Joe Doe" и "  Joe  Doe "  (второе содержит массу лишних пробелов) и они будут считаться разными, хотя на самом деле они одинаковы. Введите в класс формы видоизмененную по сравнению со старой (если вы ее видели) версию метода Trim.

string Trim (string sOld)

{

StringBuilder sNew = new StringBuilder();

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

return sNew.ToString().TrimEnd();

}

Задействуйте процесс унификации имен вводом в обработчик события RowChanged следующей строки кода:

e.Row["Name"] = Trim(e.Row["Name"].ToString());

Место вставки этой строки вычислить нетрудно. В методе Trim используется объект класса StringBuilder. Он позволяет работать со строкой текста, как с коллекцией символов. Сначала коллекция пуста, затем в цикле прохода по старой строке мы добавляем в нее только те символы, которые считаем нужными. Здесь работает метод Append, который меет 18 перегруженных версий и, поэтому, позволяет очень гибко работать со вновь генерируемой строкой. Обязательно просмотрите справку по этому методу.

Вычисляемые колонки DataTable (Expression-Based DataColumn Objects)