- •В ведение в ado.Net
- •Потребитель данных
- •Поставщики данных
- •Источник данных — xml-файл
- •Элементы управления на форме Меню
- •Как устроены планки меню, статуса и панелей инструментов
- •Планка инструментов (ToolStrip)
- •Навигатор связей
- •Контейнер, расщепляющий форму
- •Создание таблиц и внедрение их в DataSet
- •Пояснения
- •Запись и чтение данных
- •Отображение данных связанной таблицы
- •Добавляем ограничение
- •Вторая, подчиненная таблица
- •Автоматическая навигация по записям связанной таблицы
- •Элемент управления BindingNavigator
- •Реакции на события в DataTable
- •Канонизация имен студентов
- •Вычисляемые колонки DataTable (Expression-Based DataColumn Objects)
- •Поиск в таблице DataTable и в компоненте DataGridView
- •Коррекция пользовательского интерфейса
- •Результат поиска
- •Поиск в DataGridView
- •Отбор данных из DataTable и отображение их в ListView
- •Как легко вносятся ошибки
- •Образ таблицы DataView
- •Методы Find и FindRows класса DataView
- •Задание
- •Элемент управления, который позволяет управлять отображением колонок DataGridView
Как легко вносятся ошибки
Изменение в логике начальной загрузки формы (и данных) кажется очевидным, но такого рода изменения часто приводят к трудно обнаружимым ошибкам. Интересно, заметили ли вы ошибку, которую мы только что внесли?
Просмотрите код метода Open. В нем есть пара операторов, необходимость которых мы показали ранее.
ds.Tables[0].RowChanged -= OnStudsRowChanged;
// Чтение DataSet
ds.Tables[0].RowChanged += OnStudsRowChanged;
Просмотрите код метода RelateAndBind, который вызывается после вызова Open. В нем есть оператор:
ds.Tables[0].RowChanged += OnStudsRowChanged;
Вопрос: сколько заданий в списке InvocationList делегата с сигнатурой RowChanged? Ответ: два. Во избежание подобных ситуаций во многих статьях MSDN рекомендуют всегда добавлять делегатов таким образом.
ds.Tables[0].RowChanged -= OnStudsRowChanged;
ds.Tables[0].RowChanged += OnStudsRowChanged;
Первая строка выглядит глупо, если вы впервые обращаетесь к списку заданий делегата события, но она предотвращает ошибку при повторном обращении. Удаление несуществующей ссылки не нарушает логики приложения, но спасает от повторных реакций на события. Именно так и предлагаю исправить нашу ошибку. В метод RelateAndBind добавьте строку, удаляющую задание делегата перед тем, как его добавить.
Образ таблицы DataView
Этот параграф содержит обзор свойств класса DataView. Вы можете его пропустить, если недостаточно времени. Объект класса DataView не имеет своих данных, он работает с данными ассоциированного с ним объекта DataTable. Методы класса DataView позволяют преобразовать табличные данные. Их можно отфильтровать, или отсортировать. Следующий фрагмент иллюстрирует сказанное.
DataView view = new DataView(ds.Tables[0]); // Создаем образ таблицы студентов
view.RowFilter = "Name LIKE 'C*'"; // Настраиваем фильтр отбора строк
view.Sort = "Addr DESC"; // Настраиваем режим сортировки
viewGrid.DataSource = view; // Привязываем viewGrid к образу таблицы
Предполагается, что на форме есть еще один DataGridView с именем viewGrid. Последний оператор оправдывает необходимость существования класса DataView. Дело в том, что отфильтровать и отсортировать данные можно было бы с помощью метода Select класса DataTable. Для этой цели класс DataView не нужен. Но вот привязать элемент отображения (DataGridView, или ComboBox) к данным, возвращаемым методом Select, нам бы не удалось, так как привязка осуществляется с помощью свойств, а Select возвращает массив объектов DataRow[], каждый из которых можно представить в виде массива обезличенных объектов. Напомню, что класс DataRow имеет два индексатора для выбора полей данных (колонок). Вывод: DataView умеет делать все, что делает метод Select класса DataTable, но добавляет способность привязки к своим данным.
Вы, конечно знаете, что отфильтровать и отсортировать данные реальной таблицы базы данных (БД) можно другим способом — создать SQL-запрос и выполнить его относительно БД. Метод Select класса DataTable — слабое подобие этого подхода.
Класс DataView позволяет фильтровать данные не только по критерию отбора содержимого таблицы, но и по состоянию ее строк. Строки таблицы могут быть в разных состояниях. Следующая таблица поясняет сказанное.
DataViewRowState |
Описание |
Значение |
None |
None |
0 |
Unchanged |
Неизмененные (немодифицированные) строки |
2 |
Added |
Вновь добавленные строки |
4 |
Deleted |
Удаленные строки |
8 |
ModifiedCurrent |
Текущие версии модифицированных строк |
16 |
ModifiedOriginal |
Оригинальные версии модифицированных строк |
22 |
CurrentRows |
Неудаленные строки (объединение флагов ModifiedCurrent, Added, Unchanged) |
32 |
OriginalRows |
Оригинальнне версии удаленных, модифицированных и немодифицированных строк (объединение флагов ModifiedOriginal, Deleted, Unchanged) |
42 |
Для того, чтобы задействовать фильтрацию на основе состояния, к предыдущим настройкам добавим еще одну.
view.RowStateFilter = DataViewRowState.Added;
После этого в DataView попадут только вновь добавленные строки. Благодаря предыдущим настройкам (view.RowFilter = "Name LIKE 'C*'"; и view.Sort = "Addr DESC"), они будут отсортированы по убыванию адресов и в них будут отобраны студенты, имена которых начинаются на букву C. Просмотреть результат фильтрации можно с помощью следующего кодового фрагмента.
for (int i = 0; i < view.Count; i++)
{
DataRowView rv = view[i];
Console.WriteLine(rv["Name"] + ", " + rv["Addr"]);
}
Здесь работает класс DataRowView, который инкапсулирует функциональность образа строки таблицы. Напомним, что в Windows-приложениях просмотр консоли (в окне Output) работает только в режиме отладки.
Все настройки объекта DataView можно задать при помощи одного из конструкторов и не обращаться к свойствам RowFilter, Sort и RowStateFilter, как было показано выше. Например.
DataView view = new DataView (ds.Tables[0], "Name LIKE 'C*'", "Addr DESC", DataViewRowState.Deleted)
{
AllowNew = false,
AllowEdit = false,
AllowDelete = false
};
viewGrid.DataSource = view;
Возможности DataView не превышают возможностей SQL-запросов, они значительно скромнее. Например, с помощью DataView нельзя объединять данные нескольких таблиц (JOIN queries), или исключать какие-то колонки. DataView фильтрует и сортирует полные строки таблицы, результат всегда содержит все колонки таблицы.
