История создания датчика движения: Первый прибор для обнаружения движения был изобретен немецким физиком Генрихом Герцем...
Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...
Топ:
Характеристика АТП и сварочно-жестяницкого участка: Транспорт в настоящее время является одной из важнейших отраслей народного хозяйства...
Процедура выполнения команд. Рабочий цикл процессора: Функционирование процессора в основном состоит из повторяющихся рабочих циклов, каждый из которых соответствует...
Теоретическая значимость работы: Описание теоретической значимости (ценности) результатов исследования должно присутствовать во введении...
Интересное:
Принципы управления денежными потоками: одним из методов контроля за состоянием денежной наличности является...
Распространение рака на другие отдаленные от желудка органы: Характерных симптомов рака желудка не существует. Выраженные симптомы появляются, когда опухоль...
Средства для ингаляционного наркоза: Наркоз наступает в результате вдыхания (ингаляции) средств, которое осуществляют или с помощью маски...
Дисциплины:
2022-09-11 | 27 |
5.00
из
|
Заказать работу |
|
|
Таблица экзаменов является дочерней (подчиненной) по отношению к таблице студентов и связана с ней по ключевым полям (ID и StudID). Такой тип связи часто называют PK-FK (Primary-Key-Forign Key). При вводе новой записи в родительскую таблицу подчиненная таблица ведет себя инертно — в ней не появляются новые строки со списком экзаменов нового студента. Вам придется вручную ввести несколько строк в таблицу экзаменов. Эта рутинная работа будет сильно утомлять не только вас, но и пользователей вашего приложения. В некоторых сценариях работы с данными хочется это исправить и автоматизировать процесс появления строк в подчиненной таблице.
Очевидно, что добавление экзаменов надо делать в ответ на событие, которое соответствует появлению нового студента. В документации по классам библиотеки.NET Framework находим, что класс DataTable способен обработать два события (RowChanging и RowChanged), которые прямо связаны с нашим намерением. Первое происходит в момент изменения строки таблицы, а второе — после того, как изменения в строке успешно завершились. Выбираем второе и вводим реакцию на него в класс формы. Это делается стандартным способом — добавлением делегата в список делегатов события RowChanged. Введите следующий код в начало метода RelateAndBind.
//=== Добавляем адрес функции обработки события в коллекцию делегатов, поддерживаемую событием RowChanged
ds.Tables[0].RowChanged +=
Если вы правильно манипулировали механизмом IntelliSense при вводе предыдущего оператора (вводе, а не копировании текста отсюда), то заготовка метода, реагирующего на событие добавления новой записи, была автоматически создана редактором студии. Если заготовки нет, то введите ее руками, или научитесь работать с IntelliSense и повторите ввод.
|
Просмотрите код заготовки. Я изменил автоматически сгенерированное имя функции на OnStudsRowChanged. Теперь оно больше соответствует своему назначению. Второй параметр функции (задания делегата) передает ссылку на объект вспомогательного класса DataRowChangeEventArgs, который содержит важную информацию о конкретном типе изменения. Для того, чтобы узнать какие изменения в принципе отслеживаются, смотрите справку по перечислению DataRowAction. Мы используем эту информацию для фильтрации только одного типа изменений (Add).
void OnStudsRowChanged(object sender, DataRowChangeEventArgs e)
{
DataTable exams = ds.Tables[1]; // Ссылка на подчиненную таблицу экзаменов
if (e.Action == DataRowAction.Add) // Если в первой таблице появилась новая строка
{
int num = 0;
foreach (string c in courses) // Массив с именами предметов должен существовать
{
if (num++!= rand.Next(courses.Length))
ds.Tables[1].Rows.Add(CreateRandomExam((int)e.Row["ID"], c));
}
}
}
В нашей версии предполагается, что названия курсов лекций фиксированы и хранятся в массиве текстовых строк courses. Если пользователь вставил в таблицу студентов новую запись (строку), то во второй таблице появляются несколько строк. Для связывания их с родительской строкой первой таблицы (связь типа PK-FK) необходимо правильно установить значение столбца StudID, которое соответствует ключевому полю ID первой таблицы (см. код присвоения e.Row["ID"]).
Попытайтесь отладить приложение и убедиться, что в начальный момент для каждой новой записи, вносимой в первую таблицу, во второй таблице (экзаменов) появляются несколько, связанных с ней, записей.
Это действительно так, если строки добавляются в новую, пустую таблицу. Однако, обработчик события дает сбой при попытке вставить новые строки в старую таблицу, то есть ту, которая восстанавливается из файла. В чем же дело? Попробуйте самостоятельно вычислить причину такого поведения и способ его коррекции.
Вы, вероятно, догадались, что при добавлении строк, которое происходит при чтении данных из файла, возбуждается событие RowChanged и мы автоматически добавляем лишнее множество экзаменов к тем, которые уже есть в файле. Вот один из способов решения этой проблемы. Перед восстановлением всего набора данных из файла, надо выключить реакцию на событие RowChanged и вновь включить ее после прочтения данных из файла. Для этого надо пользоваться операциями –= и += события RowChanged нужной таблицы.
|
Канонизация имен студентов
В данный момент мы можем ввести двух студентов с именами: "Joe Doe" и " Joe Doe " (второе содержит массу лишних пробелов) и они будут считаться разными, хотя семантически они одинаковы. Для того, чтобы придать полю Name стандартный формат, давно напрашивается вставка метода Trim(string), который убирает пробелы не только в начале и конце имени, но и лишние пробелы между отдельными словами. Рассмотрим, как можно сделать это с помощью класса StringBuilder.
string Trim (string sOld)
{
StringBuilder sNew = new StringBuilder();
bool wasSpace = true;
for (int i=0; i<sOld.Length; i++)
{
bool isSpace = sOld[i] == ' ';
if (!(wasSpace && isSpace))
sNew.Append (sOld[i]);
wasSpace = isSpace;
}
return sNew.ToString().TrimEnd();
}
В методе Trim используется объект класса StringBuilder. Он позволяет работать со строкой текста, как с коллекцией символов. Сначала коллекция пуста, затем в цикле прохода по старой строке мы добавляем в нее только те символы, которые считаем нужными. Здесь работает метод Append, который меет 18 перегруженных версий и, поэтому, позволяет очень гибко работать с вновь генерируемой строкой. Обязательно просмотрите справку по этому методу.
Задействуйте процесс унификации имен, добавив в начало обработчика события RowChanged следующий код:
ds.Tables[0].RowChanged -= OnStudsRowChanged;
e.Row["Name"] = Trim(e.Row["Name"].ToString());
ds.Tables[0].RowChanged += OnStudsRowChanged;
На лекции мы осуждали необходимость выключения (см. операции –= и +=) и повторного включения задания делегата, реагирующего на изменения в строке таблицы студентов. Что будет, если пренебречь этим?
Временное выключение делегата необходимо, чтобы не получить бесконечный цикл обработки события RowChanged, так как присвоение e.Row["Name"] вновь генерирует событие RowChanged. Теперь коррекция имени будет производиться не только при добавлении новой строки, но и при изменении существующей. Проверьте это и объясните.
Вспомнив о возможностях класса Regex, разработаем новую версию метода Trim, которая состоит из одной строки кода. Замените существующую версию на новую.
|
string Trim(string s) { return new Regex(@"\s{2,}").Replace(s.Trim(), " "); }
При создании объекта класса Regex мы задаем шаблон регулярного выражения ("\s{2,}"). Мета-символ \s означает space (пустые символы). Шаблон говорит классу Regex, что он должен искать подстроки, которые содержат 2 или более пустых символов. Метод Replace класса Regex осуществляет замену всех найденных в строке s вхождений подстроки, определенной шаблоном, на строку " ", которая содержит только один пробел. Строка s предварительно обрабатывается методом Trim() класса string, что необходимо для уничтожения крайних пробелов.
Еще лучшим решением рассматриваемой проблемы будет добавление в проект класса Helper с методом GetName, который выуживает имя из строки символов с помощью механизма регулярных выражений. Мы использовали такой метод в предыдущей части курса.
|
|
Двойное оплодотворение у цветковых растений: Оплодотворение - это процесс слияния мужской и женской половых клеток с образованием зиготы...
Адаптации растений и животных к жизни в горах: Большое значение для жизни организмов в горах имеют степень расчленения, крутизна и экспозиционные различия склонов...
Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...
Историки об Елизавете Петровне: Елизавета попала между двумя встречными культурными течениями, воспитывалась среди новых европейских веяний и преданий...
© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!