Главная » Silverlight » Атрибуты аннотирования – ЧАСТЬ 2

0

Использование общих типов

Как показано в главе 15, слой кроссплатформенных стандартов отделяет приложе­ние Silverlight от веб-службы ASP. NET. Один из побочных эффектов разделения состо­ит в том, что приложение и служба не моїут совместно использовать общий код. Если служба возвращает объект данных (например, экземпляр класса Product), клиент по­лучает сокращенную версию класса — с данными, но без кода.

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

В принципе, в ASP.NET можно добавить эти подробности в документы XML, описы­вающие службу. Затем Visual Studio может извлечь их и добавить в атрибуты для авто­матической генерации копий кода на стороне клиента. Однако в данный момент такой подход ничем не поддерживается, и разработчик вынужден писать много кода вручную. Но даже если бы такой подход поддерживался, он был бы неприменим во многих важ­ных ситуациях, например при создании пользовательских процедур проверки. Значит, необходимы дополнительные этапы, обеспечивающие совместное использование кода классов данных в службе и клиентском приложении.

Основная сложность состоит в том, что служба и клиентское приложение компили­руются для разных платформ — полнофункциональной .NET и сокращенных библиотек Silverlight. Поэтому, даже если они смогут использовать один и тот же код, они не смогут использовать одну и ту же сборку. Сборка должна компилироваться или для одной плат­формы, или для другой. Наилучшее решение состоит в создании двух библиотечных сборок — для .NET и для Silverlight, а об устранении дублирования исходных кодов по­заботится компилятор Visual Studio. В следующих разделах описано, как это делается.

Идентификация классов данных

В главе 15 показано, что классы данных, используемые в службах WCF, должны иметь атрибут DataContract.

[DataContract () ]

public class Product : INotifyPropertyChanged

{ … )

Этот атрибут не только позволяет использовать класс в службе, но и предоставля­ет возможность уникально идентифицировать класс путем его отображения в заданное пространство имен XML. В предыдущих примерах эта возможность не использовалась, потому что в этом не было необходимости. Но если код класса данных развертывается на клиентском устройстве, она необходима. Одно и то же пространство имен должно быть предоставлено обеим версиям класса данных, используемым одна в Silverlight, а другая — в ASP.NET. Только тогда Visual Studio "поверит", что они представляют одну и ту же сущность.

Ниже приведена разметка, в которой класс Product отображается в пространство имен XML.

[DataContract(Name = "Product",

Namespace = "http://www.prosetech.com/StoreDb/Product")]

public class Product : INotifyPropertyChanged

{ … )

He забывайте, что имя пространства имен XML не обязательно должно указывать на сайт, хотя обычно используются имена, похожие на URI. Адрес домена применяется лишь для того, чтобы гарантировать уникальность пространства имен. Уникальность обеспечивается тем, что другие разработчики, не преследующие зловредных целей, на­верняка не применяют ваш адрес.

Установка решения в Visual Studio

Не подумайте, что после установки атрибута DataContract вы можете скопировать код класса данных в проект Silverlight и веб-службу. К сожалению, не все так просто. Даже когда атрибут DataContract уникально идентифицирует класс Product, при соз­дании ссылки на службу программа Visual Studio все еще пытается создать новый класс данных (и регенерировать его при каждом обновлении ссылки). Это означает, что, не­смотря на все наши усилия, в клиентском коде веб-службы по-прежнему применяется сокращенная копия класса Product.

Чтобы заставить Visual Studio применять одинаковые классы данных в обоих про­ектах, нужно соответствующим образом определить структуру проекта. Как минимум, нужно разместить клиентскую версию класса данных в отдельной сборке. Для этого вы­полните следующие операции.

1. Начните с решения, содержащего проект Silverlight и веб-сайт ASP.NET со служ­бой данных. В кодах примеров для данной главы проект приложения Silverlight называется DataControls, веб-сайт ASP.NET имеет имя DataControls .Web.

Примечание. Описываемый способ одинаково хорошо работает как при создании веб-проекта, так и на сайте без проекта в Visual Studio.

2.    Добавьте библиотеку классов Silverlight, которая будет содержать классы дан­ных. В кодах главы она называется StoreDbDataClasses. В классах должна быть ссылка на сборку System.ComponentModel.DataAnnotations.dll, чтобы можно было использовать атрибуты аннотирования данных, и ссылка на пространство имен System.Runtime.Serialization, чтобы можно было использовать атрибут DataContract.

3.    Добавьте в проект Silverlight ссылку, указывающую на проект классов данных, чтобы они были доступны в приложении.

4.    Способ установки классов данных на стороне сервера зависит от версии .NET. Если на компьютере установлены Visual Studio 2010 и .NET 4.0, можете перейти к п. 5. При использовании Visual Studio 2008 скопируйте вручную код клиент­ской стороны, как описано ниже в примечании.

5.    Добавьте новую библиотеку классов для серверной реализации классов данных (например, StroeDbDataClasses. ServerSide).

Примечание. Если на компьютере установлены Visual Studio 2008 и .NET 3.5, нужно вручную скопировать код классов данных с клиентской стороны на веб-сайт ASP.NET. Если используется веб-проект, можете разместить файл с кодом в любом месте проекта. Если же веб-сайт не имеет проекта, разместите файл в папке App_Code. Применить связывание нельзя, потому что в версии .NET 3.5 сборки System.ComponentModel .DataAnnotations. dll нет атрибута Display, описывающего поля. Поэтому нужно удалить его также из скопированной копии, хотя он должен остаться в сборке Silverlight.

6.    Добавьте в веб-сайт ASP.NET ссылку, указывающую на серверную библиотеку классов.

7.    В библиотеке классов на стороне сервера должен быть тот же код, что и на стороне клиента. Чтобы решить эту задачу без дублирования, можете применить встроен­ные в Visual Studio средства связывания. Для этого в серверной библиотеке клас­сов щелкните правой кнопкой мыши на проекте в окне Solution Explorer (Прово­дник решений) и выберите команду Add1^Existing Item (Добавить^Существующий элемент). Найдите файл с кодом для библиотеки классов Silverlight (например, Product. cs) и выделите его. Не щелкайте на кнопке Add. Вместо этого щелкните на стрелке в правой части кнопки Add. Кнопка развернется (рис. 17.5). Выберите

Рис. 17.5. Связывание с файлом исходного кода

команду Add As Link (Добавить как ссылку). Тогда у вас будет только одна копия исходных кодов, совместно используемая в разных проектах. Не имеет значения, какой проект вы редактируете, обновляться будет один и тот же файл, а измене­ния будут внедрены в обе библиотеки классов.

8. Повторите п. 7 для всех файлов исходных кодов.

Процесс довольно запутанный. Однако теперь вы не будете иметь проблем при соз­дании элементов классов. Если вы все еще сомневаетесь, стоит ли применять столь за­путанное решение, посмотрите в коды данной главы, в которых совместное использова­ние классов данных уже установлено, как описано выше.

Элемент DataGrid

Элемент управления DataGrid извлекает информацию из коллекции объектов и вы­водит ее в решетке, состоящей из строк и столбцов. Каждая строка представляет от­дельный объект, а каждый столбец — свойство объекта.

Ниже перечислены основные преимущества элемента управления DataGrid.

•       Гибкость. В решетке DataGrid можно определить используемые столбцы и вы­ражения связывания, извлекающие данные из связанных объектов. Кроме того, элемент DataGrid поддерживает два полезных инструмента, уже знакомые вам, — шаблоны и преобразователи значений.

•       Возможность настройки. С помощью свойств элемента DataGrid можно ра­дикально изменить его внешний вид, включая настройку заголовков и стилей, форматирующих отдельные компоненты решетки. Если вы очень амбициозны, то можете даже присвоить всему элементу DataGrid совершенно новый шаблон с пользовательскими визуальными элементами и анимациями.

•       Редактирование. Элемент DataGrid предоставляет возможность управлять про­цессом редактирования и отменять неправильные изменения. Он поддерживает систему проверки вводимых данных на основе исключения (см. главу 16) и ан­нотирование данных — гибкую систему правил проверки, добавляемых в классы данных с помощью атрибутов вместо кода.

•       Производительность. Элемент DataGrid обеспечивает высокую производитель­ность при обработке больших объемов данных. В отличие от других элементов управления Silverlight, в элементе DataGrid используется процедура виртуали­зации. Это означает, что элемент DataGrid хранит в оперативной памяти только данные, видимые в данный момент на экране, а не все загруженные данные. Это уменьшает время обработки и требования к объему памяти, позволяя обрабаты­вать десятки тысяч строк данных.

Создание простой решетки

Класс DataGrid определен в том же пространстве имен System.Windows .Controls, что и другие элементы Silverlight, но его определение находится не в общей сборке, а в сборке System.Windows.Controls.Data.dll. По умолчанию в проекте Silverlight нет ссылки на эту сборку. Однако при перетаскивании элемента DataGrid в разметку про­грамма Visual Studio добавляет в проект ссылку и вставляет в разметку объявление про­странства имен.

<UserControl xmlns:data= "clr-namespace:System.Windows.Controls assembly=System.Windows.Controls.Data" … >

Следовательно, элемент DataGrid и связанные с ним классы автоматически получа­ют префикс data.

Для быстрого создания простого элемента DataGrid можно применить ав­томатическую генерацию столбцов. Для этого достаточно присвоить свойству AutoGenerateColumns значение True (оно установлено по умолчанию).

<data:DataGrid x:Name="gridProducts" AutoGenerateColumns="True"x/data:DataGrid> \

После этого можно заполнить элемент DataGrid так же, как любой список, установив его свойство ItemsSource.

gridProducts.DataSource = products;

На рис. 17.6 показана решетка DataGrid, в которой используется автоматическая генерация столбцов. Решетка заполняется объектами Product. Для поиска каждого от­крытого свойства в связанном объекте данных применяется рефлексия. Для каждого свойства создается столбец. Для вывода нестроковых свойств используются вызовы ме­тода ToString (). Он правильно обрабатывает числа, даты и другие простые типы дан­ных, однако для более сложных объектов данных он непригоден, поскольку возвращает лишь имя файла. В этом случае необходимо явно определить столбцы, чтобы получить возможность связать вложенное свойство, использовать преобразователь значений или применить шаблон для правильного вывода содержимого.

В табл. 17.2 приведены некоторые свойства, которые можно использовать для грубой настройки внешнего вида элемента DataGrid. В следующих разделах рассматриваются способы более тонкого форматирования элемента DataGrid с помощью стилей и шаблонов. Кроме того, вы узнаете, как вынудить элемент DataGrid сортировать и отбирать строки.

Таблица 17.2. Свойства элемента DataGrid, влияющие на его внешний вид

Имя свойства

Описание

RowBackground И AlternatingRowBackground

Свойство RowBackground содержит кисть, используемую для прорисовки фона каждой строки. Если установить свойство AlternatingRowBackground, каждой второй строке будет присвоен другой фон, что облегчает визуальное отслеживание длинных строк. По умолчанию четным строкам присвоен светло-серый фон, а нечетным — белый

Окончание табл. 17.2

Имя свойства

Описание

ColumnHeaderHeight

Высота заголовка столбца в пикселях

RowHeaderWidth

Ширина столбца, содержащего заголовки строк, в пикселях. Этот столбец расположен первым слева. В нем не выводятся данные, он предназначен для индикации выделенной строки (стрелка) и режима редактирования строки (стрелка в кружочке)

ColumnWidth

Ширина каждого столбца, устанавливаемая по умолчанию. Если определить столбцы явно, их ширину можно переопределить. По умолчанию каждый столбец имеет ширину 100 пикселей

RowHeight

Высота каждой строки. Это свойство полезно, если планируется выводить в элементе DataGrid много строк текста или графическое содержимое (например, изображения). В отличие от столбцов, пользователь не может изменять ширину строк

GridlinesVisibility

Перечисление DataGridGridlines, определяющее видимость рамок решетки. Доступны значения Horizontal (Горизонтальные), Vertical (Вертикальные), None (Нет), АН (Все)

VerticalGrillinesBrush

Кисть, используемая для прорисовки линий рамки между столбцами

HorizontalGridlinesBrush

Кисть, используемая для прорисовки линий рамки между строками

HeadersVisibilіty

Перечисление DatagridHeaders, определяющее видимость заголовков. Доступны значения Column (Заголовки строк), Row (Заголовки столбцов), All (Все), None (Нет)

HorizontalScrollBadVisibility и VerticalScrollBarVisibility

Перечисление ScrollBarVisibility, определяющее вывод полос прокрутки. Доступны значения Auto (Автоматически при необходимости), Visible (Видимы всегда) и Hidden (Скрыть). По умолчанию оба свойства имеют значение Auto

Изменение размеров и перестановка столбцов

При выводе автоматически сгенерированных столбцов элемент DataGrid присваи­вает им ширину на основе ширины содержимого. Сначала каждый столбец получает ширину, достаточную для размещения наиболее широкой строки в текущем виде (или заголовка, если он шире).

Когда пользователь прокручивает строки, в текущем виде может появиться более широкая строка, не помещающаяся в столбце. В этом случае элемент DataGrid авто­матически увеличивает ширину столбца. Изменение ширины столбца одностороннее: когда длинная строка пытается расширить столбец за пределы текущего вида, ширина столбца не уменьшается.

Автоматическая установка размеров столбцов DataGrid — интересное и часто по­лезное средство, однако иногда желательно изменить правила установки. Решетка DataGrid, показанная на рис. 17.6, содержит столбец Description (Описание), содержа­щий длинные строки текста. Сначала столбец выводится достаточно широким, чтобы в каждой строке уместилось все содержимое. Естественно, на экране оно не помещается. Появляется горизонтальная полоса прокрутки, а остальные столбцы "убегают" вправо за пределы окна. На рис. 17.6 столбец Description показан после установки его ши­рины вручную. После установки ширины путем перетаскивания процедура автомати­ческой установки отключается и при появлении в текущем виде более широких полей ширина столбца не увеличивается.

Примечание. Не заставляйте своих пользователей работать со столбцами огромной ширины. Чтобы установить правильный размер столбца с самого начала, нужно явно определить столбец, как описано далее.

Обычно пользователь может изменить размеры столбца, перетаскивая границу за­головка. Чтобы запретить пользователю выполнять эту операцию, присвойте свойству CanUserResizeColumns значение False. Можно также установить более специфичное правило: запретить пользователю изменять ширину конкретного столбца. Для этого его свойству CanUserResize нужно присвоить значение False. Можете также запретить пользователю делать столбец слишком узким. Для этого присвойте минимальное значе­ние ширины свойству MinWidth столбца.

Пользователь может менять столбцы местами, перетаскивая их заголовки. Если нужно запретить пользователю выполнять эту операцию, присвойте значение False свойству CanUserReorderColumns элемента Grid или свойству CanUserReorder конкрет­ного столбца.

Определение столбцов

С помощью автоматической генерации столбцов можно быстро создать элемент DataGrid, выводящий все данные. Однако при этом разработчик теряет возможность управлять многими параметрами вывода. Например, нельзя задать последовательность и ширину столбцов, форматирование значений, текст заголовков и т.д.

Намного более мощный способ определения решетки состоит в отключении ав­томатической генерации столбцов путем присвоения значения False свойству AutoGenerateColumns. После этого можно определить все необходимые столбцы с тре­буемыми форматированием и последовательностью вывода. Для определения столбцов нужно заполнить коллекцию DataGrid.Columns объектами столбцов.

В текущей версии Silverlight элемент DataGrid поддерживает три типа столбцов, представленных тремя классами. Каждый из них наследует класс DataGridColumn.

•       DataGridTextColumn. Стандартный столбец для большинства типов данных. Зна­чение преобразуется в текст и выводится в элементе TextBlock. При редактиро­вании строки элемент TextBlock заменяется стандартным текстовым полем.

•       DataGridCheckBoxColumn. Поле содержит флажок. Этот тип столбца автомати­чески применяется для булевых значений. Обычно флажок выводится в режиме "только чтение", однако при редактировании строки он становится изменяемым.

•       DataGridTemplateColumn. Намного более мощный столбец, чем два предыдущих. Он позволяет определить шаблон данных для вывода значений столбца и пре­доставляет все средства шаблонов при использовании со списками. Например, столбец этого типа можно применить для вывода изображений. Можно также вставить в поле раскрывающийся список или элемент выбора дат DatePicker.

Тип DataGridTextColumn позволяет создать двухстолбчатую решетку, выводящую названия и цены продуктов. В приведенной ниже разметке заданы заголовки столбцов и расширен столбец Продукт, чтобы значения поместились во всех полях.

<data:DataGrid x:Name="gridProducts" Margin="5" AutoGenerateColumns="False"> <data:DataGrid.Columns> <data:DataGridTextColumn Header="npoflyKT" Width="175" Binding="(Binding ModelName}"> </data:DataGridTextColumn> <data:DataGridTextColumn Header="UeHa"

Binding="{Binding UnitCost}"></data:DataGridTextColumn> </data:DataGrid.Columns> </data:DataGrid>

При определении столбца почти всегда нужно установить три параметра: заголовок столбца, выводимый в верхней строке; ширину столбца; и выражение связывания, из­влекающее данные. Если нужно отключить процедуру автоматической установки ши­рины столбца, жестко закодируйте ее в пикселях. При автоматической установке ши­рины доступны три специальных значения: SizeToCells (столбец расширяется, пока не поместится самое длинное выводимое значение), SizeToHeader (ширина столбца опре­деляется шириной заголовка) и Auto (столбец расширяется, пока не поместится самое длинное выводимое значение или заголовок). При значе­ниях SizeToCells и Auto прокрутка строк при­водит к изменению ширины столбца. В одних случаях это неудобно, а в других — это является преимуществом.

Наиболее важный параметр — выражение связывания, предоставляющее информацию для столбца. В решетке DataGrid оно работа­ет немного не так, как в рассмотренных выше элементах списков. Список содержит свой­ство DisplaymemberPath, а решетка — свойство Binding. Свойство Binding более гибкое: оно по­зволяет добавить преобразователь значений без полнофункционального шаблона. Ниже приведе­на разметка с преобразователем значений, кото­рый форматирует столбец UnitCost как денежное значение (рис. 17.7).

<data:DataGridTextColumn Header="Price" Binding= "{Binding UnitCost,

Converter={StaticResource PriceConverter)}"> </data:DataGridTextColumn>

Конечно, в коллекции UserControl.Resources должен существовать экземпляр объ­екта PriceConverter с ключевым именем PriceConverter.

Рис. 17.10. Отметка строк

Существует еще один способ форматирования на основе значений. Для этого мож­но применить интерфейс iValueConverter, который проверяет связанные данные и при необходимости преобразует их. Данный способ особенно полезен в столбцах типа DataGridTemplateColumn. Например, на основе шаблона можно создать столбец, содер­жащий элемент TextBlock, и связать свойство TextBlock.Background с преобразовате­лем IValueConverter, устанавливающим цвет в зависимости от цены. Тогда, в отличие от предыдущего способа, основанного на событии LoadingRow, можно будет отформа­тировать только одну ячейку, содержащую цену, а не всю строку. Более подробно этот способ рассмотрен в главе 16.

Совет. Форматирование, задаваемое в обработчике события LoadingRow, применяется только при загрузке строки. При редактировании строки событие LoadingRow не генерируется и код обработки не выполняется (конечно, если не прокрутить решетку).

Источник: Мак-Дональд, Мэтью. Silverlight 3 с примерами на С# для профессионалов. : Пер. с англ. —- М. : ООО «И.Д. Вильяме», 2010. — 656 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии