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

Интерфейсы lEnumerable и lEnumerator

net поддержка для них предусмотрена

Поскольку интерфейсы LEnumerable И LEnumerator Образуют фундаментальную модель. NET, поддержка для них предусмотрена на уровне языка. Как в С#, так и в VB. NET имеется конструкция Foreach, Позволяющая осуществить итерацию по коллекции совсем просто: За операцией Foreach Скрыта описанная выше итерация по коллекции, использующая свойство Current И метод MoveNext Из интерфейса LEnumerator Объекта, который возвращается методом GetEnumerator. Генерируемый код на промежуточном языке IL на самом деле не использует для доступа к текущему элементу ссылку на интерфейс LEnumerator; Он просто обращается к свойству Current Самого объекта. Поэтому, если реализующий интерфейс LEnumerator Тип содержит свойство

Current, Возвращающее экземпляр конкретного типа , Цикл Foreach Может избежать упаковки и распаковки этих значений при итерации по коллекции. Подробности того, почему Foreach Реализуется подобным образом, приводятся ниже в рубрике «Проблема с небезопасным по типу перечислением». При реализации в. NET 2.0 коллекций, которые будут содержать конкретные типы, вы должны реализовать также обобщенные версии этих интерфейсов, LEnumerable<T> И IEnumerator<T>. Обобщенные типы интерфейсов используются в. NET 2.0 для обеспечения типовой безопасности для содержащихся в коллекции типов, а также чтобы избежать издержек производительности, которые могут возникать при использовании интерфейсов LEnumerable И LEnumerator В коллекциях, содержащих типы-значения. Для нетипизированных интерфейсов все равно остается место; они используются в. NET привязанными элементами управления, поскольку последние не должны делать предположений о конкретных типах в коллекциях, которые вы собираетесь привязывать, так как это ограничило бы их возможные сценарии привязки. В интерфейс LEnumerator<T> Не включен метод Reset, Чтобы упростить реализацию объектов-перечислителей. Для простых коллекций, где используется непосредственная индексация массива объектов, сброс перечислителя не представляет проблемы. Но в более сложных сценариях реализация метода Reset Может стать непростой задачей, не стоящей затраченных усилий.

Проблема с небезопасным по типу перечислением

проблема интерфейса lenumerator b b

До появления.NET 2.0 модель перечисления поддерживалась интерфейсами LEnumerable И LEnumerator. Проблема интерфейса LEnumerator Состоит в том, что его свойство Current Возвращает только ссылку типа Object, И для правильного ее использования необходимо приведение к действительному типу объекта. Помимо незащищенности в отношении типа, такое положение дел порождает проблемы производительности, когда коллекции содержат типы-значе — ния, а само приведение невозможно без некоторых затрат. Типы-значения при передаче в качестве обьектных ссылок должны упаковываться, т. е. в области сборщика мусора должна выделяться память для объекта, который будет содержать значение, значение должно быть скопировано из стека в обьект, и вы получаете в качестве обьектной ссылки ссылку на эту память. Далее обычно вы, получив доступ к элементу коллекции через свойство LEnumerator .Current, Приводите ссылку обратно к соответствующему типу. Если это тип-значение, то для приведения к нужному типу Объектная ссылка должна быть распакована и скопирована в переменную, размещенную на стеке. После этого выделенный ранее объект становится доступен для сборки в качестве мусора, что увеличивает нагрузку на сборщик. Все это связано с издержками производительности, которых следует избегать. Учитывая вышесказанное, всегда отдавайте предпочтение обобщенным типам коллекций и интерфейсов, чтобы избежать проблем, возникающих при непосредственной работе с коллекцией конкретного типа. Операция Foreach Избегает их, обращаясь к свойству Current И методу MoveNext Непосредственно объекта-перечислителя, а не через интерфейс LEnumerator. Это позволяет перечислителю возвращать действительный тип элемента, а не бессмысленную объектную ссылку. Кроме того, операция Foreach Может работать непосредственно с действительным типом элементов коллекции, обходя, таким образом, упаковку и распаковку типов-значений, если последние корректно реализуют свои перечислители.

Вы можете спросить, для чего нужны два отдельных интерфейса. Почему не определить всего один интерфейс, реализуемый самой коллекцией, который непосредственно поддерживает итерацию по коллекции? Ответ состоит в том, что вам может потребоваться поддерживать не одну форму итерации по коллекции, поэтому выделение логики итерации в отдельный объект позволяет вам при необходимости подключать дополнительные формы итерации.

Присоединение динамического поведения в классе кода поддержки

чтобы воспользоваться контекстной вкладкой нужно

После того, как вы специфицировали планировку страницы в ASPX-файле разметки, вы подключаете к странице динамическое поведение, определяя файл кода поддержки, как показано в листинге А.2.

Код поддержки для данного примера, показанный в листинге А. 2, типичен для простой Web-формы ASP. NET 1.1. Любые серверные элементы управления, определяемые в разметке ASPX-файла, включаются также в класс кода поддержки в качестве элемент-переменных. Сопоставляя имя элемент-переменной с тегом ID в файле ASPX, исполнительная система ASP. NET ассоциирует с этими переменными элемент управления, созданный по коду разметки во время исполнения. Элемент-переменные класса кода поддержки могут использоваться для программного доступа и модификации этих элементов управления при обработке страницы. Здесь можно видеть один дополнительный элемент для типизированного набора данных NorthwindDataSet, Которого нет в разметке страницы. Он был добавлен путем перетаскивания с инструментальной панели на страницу элемента DataSet В конструкторе, но поскольку он не имеет собственного визуального представления, то не добавляет ничего к разметке, а только к поддерживающему коду. Большинство страниц ASP. NET проделывают большой объем обработки в своем обработчике события Page.Load, Который в Visual Studio по умолчанию именуется Page Load. Это часто будет тем самым местом, где вы будете производить извлечение данных, необходимых странице для своего отображения, и будете сохранять эти данные в элемент-переменных, чтобы они были доступны для других методов страницы, которые вызываются при ее обработке. Помните, что для каждого входящего запроса создается новый экземпляр страницы, так что элемент-переменные находятся в области действия только в течение обработки единственного запроса. Кроме того, у вас может быть любое число дополнительных вспомогательных методов, чтобы вынести в них код, инициализирующий элементы управления страницы и их переменные, и любое число обработчиков для событий, возбуждаемых элементами управления при отсылках. Обычно вы будете выполнять первичную инициализацию отображения элементов управления на странице в обработчике Page Load, А затем производить большую часть обработки отсылок в обработчиках событий для элементов управления, хотя можно также выполнять часть обработки при отсылках в Page Load, Если для вашего сценария это целесообразно.

Манипулирование данными посредством источника привязки

после того как вы установите

Источник привязки сам по себе предоставляет вам косвенный доступ к данным, хранящимся в нижележащем источнике данных на стороне клиента. После того, как вы установите свойство DataSource Источника привязки, вам более не потребуется хранить ссылку на сам источник данных, поскольку она будет сохраняться источником привязки. И вы всегда можете получить ссылку на источник данных путем приведения значения свойства DataSource К ожидаемому типу. Единственный недостаток подобного подхода заключается в том, что в той точке кода, где вы используете ссылку из DataSource, Вы должны точно знать тип коллекции данных, к которому прикрепляется источник привязки. Ключ ко всей концепции — в понимании того, что в качестве источника данных для родительского источника привязки необходимо установить родительскую коллекцию объектов, а в качестве источника данных для дочернего источника привязки — ссылку на родительский источник привязки. Тогда свойство DataMember Дочернего источника привязки должно быть именем свойства в родительском объекте, которое является ссылкой на дочернюю коллекцию. Здесь это свойство Children, Принадлежащее к типу Binding — List<ChildObject>. При этом BindingList Является обобщенным типом коллекций, предусмотренным в. NET 2.0 специально для привязки данных в Windows Forms, a ChildObject — это тип-параметр коллекции, специфицирующий тип объектов, которые будет содержать коллекция. Используя эту методику каскадирования источников привязки, вы можете поддерживать иерархии родительских и дочерних данных произвольной глубины. Вы, кроме того, всегда можете получить текущий элемент данных в коллекции через свойство Current Источника привязки. Свойство Current Возвращает ссылку на объект, и, если вы знаете типы всех элементов коллекции, вы опять же можете выполнить соответствующее приведение типа и работать с элементами данных. Помните, что тип объекта, возвращаемого свойством Current, Всегда будет DataRowView Во всех случаях, когда вы привязываетесь к DataTable Или DataView, И это будет экземпляр какого-то объектного типа, хранящегося в коллекции, если вы работаете со специальными объектами.

Закрепление элементов управления

возможно вы хотите чтобы элемент

Для многих видов элементов управления и планировок формы вам хотелось бы, чтобы элементы управления сохраняли одно и то же положение относительно одной или нескольких сторон формы. Возможно, вы хотите, чтобы элемент управления сохранял свой размер, но оставался в том же положении относительно двух смежных сторон формы, например, левого верхнего или правого нижнего угла формы. Либо вы хотите, чтобы внешние кромки элемента управления сохраняли свое положение относительно противоположных сторон формы, т. е. чтобы он растягивался или сжимался при расширении или сокращении формы. Взгляните, например, на рис. В.14 — это одна и та же форма, но она показана при различных размерах. Для подобных форм вы, вероятно, захотите, чтобы при изменении размера сетка данных заполняла все наличное пространство формы, не используемое кнопками. Вы также, вероятно, хотели бы, чтобы кнопка в левом нижнем углу оставалась в фиксированном положении относительно этого угла, и то же самое касается кнопки справа внизу. Наконец, вы, вероятно, хотели бы, чтобы средняя кнопка оставалась по центру формы и в фиксированном положении относительно ее нижней кромки, можно видеть, Посмотрев на размеры сетки и положение кнопок на рис. В. 14, вы увидите, что можно достичь именно такого поведения, не написав вручную ни единой строки кода, а просто установив соответствующим образом свойство Anchor Каждого из элементов управления в окне Properties. Свойство Anchor Принимает перечисление типа AnchorStyles, Которое имеет флаговые значения Top, Bottom, Left И Right. Поскольку это флаговое перечисление, вы можете объединять эти значения посредством булевой операции «или» . Конструктор Visual Studio предоставляет вам удобный графический редактор для этого свойства, показанный на рис. В. 15, который позволяет визуально выбрать стороны, у которых вы хотите закрепить элемент управления. Получающийся при этом код эквивалентен следующему коду для закрепления сетки у всех четырех сторон, чтобы она изменяла размер так, что каждая из ее четырех сторон сохраняла бы свое положение относительно соответствующей стороны формы: