3. Общее представление о привязке данных в Windows Forms

Создание DataGridview с группировкой в столбцах

допустим например что у вас

В качестве примера специального элемента управления с привязкой к данным, созданного как производный класс от существующего элемента управления Framework, давайте создадим специализированную сетку DataGridview, Которая представляет привязанные данные в каждом столбце, группируя элементы данных. Допустим, например, что у вас есть таблица, содержащая сводную информацию по всем продуктам, заказывавшимся каждым клиентом, с указанием даты. Каждый клиент мог несколько раз заказывать один и тот же продукт, и мог размещать несколько различных заказов в один день. Если сортировать данные по клиентам и наименованиям продуктов, в сетке их будет проще читать, если не показывать в каждой строке одно и то же имя клиента или наименование продукта. Гораздо лучше показывать только новые значения, а строки с тем же значением, что и в предыдущей строке, представлять пустыми ячейками и показывать границы ячеек так, чтобы подчеркнуть группировку значений данных

Большинство подобных возможностей можно осуществлять применительно к отдельным случаям внутри форм, где вы используете элементы управления. Но нередко будет разумным инкапсуляция этой логики, чтобы либо отделить ее от остального кода формы, либо упаковать с целью последующей утилизации. Простейшим способом такой инкапсуляции является создание класса, производного от одного из классов элементов управления Windows Forms. Поскольку в данном случае специфицируется определенное поведение и изменяется вид данных в сетке, это хороший кандидат для получения субкласса элемента управления DataGridView. Реализация таких функций не требует написания больших объемов кода, а только переопределения некоторых методов базового класса и небольшого вмешательства в его поведение при форматировании и рисовании.

Генерация при помощи конструктора элементов управления с привязкой

весь этот код может написать

В предыдущих главах вы узнали, как пишется код, реализующий привязку данных типа «ведущий-детализация». Весь этот код может написать за вас конструктор, для чего потребуется пара несложных перетаскиваний мышью из окна Data Sources. Давайте рассмотрим этот процесс поэтапно. Создайте в Visual Studio 2005 новый проект Windows Forms. Когда проект будет создан, добавьте новый источник данных типа Database из окна Data Sources. Выберите подключение к базе данных Northwind, созданное ранее в этой главе, и выберите при помощи мастера таблицы Customers и Orders из этой базы данных. На последнем шаге мастера примите в качестве имени набора данных NorthwindDataSet. Тем самым в проект будет добавлен типизированный набор данных, пригодный для привязки «ведущий-детализация», поскольку таблица Orders связана отношением внешнего ключа с таблицей Customers, и обе эти таблицы отображаются теперь в окне Data Sources под узлом NorthwindDataSet. Если вы развернете в дереве таблицу Customers, то увидите, что наряду со столбцами таблицы, показанными с соответствующими типами элементов управления, которые будут для них генерироваться, имеется еще один элемент DataGridView для таблицы Orders. Перетащите таблицу Customers из окна Data Sources в верхний левый угол формы. Тем самым на форме будет генерирован элемент управления DataGridView, а компоненты BindingSource, BindingNa — vigator, CustomersTableAdapter и NorthwindDataSet на форме с их кодом привязки данных будут включены в файл кода конструктора. Кроме того, в обработчик события Load будет добавлен код, заполняющий набор данных, как вы уже не раз видели. Сетка будет привязана к источнику привязки, а источник привязки, через его свойства Datasource и DataMember, — к таблице Customers в экземпляре NorthwindDataSet.

Параметры @RegioniD и @RegionDescription

однако для большой таблицы сравнение

Параметры @RegioniD И @RegionDescription Были бы заполнены текущими значениями обновляемой строки, а параметры @Original_RegionlD И @Original_RegionDescription — исходными значениями строки, которые сохраняет набор данных. Однако для большой таблицы сравнение значений каждого столбца означает пересылку через соединение с базой данных больших объемов данных туда и обратно. Неплохим компромиссом, если вы контролируете схему базы данных, будет включение столбца временной отметки, версии строки или времени последней модификации, который обновляется всякий раз, когда обновляется какой-либо из столбцов строки. Затем вы, чтобы обнаружить нарушения параллелизма, просто сравниваете значение этого единственного столбца. Другим вариантом является использование некоторого подмножества столбцов в строке для определения того, произошло ли нарушение. Например, если таблица, в которой хранятся большие изображения, содержала бы также их имя, размер и хэш содержимого изображения, вы могли бы сравнивать эти столбцы, чтобы решить, было ли произведено параллельное обновление изображения или нет. Класс SqlDataAdapter Имеет встроенную логику для обнаружения нарушений оптимистической конкуренции, основанную на SQL-переменной @@ROWCOUNT, которая показывает число строк, на которые оказал воздействие исполняемый запрос. Если запрос, который вы исполняете для выполнения обновления, вставки или удаления, указывает, что число подвергшихся воздействию строк было нулевым, адаптер данных возбуждает DBConcurrencyException. Вы можете включиться в эту логику обнаружения как при использовании текстовых SQL-запросов, подобных показанному В Вышеприведенном примере, так и в случае, когда вы производите свои обновления посредством сохраняемой процедуры. Если исполняемый командой запрос, каким бы он ни был, воздействует на нулевое число строк, адаптер данных выбросит исключение, которое вы сможете перехватить и соответствующим образом обработать. Эта логика исходит из того, что число подвергшихся воздействию строк должно быть равно единице, что указывало бы на успешное обновление.

Передача информации об ошибках из специальных объектов через IDataErrorlnfo

например если бы у вас

Если вы используете для привязки данных специальные рабочие объекты, как описывалось в предыдущей главе, вы, возможно, захотите, чтобы эти объекты сами отвечали за определение того, что является, а что не является допустимыми данными. Например, если бы у вас был класс PurchaseOrder, Он мог бы содержать логику, определяющую допустимый диапазон для даты заказа. Или, возможно, логика верификации могла бы включать в себя сложную рабочую логику, которая определяла бы, что заказ размещается по определенной категории продаж в определенный день недели, и тогда цена всех пунктов заказа должна снижаться на 10%. В этом случае ввод цен для пунктов заказа должен сравниваться с катало —

Гом цен и скидкой, предоставляемой в зависимости от цены. В любом случае для рабочих объектов требуется стандартный способ уведомления привязанных элементов управления об ошибках верификации на уровне объекта. И снова на выручку приходят интерфейсы. Интерфейс IDataErrorlnfo предназначен именно для такого сценария. Если индивидуальные элементы данных в ваших коллекциях данных реализуют этот интерфейс, привязанные к данным элементы управления могут использовать его для определения того, не произошла ли ошибка, что это за ошибка и с каким свойством объекта она связана. Интерфейс IDataErrorlnfo Имеет два элемента: строковое свойство с именем Error И индексатор , Который принимает строковый параметр и возвращает строку. Индексатор принимает имя свойства или столбца в объекте данных и должен возвращать ошибку, соответствующую этому свойству, если таковая имеется. Это соответствует способу отображения ошибок в DataGridView. Как уже говорилось, DataGridView Может отображать ошибки как на уровне строки, так и на уровне ячейки. Свойство Error Интерфейса IDataErrorlnfo Соответствует ошибке уровня строки, а сообщения об ошибках, возвращаемые индексатором Item, Соответствуют ошибкам уровня ячейки.

Поиск в наборах данных

не забывайте что b dataset

Когда вы заполните набор данных, вам часто бывает нужна возможность поиска и выбора данных внутри него, либо для выполнения обновлений или обработки на каком-то подмножестве данных, либо для целей отображения. Не забывайте, что DataSet И родственные ему классы не предназначены для использования в качестве высокоэффективной машины запросов. Хотя вы можете выбирать и фильтровать данные в таблице данных на стороне клиента, во многих случаях может оказаться быстрее просто исполнить новый, более специализированный запрос к базе данных, чтобы получить специфические результаты, которые вы ищете. Это особенно верно при работе с локальным экземпляром базы данных, таким, как база данных SQL Express. Однако если данные уже находятся в памяти в DataSet, И вы хотите выбрать некоторые элементы, не путешествуя к базе данных и обратно, можно применить несколько подходов. Простейшим является использование метода Select Класса DataTable, Позволяющий исполнять SQL-подобные запросы к данным, содержащимся в таблице. Вы можете также использовать псевдотаблицы, чтобы фильтровать данные в соответствии с критериями отбора, либо использовать класс XmlDataDocument, Чтобы загрузить данные в контейнер XML-документа и исполнять на них запросы XPath. У метода Select Есть несколько перегрузок, которые позволяют вам искать по строковому критерию, напоминающему предложение WHERE в SQL, и опционально передавать порядок сортировки или перечисление DataRowviewState, Чтобы искать среди записей в определенном состоянии или состояниях. Метод Select Возвращает массив объектов DataRow, Содержащих ссылки на строки, удовлетворяющие критерию отбора. Как только вы получите этот массив строк, вы можете итерировать их и производить над ними любую необходимую обработку. Вы работаете с живыми ссылками на действительные строки в наборе данных, поэтому любые сделанные в них изменения немедленно повлияют на данные в наборе данных. Следующий код показывает операцию Select На наборе данных Customers с использованием двух перегрузок метода.