4. Привязка объектов контроля к источникам данных

Элемент управления Grid

следующий блок кода в листинге

Элемент управления Grid Является контейнером и позволяет вам легко располагать элементы управления в прямоугольной сетке на отображаемой поверхности какого-то другого элемента, установив сетку в качестве его содержимого. Следующий блок кода в листинге Б.1 создает для сетки определения столбцов и строк, после чего устанавливает их свойства width и Height, Чтобы получить желаемую планировку сетки.

Следующий блок кода вызывает вспомогательный метод, показанный в конце листинга, чтобы поместить каждый из элементов управления в нужную позицию сетки. К сожалению, при существующей в WinFx программной модели для каждого из элементов управления требуется три строки кода, чтобы просто поместить элемент в ячейку сетки: Вспомогательный метод AddControlToGrid Инкапсулирует эти три вызова, что делает вызывающий код чуть компактнее. Но по существу метод устанавливает для каждого элемента управления столбец и строку, после чего добавляет его к сетке. Обратите внимание, что позиция элемента управления в сетке устанавливается при помощи статических методов самого класса Grid, А не методов или свойств экземпляра сетки. После размещения каждого элемента управления в соответствующей ячейке сетки последняя устанавливается в качестве элемента содержания окна, и для окна вызывается метод Show. Конечным результатом является окно, вид которого показан на рис. Б.1. Этот пример дает несколько более ясное представление о том, каким образом одни элементы помещаются на уровень содержания других элементов, образуя визуальное дерево элементов управления. В данный момент такой программный подход может показаться вам довольно громоздким: что же, все это только для того, чтобы спланировать простейшую входную форму? Следует помнить, что в Windows Forms потребуется для этого не намного меньше кода, но почти никто не пишет код Windows Forms вручную на пустом месте; написание большей части этого кода возлагается на конструктор Visual Studio. Однако так будет и с WinFx, когда появится ее окончательный выпуск. В настоящий момент для работы с WinFx нет конструктора, но понимание кода поможет вам, когда этот код будет генерироваться конструктором и вы вдруг обнаружите, что ваше приложение работает не совсем так, как вы хотели.

Кодирование специального элемента управления

b сопряженность отображения в элементе

Так как элемент управления должен поддерживать привязку данных по той же схеме, что и другие привязанные элементы управления, ему понадобятся свойства DataSource И DataMember. Сопряженность отображения в элементе управления с данными отдельных элементов в привязанной коллекции требует, чтобы элемент управления имел также свойство, позволяющее задать, каково имя того поля или свойства, которое содержит идентификатор строки. По смыслу это напоминает функцию СВОЙСТВ DisplayMember И ValueMember Элемента управления ComboBox Или ListBox, И я назову это свойство Rowldentif IerMember.Основной скелет определения класса показан в листинге 8.8. Класс DataBoundBarChartControl Является производным от UserControl И реализует интерфейс ISupportlnitialize, Что позволяет ему контролировать свою привязку к данным в фазе инициализации. К классу применен атрибут ToolboxBitmap, Который устанавливает значок для элемента управления, используемый при добавлении его в Toolbox. Специфицированное имя файла относится к битовой матрице 16><16, которая добавляется в проект и помечается как встроенный ресурс. Свойства DataSource И DataMember Объявляются таким же образом, как и в классе FilteredGrid, Только в настоящем случае вы не инкапсулируете источник привязки, которому можно было бы их делегировать. Вместо этого элемент управления сохраняет свойства Datasource И DataMember В элементах-переменных класса, которые он сможет использовать для привязки данных, когда это понадобится. Set-блоки этих свойств вызывают также метод UpdateDataBinding, В котором и находится действительный код привязки данных. Экспонируется также свойство RowidentifierMember, Указывающее, какое свойство элементов данных должно использоваться для отображения меток рядом с каждым экземпляром столбчатой диаграммы.

Загрузка DataTable при помощи DataReader

если то с чем вы

Позднее я собираюсь показать, как использовать считыватель данных для загрузки специальной объектной модели, но пока мы занимаемся загрузкой наборов данных, я подумал, что стоит выделить одну новую возможность в. NET 2.0. Если то, с чем вы работаете в каждый момент времени — это единственная таблица, то создание целого набора данных с индексами таблиц для того только, чтобы добраться до ваших данных, может означать массу излишних дополнительных расходов. В. NET 2.0 вы можете создать, заполнить и использовать самостоятельную таблицу DataTable, Без необходимости иметь дело со сложностями набора данных. Вы можете также, используя считыватель данных, быстрым и эффективным образом заполнить ее, не проходя для этого через адаптер данных или адаптер таблицы. Следующий код показывает вышесказанное в действии. В этом единственном блоке кода представлено несколько новых моментов, поэтому давайте разберем их по порядку. Первое, что делает этот код — создает пустую таблицу данных и называет ее Customers. Всякий раз, когда вам требуется исполнить запрос, вам нужен объект соединения, и оно создается здесь оператором Using. Если вы исполняете запрос сами, вам нужно будет сначала явным образом открыть соединение. Всякий раз, когда вы открываете соединение, вы должны обеспечить его закрытие, и вы должны это сделать даже в том случае, если в коде, предшествующем вызову Close, Будет выброшено исключение. Одним из способов сделать это является размещение кода, открывающего соединение, в блоке Try, С вызовом Close В блоке Finally. Другим способом является использование оператора C# Using, Как сделано в этом коде.

Здесь объект соединения создается в блоке Using, Что приводит к вызову для соединения метода Dispose При выходе из области действия этого блока. Метод Dispose Объекта соединения вызывает Close, А оператор Using Всегда создает за вас блок Try-Finally С вызовом Dispose В блоке Finally. Таким образом, блок Using Предлагает вам простой, легко читаемый и безопасный способ использования объектов соединения, гарантирующий, что они будут закрыты при выходе из области действия.

Чтение данных в рабочие объекты

есть еще один важный класс

Я довольно подробно рассказал в этом приложении о наборах данных, так как они являются наиболее развитым и часто используемым контейнером реляционных данных как в приложениях Windows, так и в Web-приложениях клиента и среднего яруса. Есть еще один важный класс доступа к данным, о котором уже было вкратце рассказано: считыватель данных. Считыватель данных является быстрым поступательным указателем для чтения в возвращаемый из базы данных набор результатов. Каждый управляемый провайдер должен предоставлять свой собственный специфический класс считывателя данных. Считыватель для SQL Server называется, как и МОЖНО Было ожидать, SqlDataReader.

Класс SqlDataReader Позволяет вам исполнить запрос и быстро произвести итерацию по всем строкам возвращаемых результатов, чтобы произвести обработку этих строк. Заметьте, я не сказал, что считыватель данных является указателем в саму базу данных. Вам действительно нужно поддерживать открытое соединение, ассоциированное со считывателем, пока вы итерируете результаты. Но считыватель данных будет буферизовать результаты запроса на стороне клиента, и вы не сможете модифицировать нижележащие данные. Все, что вы можете — это читать возвращаемые строки и работать с ними. Когда вы закончите использование считывателя данных, то должны обеспечить закрытие соединения, как и для любого другого запроса. Нередко уровень доступа к данным передает считыватель в качестве возвращаемого значения некоторого метода доступа к данным. Этот код позволяет клиенту взять возвращаемый считыватель, быстро итерировать результаты и сделать с ними то, что ему требуется. Но если вы посмотрите на код, то заметите, что для этого нужно, открыв соединение с базой данных, оставить его открытым, чтобы клиент мог итерировать по содержимому считывателя данных. Однако соединение объявляется и открывается на уровне доступа к данным, и не доступно непосредственно для кода клиента, чтобы он мог закрыть соединение, когда завершит работу со считывателем. Так как же клиент может гарантировать, что соединение будет закрыто, когда он закончит использование считывателя? Вы видите здесь, что методу ExecuteReader Команды передается значение CloseConnection Из перечисления CommandBehavior.