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

Свойство Cancel EventArgs. Cancel

прежде всего фокус ввода не

Когда вы в своем обработчике события Validating Устанавливаете свойство CancelEventArgs.Cancel В True, Происходит следующее. Прежде всего, фокус ввода не покинет этот элемент управления, заставляя пользователя исправить проблему, прежде чем он сможет перейти к вводу данных в другие элементы управления. Во многих ситуациях это неплохо, так как не дает пользователям уйти слишком далеко от того контекста, где они ошиблись во вводе, прежде чем они исправят ошибку. Это также предотвратит запуск события Validated, Поскольку процесс верификации не был завершен.

Однако при таком подходе возникает несколько проблем. Во-первых, вы, возможно, не всегда захотите заставлять пользователей исправлять свои ошибки немедленно; можно позволить им заполнить все поля формы и только потребовать, чтобы они решили любые возникшие проблемы перед тем, как послать или сохранить данные. Это позволит быстро вводить данные тем людям, которым целыми днями приходится заполнять одну и ту же форму. В таких случаях они, переходя от поля к полю, обычно не смотрят все время на форму и могут не увидеть, что из-за ошибки верификации фокусу не было разрешено перейти на следующий элемент управления. Другая проблема состоит в том, что если пользователи пытаются закрыть форму с ошибками верификации, которые обрабатывались посредством отмены события Validating, По умолчанию они не смогут этого сделать. Действие щелчка на другом элементе управления, например, на кнопках обрамления окна, вызывает переключение фокуса, что запускает верификацию, которая не удается и возвращает фокус обратно на элемент управления, где произошла ошибка. Наконец, этот подход требует, чтобы элемент управления сначала получил, а затем отдал фокус другому элементу управления, прежде чем будет активирован процесс верификации. К счастью, .NET 2.0 вводит в классе Form Свойство AutoValidate, Которое позволяет вам точно специфицировать, каким должно быть поведение в случае, когда ошибка верификации происходит на уровне элемента управления. Это свойство обсуждается позднее в этой главе.

Создание 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, Соответствуют ошибкам уровня ячейки.