Ðàçðàáîòêà ôîðì Windows ñ èñïîëüçîâàíèåì ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ  ÝÒÎÉ ÃËÀÂÅ... • Óïðàæíåíèå 1.1. Ñîçäàíèå ñâÿçàííîãî ñïèñêà • Óïðàæíåíèå 1.2. Îïðåäåëåíèå ñîñòàâà äàííûõ, îòîáðàæàåìûõ â ñâÿçàííîì ñïèñêå • Óïðàæíåíèå 1.3. Ñâÿçûâàíèå è ïðîñìîòð îòäåëüíûõ òåêñòîâûõ ïîëåé ñ îòñ÷åòîì îò âûáðàííîãî ýëåìåíòà ñïèñêà • Óïðàæíåíèå 1.4. Ðåäàêòèðîâàíèå è îáíîâëåíèå äàííûõ ñ èñïîëüçîâàíèåì ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ • Óïðàæíåíèå 1.5. Äîáàâëåíèå è óäàëåíèå çàïèñåé ñ èñïîëüçîâàíèåì ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ • Óïðàæíåíèå 1.6. Îáðàáîòêà îøèáîê ñ ïîìîùüþ ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ • Óïðàæíåíèå 1.7. Îêîí÷àòåëüíîå îôîðìëåíèå ôîðìû, ñâÿçàííîé ñ äàííûìè • Óïðàæíåíèå 1.8. Ñâÿçûâàíèå äàííûõ ñ ýëåìåíòàìè óïðàâëåíèÿ ComboBox è DataGrid • Óïðàæíåíèå 1.9. Ïîâûøåíèå ñòåïåíè äåòàëèçàöèè ïðåäñòàâëåíèÿ äàííûõ â ýëåìåíòå óïðàâëåíèÿ DataGrid ÃËÀÂÀ 1 24 Глава 1 Visual Basic .NET — это один из языков, который входит в поставку программного продукта Visual Studio .NET. Он является гораздо более мощным по сравнению с язы ком Visual Basic 6.0. В этом можно убедиться, прочитав настоящую книгу. В предыдущих версиях Visual Basic для привязки элементов управления к данным нуж но было ввести в программу определенный код вручную; для этого приходилось выпол нять более значительный объем работы по сравнению с использованием связанных эле ментов управления. Но в этих версиях применение элементов управления, связанных с данными, было затруднительным, поскольку они не обеспечивали полный контроль над процессом обработки данных. Подготавливая к выпуску версию языка VB.NET, корпора ция Microsoft проделала очень большую работу. Были созданы не только развитые элемен ты управления, связанные с данными, но и обеспечена возможность автоматической ге нерации необходимого кода при размещении в форме связанных с данными элементов управления, поскольку организация всех языков .NET основана на использовании классов. В предыдущих версиях Visual Basic для создания баз данных небольшого и среднего объема в основном применялась машина базы данных Microsoft Jet, и в книгах, подобных этой, как правило, рассматривался способ доступа к данным, основанный на ее использо вании. Теперь в поставку программного обеспечения языка Visual Basic входит версия сер вера Microsoft SQL Server 2000 для настольного компьютера (MSDE — Microsoft SQL Server 2000 Desktop Edition). Это — упрощенная версия сервера SQL Server 2000, позво ляющая разрабатывать базы данных на одном компьютере, а эксплуатировать — на другом. При этом на компьютере может быть установлена либо однопользовательская локальная версия MSDE, либо полнофункциональная версия SQL Server 2000. В настоящей книге по казано, как использовать базу данных SQL Server в программе Visual Studio и в конкретных приложениях. В частности, здесь описан способ создания утилит для подключения к но вым базам данных, а также для резервного копирования и восстановления баз данных. Хотя в настоящей книге в качестве базы данных используется MSDE, для перехода на другую версию базы данных достаточно откорректировать свойство ConnectionString объекта OleDbConnection в формах и свойство ConnectionString объекта OleDbConnection, рассматриваемое в главе 4, “Манипулирование данными в среде ADO.NET”. Обратите внимание, что в коде, приведенном в указанной выше главе, имеется закомментированная строка, которая показывает, как использовать версию базы данных Northwind на основе машины баз данных Jet. Óïðàæíåíèå 1.1. Ñîçäàíèå ñâÿçàííîãî ñïèñêà Обычно при создании формы базы данных применялся подход, при котором дос таточно было связать с элементом данных набор записей и дать возможность пользо вателям выполнять прокрутку строк с данными, а также вносить в них изменения по мере необходимости. Но такой подход не всегда оправдывается при создании прило жений клиент/сервер или Webприложений. Дело в том, что следует, прежде всего, обеспечить возможность ограничения объ ема данных, предоставляемых пользователям, чтобы они могли выбирать только те записи, которые необходимо редактировать или просматривать. Это позволяет не передавать все поля таблицы по локальной сети или по Internet. Для этой цели могут применяться элементы управления списком и полем со списком. В настоящем упраж Разработка форм Windows с использованием связанных элементов... 25 нении показано, как применяются в программных приложениях два элемента управ ления данными: OleDbDataAdapter и DataSet. Эти элементы управления дают воз можность заполнить список с помощью единственной строки кода. Предположим, что необходимо обеспечить просмотр списка пользователей в форме Windows с помощью элемента управления ListBox. На данном этапе решения этой задачи не разрабатывается программа. Создается только прототип формы, по этому достаточно применить связанные с данными элементы управления. Рассмотрим способ создания списка и связывания его с данными с помощью элементов управле ния данными. Îáùåå îïèñàíèå Прежде чем приступить к изучению объектов, применяемых для представления данных в среде .NET, необходимо рассмотреть пространства имен .NET и способы их использования. Ïðèìåíåíèå ïðîñòðàíñòâ èìåí .NET Инфраструктура .NET содержит большую библиотеку классов, которая состоит из множества пространств имен. Эти пространства имен включают разнообразные клас сы, позволяющие создавать в программе собственные объекты. В пространствах имен представлены все объекты и классы, которые входят в состав таких объектов .NET, как формы, элементы управления и всевозможные объекты данных. Пространство имен может, в свою очередь, состоять из других пространств имен. Например, пространство имен System.Data включает не только собственные клас сы, такие как DataSet и DataTable, но и пространства имен System.Data.OleDb, System.Data.SQLClient и т.д. Для ознакомления с пространствами имен .NET вы берите команду Object Browser в меню View. Затем можно раскрыть пространство имен System.Data для просмотра содержащихся в нем пространств имен. Если известно, что в качестве базы данных для приложения должна использовать ся база данных SQL Server, то для обеспечения более высокой производительности этого приложения следует применять классы, которые относятся к пространству имен System.Data.SQLClient. Но если тип базы данных, применяемой в приложе нии, заранее не известен, то следует использовать классы пространства имен System.Data.OleDb. В настоящей книге используются объекты, созданные с помощью классов про странства имен System.Data.OleDb. Поэтому представленные здесь процедуры мо гут применяться для работы с другими базами данных без значительной доработки. Совет Åñëè èçâåñòíî, ÷òî â ïðèëîæåíèè â êà÷åñòâå áàçû äàííûõ ïðèìåíÿåòñÿ áàçà äàííûõ SQL Server, òî â ýòîì ïðèëîæåíèè ñëåäóåò èñïîëüçîâàòü ýëåìåíòû óïðàâëåíèÿ äàííûìè òèïà SQL Server, ïîñêîëüêó îíè îïòèìèçèðîâàíû äëÿ ðàáîòû èìåííî ñ íåé. Для создания форм Windows предназначено восемь элементов управления данны ми. В табл. 1.1 перечислены эти элементы управления и описано их назначение. Что бы получить к ним доступ, щелкните на группе элементов Data панели инструментов. 26 Глава 1 Òàáëèöà 1.1. Ýëåìåíòû óïðàâëåíèÿ äàííûìè, ïðèìåíÿåìûå äëÿ ñîçäàíèÿ ôîðì Windows Элемент управления Назначение DataSet Используется в сочетании с другими элементами управления дан ными; он позволяет сохранить результаты, возвращенные команда ми и адаптерами данных DataAdapter. В отличие от наборов запи сей, применяемых в технологиях ADO и DAO, элемент управления DataSet фактически позволяет вернуться к иерархическому пред ставлению данных. Свойства и коллекции объекта DataSet дают возможность получить полный доступ к отдельным таблицам, стро кам и столбцам OleDbDataAdapter Дает возможность управлять командами, которые должны быть приме нены к такому провайдеру данных OleDb, как Jet, Oracle или SQL Server, и хранить их. В частности, могут применяться команды выборки, об новления, вставки и удаления записей. Отслеживается также объект со единения Connection, к которому применяются эти команды OleDbConnection Позволяет сопровождать информацию о соединении для провайде ра данных OleDb. Он применяется в сочетании с элементом управ ления OleDbDataAdapter OleDbCommand Как и объект команды ADO, позволяет передавать в базу данных операторы SQL или хранимые процедуры для выполнения трудо емких операций или выборки данных SqlDataAdapter Аналогичен OleDbDataAdapter за исключением того, что он при меняется для доступа только к хранилищам данных SQL Server SqlConnection Аналогичен OleDbConnection за исключением того, что он при меняется для доступа только к хранилищам данных SQL Server SqlCommand Аналогичен OleDbCommand за исключением того, что он применя ется для доступа только к хранилищам данных SQL Server DataView Позволяет создать несколько представлений одной и той же табли цы. В частности, он обеспечивает возможность просматривать дан ные, находящиеся в различных состояниях, например, удаленные, модифицированные или отсортированные различным образом Ниже показано, как создать элементы управления данными двух описанных выше ти пов, OleDbDataAdapter и DataSet, и связать их с элементом управления списком для отображения перечня заказчиков. Следует отметить, что при этом создается также эле мент управления OleDbConnection, но эта операция выполняется в среде Visual Studio .NET. После этого достаточно ввести одну строку кода, чтобы заполнить набор данных. Ïîðÿäîê äåéñòâèé Для предварительного просмотра результатов этого упражнения откройте прило жение VB.NET - Chapter1, которое находится в папке данной главы (см. следующее примечание). Сразу после вызова на выполнение проекта этого приложения откры вается форма, с помощью которой можно получить доступ к материалам всех упраж нений, рассматриваемых в данной главе. Щелкните на элементе How-To 1.1, чтобы открыть форму для упражнения 1.1 (рис. 1.1). Разработка форм Windows с использованием связанных элементов... 27 Ðèñ. 1.1. Главная форма и форма HowTo 1.1 из первого упражнения этой главы Примечание Èñõîäíûé êîä óïðàæíåíèé êî âñåì ãëàâàì ýòîé êíèãè ïðåäñòàâëåí íà ñîïðîâîæäàþùåì Web-óçëå www.samspublishing.com. Ïåðåéäèòå ïî óêàçàííîìó àäðåñó, óêàæèòå â êà÷åñòâå ïîèñêîâîé ñòðîêè ISBN àíãëîÿçû÷íîãî èçäàíèÿ (0672322471) è çàãðóçèòå àðõèâ ñ èñõîäíûì êîäîì è ãîòîâûìè ïðèëîæåíèÿìè. 1. Создайте новый проект Visual Studio .NET с использованием шаблона проекта Windows Application. В результате будет создана начальная форма с именем Form1, которая используется и в дальнейшем. 2. Перетащите на форму элемент управления OleDbDataAdapter из группы эле ментов Data Controls, находящейся на панели инструментов. Откроется окно мас тера настройки конфигурации адаптера данных Data Adapter Configuration Wizard. Прочитайте вступительный текст на экране, а затем щелкните на кнопке Next, чтобы выбрать соединение данных. Если в данный момент вы не можете найти соединение данных с базой данных Northwind в раскрывающемся списке соединений данных, щелкните на кнопке New Connection. После этого откроется диалоговое окно свойств канала передачи данных Data Link Properties, знакомое тем, кто уже использовал другие программные продукты Microsoft, такие как Visual Studio 6.0. Укажите в качестве имени сервера (local), выберите пере ключатель Use Windows NT Integrated Security, который обеспечивает использо вание встроенных средств защиты Windows NT, укажите в качестве базы данных Northwind (рис. 1.2) и щелкните на кнопке OK. 3. После этого снова откроется страница выбора соединения данных Choose Your Data Connection программы Data Adapter Configuration Wizard, на которой в раскрывающемся списке Data Connection будет отмечена база данных Northwind. Щелкните на кнопке Next. Теперь откроется страница, позволяю щая выбрать тип запроса, на использовании которого будет основан приме няемый адаптер данных. Оставьте предусмотренное по умолчанию значение Use SQL Statements (Использовать операторы SQL) и щелкните на кнопке Next. Откроется поле ввода, обозначенное вопросом What Data Should the Data Adapter Load into the Dataset? (Какие данные должны загружаться этим адапте ром данных в набор данных?) Введите в этом поле следующее: Select CustomerID, CompanyName From Customers 28 Глава 1 Ðèñ. 1.2. Соединение данных, которое в дальнейшем будет использоваться по умолчанию в окне Server Explorer программы Visual Studio .NET на этом компьютере Примечание Ïî óìîë÷àíèþ ïðîãðàììà-ìàñòåð Data Adapter Configuration Wizard ñîçäàåò îïåðàòîðû SQL íå òîëüêî äëÿ âûáîðêè (ïðîñìîòðà) äàííûõ, íî òàêæå äëÿ âñòàâêè, îáíîâëåíèÿ è óäàëåíèÿ äàííûõ. Åñëè âû õîòèòå èñïîëüçîâàòü â ñâîèõ ïðèëîæåíèÿõ òîëüêî ñðåäñòâà âûáîðêè äàííûõ, òî ùåëêíèòå íà êíîïêå Advanced Options (Äîïîëíèòåëüíûå îïöèè) â ëåâîì íèæíåì óãëó ýòîãî äèàëîãîâîãî îêíà. Ñíèìèòå îòìåòêó ñ ôëàæêà Generate Insert, Update, and Delete statements.  ðàññìàòðèâàåìîì ïðèëîæåíèè îïåðàòîðû Insert, Update è Delete íå òðåáóþòñÿ, ïîñêîëüêó äàííûå â íåì ïðèìåíÿþòñÿ òîëüêî äëÿ çàïîëíåíèÿ ýëåìåíòà óïðàâëåíèÿ ListBox. Ùåëêíèòå íà êíîïêå OK, ÷òîáû çàêðûòü äèàëîãîâîå îêíî Advanced Options. 4. Щелкните на кнопке Next для просмотра результатов выполнения оператора выборки, как показано на рис. 1.3. Если внешний вид окна будет отличаться от показанного на рис. 1.3, это означает, что вы неправильно ввели оператор Select или не отменили использование дополнительных опций. 5. Щелкните на кнопке Finish, чтобы создать адаптер данных и объект соединения. Затем на экране появится новый элемент адаптера данных, обозначенный как OleDbDataAdapter1, и элемент управления соединением OleDbConnection1. Оба эти элементы управления находятся в области Components в нижней части ок на Form Designer. 6. После создания первых двух элементов управления необходимо перейти к созда нию объекта Dataset. Щелкните правой кнопкой мыши на команде Data Adapter и выберите элемент Generate Dataset из всплывающего меню. Откроется диалоговое окно Generate Dataset. Оставьте неизменными все значения, предусмотренные по Разработка форм Windows с использованием связанных элементов... 29 умолчанию, и просто щелкните на кнопке OK, чтобы создать элемент управления набором данных, обозначенный как DataSet<number>. (Порядковый номер <number> увеличивается по мере создания новых элементов управления набором данных.) 7. Теперь можно приступить к созданию элемента управления ListBox. Перета щите на форму элемент управления ListBox из группы элементов Windows Forms панели инструментов. Растяните окно этого элемента управления до размеров формы, а затем задайте для элемента управления ListBox значения свойств, приведенные в табл. 1.2. Ðèñ. 1.3. Пример успешного создания адаптера данных Òàáëèöà 1.2. Çíà÷åíèÿ ñâîéñòâ ýëåìåíòà óïðàâëåíèÿ ListBox, íåîáõîäèìûå äëÿ ñâÿçûâàíèÿ åãî ñ ýëåìåíòîì óïðàâëåíèÿ DataSet Свойство Значение DataSource DataSet<Number> DisplayMember Customers.CompanyName ValueMember Customers.CustomerID Хотя этот набор данных правильно связан со свойствами элемента управления ListBox, в данный момент после вызова формы на выполнение в ней откроет ся пустой элемент управления ListBox. 8. На данном этапе выполнения рассматриваемого упражнения осталось ввести в об работчик событий Load формы единственную строку кода. Щелкните на кнопке View Code в окне Solutions Explorer или выберите команду Code в меню View. В окне Code Editor выберите из раскрывающегося списка имен классов Class Name строку, соответствующую основным объектам класса (Base Class Objects), а затем выбери те Load из раскрывающегося списка Methods. После этого введите приведенную ниже строку кода, представляющую собой команду для адаптера данных, согласно которой он должен заполнить данными набор данных: 30 Глава 1 OleDbDataAdapter1.Fill(DataSet1) Проследите за тем, чтобы в этой команде использовались имена созданных ва ми элементов управления. В листинге 1.1 приведен код обработчика событий Load для формы frmHowTo1_1, используемой в этих примерах. Ëèñòèíã 1.1. frmHowTo1_1.vb — çàïîëíåíèå íàáîðà äàííûõ, ñ êîòîðûì ñâÿçàí ýëåìåíò óïðàâëåíèÿ ListBox1 Private Sub frmHowTo1_1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.OleDbDataAdapter1.Fill(Me.DataSet1) End Sub Îïèñàíèå ïîëó÷åííûõ ðåçóëüòàòîâ После загрузки формы frmHowTo1_1 вызывается метод Fill элемента управления OleDbDataAdapter1 и ему передается набор данных DataSet1. Поскольку в качестве значения свойства DataSource элемента управления ListBox1 указано имя DataSet1, а значения свойств ValueMember и DisplayMember заданы соответст вующим образом, то элемент управления ListBox1 заполняется данными из столбцов CustomerID и CompanyName таблицы Customers базы данных Northwind. На рис. 1.4 показано, какой окончательный вид имеет эта форма в окне программы Designer, а на рис. 1.5 показано, какой вид она принимает после вызова ее на выполнение. Ðèñ. 1.4. Окончательный вид проекта первого упражнения по использованию базы данных Разработка форм Windows с использованием связанных элементов... 31 Ðèñ. 1.5. Список, содержащий данные таблицы Customers базы данных Northwind SQL Server Êîììåíòàðèè При разработке версии языка Visual Basic для инфраструктуры .NET корпорация Microsoft предприняла значительные усилия по обеспечению надежного функциониро вания элементов управления данными. Одной из замечательных особенностей новых версий элементов данных является то, что пользователь имеет возможность проследить за выполнением большинства задач с помощью языка Visual Basic .NET. Даже если функционирование элементов управления данными, размещенных в форме, обеспечи вается автоматически, при этом в среде Visual Studio создается код, выполняющий соот ветствующие действия. Для просмотра этого кода можно щелкнуть на элементе #Region, который выглядит примерно так: #Region " Windows Form Designer generated code " Следует учитывать, что под этим элементом представлен большой объем кода, и разработчик не должен вносить в него изменения. Но изучение такого кода позволяет узнать очень многое. По мере дальнейшего использования представленных здесь элементов управления данными вы успешно освоите основные способы модификации различных свойств этих элементов управления и узнаете, какие возможности они предоставляют. Óïðàæíåíèå 1.2. Îïðåäåëåíèå ñîñòàâà äàííûõ, îòîáðàæàåìûõ â ñâÿçàííîì ñïèñêå Если в таблице содержится много данных, то заполнение списка данными даже из нескольких столбцов требует больших затрат вычислительных ресурсов. В этом уп ражнении показано, как создать параметризованный оператор SQL для ограничения количества элементов, отображаемых в списке, что позволяет уменьшить потреб ность в ресурсах и тем самым повысить производительность выполнения форм. Предположим, что в базе данных содержатся данные о сотнях тысяч заказчиков и поэтому не следует загружать в элемент управления списком сразу всю таблицу заказ чиков. Ниже описаны способы ограничения объема данных, отображаемых в списке. 32 Глава 1 Îáùåå îïèñàíèå Прежде всего, необходимо сделать копию формы, созданной в упражнении 1.1. Затем в форму нужно ввести элементы управления Label и TextBox, из которых в оператор Select, содержащийся в элементе управления OleDbDataAdapter, будет поступать информация, позволяющая ограничить объем данных, отображаемых в списке. Кроме того, в форму будет введена кнопка, позволяющая вызывать метод Fill элемента управления OleDbDataAdapter после каждого обновления содержи мого текстового поля и щелчка на ней (рис. 1.6). Ðèñ. 1.6. Форма, позволяющая ограничить объем данных, загружаемых в список Ïîðÿäîê äåéñòâèé Чтобы приступить к выполнению этого упражнения, щелкните правой кнопкой мыши на форме, созданной в упражнении 1.1, которая должна быть указана в перечне форм окна Solutions Explorer. Выберите команду Copy из всплывающего меню. Затем щелкните правой кнопкой мыши на этом проекте в окне Solutions Explorer и выберите команду Paste из всплывающего меню. Теперь в окне Solutions Explorer появится но вый объект Class с именем Copy Of<предыдущее имя формы>. Присвойте вновь соз данной форме произвольное имя. Затем выделите подсветкой эту форму и щелкните на кнопке Code в верхней части окна Solutions Explorer. Откорректируйте первую строку кода следующим образом: Public Class <новое имя формы> Вполне очевидно, что эта строка кода не была откорректирована в среде VS авто матически после изменения имени формы. Дело в том, что разработчик мог просто создать дубликат определения объекта Class, поэтому такая корректировка не долж на выполняться автоматически. После этого вы обнаружите, что пиктограмма рассматриваемой формы имеет пра вильное имя. Теперь можно приступить к выполнению дальнейших этапов этого уп ражнения. 1. Выберите созданный вами адаптер данных. В области окна Properties после щелчка на знаке “плюс” (+) рядом со свойством SelectCommand будет показано свойство CommandText. Замените текущее значение свойства CommandText (Текст команды) следующей командой: Разработка форм Windows с использованием связанных элементов... 33 SELECT CustomerID, CompanyName FROM Customers WHERE (CompanyName LIKE ? + '%') Дополнительная информация об операторе Select представлена в главе 3, “Просмотр данных с применением средств ADO.NET”. Однако отметим, что в при меняемой здесь конструкции WHERE предусмотрено сравнение содержимого поля CompanyName с заданным параметром, как показывает применяемая здесь опера ция, обозначенная как ? (вопросительный знак). Это действие выполняется с ис пользованием кода, который будет рассматриваться на последнем этапе данного упражнения. Знак процента (%) представляет собой подстановочный символ, кото рый указывает серверу, что должен быть выполнен поиск подстроки. 2. Измените размеры окна элемента управления ListBox и освободите место в верхней части формы для элементов управления Label, TextBox и Button. Создайте эти три элемента управления и откорректируйте значения их свойств, как показано в табл. 1.3. Òàáëèöà 1.3. Çíà÷åíèÿ ñâîéñòâ ýëåìåíòîâ óïðàâëåíèÿ Label, TextBox è Button Объект Свойство Значение Label Text Customer TextBox Name txtCustLimit Text A Name btnLoadList Text Load List Button 3. Дважды щелкните на вновь созданной кнопке, обозначенной как btnLoadList. Введите в обработчик событий Click кнопки btnLoadList код, приведенный в листинге 1.2. Этот код загружает данные, введенные в поле txtCustLimit, в па раметр OleDBDataAdapter1, который был создан с помощью операции ? в опе раторе Select адаптера данных. После этого происходит уничтожение всех дан ных, хранящихся в наборе данных Dataset1, с помощью метода Clear. И нако нец, объект DataSet1 снова заполняется данными с учетом значения txtCustLimit; для этого применяется адаптер данных. Ëèñòèíã 1.2. frmHowTo1_2.vb — ïåðåäà÷à ïàðàìåòðà îáúåêòó DataAdapter è çàïîëíåíèå íàáîðà äàííûõ Private Sub btnLoadList_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles _ btnLoadList.Click Me.OleDbDataAdapter1.SelectCommand.Parameters(0).Value = _ Me.txtCustLimit.Text Me.DataSet1.Clear() Me.OleDbDataAdapter1.Fill(Me.DataSet1) End Sub 4. Выделите подсветкой и удалите из формы обработчик событий Load, посколь ку здесь не ставится задача заполнять форму, перехватывая это событие при ее 34 Глава 1 загрузке. В данном случае предусмотрено, что пользователь должен щелкнуть на кнопке btnLoadList. Примечание Ìåæäó ýëåìåíòàìè óïðàâëåíèÿ OleDbDataAdapter è SqlDataAdapter åñòü îäíî âàæíîå ðàçëè÷èå. Ýëåìåíò óïðàâëåíèÿ OleDbDataAdapter ïðåäóñìàòðèâàåò èñïîëüçîâàíèå îïåðàöèè ? äëÿ óêàçàíèÿ ïàðàìåòðà â îïåðàòîðå Select, à äëÿ ýëåìåíòà óïðàâëåíèÿ SqlDataAdapter òðåáóåòñÿ èìåíîâàííûé ïàðàìåòð, òàêîé êàê @parCustLimit. Ïîýòîìó âìåñòî óêàçàííîãî â øàãå 1 ñëåäóþùåãî îïåðàòîðà Select: SELECT CustomerID, CompanyName FROM Customers WHERE (CompanyName LIKE ? + '%') ïðèìåíÿåòñÿ îïåðàòîð Select â òàêîé ôîðìå: SELECT CustomerID, CompanyName FROM Customers WHERE (CompanyName LIKE @parCustLimit + '%') Ïðè ýòîì ôàêòè÷åñêè ïðèìåíÿåìîå èìÿ ïàðàìåòðà çàâèñèò îò êîíêðåòíîé ïðîãðàììû. Îïèñàíèå ïîëó÷åííûõ ðåçóëüòàòîâ После загрузки формы, созданной в этом упражнении, или вызова на выполнение формы frmHowTo1_2 появляются пустой элемент управления ListBox и располо женное над ним текстовое поле с введенной в нем буквой A. После щелчка на кнопке btnLoadList окно списка загружается значениями, которые соответствуют букве (или буквам), введенной в элементе управления txtCustLimit, с помощью кода, описанного в шаге 3. Êîììåíòàðèè Попытайтесь ввести несколько других букв, а затем очистить поле ввода. При этом ко личество отображаемых строк уменьшается по мере увеличения количества введенных букв, а если в текстовом поле не введено ни одной буквы, отображаются все записи. Описанный здесь метод является простым, но достаточно мощным и может при меняться во многих приложениях. Рассматриваемая форма будет использоваться еще в нескольких упражнениях. Вы можете скопировать эту форму и на ее основе начать разработку новой, как описано в начале данного упражнения. Еще один вариант состоит в том, что ко времени выпол нения упражнения 1.8 будет разработана форма ввода данных, которую можно ис пользовать в дальнейшей работе. Тем не менее для каждого упражнения, описанного в этой главе, имеется готовое решение. Разработка форм Windows с использованием связанных элементов... 35 Óïðàæíåíèå 1.3. Ñâÿçûâàíèå è ïðîñìîòð îòäåëüíûõ òåêñòîâûõ ïîëåé ñ îòñ÷åòîì îò âûáðàííîãî ýëåìåíòà ñïèñêà В настоящем упражнении на примере списка, аналогичного описанному в пре дыдущем упражнении, будет показано, как создать дополнительные объекты OleDbDataAdapter и DataSet и связать их с отдельными текстовыми полями для просмотра данных. Списки являются удобным средством отображения ряда полей формы и ограни чения количества выводимых строк, но иногда возникает необходимость ознако миться с подробными сведениями, представленными в отдельных текстовых полях, выполнив щелчок на элементе в списке. Îáùåå îïèñàíèå На данном этапе дорабатывается форма, созданная в упражнении 1.2; в эту фор му вводятся дополнительные элементы управления данными, в частности, еще один адаптер данных и набор данных. Здесь также показано, как ввести в новый адаптер данных оператор Select, который принимает в качестве параметра выбранный элемент списка. После этого набор данных заполняется данными и в текстовых по лях отображаются поля текущей записи, полученные с использованием рассматри ваемого набора данных в качестве источника данных. Пример полученных резуль татов показан на рис. 1.7. Ðèñ. 1.7. Пример связывания с набором данных текстовых полей, а не списков Ïîðÿäîê äåéñòâèé В процессе дальнейшей разработки рассматриваемой формы необходимо переимено вать адаптер данных, набор данных и список, которые в настоящее время представлены в форме, и присвоить им более содержательные имена, которые приведены в табл. 1.4. Глава 1 36 Òàáëèöà 1.4. Èçìåíåíèÿ, âíåñåííûå â îáúåêòû, êîòîðûå â íàñòîÿùåå âðåìÿ ïðåäñòàâëåíû â ôîðìå Объект Свойство Старое значение Новое значение ListBox Name ListBox1 lstCustomers OleDbDataAdapter Name OleDbDataAdapter1 odaCustomerList DataSet Name DataSet1 dsCustomerList Совет Ïðèñâàèâàéòå èìåíà îáúåêòàì íåïîñðåäñòâåííî âî âðåìÿ èõ ñîçäàíèÿ. Ýòà ðåêîìåíäàöèÿ îòíîñèòñÿ êî âñåì ïðîãðàììàì, ïðîåêòàì è ôîðìàì, à òàêæå ê ýëåìåíòàì óïðàâëåíèÿ, êîòîðûå èñïîëüçóþòñÿ â ôîðìàõ. ßçûêè, ïðèìåíÿåìûå â ñðåäå .NET, ÿâëÿþòñÿ îáúåêòíî-îðèåíòèðîâàííûìè è îáåñïå÷èâàþò àâòîìàòè÷åñêóþ âûðàáîòêó áîëüøîãî îáúåìà êîäà, ïîýòîìó ïðîöåññ ïåðåèìåíîâàíèÿ îáúåêòîâ ïîñëå èõ ñîçäàíèÿ ÿâëÿåòñÿ âåñüìà ñëîæíûì.  ÷àñòíîñòè, åñëè òàêîå ïåðåèìåíîâàíèå âûïîëíÿåòñÿ â ñðåäå Visual Studio, òî, ïî-âèäèìîìó, ïðè ýòîì íå ó÷èòûâàþòñÿ âñå ó÷àñòêè êîäà, êîòîðûå äîëæíû áûòü îòêîððåêòèðîâàíû.  êà÷åñòâå íàãëÿäíîãî ïðèìåðà ìîæíî óêàçàòü ïåðåèìåíîâàíèå ôîðìû.  ÷àñòíîñòè, íàïîìíèì, ÷òî íàì ïðèøëîñü îòêîððåêòèðîâàòü â êîäå îïåðàòîð Public Class, ÷òîáû îí ñîîòâåòñòâîâàë íîâîìó èìåíè ôîðìû. 1. Перетащите на форму еще один элемент управления Data Adapter, взяв его из группы Data на панели инструментов. Примените существующее соединение данных, укажите, что будут применяться операторы SQL, и присвойте этому эле менту управления следующий оператор Select, в котором используется пара метр, заданный во время выполнения с помощью выбранного элемента списка. SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Country, Phone, Fax FROM Customers WHERE (CustomerID = ?) После этого щелкните на кнопке Advanced Options на странице с оператором Select и отмените опцию создания операторов Insert, Update и Delete. За вершите работу в программе Data Adapter Wizard и переименуйте элементы управления odaCustomerIndividual. 2. Щелкните правой кнопкой мыши на элементе odaCustomerIndividual и вы берите команду Generate Dataset из всплывающего меню. Создайте новый на бор данных dsCustomerIndividual. Щелкните на кнопке OK. Ко времени на писания данной книги в среде VS предусматривалось размещение символа 1 в конце имени указанного набора данных. Откорректируйте это имя, удалив сим вол 1. Теперь в вашей форме должно быть два адаптера данных (odaCustomerList и odaCustomerIndividual) и два набора данных (dsCustomerList и dsCustomerIndividual). 3. На этом этапе необходимо ввести текстовые поля. Откорректируйте размеры формы, чтобы в нее можно было добавить столбец, состоящий из текстовых полей с надписями рядом с ними. Затем введите надписи и текстовые поля; укажите в качестве свойства Text текстовых полей имена столбцов в таблице Customers, к которым предоставляется доступ с помощью набора данных dsCustomerIndividual. Свойство Text текстовых полей относится к катего Разработка форм Windows с использованием связанных элементов... 37 рии Data Binding, представленной в окне свойств. В табл. 1.5 перечислены эле менты управления и значения их свойств. Пример размещения элементов управления приведен на рис. 1.8. Òàáëèöà 1.5. Çíà÷åíèÿ ñâîéñòâ íîâûõ ýëåìåíòîâ óïðàâëåíèÿ Label è TextBox äëÿ ôîðìû frmHowTo1_3 Объект Свойство Значение Label Text Customer ID Label Text Company Name Label Text Contact Label Text Contact Title Label Text Address Label Text City Label Text Region Label Text Country Label Text Phone Label Text Fax TextBox Name txtCustomerID Text dsCustomerIndividual - Customers.CustomerID TextBox Name txtCompanyName Text dsCustomerIndividual - Customers.CompanyName TextBox Name txtContact Text dsCustomerIndividual - Customers.Contact TextBox Name txtContactTitle Text dsCustomerIndividual - Customers.ContactTitle Name txtAddress TextBox Text dsCustomerIndividual - Customers.Address TextBox Name txtCity Text dsCustomerIndividual - Customers.City TextBox Name txtRegion Text dsCustomerIndividual - Customers.Region TextBox Name txtPostalCode Text dsCustomerIndividual - Customers.PostalCode TextBox Name txtCountry Text dsCustomerIndividual - Customers.Country Name txtPhone TextBox TextBox Text dsCustomerIndividual - Customers.Phone Name txtFax Text dsCustomerIndividual - Customers.Fax 4. Теперь необходимо приступить к разработке кода. Для этого нужно, прежде всего, откорректировать код обработчика событий Click для кнопки btnLoadList 38 Глава 1 (листинг 1.3). Первые три строки этого кода в основном совпадают со строками, приведенными в последнем упражнении, за исключением того, что в них изменено имя и добавлено несколько строк в качестве комментариев к коду. Ëèñòèíã 1.3. frmHowTo1_3.vb — ââîä â ïðîãðàììó âûçîâà ïðîöåäóðû RefreshIndividual Private Sub btnLoadList_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles _ btnLoadList.Click ' Присвоить параметру адаптера данных значение, введенное для ' ограничения объема списка Me.odaCustomerList.SelectCommand.Parameters(0).Value = _ Me.txtCustLimit.Text ' Удалить данные, находящиеся в настоящее время в наборе данных Me.dsCustomerList.Clear() ' Заполнить набор данных со списком заказчиков Me.odaCustomerList.Fill(Me.dsCustomerList) ' Заполнить отдельный набор данных, соответствующий ' начальной записи RefreshIndividual() End Sub Единственная новая строка кода находится непосредственно перед оператором End Sub (листинг 1.4); в этой строке вызывается процедура RefreshIndividual для получения первого элемента вновь заполненного списка. В данной процедуре вначале выполняется очистка набора данных dsCustomerIndividual. Это позво ляет выбрать имя заказчика из списка, а затем передать выбранный элемент в каче стве значения параметра для адаптера данных odaCustomerIndividual. После этого заполняется набор данных dsCustomerIndividual и в текстовых полях, связанных с этим набором данных, отображаются данные. Ëèñòèíã 1.4. frmHowTo1_3.vb — îáíîâëåíèå íàáîðà äàííûõ, èç êîòîðîãî ïîñòóïàþò äàííûå â òåêñòîâûå ïîëÿ Private Sub RefreshIndividual() ' Очистить отдельные клиентские наборы данных Me.dsCustomerIndividual.Clear() ' Определить, выбран ли элемент If lstCustomers.SelectedIndex <> -1 Then ' Присвоить параметру адаптера данных SQL выбранный ' идентификатор заказчика Me.odaCustomerIndividual.SelectCommand.Parameters(0).Value = _ Me.lstCustomers.SelectedItem(0) ' Заполнить набор данных Me.odaCustomerIndividual.Fill(Me.dsCustomerIndividual) End If End Sub Разработка форм Windows с использованием связанных элементов... 39 Теперь достаточно предусмотреть только код (листинг 1.5), который выполня ется после выбора нового элемента в списке. Он обеспечивает обновление со держимого текстовых полей и ввод в них новых данных. Этот код выполняется при активизации события SelectedIndexChanged, которое относится к спи ску lstCustomers. Ëèñòèíã 1.5. frmHowTo1_3.vb — âûçîâ ïðîöåäóðû RefreshIndividual Private Sub lstCustomers_SelectedIndexChanged(ByVal sender _ As System.Object,ByVal e As System.EventArgs) _ Handles lstCustomers.SelectedIndexChanged ' Заполнить отдельный набор данных текущего элемента списка RefreshIndividual() End Sub Îïèñàíèå ïîëó÷åííûõ ðåçóëüòàòîâ После того как пользователь вводит любую букву в текстовом поле txtCustLimit и щелкает на кнопке btnLoadList, список заполняется элементами, соответствую щими тексту в этом текстовом поле. После заполнения списка lstCustomers пользо ватель видит на экране подробные сведения, относящиеся к первому элементу списка, которые отображаются в текстовых полях. Для этого служит процедура RefreshIndividual. Выбранный элемент используется в качестве параметра для адаптера данных odaCustomerIndividual, после чего заполняется набор данных dsCustomerIndividual. Если пользователь выбирает в списке другие элементы, отображаются данные, соответствующие выбранному элементу. Совет Ðåêîìåíäóåòñÿ âñåãäà ðàçáèâàòü êîä ïðîãðàììû íà îòäåëüíûå ïðîöåäóðû, òàêèå êàê RefreshIndividual. Ýòî ïîçâîëÿåò óïðîñòèòü èçó÷åíèå è ñîïðîâîæäåíèå êîäà, à òàêæå èçáåæàòü îøèáîê, êîòîðûå ìîãóò âîçíèêàòü ïðè íåîäíîêðàòíîì ââîäå îäíîãî è òîãî æå êîäà â ðàçíûõ ìåñòàõ ïðîãðàììû. Ê òîìó æå, åñëè âîçíèêíåò íåîáõîäèìîñòü îòêîððåêòèðîâàòü êîä, òî ñîîòâåòñòâóþùèå èçìåíåíèÿ äîñòàòî÷íî áóäåò ââåñòè òîëüêî â îäíîì ìåñòå. Êîììåíòàðèè Способ связывания текстовых полей с наборами данных позволяет упростить ра боту по программированию операции переключения с одной записи на другую, по скольку не требуется каждый раз заполнять все текстовые поля данными. Такой спо соб позволяет также упростить использование адаптеров данных и наборов данных для корректировки данных в форме. Как показано в следующих упражнениях, связанные наборы данных особенно удоб ны, если требуется обеспечить редактирование, добавление и удаление данных в форме. 40 Глава 1 Óïðàæíåíèå 1.4. Ðåäàêòèðîâàíèå è îáíîâëåíèå äàííûõ ñ èñïîëüçîâàíèåì ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ В некоторых приложениях достаточно только обеспечить просмотр данных, но более важными средствами программы является редактирование данных в текстовых полях и обновление данных на сервере. В этом упражнении показаны именно эти средства программирования с использованием некоторых новых методов и свойств различных элементов управления данными, включая автоматическое формирование команд, обеспечивающих создание операторов Update, Insert и Delete языка SQL. В данном упражнении рассматривается также класс BindingContext, который ис пользуется для проведения обновлений с помощью связанных элементов управления. Форма, разработанная в упражнении 1.4, очень хорошо подходит для просмотра данных различных записей. Но форма, предназначенная для редактирования и об новления данных, должна быть организована по другому принципу. Îáùåå îïèñàíèå Продолжая разработку формы, которая использовалась в предыдущих упражнени ях, введем несколько кнопок с кодом, с помощью которых можно выполнить следую щие действия • Кнопка Edit. Позволяет переключаться из режима просмотра в режим редактиро вания текстовых полей и изменять при этом их внешний вид, чтобы пользователь знал, что он может в этих элементах управления просматривать и редактировать или только просматривать данные; при этом изменяется форма рамок текстового поля: в первом случае они становятся плоскими, а во втором — рельефными. • Кнопка Save. Обеспечивает сохранение на сервере изменений, внесенных в данные. После записи данных в базу данных внешний вид рамок текстовых по лей снова изменяется и они становятся плоскими, чтобы дать пользователю знать, что данные нельзя редактировать. • Кнопка Cancel. Позволяет отменить режим редактирования данных; при этом рамки текстовых полей снова становятся плоскими, чтобы пользователь мог видеть, что данные больше нельзя редактировать и что запись откорректиро ванных данных не была выполнена. Очень важно, чтобы пользователи могли определить, могут ли они редактировать данные или только просматривать их. В рассматриваемом приложении предусмотре но использование двух стилей рамок текстовых полей (плоских и рельефных) и двух цветов текстовых полей (серого и белого). Переходя от одного стиля отображения к другому, можно наглядно показать пользователям, разрешено ли редактирование данных при определенных обстоятельствах (рис. 1.8). В этом упражнении рассматривается еще один важный компонент программы — класс BindingContext. Этот класс упрощает работу с элементами управления, свя занными с данными. Все элементы управления в форме Windows включают собствен ный объект BindingContext, а также по одному объекту BindingContext для каж Разработка форм Windows с использованием связанных элементов... 41 дого содержащегося в нем элемента управления. Объект BindingContext имеется также в каждой форме. Объекты BindingContext управляют объектом (объектами) класса BindingManagerBase, который относится к каждому элементу управления. В частности, объект BindingContext позволяет управлять процессом редактирования и обновления данных, а также передачей данных на сервер. С другой стороны, объек ты BindingManagerBase обеспечивают синхронизацию наборов данных с элемен тами управления. Класс BindingContext широко применяется во всех остальных уп ражнениях данной главы, но при этом используются не все его методы. Ðèñ. 1.8. Пример использования стиля для указания того, что пользователь имеет возможность редактировать данные Ïîðÿäîê äåéñòâèé Откройте папку, в которой находится приложение VB.NET How-To - Chapter 1, содержащее решения к упражнениям этой главы, и вызовите его на выполнение. В ос новной форме щелкните на кнопке How-To 1.4. Затем щелкните на кнопке Load List. От кроется форма со списком, заполненным именами заказчиков, которые начинаются с буквы A, а в правой части формы появятся подробные сведения о первом заказчике в списке. Щелкните на кнопке Edit. После этого вы получите возможность корректиро вать данные в текстовых полях. Отредактировав несколько полей, щелкните на кнопке Save. После того как вы выберете другого заказчика из списка, снова вернитесь к дан ным о заказчике, которые вы уже корректировали. Вы сможете убедиться в том, что внесенные вами изменения действительно записаны в базу данных. А если вместо кноп ки Save вы щелкнете на кнопке Cancel, внесенные изменения не будут записаны. Обра тите внимание, что если вы откорректируете название компании заказчика, то вам нуж но будет снова загрузить список заказчиков, чтобы увидеть в списке результаты внесен ных изменений. 1. Введите в форму три кнопки, как показано на рис. 1.8, со свойствами, значения которых приведены в табл. 1.6. 2. Введите код, показанный в листинге 1.6, в обработчик событий Click кнопки btnEdit. Глава 1 42 Òàáëèöà 1.6. Êíîïêè äëÿ ðåäàêòèðîâàíèÿ, ñîõðàíåíèÿ è îòìåíû èçìåíåíèé â äàííûõ Объект Свойство Значение Button Name btnEdit Caption &Edit Name btnSave Caption &Save Name btnCancel Caption &Cancel Button Button Ëèñòèíã 1.6. frmHowTo1_4.vb — âûçîâ ïðîöåäóðû ActivateEditing ñ ïîìîùüþ êíîïêè btnEdit Private Sub btnEdit_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnEdit.Click ' Разрешить редактирование формы ActivateEditing(True) End Sub В этом обработчике событий вызывается процедура ActivateEditing, приведенная ниже (листинг 1.7). В представленном здесь коде выполняется просмотр всех элементов управления в форме и используется свойство TypeOf для определения того, является ли текущий элемент управления текстовым полем. Предусмотрена также дополнительная проверка для кон троля над тем, что рассматриваемый элемент управления не является тек стовым полем txtCustLimit. Если элемент управления является тексто вым полем и процедуре передан параметр bEnable со значением True, то стиль рамки текстового поля изменяется на рельефный с помощью свойст ва BorderStyle, а в качестве значения свойства цвета фона BackColor применяется белый цвет. В ином случае свойству BorderStyle присваива ется значение FixedSingle, которое соответствует плоскому стилю рамки, а значение свойства BackColor становится таким же, как цвет фона фор мы. Свойству Enabled текстового поля присваивается соответствующее значение параметра bEnabled (True или False). Ëèñòèíã 1.7. frmHowTo1_4.vb — ïðîöåäóðà, êîòîðàÿ ïðèìåíÿåòñÿ äëÿ èçìåíåíèÿ çíà÷åíèÿ ñâîéñòâà Enabled è âíåøíåãî âèäà òåêñòîâûõ ïîëåé Private Sub ActivateEditing(ByVal bEnable As Boolean) Dim oCurr As Object ' Обработать в цикле каждый элемент управления в форме For Each oCurr In Me.Controls() ' Определить, является ли элемент управления текстовым полем If TypeOf oCurr Is TextBox And oCurr.Name <> "txtCustLimit" Then Разработка форм Windows с использованием связанных элементов... 43 ' В случае положительного ответа изменить значения свойств ' на противоположные If bEnable Then oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.Fixed3D oCurr.BackColor() = System.Drawing.Color.White Else oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.FixedSingle oCurr.BackColor() = Me.BackColor End If oCurr.Enabled = bEnable End If Next End Sub 3. Введите этот код в обработчик событий Click кнопки btnSave (листинг 1.8). В этом коде вызывается новая процедура SaveRecord, фактически обеспечи вающая запись данных в базу данных. После записи данных вызывается проце дура ActivateEditing, которой в качестве параметра передается значение False, чтобы запретить корректировку данных в элементах управления, по скольку считается, что данные записываются на диск только после завершения редактирования. Ëèñòèíã 1.8. frmHowTo1_4.vb — âûçîâ ïðîöåäóðû SaveRecord è îòìåíà ðåæèìà ðåäàêòèðîâàíèÿ òåêñòîâûõ ïîëåé ïóòåì âûçîâà ïðîöåäóðû ActivateEditing Private Sub btnSave_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSave.Click ' Сохранить информацию SaveRecord() ' Отключить текстовые поля ActivateEditing(False) End Sub Ниже приведен код процедуры SaveRecord (листинг 1.9). В этой процедуре вызы вается метод EndCurrentEdit класса BindingContext; ей передается набор дан ных dsCustomerIndividual с указанием таблицы Customers. Затем из адаптера данных odaCustomerIndividual вызывается метод Update и ему передаются те же параметры. В результате внесенные изменения вносятся в набор данных. И на конец, изменения в наборе данных пересылаются обратно на сервер. 44 Глава 1 Ëèñòèíã 1.9. frmHowTo1_4.vb — ïåðåäà÷à íà ñåðâåð èçìåíèâøèõñÿ äàííûõ Private Sub SaveRecord() ' Применить класс BindingContext для завершения текущего сеанса ' редактирования, чтобы иметь возможность записать обновленные ' данные на сервер Me.BindingContext(Me.dsCustomerIndividual, _ "Customers").EndCurrentEdit() ' Выполнить требуемую задачу на уровне набора данных ' с использованием адаптера данных Me.odaCustomerIndividual.Update(Me.dsCustomerIndividual, _ "Customers") ' После подтверждения изменений передать данные обратно ' на сервер Me.dsCustomerIndividual.AcceptChanges() End Sub Примечание Åñëè ÷èòàòåëü âïåðâûå çíàêîìèòñÿ ñ ðàáîòîé ñðåäû ADO.NET, òî äëÿ íåãî ìîæåò ïîêàçàòüñÿ ñòðàííûì ïðèìåíÿåìûé ïðè ýòîì ïîäõîä: îáíîâëåíèå íàáîðà äàííûõ, ïîäòâåðæäåíèå âíåñåííûõ èçìåíåíèé, à çàòåì ïåðåäà÷à ýòèõ èçìåíåíèé îáðàòíî íà ñåðâåð. Íî äåëî â òîì, ÷òî ôóíêöèîíèðîâàíèå ñðåäû ADO.NET îñíîâàíî íà èñïîëüçîâàíèè ðàçúåäèíåííûõ íàáîðîâ äàííûõ. Ïðè ñîçäàíèè íàáîðà äàííûõ ñ èñïîëüçîâàíèåì àäàïòåðà äàííûõ ôàêòè÷åñêè ôîðìèðóåòñÿ ôàéë â êîäå XML. ×òîáû óáåäèòüñÿ â ýòîì, ðàññìîòðèòå ôàéë dsCustomerIndividual.xsd, êîòîðûé ìîæíî íàéòè â êàòàëîãå ïðîãðàììû Solutions Explorer. <xsd:schemaid="dsCustomerIndividual"targetNamespace="http://www.tem puri.org/dsCustomerIndividual.xsd"xmlns="http://www.tempuri.org/dsC ustomerIndividual.xsd"xmlns:xsd="http://www.w3.org/2001/XMLSchema "xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault="qualified"elementFormDefault="qualified"> <xsd:element name="dsCustomerIndividual" msdata:IsDataSet="true"> <xsd:complexType> <xsd:choice maxOccurs="unbounded"> <xsd:element name="Customers"> <xsd:complexType> <xsd:sequence> <xsd:element name="CustomerID" type="xsd:string" /> <xsd:element name="CompanyName" type="xsd:string" /> <xsd:element name="ContactName" type="xsd:string" minOccurs ="0" /> <xsd:element name="ContactTitle" type="xsd:string" minOccurs ="0" /> <xsd:element name="Address" type="xsd:string" minOccurs= "0" /> <xsd:element name="City" type="xsd:string" minOccurs="0" /> <xsd:element name="Region" type="xsd:string" minOccurs = "0" /> <xsd:element name="PostalCode" type="xsd:string" minOccurs = "0" /> <xsd:element name="Country" type="xsd:string" minOccurs= "0" /> <xsd:element name="Phone" type="xsd:string" minOccurs="0" /> <xsd:element name="Fax" type="xsd:string" minOccurs="0" /> Разработка форм Windows с использованием связанных элементов... 45 </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:choice> </xsd:complexType> <xsd:unique name="Constraint1" msdata:PrimaryKey="true"> <xsd:selector xpath=".//Customers" /> <xsd:field xpath="CustomerID" /> </xsd:unique> </xsd:element> </xsd:schema> Âñå ýòè äåéñòâèÿ âûïîëíÿþòñÿ íåçàìåòíî äëÿ ïîëüçîâàòåëÿ, ïîýòîìó äëÿ ðàáîòû ñ íàáîðàìè äàííûõ è ñðåäîé ADO äàæå íå ïðèõîäèòñÿ èçó÷àòü ÿçûê XML. Äîïîëíèòåëüíàÿ èíôîðìàöèÿ ïî ýòîé òåìå ïðèâåäåíà â ãëàâå 3, “Ïðîñìîòð äàííûõ ñ ïðèìåíåíèåì ñðåäñòâ ADO.NET”. 4. Последнее задание этого упражнения состоит в реализации возможности от мены редактирования. Для этого достаточно поместить следующий код в обра ботчик событий Click кнопки btnCancel (листинг 1.10). Текущие результаты редактирования отменяются с использованием метода CancelCurrentEdit объекта BindingContext данной формы. После этого происходит отмена ре жима редактирования текстовых полей с помощью процедуры ActivateEditing. Ëèñòèíã 1.10. frmHowTo1_4.vb — îòìåíà èçìåíåíèé, âíåñåííûõ â äàííûå, è ïîâòîðíîå çàïðåùåíèå ðåäàêòèðîâàíèÿ òåêñòîâûõ ïîëåé Private Sub btnCancel_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles _ btnCancel.Click ' Для отмены текущей операции редактирования применяется ' класс BindingContext Me.BindingContext(Me.dsCustomerIndividual, _ "Customers").CancelCurrentEdit() ActivateEditing(False) End Sub Îïèñàíèå ïîëó÷åííûõ ðåçóëüòàòîâ После того как пользователь щелкнет на кнопке btnEdit, процедура ActivateEditing показывает, что он может редактировать данные в текстовых по лях. Текстовые поля переводятся в режим редактирования. Если пользователь после этого щелкнет на кнопке btnSave, то откорректиро ванные им данные вводятся в набор данных, а затем передаются на сервер для их сохранения. Если же пользователь щелкнет на кнопке btnCancel, то внесенные им изменения отменяются. В обоих случаях вызывается процедура ActivateEditing, которая отменяет режим редактирования текстовых полей и, изменив стиль ото бражения текстовых полей, показывает пользователю, что текстовые поля больше нельзя редактировать. 46 Глава 1 Êîììåíòàðèè В этом упражнении рассматриваются основные функции редактирования и обнов ления данных. Здесь представлены наиболее важные операции, с которых начинает ся разработка реальных программ. А в следующих упражнениях показаны способы добавления и удаления записей, а также обработки ошибок. Способы применения связанных элементов управления в среде ADO.NET немного напоминают способы доступа к данным, которые используются в таких технологиях, как ADO и DAO. Но объекты BindingContext и BindingManagerBase намного уп рощают работу со связанными объектами в приложениях. Óïðàæíåíèå 1.5. Äîáàâëåíèå è óäàëåíèå çàïèñåé ñ èñïîëüçîâàíèåì ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ Не менее важной задачей, чем редактирование данных, является добавление но вых и удаление существующих записей в таблице. В этом упражнении показано, как выполнить эту задачу с помощью класса BindingContext. Пользователи должны иметь возможность не только редактировать существующие записи, но также добавлять и удалять записи. Ниже описаны способы добавления и удаления записей с помощью связанных элементов управления. Îáùåå îïèñàíèå Чтобы ввести в программу средство добавления новой записи Add New Record, разместим на форме новую кнопку btnAddNew и добавим в программу соответст вующий код. Для ввода новой записи с помощью метода AddNew снова используется объект BindingContext. В форме применяется переменная уровня модуля для контроля над тем, происходит ли добавление или редактирование записи. Если вводится новая запись, то при обновлении данных в приложении необходимо пере загрузить данные в списке в том случае, если значение поля CompanyName новой записи соответствует области охвата списка, который определен согласно содер жимому текстового поля txtCustLimit. С другой стороны, чтобы ввести в приложение средство удаления записи Delete Record, на форме размещена кнопка btnDelete. Код, который обеспечивает функ ционирование этой кнопки, включает метод RemoveAt объекта BindingContext, используемый для удаления записи из набора данных. Затем откорректированные данные снова возвращаются на сервер. Ïîðÿäîê äåéñòâèé Откройте папку, в которой находится приложение VB.NET How-To - Chapter 1, содержащее решения к упражнениям этой главы, и вызовите его на выполнение. В ос новной форме щелкните на кнопке How-To 1.5. Щелкните на кнопке Load List, а затем на кнопке New. Введите текст ALF в поле Customer ID и Alfred's Fried Foods в поле Company Name. После этого щелкните на кнопке Save и проследите за тем, как проис Разработка форм Windows с использованием связанных элементов... 47 ходит добавление к списку только что введенной записи. После ввода записи можно проверить средства удаления, щелкнув на кнопке Delete. Запись исчезнет, и на экране появится откорректированный список. 1. Под кнопкой btnEdit поместите новую кнопку, а затем укажите в качестве свойст ва Name этой кнопки значение btnNew, а в качестве свойства Caption — &Save. 2. Введите новую переменную уровня модуля mbAddNew, которая представляет собой логическую переменную, применяемую для контроля над тем, происхо дит ли добавление новой записи. Код объявления этой переменной будет нахо диться за пределами кода всех процедур, непосредственно вслед за кодом форм, как показано на рис. 1.9. Ðèñ. 1.9. Пример размещения переменной под кодом, сгенерированным програм# мой проектирования форм Windows, и ее объявления с атрибутом Private, что позволяет обеспечить к ней доступ из процедур класса, а не из внешних процедур Совет Ïðåäóñìîòðåíà âîçìîæíîñòü ñâåðòûâàòü è ðàçâåðòûâàòü êîä ïðîöåäóð, âõîäÿùèõ â ñîñòàâ ðàçðàáàòûâàåìûõ ìîäóëåé, â îêíå ïðîãðàììû ïðîåêòèðîâàíèÿ ôîðì. Ýòî ïîçâîëÿåò óïðîñòèòü ðàáîòó ïðè ñîçäàíèè íîâûõ ïðîöåäóð (êîä êîòîðûõ ìîæåò áûòü ðàçâåðíóò íà ýêðàíå) è èñêëþ÷èòü íåîáõîäèìîñòü âèäåòü ïîëíûé òåêñò ñóùåñòâóþùèõ ïðîöåäóð (êîòîðûé ìîæåò áûòü âåñüìà ïðîñòðàííûì). 3. Введите следующий код в обработчик событий Click новой кнопки btnNew (листинг 1.11). В этом коде прежде всего логической переменной mbAddNew присваивается значение True. Затем в нем используется метод AddNew объекта 48 Глава 1 BindingContext формы для добавления новой записи к набору данных dsCustomerIndividual. И наконец, в этом коде вызывается процедура ActivateEditing для перехода в режим редактирования текстовых полей. Ëèñòèíã 1.11. frmHowTo1_5.vb — äîáàâëåíèå íîâîé çàïèñè ê íàáîðó äàííûõ dsCustomerIndividual è ñìåíà ðåæèìà ðåäàêòèðîâàíèÿ òåêñòîâûõ ïîëåé Private Sub btnNew_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnNew.Click mbAddNew = True ' Добавить новую запись с использованием класса BindingContext Me.BindingContext(Me.dsCustomerIndividual, "Customers").AddNew() ActivateEditing(True) End Sub 4. Откорректируйте код обработчика событий Click кнопки btnSave и преду смотрите в нем проверку того, присвоено ли флажку mbAddNew значение True, что означает добавление новой записи (листинг 1.12). Если флажок имеет зна чение True, то после сохранения записи путем вызова процедур SaveRecord и ActivateEditing вызываются процедуры LoadList и RefreshIndividual для загрузки данных новой записи. Обратите внимание, что код процедур SaveRecord, ActivateEditing и RefreshIndividual не изменился по сравнению с упражнением 1.4. После этого переменной mbAddNew присваива ется значение False. Ëèñòèíã 1.12. frmHowTo1_5.vb — ñîõðàíåíèå èçìåíèâøèõñÿ äàííûõ, ñìåíà ðåæèìà ðåäàêòèðîâàíèÿ òåêñòîâûõ ïîëåé, à òàêæå ïåðåçàãðóçêà ñïèñêà è ïåðâîé çàïèñè â ñïèñêå Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click ' Сохранить информацию SaveRecord() ' Отключить текстовые поля ActivateEditing(False) If mbAddNew Then LoadList() RefreshIndividual() mbAddNew = False End If End Sub 5. Откорректируйте код обработчика событий Click кнопки btnCancel, чтобы в нем переменной mbAddNew присваивалось значение False, как показано в лис тинге 1.13. Разработка форм Windows с использованием связанных элементов... 49 Ëèñòèíã 1.13. frmHowTo1_5.vb — îòìåíà ðåæèìà ðåäàêòèðîâàíèÿ è èçìåíåíèå çíà÷åíèÿ ïåðåìåííîé mbAddNew Private Sub btnCancel_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCancel.Click ' Для отмены текущей операции редактирования применяется ' класс BindingContext Me.BindingContext(Me.dsCustomerIndividual, _ "Customers").CancelCurrentEdit() ActivateEditing(False) mbAddNew = False End Sub 6. Теперь можно приступить к разработке функциональных средств удаления записей. Для этого введите следующий код в обработчик событий Click но вой кнопки, обозначенной как btnDelete (листинг 1.14). Первая строка вновь введенного кода начинается с оператора вызова нового метода RemoveAt и нового свойства Position, которые используются с объектом BindingContext. Выполнение компонентов этого оператора происходит, начиная от внутренних и заканчивая внешними программными конструк циями. Свойство Position применяется для отслеживания позиции текущей записи в наборе данных, в рассматриваемом случае dsCustomerIndividual. Метод RemoveAt позволяет отметить запись, находящуюся в определенной позиции, как подлежащую удалению. Затем используется метод Update адаптера данных odaCustomerIndividual для вызова оператора DELETE языка SQL применительно к рассматриваемому набору данных и фактического удаления строк из набора данных. Для передачи на сервер информации об изменениях, внесенных в набор данных (в этом слу чае — об удалении записи), применяется метод AcceptChanges. И наконец, вызываются процедуры LoadList, RefreshIndividual и ActivateEditing для обновления списка, выборки новых данных из первой записи в списке и отображения этих данных в текстовых полях, а также переключения текстовых полей в режим просмотра, чтобы дать пользователю понять, что эти данные нельзя редактировать. Ëèñòèíã 1.14. frmHowTo1_5.vb — óäàëåíèå âûáðàííîé çàïèñè è ïåðåçàãðóçêà ñïèñêà Private Sub btnDelete_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles _ btnDelete.Click ' Отметить строку для удаления с использованием ' метода RemoveAt объекта BindingContext Me.BindingContext(Me.dsCustomerIndividual, _ "Customers").RemoveAt(Me.BindingContext(Me.dsCustomerIndividual, _ "Customers").Position) ' Выполнить требуемую задачу на уровне набора данных ' с использованием адаптера данных 50 Глава 1 odaCustomerIndividual.Update(dsCustomerIndividual, "Customers") ' После подтверждения изменений передать данные обратно ' на сервер dsCustomerIndividual.AcceptChanges() ' Перезагрузить список LoadList() ' Отобразить первую запись RefreshIndividual() ' Отключить текстовые поля ActivateEditing(False) End Sub Îïèñàíèå ïîëó÷åííûõ ðåçóëüòàòîâ После того как пользователь щелкнет на кнопке btnNew, флажку mbAddNew при сваивается значение True, набор данных подготавливается для добавления записи с помощью метода AddNew объекта BindingContext, а текстовые поля переводятся в режим редактирования. Если пользователь после этого щелкнет на кнопке btnSave, то откорректирован ные им данные вводятся в набор данных, а затем передаются на сервер для сохране ния. Если же пользователь щелкнет на кнопке btnCancel, то внесенные изменения отменяются. В обоих случаях переменной mbAddNew присваивается значение False и вызывается процедура ActivateEditing, которая отменяет режим редактирования и изменяет стиль отображения текстовых полей, чтобы дать пользователю знать, что текстовые поля недоступны для редактирования. И наконец, если сделан щелчок на кнопке btnSave, а переменной mbAddNew присвоено значение True, то вызываются процедуры LoadList и RefreshIndividual. После того как пользователь щелкнет на кнопке btnDelete, запись удаляется из набора записей, а затем из базы данных на сервере. Перезагружается список, и в тек стовых полях отображаются данные первой записи в списке. После этого отменяется режим редактирования текстовых полей. Êîììåíòàðèè В этом упражнении показаны основные программные конструкции, необходимые для создания полнофункциональной формы ввода данных. С помощью этой формы пользова тель имеет возможность добавлять, редактировать и удалять записи. Для этого фактически требуется меньший объем кода, чем при использовании языка Visual Basic 6.0. Вполне очевидно, что объект BindingContext позволяет выполнить значитель ную часть работы по обработке связанных данных. Разработка форм Windows с использованием связанных элементов... 51 Óïðàæíåíèå 1.6. Îáðàáîòêà îøèáîê ñ ïîìîùüþ ñâÿçàííûõ ýëåìåíòîâ óïðàâëåíèÿ В процессе эксплуатации приложений и баз данных иногда приходится сталки ваться с ошибками времени выполнения. В среде .NET всевозможные возникающие при этом ошибки принято называть исключениями. В настоящем упражнении приведе ны примеры ситуаций, при которых могут возникать исключения, и показаны спосо бы обработки исключений с помощью операторов Try, Catch и Finally. Возможность добавления и удаления записей в программе является очень важной, но необходимо также предусмотреть выполнение определенных действий при воз никновении ошибок. Ниже приведен пример окна с сообщением, которое появилось при попытке удалить данные о существующей компании (рис. 1.10). Ðèñ. 1.10. Сообщение о необработанной ошибке, которое в среде .NET называется ис# ключением Ниже описаны способы корректной обработки ошибок в приложении, в котором используются связанные элементы управления. Îáùåå îïèñàíèå Обработка ошибок, которые обычно возникают в процессе ввода данных пользовате лем и обновления базы данных на сервере, является одной из наиболее важных состав ляющих работы с данными. Если в программе не предусмотрено применение соответст вующих средств обработки ошибок, то в лучшем случае система выводит сообщение об ошибке, которое с трудом поддается расшифровке, а в худшем — аварийно завершает свою работу или записывает в базу данных ошибочные данные. В среде Visual Studio .NET для обработки ошибок применяются классы, называемые исключениями. В иерархию исключе ний входит большое число различных (в основном унаследованных) типов исключений. Исключения времени выполнения могут возникать почти в любой части приложе ния. В программе может быть предусмотрена обработка этих исключений с помощью конструкций Try...Catch...Finally или эти исключения могут остаться необра ботанными, и тогда на экране отображается сообщение об ошибке, аналогичное при веденному на рис. 1.10. В листинге 1.15 показан общепринятый способ перехвата исключений. Глава 1 52 Ëèñòèíã 1.15. Ñòàíäàðòíûé êîä îáðàáîòêè èñêëþ÷åíèé Private Sub MySub() Try ' Здесь находится код, в котором могут активизироваться ' исключения Catch dataException as Exception MessageBox.Show(dataException.Message) Finally ' Код, выполняемый независимо от того, возникла ошибка ' или нет End Try End Sub Ниже перечислены некоторые основные сведения, которыми следует руководство ваться при работе с исключениями и использовании блоков Try...Catch...Finally. • Для объекта исключения может быть выбрано любое имя. Имя dataException было взято лишь в качестве примера. • Конкретные типы исключений происходят от базового класса System.Exception. Одним из таких производных классов является OleDbException, и примеры его применения будут показаны в данном упражнении. • В блочном операторе Catch может находиться оператор Throw, который по зволяет вновь активизировать это же исключение, после чего оно передается в вызывающую процедуру. • Для перехвата конкретных исключений может использоваться конструкция When оператора Catch. • При использовании нескольких операторов Catch выполняется каждый из них, если в блок Catch не включен оператор End Try или End Sub, как в дан ном упражнении. • В программе может быть предусмотрено несколько операторов Catch для об работки всех возможных исключений, которые могут в ней возникнуть. В данном упражнении показано, как эти рекомендации применяются на практике. Ïîðÿäîê äåéñòâèé В этом упражнении взята за основу разработанная форма, в которую введен код обработки исключений, возникающих при сохранении записи в базе данных (после ее добавления или корректировки) и при удалении записи. Здесь предусмотрено так же применение кода обработки события, возникающего при закрытии формы. 1. Откорректируйте код обработчика событий Click кнопки btnSave (листинг 1.16). Для этого необходимо заключить вызов процедуры SaveRecord в блок Try...Catch...End Try. Если возникает исключение, то вызывается метод Show класса MessageBox и ему передается свойство Message объекта