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

Обратите внимание на массу ресурсов (картинок), которые студия автоматически добавила в проект (см. файл MainForm.resx). Всю эту работу можно (в качестве полезного упражнения) сделать и вручную, но она потребует от вас заметных усилий. Технология работы с ресурсами — это особая статья трудозатрат программиста, она требует большого внимания и осторожности, так как легко подпортить уже работающий проект.

Важно помнить, что ресурсы бывают двух типов: внедряемые в файл ресурсов (Embedded in .resx) или подключаемые при компиляции (Linked at compile time). Внедряемые ресурсы в конце концов попадают в exe-файл, их нельзя редактировать и поэтому лучше использовать в случаях, кода вы не хотите, чтобы кто-либо, кроме вас, мог изменить облик приложения. Подключаемые ресурсы хранятся в виде отдельных файлов проекта (например в формате jpg), которые легко заменить в уже готовом проекте.

Итак, навигатор связывания BindingNavigator готов к работе и ждет, когда его подключат. Сделайте это одной строкой кода, местоположение которой вычислите с помощью логики использования навигатора.

bn.BindingSource = bsStuds;

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

Реакции на события в DataTable

Недостаток в логике работы приложения обнаруживается при вводе новых записей в первую, родительскую таблицу. Вторая таблица exams является дочерней по отношению к первой и связана с ней по ключевым полям (колонкам ID и StudID). При вводе новой записи в первую таблицу, вторая таблица ведет себя инертно — в ней не появляются новые строки со списком экзаменов для нового студента. Хочется это исправить и автоматизировать процесс появления строк, отображающих весь набор экзаменов.

Очевидно, что добавление экзаменов надо делать в ответ на событие, которое соответствует появлению нового студента. В документации по классам библиотеки .NET Framework находим, что класс DataTable способен обработать два события (RowChanging и RowChanged), которые прямо связаны с нашим намерением. Первое происходит в момент изменения строки таблицы, а второе — после того, как изменения в строке успешно завершились. Выбираем второе и вводим в класс формы реакцию на него. Это делается стандартным способом — добавлением делегата в список делегатов события RowChanged. Введите изменения в метод InitDataSet, как показано ниже.

//=== Добавляем адрес функции обработки события в коллекцию делегатов, поддерживаемую событием RowChanged

studs.RowChanged += new DataRowChangeEventHandler(studs_RowChanged);

Если вы правильно манипулировали механизмом IntelliSense при вводе предыдущего оператора (вводе, а не копировании), то заготовка метода studs_RowChanged класса MainForm, реагирующего на событие добавления новой записи, была автоматически создана редактором студии. Если заготовки нет, то вводите ее руками, или научитесь работать с IntelliSense и повторите ввод.

Просмотрите код заготовки. В качестве параметра она получает ссылку на объект вспомогательного класса DataRowChangeEventArgs, который содержит важную информацию о конкретном типе изменения. Для того, чтобы узнать какие изменения в принципе отслеживаются, смотрите справку по перечислению DataRowAction. Мы используем эту информацию для фильтрации только одного типа изменений (Add).

void studs_RowChanged(object sender, DataRowChangeEventArgs e)

{

    DataTable exams = ds.Tables[1];   // Ссылка на связанную таблицу

    if (e.Action == DataRowAction.Add) // Если в первой таблице появилась новая строка

    {

      for (int j = 0; j < courses.Length; j++)    // Создаем 4 записи во второй таблице

      {

        DataRow row = exams.NewRow();

        row["StudID"] = e.Row["ID"];// Первичный и связанный ключи должны сопадать

        row["Course"] = courses[j]; // Массив с именами предметов должен существовать

        row["Credit"] = false;

        row["Date"] = DBNull.Value; // Значение DBNull соответствует незаполненным полям