Книга
Книга
Введение в
Microsoft'
Microsoft
ВТОРОЕ ИЗДАНИЕ
Silverlight" 2
Лоуренс Морони
Введение в
Microsoft® Silverlight™ 2
Второе издание
Лоуренс Морони
Здравствуйте, дорогой читатель!
Мы очень рады представить Вам первую книгу о технологии Microsoft Silverlight на русском языке!
Microsoft Silverlight позволяет разработчикам с помощью простых и мощных инструментов создавать интерактивные Интернет- приложения, которые становятся все популярнее среди широкого круга пользователей. Данная технология уже используется на многих известных ресурсах - как в мире, так и в России.
Silverlight 2 обладает существенным набором нововведений и улучшений. Каждый четвертый пользователь Интернета использует компьютер, на котором установлен Silverlight. Принимая во внимание текущую динамику, можно с уверенностью сказать, что данная технология будет и дальше распространяться среди пользователей во всем мире и Россия здесь не исключение.
Microsoft всегда с большой радостью рассказывает разработчикам о наших новых технологиях, в том числе Silverlight. От Вас, наших
читателей, пользователей, слушателей мероприятий, мы часто слышим о необходимости более комплексного подхода к изучению материала - прежде всего, в виде книги. Именно поэтому мне особенно приятно представлять Вам настоящее издание. Для перевода мы выбрали одного из наиболее популярных авторов настоящего времени по современным технологиям - Лоуренса Морони. Его книги пользуются неизменной популярностью у разработчиков во всем мире, отличаясь легкостью подачи материала, комплексным подходом и наглядностью примеров.
Надеюсь, данная книга позволит Вам максимально использовать Ваш потенциал для создания интересных, приятных и полезных приложений. Мы всегда с большой радостью рассказываем об удачных примерах использования наших технологий. Если с помощью Silverlight Вы сделаете оригинальное и интересное приложение, напишите нам об этом - devtlz@microsoft.com.
В завершение хочу поблагодарить Вас за интерес к технологии Microsoft Silverlight и предлагаю окунуться в увлекательный мир интерактивности.
Дмитрий Халин
Директор департамента стратегических технологий
Майкрософт Россия
ОПУБЛИКОВАНО
Microsoft Press
A Division of Microsoft Corporation
One Microsoft Way
Redmond, Washington 98052 6399
Copyright © 2008 by Laurence Moroney
Все права защищены. Ни одна часть данной книги не может быть воспроизведена в любой форме или любыми средствами без письменного разрешения издателя.
Контрольный номер Библиотеки Конгресса: 2008920565
Каталогизационная запись CIP этой книги предоставлена Британской библиотекой.
Книги Microsoft Press распространяются по всему миром оптом и в розницу. Для получения дополнительной информации о международных изданиях обращайтесь в региональный офис Корпорации Microsoft или напрямую в Microsoft Press International по факсу (425) 936 7329. Посетите наш Веб сайт по адресу www.microsoft.com/mspress. Присылайте комментарии на адрес электронной почты mspinput@microsoft.com.
Microsoft, Microsoft Press, Access, DirectShow, Expression, Expression Blend, InfoPath, IntelliSense, Internet Explorer, MSDN, Outlook, Silverlight, SQL Server, Visio, Visual Basic, Visual C#, Visual Studio, Win32, Windows, Windows Media, Windows NT, Windows Server и Windows Vista являются или зарегистрированными торговыми марками или торговыми марками групп компаний Microsoft. Другие упоминаемые здесь наименования продуктов или названия компаний могут быть торговыми марками соответствующих владельцев.
Все упоминаемые в книге названия компаний, организаций, продуктов, доменные имена, адреса электронной почты, логотипы, люди, места и события являются вымышленными. Никакой связи с реальными компаниями, организациями, продуктами, доменными именами, адресами электронной почты, логотипами, людьми, местами или событиями они не подразумевают и не имеют.
Данная книга представляет видение и мнение автора. Информация, содержащаяся в ней, предоставляется без всяких выраженных, установленных или предполагаемых гарантий. Ни авторы, Microsoft Corporation, ни распространители или продавцы не несут никакой ответственности за любой ущерб, который может быть причинен прямо или косвенно данной книгой.
Body Part No. X14 55515
Нелегко быть женой или детьми писателя. Я посвящаю эту книгу своей жене Ребекке и моим детям, Клодии и Кристоферу. Прошу прощения за все те бесчисленные «еще минуточку, пока я закончу эту часть» и бесконечные ожидания меня к столу или поиграть. Спасибо вам, ребята; вы лучшие!
Также хочу поблагодарить того, кто сделал все это возможным, - Бога Авраама, Исаака, Якова и Иисуса, за то, что даровал нам жизнь, любовь, счастье и надежду.
Содержание
Почему Silverlight?xii
Для кого эта книгаxiii
О чем эта книгаxiv
Системные требованияxiv
Веб-сайт компанииxiv
Поддержка книгиxiv
Вопросы и комментарииxv
Об автореxv
Silverlight и взаимодействие с пользователем16
Архитектура Silverlight18
Silverlight и XAML20
Silverlight и пакет инструментов ExpressionStudio22
Silverlight и Expression Design23
Silverlight и Expression Blend25
Проект Silverlight 125
Веб-страница по умолчанию26
Silverlight и Expression Encoder28
Заключение31
Начало работы с Expression Blend32
Создание приложения Silverlight 233
Страница по умолчанию34
Файл App.xaml и файлы с выделеннымкодом по умолчанию35
Выполнение приложения36
Интегрированная среда разработки Expression Blend37
Панель инструментов38
Панель взаимодействий38
Рабочая поверхность39
Панель проекта40
Панель свойств41
Использование Blend для создания приложений Silverlight42
Компоновка42
Использование сетки43
Использование StackPanel45
Использование ScrollViewer46
Элемент управления Border47
Размещение и настройка визуальных элементов47
Размещение и настройка элементов управления48
Использование Blend для создания анимаций49
Заключение51
Установка Visual Studio Tools для Silverlight53
Использование Visual Studio для создания приложения Silverlight55
Создание Silverlight-приложения в Visual Studio 200855
Проект элемента управления Silverlight57
Понимание свойств проекта Silverlight58
Файлы свойств59
Ссылки59
Файлы App.xaml и App.xaml.cs60
Файлы Page.xaml и Page.xaml.cs61
Веб-проект62
Написание игры на Silverlight 264
Создание UI в XAML64
Написание кода игры64
Инициализация структур данных64
Создание фрагментов головоломки65
Перемешиваем фрагменты67
Отрисовка игрового поля67
Обработка действий пользователя68
Проверка условия выигрыша69
Заключение70
Компоновочные свойства XAML71
Кисти XAML73
SolidColorBrush 73
LinearGradientBrush73
Изменение направления распространения градиента74
Добавление точек градиента74
RadialGradientBrush 76
Задание фокуса76
Изменение SpreadMethod77
Задание радиуса RadialGradientBrush78
Использование ImageBrush79
Растягивание изображения79
Выравнивание изображения80
VideoBrush81
Визуальные свойства XAML81
Использование свойств XAML для задания размеров и местоположения81
Использование прозрачности82
Поведение курсора82
Управление свойством Stroke82
Задание ширины обводки83
Задание обводки пунктиром84
Определение типа соединения линий85
Фигуры в XAML86
Использование объекта Ellipse86
Использование объекта Rectangle86
Использование объекта Line87
Использование контуров и геометрических элементов87
Объект ArcSegment88
Объект LineSegment88
Объект PolyLineSegment89
Объект BezierSegment89
Объект PolyBezierSegment89
Объект QuadraticBezierSegment90
Объект PolyQuadraticBezierSegment91
Составные сегменты контура92
Использование объекта GeometryGroup92
Язык описания контуров93
Вырезание и геометрические элементы в XAML94
Элементы управления XAML в Silverlight95
Элемент Canvas95
Элемент Image96
Участки и разрывы строк98
Заключение99
Трансформации100
Вращение с помощью RotateTransform100
Масштабирование с помощью ScaleTransform102
Перемещение объекта с помощью TranslateTransform103
Наклон объекта с помощью свойства SkewTransform104
Имитация трехмерного изображения с помощью SkewTransform105
Определение собственных трансформаций с помощью MatrixTransform106
Сочетание трансформаций107
Анимация108
Использование триггеров и триггеров событий108
Использование BeginStoryboard и Storyboard109
Определение параметров анимации109
Задание объекта анимации110
Задание продолжительности110
Задание момента начала110
Использование свойства SpeedRatio110
Использование свойства AutoReverse110
Задание свойства RepeatBehavior110
Анимация значения с помощью DoubleAnimation111
Анимация цвета с помощью ColorAnimation111
Анимация точки с помощью PointAnimation112
Использование ключевых кадров112
Использование линейных ключевых кадров113
Использование ключевых кадров дискретной анимации114
Использование ключевых кадров сглаженной анимации114
Анимация и Expression Blend115
Заключение119
Размещение Silverlight в браузере120
Использование тега Object напрямую123
Реакция на события загрузки страницы124
Обработка параметров124
Пользовательский контекст125
Реакция на события, возникающие в случае ошибки на странице127
Стандартный обработчик событий128
Использование собственного обработчика ошибок128
Свойства элемента управления Silverlight130
Непосредственные свойства130
Свойства содержимого130
Свойства настроек130
Методы элемента управления Silverlight131
Метод createFromXaml131
Метод createFromXamlDownloader132
Метод createObject132
Метод findName132
Объект Downloader132
Свойства объекта Downloader132
Методы объекта Downloader132
События объекта Downloader133
Использование объекта Downloader133
Программирование элементов UI134
Методы элементов UI134
Методы AddEventListener и RemoveEventListener134
Метод findName135
Организация доступа к элементу управления с помощью метода GetHost135
Организация доступа к родительскому элементу с помощью метода getParent135
Использование методов GetValue и SetValue135
Использование SetFontSource136
События элементов UI137
Реализация перемещения элементов методом «Drag-and-Drop»138
Заключение140
Элемент управления Button141
Элемент управления CheckBox142
Элемент управления HyperlinkButton143
Элемент управления Image144
Элемент управления ListBox145
Элемент управления RadioButton147
Элемент управления TextBox150
Общие свойства, события и методы152
Обработка фокуса152
Обработка событий мыши153
Использование событий мыши для реализации перемещения объектов методом «Drag-and-drop»153
Использование клавиатуры155
Заключение156
Элемент управления DataGrid157
Элементы управления Calendar и DatePicker162
Элементы управления RepeatButton и ToggleButton164
Элемент управления ScrollViewer165
Элемент управления Slider167
Заключение167
Создание проекта168
Добавление шаблона элемента управления169
Написание кода элемента управления170
Создание библиотек классов Silverlight172
Заключение176
Подключение приложений с помощью XAML177
Silverlight и PHP177
Ваша первая PHP-страница177
Учебный пример PHP и XAML178
Silverlight и Java186
Создание сервлета для генерирования XAML187
Отображение Silverlight из JSP190
Использование JavaScript для создания приложений, взаимодействующих с сервером191
Использование AJAX191
Создание серверного приложения для получения текущего времени191
Создание клиентского приложения для отображения времени192
Использование ASP.NET AJAX и Веб-сервисов194
Взаимодействие и данные в .NET196
Класс WebClient196
Класс WebRequest197
Использование SyndicatedFeed для организации доступа к RSS и ATOM199
Silverlight и WCF201
Элемент управления MediaElement205
Использование элемента управления MediaElement206
Простое воспроизведение видео с помощью элемента управленияMediaElement206
Размеры элемента управления MediaElement207
Растяжение мультимедиа207
Прозрачность видеоизображения209
Использование трансформаций с элементом управления MediaElement209
Расположение содержимого поверх видеоизображения210
Вырезание мультимедиа геометрическими формами210
Автоматическое воспроизведение211
Управление воспроизведением звука211
Программирование MediaElement212
Базовые элементы управления воспроизведением212
Управление буферизацией и загрузкой214
Управление текущим состоянием видео215
Управление положением курсора воспроизведения216
Использование маркеров временной шкалы мультимедиа217
Закрашивание поверхностей видеоизображением с помощью VideoBrush219
Элемент управления InkPresenter220
Пример рукописных примечаний в Silverlight221
Классы рукописного ввода в Silverlight для разработчиков на JavaScript222
Тип StrokeCollection222
Тип Stroke222
Тип StylusPointCollection223
Тип StylusPoint223
Аргументы событий мыши и рукописный ввод224
Программирование для рукописного ввода в Silverlight224
Реализация Deep Zoom с помощью элемента управления MultiScaleImage228
Использование редактора Deep Zoom230
Первый проект Deep Zoom233
Использование мыши и логических координат в Deep Zoom234
Создание функциональности масштабирования с использованиемколеса мыши236
Коллекции в Deep Zoom237
Заключение239
Понимание стилевого оформления240
Создание стиля241
Изменение области действия стиля242
Шаблоны243
Заключение245
Серверный элемент управления Silverlight246
Использование счетчика частоты кадров246
Задание максимальной частоты кадров248
Обеспечение доступа к HTML248
Использование перерисовываемых областей249
Задание свойства PluginBackground249
Управление установкой подключаемого модуля250
Использование режима Stretch251
Использование режима Windowless252
События серверного элемента управления Silverlight253
Элемент управления MediaPlayer в ASP.NET254
Настройка при помощи MediaPlayer Tasks254
Взаимодействие с мультимедиа255
Заключение256
Ваше первое Silverlight-приложение на IronPython257
Использование Ruby и JavaScript261
Использование Ruby262
Использование Dynamic JavaScript262
Более сложный пример263
Заключение267
Благодарности
Спасибо всем сотрудникам Microsoft Press и Microsoft Learning за сведение этой книги воедино. Отдельная благодарность Виктории Талман (Victoria Thulman), которая руководила этим проектом. Я чрезвычайно признателен ей за то, что была со мной откровенна и не давала выбиться из графика.
Введение
Почему Silverlight?
По мере роста и развития Веб, растут и ожидания Веб-пользователя. Первый Веб-браузер обеспечивал относительно простой способ создания ссылок между документами. Когда эти браузеры были объединены с протоколами межмашинного взаимодействия, появился Интернет и неожиданно документы, хранящиеся на серверах по всему миру, стали доступными друг для друга.
Со временем аудитория, использующая Интернет, изменилась. Сейчас это уже не маленькая группа людей, связанных с наукой и исследованиями в области вычислительной техники, а все население планеты в целом. И то, что было приемлемым пользовательским интерфейсом для экспертов в этой области, выглядит совершенно скудно для коммерческих приложений. Сейчас люди хотят иметь насыщенные, но при этом простые в использовании пользовательские интерфейсы, и чем больше типов информации становится доступно в Интернете (включая разнообразные виды медиафайлов), тем сложнее отвечать ожиданиям пользователей, касающимся простоты доступа к необходимым им данным.
Необходимость снабдить пользователей сложными средствами доступа к Интернет-ресурсам, которые были бы просты в использовании, приводят к появлению расширенных технологий разработки приложений. Одной из таких технологий является, например, создание «подключаемых» инструментов, которые позволяют браузеру частично использовать локальные вычислительные ресурсы пользователей.
Элементы управления ActiveX, Java-апплеты и Flash-приложения - все это примеры технологии подключаемых модулей. Асинхронный JavaScript и XML (AJAX) - еще один инструмент, созданный для разработки замечательных пользовательских интерфейсов нового поколения, в основе которых лежит концепция немедленных частичных обновлений. При использовании AJAX область экрана браузера не мигает и не блокируется, потому что полное обновление страницы выполняется редко.
AJAX позволяет разработчикам создавать более динамичные Веб-сайты, с более сложным содержимым, чем мог бы обеспечить только HTML, но его возможности тоже не безграничны. Например, он реализует асинхронный обмен информацией с сервером. Это позволяет приложениям самостоятельно обновляться в фоновом режиме и устраняет проблему с мерцанием экрана, что так часто можно наблюдать в сложных пользовательских Веб-интерфейсах. Но AJAX - это лишь механизм связи браузер- сервер. В нем нет поддержки графики, анимации, видео и других возможностей, необходимых для создания по-настоящему мультимедийных пользовательских интерфейсов.
Для выхода за рамки этих ограничений Microsoft разработана стратегия взаимодействия пользователя (UX) с Веб. В ней определяется три уровня качества взаимодействия - «хорошее», «замечательное» и «предельное», - соответственно которым принимается решение о применяемых технологиях разработки и выполнения. В данной книге эта классификация тесно связана с понятиями «насыщенный» и «насыщенность». Когда я говорю «насыщенный», я пытаюсь описать концепцию, которую сложно выразить словами. Сравните ощущение, испытываемое при работе с традиционным Веб-приложением, ограниченным возможностями браузера и HTML, с тем, когда вы работаете с настольным приложением, имеющим в своем распоряжении службы и возможности всей операционной системы. Сегодняшние Веб-приложения не обеспечивают функциональности настольных приложений, и пользователь обычно понимает, что причиной их ограниченности является технология. Применяя Silverlight (и AJAX), мы ставим цель создать Веб-приложения, очень близкие к настольным приложениям и, в конечном счете, неотличимые от них.
Самый простой уровень взаимодействия с пользователем можно реализовать в браузере, расширенном AJAX. Этот уровень определяет базовое на сегодняшний день ожидание UX - асинхронное динамическое приложение браузера, обеспечиваемое AJAX.
Верхний или «предельный» уровень - это насыщенное клиентское настольное приложение, выполняющее Windows Vista и использующее Windows Presentation Foundation (WPF) и .NET Framework. Эти технологии предлагают среду выполнения, которая позволяет разработчикам создавать исключительно насыщенные приложения, легко развертываемые и обслуживаемые. На этом уровне доступна передача качественной графики, видео и анимации, а также службы приложений, такие как хранение в виде файлов и интеграция с другими настольными приложениями. Кроме того, WPF разделяет технологии дизайна и разработки, таким образом, дизайн и представление пользовательских интерфейсов создаются на новом языке программирования, называемом XML Application Markup Language (XAML). Дизайнеры получили созданные специально для них инструменты дизайна, такие как серия Microsoft Expression, и могут теперь представлять свою работу в виде XAML-документов. А разработчики претворяют в жизнь мечты дизайнеров, активируя этот XAML кодом на С#, VB.NET или JavaScript.
Я упомянул три уровня в стратегии UX, потому что по мере развития AJAX и .NET/WPF стало очевидным наличие промежуточной ниши для новой технологии, эффективно сочетающей в себе лучшие черты обоих миров - глобальную масштабируемость Интернет-приложения и насыщенность настольного приложения. Такое взаимодействие с пользователем было названо «замечательным» и обеспечивается браузером, расширенным AJAX и новой технологией, Silverlight.
Silverlight - это подключаемый модуль для браузера, формирующий визуальное представление XAML и предоставляющий программный интерфейс. Таким образом, он обеспечивает возможность совместной работы дизайнеров и разработчиков при создании Интернет-приложений, обладающих насыщенностью настольных приложений.
Первая выпущенная версия Silverlight представила JavaScript-ориентированную модель программирования, которая обеспечила мощное средство написания сценариев для XAML-элементов в браузере. Silverlight 2 существенно расширяет эту модель поддержкой .NET, благодаря которой появляется возможность использования языков программирования .NET и переход на новый уровень за счет работы с XAML, обеспечения использования готовых элементов управления, поддержки работы с сетью, мощных библиотек данных, расширяемости и существенного улучшения производительности.
В данной книге рассматривается Silverlight и то, как он обеспечивает лучшее взаимодействия с пользователем в Веб.
Silverlight может изменить ваше представление о построении приложений для Веб. Вместо Веб-сайтов теперь будет создаваться Веб-впечатление. В основе замечательного впечатления лежит замечательный дизайн, и Silverlight через XAML и инструменты пакета Microsoft Expression позволяет дизайнерам и разработчикам объединить свои усилия на пути к достижению этой цели.
При написании этой книги я ставил перед собой задачу обеспечить понимание технологий, используемых совместно для разработки и развертывания Веб-приложений Silverlight, от написания базового кода для Silverlight до расширенных инструментов для создания и доставки Silverlight-содержимого. Прочитав эту книгу и проработав все примеры, вы должны быть готовы применять изученное на практике для улучшения Веб-приложений, развертываемых сейчас. А представьте, что вы сможете сделать завтра!
Для кого эта книга
Эта книга написана для разработчиков, которые готовы ежедневно работать над созданием новых и лучших Веб-приложений для пользователей Интернет и которые хотят добавить эту передовую технологию Microsoft в комплект своих знаний, чтобы понять, как с ее помощью обеспечить более интересные, функциональные и эффективные пользовательские интерфейсы. Книга написана доступно и может быть полезной также руководителям разработки для понимания места Silverlight в мире Вебтехнологий Microsoft. Руководители даже могут почерпнуть из нее базовые технические сведения, которые им понадобятся, когда их разработчики с взволнованным видом придут поговорить о Silverlight. По крайней мере, они будут понимать, чем вызван такой энтузиазм!
О чем эта книга
Эта книга разделена на две части. Часть I, Введение в Silverlight 2, представляет основы Silverlight. В ней рассматривается, что такое Silverlight, и какие инструменты используются для создания и обслуживания Silverlight-приложений, включая Microsoft Expression Blend и Microsoft Visual Studio.
В Части I также обсуждается технология XAML и то, как она использует XML для описания всего пользовательского интерфейса, начиная от компоновки элементов управления, до анимации и пр. Наконец, в этой части подробно рассматривается сам подключаемый модуль Silverlight и его взаимодействие с браузером, благодаря которому ваши приложения становятся полноправными обитателями браузера.
В Части II, Программирование в Silverlight 2, мы переходим к деталям высокоуровневых концепций Silverlight 2. Это обсуждение ни в коем случае не является исчерпывающим справочником, но написано как простое и строгое введение в разработку в Silverlight. Сначала рассматриваются встроенные элементы управления, им посвящены две главы, затем демонстрируется, с какой легкостью могут создаваться собственные элементы управления. Вы изучите данные, взаимодействие по сети, программирование анимации, элементы управления ASP.NET для Silverlight, а также некоторые расширенные элементы управления для работы с мультимедиа и рукописным вводом и новый компонент DeepZoom, обеспечивающий сногсшибательное представление изображений. И завершается книга обзором новой захватывающей возможности Silverlight: поддержки динамических языков программирования.
Системные требования
Для разработки Silverlight-приложений, представленных в данной книге, понадобиться следующее (опять же, все доступно на сайте http://silverlight.net/GetStarted/):
Microsoft Visual Studio 2008 с пакетом обновлений SP1
Microsoft Expression Design
Microsoft Expression Blend 2 с пакетом обновлений SP1
Microsoft Silverlight Software Development Kit
Рекомендуемая конфигурация системы для Microsoft Silverlight: 128 МБ оперативной памяти и процессор с частотой 450 МГц или более для Windows и 1 ГБ оперативной памяти и процессор Intel с частотой 1,83 ГГц или более для Mac OSX.
Рекомендуемая конфигурация для Microsoft Visual Studio 2008: ЦП с частотой 2,2 ГГц или более, оперативной памяти 1024 МБ или более, экран 1280 x 1024, жесткий диск с частотой вращения 7200 об/мин или выше. (Минимальные требования: ЦП с частотой 1,6 ГГц, 384 МБ оперативной памяти, экран 1024 x 768, жесткий диск с частотой вращения 5400 об/мин.) Для Windows Vista рекомендуется: ЦП с частотой 2,4 ГГц, 768 МБ оперативной памяти.
Веб-сайт компании
Данная книга представлена на Веб-сайте компании, где можно найти весь используемый в ней код. Он организован по главам. Скачать его можно с сайта компании по адресу:
http://www.microsoft.com/mspress/companion/9780735625280
Поддержка книги
Microsoft Press обеспечивает поддержку книг и сопроводительных материалов на следующем Вебсайте:
http://www.microsoft.com/learning/support/books/
Дополнительные материалы можно найти в сети Все новые или обновленные материалы, дополняющие эту книгу, будут размещаться на Веб-сайте Microsoft Press Online Developer Tools. К таким материалам относятся обновления содержимого книги, статьи, ссылки на сопроводительные материалы, список опечаток, примеры глав и многое другое. Этот Веб-сайт будет доступен в скором времени по адресу www.microsoft.com/learning/books/online/developer и будет периодически обновляться.
Вопросы и комментарии
Все комментарии, вопросы или предложения, касающиеся данной книги или сопроводительных материалов, и вопросы, ответы на которые вы не смогли найти на перечисленных выше сайтах, пожалуйста, направляйте в Microsoft Press по электронной почте:
mspinput@microsoft.com
или по почте:
Microsoft Press
Attn: Introducing Microsoft Silverlight 2 Editor
One Microsoft Way
Redmond, WA 98052-6399
Обратите внимание, что по указанным адресам не предоставляется поддержка программных продуктов Microsoft.
Об авторе
Лоуренс Морони (Laurence Moroney) является Ведущим экспертом по технологиям Microsoft, специализирующимся на Silverlight и User Experience. Имеет более чем десятилетний опыт разработки и реализации программного обеспечения и является автором около десятка книг по разнообразнейшим тематикам, среди которых Windows Presentation Foundation, Веб-разработка, безопасность и способность к взаимодействию. Кроме того, им написано более 150 статей для различных печатных и онлайн изданий и сделано множество докладов по этим темам на многих конференциях
по всему миру. Когда не занят Silverlight или написанием книг, он подрабатывает спортивным обозревателем для Высшей футбольной лиги, национальных мужской и женской сборных США и нового ФК Seattle Sounders. Лоуренс живет со своей женой Ребеккой и двумя детьми в Саммамиш (Sammamish), штат Вашингтон.
Глава 1
Введение в Silverlight 2
Silverlight является следующим шагом в направлении к улучшению взаимодействия с пользователем через Веб. Цель Silverlight - обеспечить в Веб-приложениях точность отображения и качество пользовательского интерфейса (user interface, UI) доступное в настольных приложениях, позволяя Вебразработчикам и дизайнерам реализовывать в создаваемых решениях особые требования заказчиков. Silverlight заполняет технологический вакуум между дизайнерам и разработчикам, предоставляя им общий формат для работы. Этот формат обрабатывается браузером и основывается на XML, что упрощает создание шаблонов и автоматическое формирование представления. Таким форматом является XAML - Extensible Application Markup Language (расширяемый язык разметки приложений).
До появления XAML дизайнер Веб-приложений создавал дизайн, используя какой-то определенный набор инструментов и хорошо знакомую ему технологию. Затем разработчик брал то, что сделал дизайнер, и интерпретировал это с помощью другой технологии по своему выбору. Трансформировать то, что было создано дизайнером, без проблем и правильно получалось не всегда, и разработчикам приходилось вносить множество изменений, которые подчас нарушали дизайн. С Silverlight дизайнер может с помощью определенных инструментов изобразить дизайн в виде XAML, передать этот XAML разработчику, который, в свою очередь, может наполнить его функциональностью при помощи кода и развернуть.
Microsoft Silverlight - это подключаемый модуль, который может использоваться в разных браузерах и на разных платформах, разработанный для обеспечения возможности создания сложных сценариев воспроизведения мультимедиа и создания насыщенных интерактивных Интернет-приложений с использованием современных технологий. Он предлагает завершенную модель программирования, которая поддерживает AJAX, .NET и такие динамические языки программирования, как Python и Ruby. Возможность программирования в Silverlight 1.0 обеспечивалась поддержкой существующих Вебтехнологий, включая AJAX, JavaScript и DHTML. В Silverlight 2 добавляется поддержка динамических языков программирования и языков программирования .NET, а также появляются новые возможности, доступные только при использовании .NET Framework, такие как Изолированное хранилище (Isolated Storage), Работа с сетью (Networking), обширный набор элементов управления и т.д.
В первой части данной книги представлены основы Silverlight 2 и предлагаемые инструменты для дизайна и разработки. Вторая часть книги посвящена более детальному рассмотрению модели программирования.
Silverlight и взаимодействие с пользователем
Silverlight создан как часть огромной экосистемы, используемой для обеспечения наилучшего взаимодействия с конечным пользователем. Существует ряд типовых сценариев доступа к информации через Интернет:
Посредством мобильных устройств
Посредством продуктов типа «Цифровой дом»
Посредством нерасширяемых браузеров (без подключаемых модулей)
Посредством расширяемых браузеров (использующие такие подключаемые модули, как Flash, Java или Silverlight)
Посредством настольных приложений
Посредством офисных программ
С годами ожидания пользователей относительно того, как должны работать эти приложения, изменились. Например, ожидание, что приложение на настольном компьютере должно быть более функцио-
нальным, чем приложение того же типа в мобильном устройстве. Мы как пользователи привыкли к намного большим возможностям настольных устройств по сравнению с мобильными. Кроме того, многие считают, что «так как приложение развернуто в Веб», оно может не обладать теми возможностями, которые предлагает аналогичное настольное приложение. Например, пользователь предъявляет меньшие требования к почтовому Веб-приложению, потому что не верит, что оно может предлагать те же возможности работы с электронной почтой, что и офисные программы, такие как обеспечивает Microsoft Office Outlook.
Однако по мере сближения этих платформ ожидания пользователя растут, и теперь для описания возможностей, превышающих текущий базовый уровень ожиданий, широко используется термин насыщенный (rich). Например, понятие «насыщенное Интернет-приложение» появилось в ответ на повышение уровня сложности приложений с поддержкой AJAX для обеспечения более широких динамических возможностей в таких сценариях, как работа с электронной почтой и картографическими системами. Эволюция ожиданий привела к появлению пользователей, которые хотят получать самые широкие возможности, отвечающие не только требованиям с точки зрения функциональности и эффективности приложения, но также обеспечивающие чувство удовлетворенности продуктами и службами компании, что может служить основной для установления длительных отношений между пользователем и компанией.
В результате, Microsoft направила свои ресурсы на Взаимодействие с пользователем (User Experience, UX) и поставляет инструменты и технологии, которые разработчики могут использовать для реализации UX насыщенных приложений. Кроме того, все эти средства согласованы, т.е. навыки разработки UX- ориентированных приложений будут применимы во всех областях разработки настольных и Вебприложений. Итак, если требуется создать Веб-версию насыщенного настольного приложения, нет необходимости осваивать новые инструменты и технологии. Аналогично, если создается мобильное приложение и требуется Интернет-версия, нет необходимости иметь два набора навыков, два набора инструментов и два группы разработчиков.
На рис. 1-1 показаны доступные на сегодняшний день модели формирования представления и программирования с ориентированием на Веб. Как можно видеть, типовыми технологиями разработки Веб-приложений являются CSS/DHTML в модели представления и JavaScript/AJAX/ASP.NET в модели разработки. Для настольных приложений, создаваемых на .NET Framework 3.x, XAML обеспечивает модель представления, а модель разработки обеспечивается самой средой .NET. На пересечении этих технологий - браузер с поддержкой Silverlight, обеспечивающий объединение «лучшего из обоих ми
ров».
РИС. 1 1 Модели программирования и представления для Веб.
Типовое насыщенное интерактивное приложение основывается на технологиях, располагающихся в категории «нерасширяемый браузер». Типовое настольное приложение находится в другой части диапазона, для его создания используются совершенно другие технологии. Объединить эти приложения в полнофункциональное легковесное приложение, выполняющееся в браузере, позволяет браузер с
поддержкой Silverlight, обеспечивающий модель дизайна CSS/DHTML и XAML и модель программирования JavaScript/AJAX/.NET Framework.
Silverlight достигает этого за счет предоставления подключаемого модуля, расширяющего функциональность браузера такими типовыми технологиями насыщенных UI, как анимация с использованием временной шкалы, векторная графика и аудиовизуальные мультимедиа. Это возможно благодаря средствам формирования визуального представления XAML для браузера, предоставляемым Silverlight. Насыщенный UI может создаваться как XAML-код, и поскольку XAML - язык, основанный на XML, и XML - это просто текст, приложение является совместимым с брандмауэром и (потенциально) удобным для поискового механизма. Браузер получает XAML и визуализирует его.
В сочетании с такой технологией, как AJAX и JavaScript, это может быть динамическим процессом. Фрагменты XAML можно загружать и добавлять в UI, или можно редактировать, реорганизовывать или удалять XAML, находящийся в данный момент в дереве визуального представления, используя простое программирование на JavaScript.
Архитектура Silverlight
Как говорилось выше, основная функциональность Silverlight обеспечивается подключаемым модулем браузера. Этот модуль формирует визуальное представление XAML и обеспечивает модель программирования, которая может основываться либо на JavaScript, либо на .NET Framework и CLR. Поддерживающая это архитектура представлена на рис. 1-2. Основным механизмом программирования поведения приложения Silverligth 1.0 в браузере является JavaScript DOM API. Он позволяет перехватывать пользовательские события, возникающие в приложении (такие как перемещения мыши или щелчки определенного элемента), и вызывать код, определяющий реакцию на них. С помощью методов JavaScript DOM можно манипулировать элементами XAML, например, управлять воспроизведением мультимедиа или анимацией.
Для создания еще более насыщенного и функционального интерфейса доступны все возможности .NET Framework CLR. Помимо того, что можно сделать в JavaScript, данная возможность предлагает множество пространств имен и элементов управления, поставляемых как часть .NET Framework, что позволяет делать вещи, которые было очень сложно, или вообще невозможно, реализовать в JavaScript. Например, доступ к данным с помощью ADO.NET и LINQ, обмен информацией с Веб-сервисами, создание и использование пользовательских элементов управления и т.д.
Архитектура Silverlight
Визуализация[ JavaScript DOM APIВизуализация[ JavaScript DOM APIСреда выполнения.NETСреда выполнения.NETXAMLXAMLЭлементы управления /расширяемостьЭлементы управления /расширяемость[ Видео/аудио кодеки ] Ядро визуализации ][ Видео/аудио кодеки ] Ядро визуализации ]Сетевые подключения /данныеСетевые подключения /данные[домен приложений CLR ][домен приложений CLR ]
Визуализация
[ JavaScript DOM API
Визуализация
[ JavaScript DOM API
Среда выполнения.NET
Среда выполнения.NET
XAML
XAML
Элементы управления /расширяемость
Элементы управления /расширяемость
[ Видео/аудио кодеки ] Ядро визуализации ]
[ Видео/аудио кодеки ] Ядро визуализации ]
Сетевые подключения /данные
Сетевые подключения /данные
[домен приложений CLR ]
[домен приложений CLR ]
Изолированноехранилище
Подключаемый модуль браузера
Поддержка браузеровПоддержка браузеров
Поддержка браузеров
Поддержка браузеров
рис. 12 Архитектура Silverlight.
Кроме того, среда формирования представления поставляется вместе с компонентами, необходимыми для обеспечения возможности воспроизведения в браузере таких файлов, как WMV, WMA и MP3, без всяких внешних зависимостей. Так, например, пользователям Macintosh не нужен проигрыватель Windows Media для воспроизведения WMV-содержимого, достаточно одного Silverlight. Основой всей среды формирования представления является код представления, и он управляет всем процессом визуализации. Все это встроено в подключаемый модуль браузера, поддерживающий основные браузеры Windows и Macintosh.
На рис. 1-3 представлена архитектура простого приложения, выполняющегося в браузере с использованием Silverlight.
РИС. 1 3 Архитектура приложения, использующего Silverlight.РИС. 1 3 Архитектура приложения, использующего Silverlight.
РИС. 1 3 Архитектура приложения, использующего Silverlight.
РИС. 1 3 Архитектура приложения, использующего Silverlight.
В основе выполняющегося в браузере приложения обычно лежит HTML. Эта разметка содержит вызовы для создания экземпляров подключаемого модуля Silverlight. При взаимодействии с приложением Silverlight пользователи генерируют события, которые могут быть обработаны функциями JavaScript или .NET Framework. В свою очередь, код программы может вызывать методы элементов содержимого Silverlight для управления ими, добавления нового или удаления существующего содержимого. Наконец, подключаемый модуль может читать и формировать визуальное представление XAML. Сам XAML
может быть встроен в страницу, существовать как внешний статический файл или как динамический XAML, возвращаемый сервером.
Silverlight и XAML
Теперь, получив общее представление об архитектуре Silverlight и о том, как будет выглядеть типовое приложение, обратимся к основе UX: XAML.
XAML - это язык разметки на базе XML, используемый для определения визуальных элементов приложения. К ним относятся UI, графические элементы, анимации, мультимедиа, элементы управления и пр. XAML был представлен Microsoft в Windows Presentation Foundation (WPF), ранее называемом Avalon, который является технологией, ориентированной на выполнение на клиентском компьютере, и частью .NET Framework 3.0 и последующих версий. Как обсуждалось ранее, он разработан с целью заполнения технологической пропасти между дизайнерами и разработчиками при создании приложений.
XAML, используемый в Silverlight, отличается от XAML в WPF. В данном случае XAML - это подмножество , ориентированное на возможности Веб-приложений. Так что те, кто знаком с XAML из WPF, заметят отсутствие некоторых тегов и функциональности, например, элемента <Window>.
XAML использует XML для определения UI с помощью элементов XML. Корнем всех XAML-документов Silverlight является элемент-контейнер, такой как Canvas (Холст), определяющий область, в которой будет отрисован ваш UI. При построении Silverlight-приложения корневой элемент Canvas будет содержать объявления пространств имен XML, необходимых Silverlight.
Рассмотрим пример XAML-документа в Silverlight 1.0:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Background="White" >
</Canvas>
Можно заметить, что объявлены два пространства имен. Типовой документ XAML содержит базовый набор элементов и атрибутов и дополнительный набор, для описания которого обычно используется префикс х:. Примером дополнительного атрибута пространства имен является широко используемый x:Name, с помощью которого задается имя элемента XAML, что позволяет ссылаться на него в коде. Корневой элемент Canvas объявляет местоположение пространства имен всех элементов.
Элемент Canvas является контейнером. Это означает, что он может содержать другие элементы как дочерние. Эти элементы тоже могут быть контейнерами для других элементов, определяя UI как дерево XML-документа. Например, ниже представлен простой XAML-документ с рядом дочерних элементов, некоторые из которых сами являются контейнерами Canvas:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Background="Black" >
<Rectangle Fill="#FFFFFFFF" Stroke="#FF000000"
Width="136" Height="80"
Canvas.Left="120" Canvas.Top="240"/>
<Canvas>
<Rectangle Fill="#FFFFFFFF" Stroke="#FF000000"
Width="104" Height="96"
Canvas.Left="400" Canvas.Top="320"/>
<Canvas Width="320" Height="104"
Canvas.Left="96" Canvas.Top="64">
<Rectangle Fill="#FFFFFFFF" Stroke="#FF000000"
Width="120" Height="96"/>
<Rectangle Fill="#FFFFFFFF" Stroke="#FF000000"
Width="168" Height="96"
Canvas.Left="152" Canvas.Top="8"/> </Canvas>
</Canvas>
</Canvas>
Здесь можно увидеть, что у корневого Canvas есть два дочерних элемента: Rectangle и другой Canvas. Второй Canvas также содержит Rectangle и Canvas, и в последнем Canvas находится еще два элемента Rectangle. Такая иерархическая структура позволяет логически группировать элементы управления и использовать для них общую компоновку и поведение.
XAML в Silverlight поддерживает ряд фигур, которые можно сочетать для получения более сложных объектов. Намного более подробно использование XAML рассматривается в Главе 4, «Основы XAML», сейчас остановимся лишь на основных фигурах:
Rectangle Позволяет определять на экране прямоугольную форму
Ellipse Позволяет определять эллипс или круг
Line Отрисовывает прямую линию, соединяющую две точки
Polygon Отрисовывает многоугольник
Polyline Отрисовывает ломаную линию
Path Позволяет создавать нелинейные контуры (например, каракули)
Помимо этого, XAML поддерживает кисти (brushes), которые определяют, как объект закрашивается на экране. Внутренняя область объекта закрашивается с помощью кисти fill, а контур объекта отрисовывается кистью stroke. Существует множество типов кистей, включая одноцветные кисти, градиентные, изображения и видео.
Рассмотрим пример использования кисти SolidColorBrush (Одноцветная кисть) для закрашивания эллипса:
<Ellipse Canvas.Top="10" Canvas.Left="24" Width="200" Height="150">
<Ellipse.Fill>
<SolidColorBrush Color="Black" />
</Ellipse.Fill>
</Ellipse>
В данном случае кисть использует один из 141 поддерживаемых Silverlight именованных цветов, Black (черный). Также может использоваться стандартная шестнадцатеричная RGB-запись для создания цветов.
Заливки и обводки также могут иметь градиентную заливку. Для этого используется градиентная кисть. Градиент определяется рядом контрольных точек градиента (gradient stops) в нормированном пространстве (normalized space). Так, например, если требуется определить линейный градиент, в котором цвета будут изменяться слева направо от черного к белому через оттенки серого, необходимо задать соответствующие контрольные точки на нормированной линии. В этом случае начало нормированной линии принимается за точку 0, и конец - за точку 1. Таким образом, градиент слева направо в одномерном пространстве имеет две точки градиента, 0 и 1. Если необходимо получить градиент с переходами между несколькими цветами - от черного к красному и затем к белому, например, - пришлось бы задать третью точку где-то между 0 и 1. Однако следует помнить, что при создании заливки мы работаем в двумерном пространстве, поэтому верхний левый угол представляет точка (0,0), и нижний правый угол представляет точка (1,1). Таким образом, для заливки прямоугольника с помощью градиентной кисти использовалась бы LinearGradientBrush следующим образом:
<Rectangle Width="200" Height="150" >
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <LinearGradientBrush.GradientStops>
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Black" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
XAML также поддерживает отображение текста. Для этого используется элемент TextBlock. Типовые свойства текста, такие как содержимое, тип шрифта, размер шрифта, обтекание и др., можно изменять через атрибуты. Вот простой пример:
<TextBlock TextWrapping="Wrap" Width="100">
Hello there, how are you?
</TextBlock>
Трансформация объектов в XAML осуществляется с помощью ряда трансформаций. К ним относятся:
RotateTransform Поворачивает элемент на заданный угол
ScaleTransform Используется для изменения масштаба объекта
SkewTransform Наклоняет объект в заданном направлении на заданный угол
TranslateTransform Перемещает объект в направлении, соответственно заданному вектору
MatrixTransform Используется для создания математического преобразования, которое может сочетать все вышеперечисленное
Возможна группировка трансформаций. Группируя существующие трансформации, можно создать сложную трансформацию. То есть можно, например, переместить объект с помощью трансляции, изменить его размер с помощью масштабирования и при этом повернуть его. Рассмотрим пример, в котором выполняется разворот и изменение масштаба холста:
<Canvas.RenderTransform>
<TransformGroup>
<RotateTransform Angle="-45" CenterX="50" CenterY="50"/>
<ScaleTransform ScaleX="1.5" ScaleY="2" />
</TransformGroup>
</Canvas.RenderTransform>
Поддержка анимации в XAML реализована посредством определения изменений свойств со временем. Для этого используется временная шкала. Временные шкалы располагаются в раскадровке (storyboard ). Существуют различные типы анимации:
DoubleAnimation Обеспечивает возможность анимации числовых свойств, например таких, которые используются для определения положения
ColorAnimation Обеспечивает возможность анимации цветовых свойств, таких как заливки
PointAnimation Обеспечивает возможность анимации точек, определенных в двухмерном простран
стве
Изменять свойства можно линейно, тогда свойство меняет значения с течением времени, или в режиме «ключевого кадра», когда определяется ряд контрольных точек, переходы между которыми и создают анимацию. Более подробно эти вопросы будут рассмотрены в Главе 5, «Трансформация и анимация в XAML».
Но применение XAML выходит далеко за рамки рассмотренных здесь основных понятий. С помощью XAML описываются элементы управления и компоновка UI. Боле подробно это будет рассмотрено в Главе 7, «Элементы управления Silverlight: представления и компоновки», и в главах Части 2, «Программирование в Silverlight 2».
Silverlight и пакет инструментов Expression Studio
Компанией Microsoft был создан пакет инструментов Expression Studio. Это современный надежный набор инструментов для дизайнеров, позволяющий им создавать артефакты, которые затем могут быть включены разработчиками при работе с пакетом инструментов Microsoft Visual Studio.
В Expression Studio входит несколько продуктов:
Expression Web Это инструмент для Веб-разработки, который обеспечивает возможность использовать HTML, DHTML, CSS и другие стандартные Веб-технологии для проектирования, построения и управления Веб-приложениями.
Expression Media Это инструмент управления мультимедиа ресурсами, который позволяет каталогизировать и организовывать эти элементы, включая возможность кодирования и перекодирования из формата в формат.
Expression Encoder Это приложение разработано для обеспечения возможности управления кодированием мультимедиа ресурсов. Также может использоваться для комплектации мультимедия Silverlight- медиаплеером в виде соответствующего кода.
Expression Design Это инструмент графического дизайна, который можно использовать для создания иллюстраций, графических элементов и ресурсов для UI Веб- и настольных приложений.
Expression Blend Этот инструмент обеспечивает возможность создавать UI на базе XAML для настольных приложений на WPF или Веб-приложений на Silverlight.
При работе с Silverlight вы будете использовать некоторые или все эти приложения. Далее в данной главе мы рассмотрим, как Design, Blend и Encoder расширяют ваш инструментарий для проектирования и построения Silverlight-приложений.
Silverlight и Expression Design
Expression Design - это инструмент графического дизайна, с помощью которого можно создавать графические ресурсы, используемые в приложениях. Это мощный и сложный инструмент, поэтому в данной книге приводится просто обзор того, как он может применяться для Silverlight XAML. Expression Design позволяет сочетать векторные и растровые изображения для обеспечения абсолютной гибкости.
Он поддерживает импорт множества форматов графических файлов. В Expression Design можно импортировать файлы в форматах:
Adobe Illustrator—PDF-совместимые (*.ai)
Adobe Photoshop (*.psd)
Graphical Interchange Format (.gif)
Формат Portable Network Graphics (.png)
Растровые изображения (.bmp, .dib, .rle)
Форматы JPEG (jpeg, jpg, jpe, jfif, .exif)
Windows Media Photos (.wdp, .hdp)
Tagged Image File Format (.tiff, .tif)
Значки (.ico)
Поддерживается экспорт следующих типов изображений:
XAML Silverlight Canvas
XAML WPF Resource Dictionary
XAML WPF Canvas
Adobe Illustrator (.ai)
Portable Document Format (.pdf)
Adobe Photoshop (.psd)
Tagged Image File Format (.tif, .tiff)
Форматы JPEG (jpeg, jpg)
WindowsBitmap (.bmp)
Формат Portable Network Graphics (.png)
GraphicalInterchange Format (.gif)
WindowsMedia Photos (.wdp)
Как видите, Expression Design поддерживает экспорт графических ресурсов в виде XAML-файлов. Позже в данной главе будет показано, как в Expression Design разрабатывается дизайн графических элементов простого приложения. Вы будете экспортировать эти элементы в виде XAML-кода, который сможете использовать для создания приложения в Expression Blend и Visual Studio.
На рис. 1-4 представлено диалоговое окно Export (Экспорт) в Expression Design. В нем можно увидеть несколько вариантов выбора формата, один из которых-XAML Silverlight Canvas (отображается выбранным). Выбор этой опции обеспечит форматирование рисунка с использованием подмножества элементов XAML, которые использует Silverlight, что позволит импортировать полученный в результате XAML в Visual Studio или Expression Blend для построения Silverlight приложения.
РИС. 1 4 Экспорт XAML из Expression Design.
Это обеспечит экспорт содержимого в виде XML-документа, включающего элемент Canvas, в котором содержатся элементы вашего дизайна. Рассмотрим пример (сокращенный):
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Document">
<Canvas x:Name="Layer 1" Width="640.219" Height="480.202" Canvas.Left="0" Canvas.Top="0">
<Ellipse x:Name="Ellipse" Width="135" Height="161" Canvas.Left="0.546544"
Canvas.Top="20.3998" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFFFC800"/>
<Path x:Name="Path" Width="135.103" Height="66.444" Canvas.Left="-0.555986"
Canvas.Top="-0.389065" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF000000" Data="..."/>
<Path x:Name="Path 0" Width="19.4583" Height="23.9019" Canvas.Left="75.8927"
Canvas.Top="76.1198" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF000000" Data="..."/>
<Path x:Name="Path 1" Width="11.0735" Height="24.0564" Canvas.Left="60.473"
Canvas.Top="106.4" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF000000" Data="..."/>
<Path x:Name="Path 2" Width="76" Height="29.8274" Canvas.Left="31.5465"
Canvas.Top="127.4" Stretch="Fill" StrokeThickness="7" StrokeLineJoin="Round"
Stroke="#FF000000" Data="..."/>
<Path x:Name="Path 3" Width="20.3803" Height="27.1204" Canvas.Left="31.2028"
Canvas.Top="75.306" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000"
Fill="#FF000000" Data="..."/>
</Canvas>
</Canvas>
Теперь этот XAML можно вырезать и вставить в Expression Blend или Visual Studio, и вы сможете использовать графический элемент в своем приложении.
Silverlight и Expression Blend
Expression Blend обладает возможностью создания приложений Silverlight. При запуске Expression Blend и создании нового проекта предлагается два типа Silverlight проектов, как видно на рис. 1-5.
РИС. 1 5 Поддержка Silverlight в Expression Blend.
Этими двумя типами проектов Silverlight являются:
Silverlight 1 Site Эта опция обеспечивает создание проекта Silverlight JavaScript. Вы получаете папку, содержащую простое Веб-приложение с HTML-страницей, имеющей необходимые сценарии для вставки объекта Silverlight, а также стандартный XAML-документ с одним холстом. Он не содержит никаких деталей реализации для программирования на .NET, поэтому для его описания используется термин 1 Site, хотя это версия 2.0 элемента управления Silverlight. Скорее всего, в будущих версиях Expression Blend название этого типа проекта заменят на Silverlight JavaScript Site. В Главе б, «Элемент управления браузера Silverlight», программирование приложений JavaScript будет рассмотрено более подробно.
Silverlight 2 Application Эта опция обеспечивает создание Silverlight-проекта со всем необходимым для программирования с использованием .NET Framework. Больше информации о Silverlight 2 приводится в Главе 3, «Использование Visual Studio с Silverlight 2», и затем в Части 2 данной книги (Главах 714) этот тип проекта будет рассмотрен намного более подробно.
Проект Silverlight 1
При создании нового приложения Silverlight Script с использованием Blend получаемый проект будет содержать стандартный HTML-файл со всем необходимым JavaScript-кодом для создания экземпляра элемента управления Silverlight. Кроме того, Blend также создает базовую XAML-страницу Page.xaml и связанный с ней JavaScript-файл Page.xaml.js. Expression Blend трактует его как JavaScript-файл с выделенным кодом, аналогично тому как Visual Studio трактует C#-файл с выделенным кодом, связанный со страницей ASPX. Наконец, Blend предоставляет копию файла Silverlightjs, который является частью пакета для разработчика ПО (software development kit, SDK) Silverlight. Этот файл управляет созданием экземпляров и загрузкой подключаемого модуля Silverlight для ваших пользователей. Структура проекта представлена на рис. 1-6.
РИС. 1 6 Структура проекта приложения Silverlight JavaScript.
Веб-страница по умолчанию
В Листинге 1-1 представлен код базовой Веб-страницы, создаваемой Blend для проектов Silverlight.
ЛИСТИНГ 1 1 Файл Default.html из шаблона Silverlight
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- transitional.dtd">
<!-- saved from url=(0014)about:internet -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SilverlightSite1</title>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="Page.xaml.js"></script>
<style type="text/css">
#silverlightControlHost {
height: 480px;
width: 640px;
}
#errorLocation {
font-size: small;
color: Gray;
}
</style>
<script type="text/javascript">
function createSilverlight()
{
var scene = new SilverlightSite1.Page();
Silverlight.createObjectEx({
source: "Page.xaml",
parentElement: document.getElementById("silverlightControlHost"),
id: "SilverlightControl",
properties: {
width: "100%",
height: "100%", version: "1.0"
},
events: {
onLoad: Silverlight.createDelegate(scene, scene.handleLoad),
onError: function(sender, args) {
var errorDiv = document.getElementById("errorLocation");
if (errorDiv != null) {
var errorText = args.errorType + "- " + args.errorMessage;
if (args.ErrorType == "ParserError") {
errorText += "<br>File: " + args.xamlFile;
errorText += ", line " + args.lineNumber;
errorText += " character " + args.charPosition;
}
else if (args.ErrorType == "RuntimeError") {
errorText += "<br>line " + args.lineNumber;
errorText += " character " + args.charPosition;
}
errorDiv.innerHTML = errorText;
}
}
}
});
}
if (!window.Silverlight)
Silverlight = {};
Silverlight.createDelegate = function(instance, method) { return function() {
return method.apply(instance, arguments);
}
}
</script>
</head>
<body>
<div id="silverlightControlHost">
<script type="text/javascript"> createSilverlight();
</script>
</div>
<div id='errorLocation'></div>
</body>
</html>
Как видите, здесь импортируются два JavaScript-файла: Silverlightjs и Page.xaml.js. Вскоре каждый из них будет рассмотрен более подробно.
Создание экземпляра элемента управления Silverlight происходит в элементе <div> внизу страницы. Для этого происходит вызов функции createSilverlight, которая реализована вверху страницы. Эта функция создает новый объект Silverlight, используя либо функцию createObjectEx (которая, в свою очередь, находится в Silverlightjs), либо функцию createObject. Если применяется функция createObjectEx, параметры задаются с использованием синтаксиса JavaScript Object Notation (JSON), как показано в данном примере. В качестве альтернативы можно использовать функцию createObject, которая использует стандартные параметры.
Первый параметр - исходный XAML. Это может быть ссылка на статический внешний файл (что используется в данном случае - Page.xaml), ссылка на URL службы, которая может формировать XAML, или ссылка на именованный блок сценария на странице, содержащей XAML.
Второй параметр - родительский элемент. Это имя элемента <div>, содержащего элемент управления Silverlight. Как можно видеть в Листинге 1-1, он называется SilverlightControlHost.
Третий параметр - ID, который будет использоваться для этого элемента управления. Если на странице располагается несколько элементов управления Silverlight, каждый из них должен иметь собственный уникальный ID.
Четвертый параметр - параметры свойств элемента управления. Сюда могут входить простые свойства, такие как ширина, высота и цвет фона, а также составные свойства. К более сложным параметрам свойств относятся:
inplacelnstallPrompt Определяет тип установки для Silverlight. Если задано значение true, пользователь неявно принимает лицензию и напрямую скачивает и устанавливает подключаемый модуль. Если задано значение false, пользователь направляется на http://www.silverlight.net, с этого сайта он может принять лицензионное соглашение и загрузить подключаемый модуль.
isWindowless Если задано true, элемент управления считается безоконным (windowless), т.е. поверх него может быть наложено не-Silverlight содержимое.
framerate Определяет максимальную частоту кадров для анимаций.
version Определяет минимально необходимую версию Silverlight, которую будет поддерживать приложение. Как можно видеть в Листинге 1-1, версия указывается как 1.0 - это не ошибка, а просто инструкция, что данное приложение является обратно совместимым и должно работать на версии 1.0. Если
бы вместо этого была задана версия 2.0, и Silverlight 2 не был бы установлен, пользователю было бы предложено установить Silverlight 2.
Пятый параметр используется для сопоставления событий с обработчиками событий. События реализовываются в классе JavaScript, называемом scene (сцена), который был объявлен в начале функции:
var scene = new SilverlightSite1.Page();
Функция createSilverlight объявляет, что событие onLoad должно обрабатываться методом scene.handleLoad класса scene. Для этого создается делегат, используя следующий синтаксис:
onLoad: Silverlight.createDelegate(scene, scene.handleLoad)
Данный класс реализован в JavaScript-файле выделенного кода для Page.xaml под названием Page.xaml.js. Это можно видеть в Листинге 1-2.
ЛИСТИНГ 1 2 JavaScript файл выделенного кода Page.xaml
if (!window.SilverlightSite1) SilverlightSite1 = {};
SilverlightSite1.Page = function() { }
SilverlightSite1.Page.prototype = {
handleLoad: function(control, userContext, rootElement) { this.control = control;
// Пример перехвата события:
rootElement.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
},
// Пример обработчика события handleMouseDown: function(sender, eventArgs) {
// В следующее строке кода показано, как находить элемент по имени
// this.control.content.findName("Storyboard1").Begin();
} }
Здесь представлен код на JavaScript для создания класса SilverlightSite1.Page. Он содержит две функции-члены, handleLoad и handleMouseDown.
Функция handleLoad добавляет еще один обработчик события MouseLeftButtonDown, создавая делегат, связывающий это событие и функцию handleMouseDown, которая также определена в этом JavaScript- коде.
Таким образом, шаблонное приложение создает стандартный HTML-файл, который содержит экземпляр Silverlight с единственным холстом, формирующим события при загрузке. В обработчике события загрузки происходит регистрация обработчика события нажатия кнопки мыши. Это демонстрирует, что объявление события, делегирование и обработка доступны как во время проектирования, так и во время выполнения.
Silverlight и Expression Encoder
Expression Encoder - это приложение, обеспечивающее возможность кодирования, улучшения и публикации видеосодержимого с использованием Silverlight. Он поставляется с UI, единообразным по стилю, виду интерфейса и управлению с остальными приложениями Expression Studio, или с интерфейсом командной строки, который может использоваться для обработки в пакетном режиме. Expression Encoder показан на рис. 1-7.
РИС. 1 7 Expression Encoder.
Expression Encoder позволяет импортировать видео из любого формата, для которого в вашей системе доступен и установлен фильтр DirectShow. После этого Expression Encoder перекодирует видео в VC-1 WMV, используя один из множества предустановленных профилей, оптимизированных под конечного пользователя. Они включают настройки для устройств, а также для содержимого, доставляемого через Интернет путем потоковой передачи или по запросу.
Вы не ограничены возможностями, предлагаемыми предустановленными профилями. Все параметры кодирования аудио- и водеоданных можно переопределить. На рис. 1-8 (на странице 20) представлен пример настройки кодирования видеоданных.
Media Encoder включает ряд предустановленных медиаплееров для Silverlight. Они создадут для вашего видео Silverlight-приложение на базе JavaScript, которое может использоваться на любом Вебсервере и обеспечит полноценный просмотр с помощью Silverlight.
Кроме кодирования, в видео могут быть добавлены метаданные. Классический вариант введения метаданных - кодирование тегов в видео, после чего приложение реагирует на эти теги. С Expression Encoder вставлять теги очень просто. Курсор воспроизведения перетягивается в необходимую точку, выбирается команда Add Marker (Добавить маркер) и вводится соответствующая информация для маркера.
РИС. 1 8 Настройка профиля кодирования видео.
Это можно видеть на рис. 1-9 в правой части экрана, где для маркера заданы время и тип мяча, отображаемого в этот момент на экране.
РИС. 1 9 Добавление маркеров в поток.
На вкладке Output (Вывод) можно выбрать шаблон проигрывателя, который вы желаете использовать.
На рис. 1-10 показано, где выбирается шаблон, соответствующий линии продуктов Expression. Чтобы создать видеоплеер с использованием этого шаблона, просто импортируйте видео, выберите этот шаблон и нажмите кнопку Encode (Кодировать).
РИС. 1 10 Использование Encoder для создания медиаплеера Silverlight.
Сделав это, вы получите полнофункциональный медиаплеер в Silverlight для своего видео. Пример медиаплеера Silverlight можно увидеть на рис. 1-11.
В данном разделе мы лишь слегка прикоснулись к тому, что можно сделать с помощью Expression Encoder и как он может использоваться с Silverlight. Более детальную информацию можно найти на сайте http://www.microsoft.com/expression.
РИС. 1 11 Медиаплеер, сформированный Expression Encoder.
Заключение
В данной главе представлен Silverlight 2 и показана его роль в мире Веб и UX. Показано, как технология Microsoft применяется к современным сценариям UX, и дан обзор архитектуры Silverlight, включая XAML и его использование для реализации насыщенных UI.
Кроме того, было показано, как Microsoft Expression Studio дополняет традиционные средства разработки, такие как Visual Studio, для создания приложений Silverlight. В частности, рассмотрено, как с помощью Expression Design создаются графические ресурсы и как они объединяются в интерактивное приложение с помощью Expression Blend, а также как можно управлять видеоресурсами, используя Expression Encoder.
Теперь пора идти дальше. В следующих нескольких главах вы больше узнаете о Silverlight API, и начнем мы с более тщательного рассмотрения Expression Blend и его использования в Silverlight в следующей главе.
Глава 2
Использование Expression Blend с Silverlight 2
Expression Blend - это профессиональный дизайнерский инструмент, предназначенный для создания красивых интерфейсов для Windows и Веб-приложений. Благодаря ему, с помощью одного инструмента можно объединить все необходимые элементы дизайна для Веб, включая видео, векторную графику, текст, анимацию, изображения, а также элементы управления. Expression Blend разработан, чтобы помочь дизайнерам создавать как Windows, так и Веб-приложения. В данной главе вы познакомитесь с этим инструментом, совершив краткий тур по предлагаемым им возможностям. Одной главы совершенно не достаточно, чтобы охватить все многочисленные аспекты Expression Blend, но к концу этой главы вы освоите базовые понятия и будете готовы к дальнейшему изучению возможностей этого замечательного инструмента самостоятельно!
Начало работы с Expression Blend
Expression Blend доступен как часть пакета Microsoft Expression. Подробнее об этом можно узнать на сайте http://www.microsoft.com/expression.
После загрузки и установки Expression Blend запустите его из меню Пуск (Start). Вы увидите Интегрированную среду разработки (integrated development environment, IDE) Blend (рис. 2-1).
РИС. 2 1 Expression Blend IDE.
Чтобы создать новое приложение, выберите в меню File (Файл) New Project (Новый проект), и откроется диалоговое окно New Project, как показано на рис. 2-2.
РИС.2 2 Диалоговое окно New Project в Expression Blend.
Данное диалоговое окно предлагает следующие опции:
WPF Application (.exe) Выбор этой опции обеспечивает создание клиентского приложения, построенного на Windows Presentation Foundation (WPF); данный тип проекта является приложением только для Windows.
WPF Control Library Выбор этой опции обеспечивает создание DLL-файла, который может использоваться для элементов управления, используемых совместно приложениями WPF; данный тип проекта является приложением только для Windows.
Silverlight 1 Site Выбор этой опции обеспечивает создание Веб-сайта, использующего элемент управления Silverlight. Он содержит базовые компоненты JavaScript для создания экземпляра элемента управления Silverlight, а также образец документа XAML с обработчиками событий на базе JavaScript. Он рассматривался в Главе 1, «Введение в Silverlight 2». В этом случае создается Веб- и, следовательно, многоплатформенное приложение.
Silverlight 2 Application Эта опция обеспечивает создание Silverlight-приложения, основанного на среде выполнения Silverlight 2. Это приложение включает среду выполнения .NET Framework, которая поддерживает ваши .NET-приложения, обеспечивая возможность их выполнения в браузере. При выборе этого типа проекта вы можете использовать язык программирования по своему усмотрению (либо Microsoft Visual Basic, либо Microsoft Visual C#). В этом случае создается Веб- и, следовательно, многоплатформенное приложение.
В Главе 1 были представлены некоторые детальные сведения о шаблоне Silverlight 1 Site, поэтому вы можете вернуться к той главе для получения более подробной информации по этой опции. Далее данная глава будет посвящена шаблону Silverlight 2 Application.
Создание приложения Silverlight 2
Чтобы создать приложение Silverlight 2, откройте диалоговое окно New Project и задайте имя для своего нового проекта (в данном случае - TestApp). Expression Blend создаст для вас новый проект со всем необходимым для Silverlight 2 .NET-приложения.
Структуру создаваемого проекта можно увидеть на рис. 2-3. Она идентична структуре продукта, создаваемой Visual Studio, которая будет обсуждаться подробно в Главе 3, «Использование Visual Studio с Silverlight 2».
РИС. 2 3 Структура проекта Silverlight 2.
Рассматривая структуру проекта, важно отметить, что в этом приложении два XAML-файла, и ни один из них не является Silverlight XAML-страницей, как это было в Silverlight 1. Это одно из фундаментальных отличий проекта Silverlight 2 Application от проекта Silverlight 1 Site.
Страница по умолчанию
Silverlight 2 работает с вашим XAML как со страницей. Таким образом, шаблон создает стандартное XAML-содержимое приложения в виде файла Page.xaml. Корневым элементом данного файла, что не удивительно, является UserControl (Пользовательский элемент управления), а не Canvas, к которому вы, возможно, привыкли в Silverlight 1.
Далее представлен XAML для стандартного Page.xaml:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="TestApp.Page" Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White"/>
</UserControl>
Обратите внимание, что для размещения содержимого используется <UserControl>.
Можно увидеть, что Page имеет сформированный для вас файл выделенного кода. Ему будет присвоено имя Page.xaml.cs или Page.xaml.vb в зависимости от того, какой язык программирования выбран для проекта. Файл содержит базовый код, необходимый для создания UserControl. Он представлен в следующем фрагменте:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace TestApp {
public partial class Page : UserControl
{
public Page()
{
// Необходимо для инициализации переменных
InitializeComponent();
}
} }
Конечно, для реализации логики своего приложения вы не ограничены этим файлом и можете создавать другие файлы .cs (или .vb) для этого, но данный файл будет запускаться при каждом создании экземпляра элемента управления средой выполнения Silverlight.
Файл App.xaml и файлы с выделенным кодом по умолчанию
Файлы App.xaml и App.xaml.cs определяют условия запуска создаваемого приложения. Silverlight будет загружать и выполнять их первыми при запуске и закрывать последними при завершении приложения.
Для реализации этого используются события OnStartup и OnExit. Это настройка, выполняемая для вас шаблоном проекта. Обратите внимание, что визуальное представление Page не формируется по умолчанию, необходимо задать, чтобы он создавался при запуске приложения. Это выполняется в обработчике события OnStartup, где свойство приложения RootVisual задается как экземпляр Page:
public App() {
this.Startup += this.OnStartup;
this.Exit += this.OnExit;
InitializeComponent();
}
private void OnStartup(object sender, StartupEventArgs e) {
// Здесь загружается основной элемент управления this.RootVisual = new Page();
}
private void OnExit(object sender, EventArgs e) {
}
App.xaml не поддерживает визуальные элементы напрямую, поэтому нельзя в него напрямую добавлять элементы управления или другие визуальные элементы. Не рассматривайте это как рабочую поверхность только потому, что это XAML. В данном случае, XAML используется только для определений. Например, с его помощью можно описать ресурсы для создаваемого приложения.
App.xaml.cs полезен для инициализации данных, которые предполагается использовать в нескольких пользовательских элементах управления. Помните об этом при разработке своего приложения. Например, можно сохранить некоторый текст, который будет использоваться приложением, объявив его ресурсом в App.xaml:
<Application
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="TestApp.App">
<Application.Resources>
<TextBlock x:Key="txtResource" Text="Hello"></TextBlock>
</Application.Resources>
</Application>
Теперь это содержимое может быть без труда извлечено для любого элемента управления в приложении следующим образом:
TextBlock t = (TextBlock)Application.Current.Resources["txtResource"]; string strTest = t.Text;
Выполнение приложения
Особо внимательные заметят, что здесь не хватает страницы для размещения элемента управления Silverlight. Не волнуйтесь! Blend автоматически сформирует ее для вас. Вы увидите это, когда запустите приложение.
Прежде чем двигаться дальше, добавим в UserControl простой TextBlock (Текстовый блок) для отображения некоторого текста. Вот пример:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="TestApp.Page"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White" >
<TextBlock Text="Hello"/>
</Grid>
</UserControl>
Теперь, если выполнить это приложения (Project > Test Solution), вы увидите на экране примерно то, что представлено на рис. 2-4.
РИС. 2 4 Выполнение приложения Silverlight из Blend.
Это простое приложение выполняется с использованием Веб-сервера Cassini (отсюда случайный номер порта, 4553, который можно видеть в адресной строке на рис. 2-4) путем формирования HTML- страницы для размещения Silverlight-содержимого.
Посмотрим на исходный код этой страницы с помощью команды браузера View Source (Просмотр исходного кода):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>TestApp</title>
<style type="text/css">
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost { height: 100%;
}
</style>
<script type="text/javascript">
function onSilverlightError(sender, args) {
var appSource = "";
if (sender != null && sender != 0) {
appSource = sender.getHost().Source;
}
var errorType = args.ErrorType;
var iErrorCode = args.ErrorCode;
var errMsg = "Unhandled Error in Silverlight 2 Application " + appSource + "\n" ;
errMsg += "Code: "+ iErrorCode + "\n";
errMsg += "Category: " + errorType + "\n";
errMsg += "Message: " + args.ErrorMessage + "\n";
if (errorType == "ParserError") { errMsg += "File: " + args.xamlFile + "\n";
errMsg += "Line: " + args.lineNumber + "\n";
errMsg += "Position: " + args.charPosition + "\n";
}
else if (errorType == "RuntimeError")
{
if (args.lineNumber != 0)
{
errMsg += "Line: " + args.lineNumber + "\n";
errMsg += "Position: " + args.charPosition + "\n";
}
errMsg += "MethodName: " + args.methodName + "\n";
}
throw new Error(errMsg);
}
</script>
</head>
<body>
<div id='errorLocation' style="font-size: small;color: Gray;"></div>
<div id="silverlightControlHost">
<object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="TestApp.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="2.0.31005.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border- style: none"/>
</a>
</object>
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>
</body>
</html>
Обратите внимание на тег <object>. В нем делается попытка создания экземпляра Silverlight. В случае сбоя он формирует изображение с гипертекстовой ссылкой (HREF) на адрес, с которого можно загрузить Silverlight. Более подробно об этом и других способах создания экземпляра объекта Silverlight рассказывается в Главе б, «Элемент управления браузера Silverlight».
Интегрированная среда разработки Expression Blend
Expression Blend предлагает гибкую интегрированную среду разработки (IDE), которая позволяет максимально увеличить количество информации, выводимой на экран. При этом пользователь может без труда понимать, что происходит.
IDE имеет две варианта организации рабочей области приложения: рабочая область Design (Дизайн), используемая преимущественно для создания и настройки пользовательского интерфейса (UI), и рабочая область Animation (Анимация), которая используется, главным образом, для создания анимаций с использованием временной шкалы. Переключаться между рабочими областями можно с помощью клавиши F6, или выбирая необходимую рабочую область в опциях Active Workspace (Активная рабочая область) меню Window.
Экран в Expression Blend IDE разделен на панели. Каждая панель имеет собственное назначение, как вы увидите прямо сейчас во время их обзора.
Панель инструментов
Панель инструментов располагается на экране с левого края. Она содержит инструменты, такие как Selection (Выбор) или Direct Selection (Прямой выбор), которые могут использоваться для обработки любого объекта; визуальные элементы, такие как Rectangle (Прямоугольник) или Ellipse (Эллипс); компоновочные элементы, такие как StackPanel или Canvas; и элементы управления, такие как Button (Кнопка) или TextBox (Текстовое поле). Панель инструментов представлена на рис. 2-5.
РИС. 2 5 Панель инструментов Expression Blend.
В Blend схожие инструменты могут быть собраны под одним значком на панели инструментов. На рис. 2-5 видно, как можно просматривать набор подобных инструментов. Если в нижнем правом углу инструмента есть белый треугольник, вы можете навести курсор на этот инструмент и нажать кнопку мыши, чтобы увидеть всех членов «семейства» выбранного объекта. Так, например, если навести курсор на инструмент Rectangle и нажать кнопку мыши, появится выпадающее окно, в котором будут представлены все остальные доступные фигуры, как видно на рис. 2-6.
РИС. 2 6 Группировка инструментов.
Blend обладает замечательным свойством - он отображает на панели инструментов значок того инструмента семейства инструментов, который вы использовали. То есть, на панели инструментов будет отображаться инструмент, который использовался последним, так что вам не придется в следующий раз удерживать кнопку мыши, ожидать открытия меню и выбирать этот инструмент снова.
Так, например, на рис. 2-6 на панели инструментов отображается Rectangle, и по нажатию кнопки мыши вы увидите окно с остальными доступными инструментами визуальных элементов этого типа. Если выбрать Ellipse и нарисовать с его помощью что-то на рабочей поверхности, на панели инструментов будет отображаться значок Ellipse, а не Rectangle.
Панель взаимодействий
Панель взаимодействий представлена на рис. 2-7 и обычно располагается правее панели инструментов. Она создана с целью упрощения выполнения следующих задач:
Просмотр всех объектов рабочей поверхности, а также их иерархии при использовании объектов- контейнеров.
Выбор объектов для их изменения. Это не всегда возможно на рабочей поверхности, потому что объекты могут размещаться вне экрана или за другими объектами.
Создание и изменение временных шкал анимаций. Более подробно об этом будет рассказано в разделе «Использование Blend для создания анимаций» далее в этой главе.
Панель взаимодействий имеет два разных вида подсветки. Выбранный в настоящий момент элемент подсвечивается серым. На рис. 2-7 можно видеть, что элемент управления Border (Граница) выделен серым. Выделенный объект можно изменять, используя окно свойств или перетягивая его по рабочей поверхности.
Хотя на черно-белом рисунке он кажется серым, на экране компьютера элемент управления LayoutRoot (Корень компоновки) был бы обведен желтой рамкой. На рабочей поверхности также будет видна эта желтая рамка. Она указывает на то, что данный контейнер выбран в настоящий момент.
Кроме работы с объектами, панель взаимодействий используется для создания анимаций и раскадровок. Делается это путем нажатия кнопки со знаком плюс (+) вверху панели взаимодействий. Возможные пути создания анимаций будут рассмотрены в разделе «Использование Blend для создания анимаций» далее в данной главе.
РИС. 2 7 Панель взаимодействий.
Рабочая поверхность
Рабочая поверхность - основная панель экрана Expression Blend IDE. Здесь можно манипулировать всеми объектами визуально или путем непосредственного изменения, лежащего в основе XAML-кода.
В правой части рабочей поверхности имеется три вкладки:
Вкладка Design (Дизайн) открывает рабочую поверхность.
Вкладка XAML открывает окно редактирования XAML-кода.
Вкладка Split (Совместить) открывает разделенное окно, одна половина которого представляет рабочую поверхность, и во второй половине отображается XAML.
Рабочая поверхность в совмещенном режиме представлена на рис. 2-8.
РИС. 2 8 Рабочая поверхность в совмещенном режиме.
Обратите внимание, что в режиме просмотра дизайна доступна возможность Zoom (Масштаб), поэтому при работе над сложными интерфейсами можно увеличивать масштаб для более детального просмотра и уменьшать масштаб изображения для получения общего вида. Для этого используется инструмент Zoom, располагающийся в нижнем левом углу рабочей поверхности. Его можно развернуть и выбрать стандартный масштаб, можно ввести определенное значение в предоставленном поле или установить заданный масштаб с помощью мыши.
Панель проекта
Панель проекта (представленная на рис. 2-9) используется для управления файлами проекта. Что важно заметить об этой панели, это использование контекстных меню. В зависимости от того, в каком месте панели находится курсор в момент щелчка правой кнопкой мыши, появляются разные (но соответствующие) контекстные меню. Возможно, вам знакомы контекстные меню, предлагающие команды для определенной панели, но, в данном случае, разные меню выводятся по щелчку правой кнопкой мыши на решении, проекте, папке References (Ссылки) и других элементов панели проекта.
РИС. 2 9 Панель проекта.
Solution (Решение) - это коллекция из одного или более проектов. При редактировании решения им можно управлять как угодно: выполнять его сборку, отладку, очистку и управление отдельными проектами. На рис. 2-9 решение TestApp располагается вверху панели проекта, и панель показывает, что данное решение содержитодин проект.
Project (Проект) - это коллекция элементов, сочетание которых образует приложение, содержащее одну или более страниц Silverlight. Все ссылки на внешние компоненты, необходимые данному приложению, находятся в папке References описания проекта. По правому щелчку мыши проекта появляется контекстное меню, с помощью которого можно манипулировать содержимым проекта. В контекстном меню предлагаются такие опции, как добавление новых шаблонных элементов, добавление существующих элементов из других проектов или удаление элементов из проекта.
Папка References в проекте используется для управления ссылками на сборки, содержащие информацию, которая необходима в создаваемом проекте. Например, если необходим специальный элемент управления, он будет скомпилирован в сборку. Тогда если вы укажете эту сборку в ссылках, вы сможете использовать ее в своем приложении.
Папка Properties (Свойства) содержит файл манифеста приложения, описывающий все свойства проекта, включая список ссылок, чтобы приложение понимало, откуда они загружаются во время выполнения. Не следует путать папку Properties с панелью свойств, обозначенной вкладкой Properties вверху окна, которое показано на рис. 2-9, и описываемой более подробно в следующем разделе.
Панель свойств
Панель свойств используется для управления всеми визуальными аспектами отдельного элемента. Поскольку элементы XAML имеют множество настраиваемых свойств, эта панель предлагает два очень полезных ярлыка.
Под первым ярлыком представлены свойства редактируемого элемента, сгруппированные по категориям. Обычно здесь предоставляется доступ к следующим визуальным аспектам элементов:
Brushes (Кисти) Позволяет задавать для элемента заливку и обводку, а также использовать маску прозрачности. Намного более подробно использование кистей рассматривается в Главе 4, «Основы XAML».
Appearance (Вид) Позволяет задавать для объекта расширенные свойства отображения. Обратите внимание, что доступные свойства отображения будут меняться в зависимости от того, какой объект редактируется в настоящий момент. Например, если редактируется элемент Rectangle, раздел Appearance панели свойств предложит задать такой параметр, как радиус скругления углов, но при редактировании элемента Button, который не имеет радиуса скругления, эта опция будет недоступна.
Layout (Компоновка) Позволяет редактировать различные опции компоновки для объекта, такие как Width (Ширина), Height (Высота) и опции Alignment (Выравнивание). Также опции компоновки можно использовать для изменения положения объекта внутри сетки, если компоновка выполняется на сетке.
Common Properties (Общие свойства) Включает свойства, общие для данного типа объектов. Например, здесь обычно редактируются общие свойства элементов управления, не являющихся фигурами. Доступность этих опций зависит от типа редактируемого объекта. Например, если редактируется элемент управления, общим свойством будет его индекс перехода по клавише Tab, но в случае редактирования фигуры индекс перехода по клавише Tab будет недоступен.
Transform (Трансформация) Обеспечивает возможность редактировать свойство RenderTransform (Трансформация визуального представления) объекта. Это свойство определяет, как система формирования визуального отображения может изменять объект. Более подробно трансформации рассматриваются в Главе 5, «Трансформация и анимация в XAML».
Miscellaneous (Разное) Место размещения всех свойств, которые не подходят ни под одну категорию.
Обратите внимание, что эти категории могут иметь подкатегории. У многих из них есть стрелка внизу, с помощью которой можно разворачивать и сворачивать панель свойств. Это позволяет скрывать свойства, которые используются реже.
Второй ярлык панели свойств - это Search (Поиск), который позволяет выполнять поиск определенного свойства. Например, если требуется редактировать некоторые свойства шрифта, но вы не знаете имя самого свойства, можно ввести font в строку поиска. Категории и доступные свойства будут отфильтрованы, и на панель будут выведены только те из них, которые имеют отношение к шрифтам. Это происходит непосредственно в процессе ввода слова поиска, поэтому если вы ищете свойство шрифта - т.е. для нашего примера, как только введены буквы fo - вы увидите доступные свойства, такие как foreground и rendertransform, а также доступные свойства шрифта, как показано в нижней части рис. 2-10.
РИС. 2 10 Использование панели свойств.
Теперь рассмотрим то, как можно использовать все эти представленные выше инструменты для построения приложений Silverlight.
Использование Blend для создания приложений Silverlight
К основным ориентированным на дизайн функциям, которые можно использовать в Blend для создания приложения относятся:
Организация компоновки
Размещение и настройка визуальных элементов
Размещение и настройка визуальных элементов управления
Создание анимаций
Все эти функции рассматриваются далее в данной главе.
Компоновка
В Silverlight для создания и организации компоновки приложения используются специальные инструменты. Пользователю доступны несколько вариантов, рассмотрим каждый из них по очереди.
Использование сетки
Элемент компоновки Grid (Сетка) позволяет раскладывать элементы в структуру, похожую на таблицу. (Не путайте элемент компоновки Grid с элементом управления Grid, который обеспечивает функциональность, аналогичную электронной таблице.) При использовании инструмента компоновки Grid расположение своих элементов можно задавать, указывая их координаты как виртуальные строки и столбцы компоновочного элемента Grid. Например, рассмотрим следующий XAML:
<Grid x:Name="LayoutRoot" Background="White" >
<Button Height="38" Margin="104,72,0,0" Width="58" Content="KnonKa"/>
<Button Height="24" Margin="210,72,0,0" Width="54" Content="KnonKa"/>
<Button Height="49" Margin="0,96,158,0" Width = "80" Content="KnonKa"/>
<Button Height="54" Margin="297,185,270,0" Width="67" Content="KnonKa"/>
<Button Height="33" Margin="104,217,0,213" Width="87" Content="KnonKa"/>
</Grid>
При формировании визуального представления это будет выглядеть, как показано на рис. 2-11.
РИС. 2 11 Кнопки, расположенные случайным образом.
Теперь, для упорядочивания этих кнопок можно задать их позиции, аккуратно перетягивая их по рабочей поверхности. Но в этом случае вам пришлось бы воспользоваться инструментом масштабирования, чтобы убедиться в том, что они точно выровнены.
В качестве альтернативного варианта можно использовать компоновочный элемент Grid. Здесь местоположение кнопки на сетке задается с помощью компоновочных свойств. При создании нового Silver- light проекта, вы увидите, что файл Page.xaml уже имеет компоновочный элемент Grid под именем LayoutRoot. Выберите этот элемент на панели Interaction (Взаимодействие) и посмотрите, какие компоновочные свойства с ним связаны. Разворачивайте обозреватель свойств до тех пор, пока не увидите настройки для ColumnDefinitions (Описания столбцов) и RowDefinitions (Описания строк), как показано на рис. 2-12.
РИС. 2 12 Редактор компоновки для сетки.
ColumnDefinitions и RowDefinitions - коллекции, поэтому справа от каждого из них располагается кнопка с многоточием (...). Это указывает на то, что если щелкнуть этот параметр, откроется другое диало-
говое окно. Выберите кнопку рядом с параметром ColumnDefinitions, и на экране появится редактор коллекции ColumnDefinition, как показано на рис. 2-13.
РИС. 2 13 Редактор коллекции ColumnDefinition.
Используйте это диалоговое окно для добавления, удаления и управления столбцами. Щелкните кнопку Add Another Item (Добавить еще один элемент) трижды и добавьте три столбца. Повторите аналогичные действия для параметра свойства RowDefinitions, чтобы получить сетку, состоящую из трех строк и трех столбцов. После внесения этих изменений в ColumnDefinitions и RowDefinitions, вы увидите на рабочей поверхности компоновочную сетку 3x3 (рис. 2-14).
РИС. 2 14 Компоновочная сетка 3 х 3.
Теперь при размещении любого элемента на экране вы будете видеть розовые направляющие линии, указывающие на то, как можно выполнить его привязку к определенному элементу сетки. Это показано на рис. 2-15. (На рисунке розовые линии выглядят как боле толстые серые.) Такая привязка кнопки к сетке и столбцу гарантирует, что кнопка всегда будет сохранять данные положение и размер относительно сетки.
Поместите другую кнопку в центральную ячейку сетки, как показано на рис. 2-15. На этот раз не выполняйте привязку к сетке. Затем запустите приложение и поэкспериментируйте с изменениями размеров окна. Вы увидите, что относительное местоположение и размер первой кнопки будут оставаться неизменными, тогда как вторая кнопка будет менять свои ширину и/или высоту, сохраняя пропорции относительно размеров экрана.
РИС. 2 15 Использование компоновки Grid.
Использование Canvas
Компоновочный элемент Canvas является поверхностью для рисования с совершенно свободным форматом. Определить местоположение элемента управления в данном случае можно, задавая его свойства Canvas.Top и Canvas.Left или с помощью свойства Margin (Поля).
Например, рассмотрим следующий XAML:
<Canvas Height="261" Width = "439">
<Button Height="101" Width = "110" Canvas.Left="101" Canvas.Top = "82.5" Content="KHonKa"/>
</Canvas>
Как видите, свойства Canvas.Top и Canvas.Left заданы. Они показывают, что кнопка всегда будет сохранять это местоположение относительно верхнего левого угла родительского элемента Canvas. Так что, если Canvas будет перемещаться, кнопка тоже будет двигаться. Более подробно компоновочный элемент Canvas рассматривается в Главе 4.
Использование StackPanel
Компоновочный элемент StackPanel всегда будет выравнивать свои дочерние элементы управления в горизонтальном или вертикальном направлении, укладывая1 их, исходя из значения свойства Orientation (Ориентация). Обратите внимание, что панель переопределяет позиционирование элементов управления. Например, рассмотрим следующий XAML:
<StackPanel Height="337" Width="224" Orientation="Vertical">
<Button Canvas.Top="100" Height="64" Width = "98" Content="KHonKa"/>
<Button Height="85" Width="92" Content="KHonKa"/>
<Button Height="48" Width="205" Content="KHonKa"/>
</StackPanel>
Как видим, свойству Canvas.Top первой кнопки задано значение 100. Можно было бы ожидать, что данный элемент управления будет отрисовываться в этой позиции, но, как видно на рис. 2-16, это не так. Компоновочный элемент StackPanel расположил эту кнопку вверху StackPanel (потому что свойству Orientation элемента StackPanel задано значение Vertical (Вертикально)).
1По английски «stacking», отсюда и название (прим, переводчика).
РИС. 2 16 Кнопки в StackPanel.
Когда в StackPanel располагается много элементов управления, они могут выходить за рамки самого элемента управления Panel. В этом случае элементы управления будут обрезаны границами StackPanel. Решить эту проблему поможет элемент управления ScrollViewer (Прокручиваемая область), который рассматривается в следующем разделе.
Использование ScrollViewer
Элемент ScrollViewer обеспечивает полосы прокрутки, которые позволяют пользователю перемещаться по содержимому компоновки, выходящему за границы ScrollViewer. У этого элемента может быть только один дочерний элемент управления, поэтому обычно он используется только для размещения других контейнеров и для элементов управления с большой областью просмотра (такими как Image).
Например, ниже представлен StackPanel, содержимое которого превышает доступный размер по вертикали:
<StackPanel Height="300" Width="199">
<Button Height="44" Width = "86" Content="KnonKa"/>
<Button Height="57" Width = "75" Content="KnonKa"/>
<Button Height="70" Width = "59" Content="KnonKa"/>
<Button Height="109" Width="95" Content="KnonKa"/>
<Button Height="104" Width="88" Content="KnonKa"/>
</StackPanel>
В данном примере высота StackPanel составляет 300 пикселов, но общая высота всех кнопок - 384 пиксела. Таким образом, нижняя кнопка будет обрезана, что можно видеть на рис. 2-17.
РИС. 2 17 Элементы, не поместившиеся в StackPanel.
Но если поместить этот элемент в ScrollViewer, результат будет более приемлемым. Обратите внимание, что если не изменить высоту StackPanel, он по-прежнему будет обрезать кнопки. Поэтому если необходимо иметь область высотой 300 пикселов, можно задать эту высоту для ScrollViewer, а для StackPanel задать другое значение высоты. Вот пример XAML для этого:
<ScrollViewer Height="300" Width="300">
<StackPanel Height="400" Width="199">
<Button Height="44" Width="86" Content="KnonKa"/>
<Button Height="57" Width="75" Content="KnonKa"/>
<Button Height="70" Width="59" Content="KnonKa"/>
<Button Height="109" Width = "95" Content="KnonKa"/>
<Button Height="104" Width="88" Content="KnonKa"/>
</StackPanel>
</ScrollViewer>
То, как выглядит созданный в данном примере ScrollViewer, представлено на рис. 2-18.
РИС. 2 18 Использование Scrollviewer.
Теперь можно прокручивать список кнопок вверх и вниз, и все кнопки будут доступны; ни одна из них не будет обрезана, потому что применяется ScrollViewer. Обратите внимание, что нижнюю кнопку (рис. 2-18) можно увидеть, если перетянуть полосу прокрутки вниз.
Элемент управления Border
Элемент управления Border используется только для отрисовки рамки, фона или того и другого вокруг элемента. Например, рассмотрим следующий XAML:
<Border Height="318" Width="405" Background="#FFFF0000">
<Button Height="234"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="239"
RenderTransformOrigin="0.5,0.5"
Content="KnonKa">
</Button>
</Border>
Это обеспечит создание красного фона за кнопкой.
Размещение и настройка визуальных элементов
Доступные визуальные элементы определены в спецификации XAML. Более подробно каждый из них рассматривается в Главе 4. А сейчас давайте перечислим основные фигуры и инструменты, предлагаемые панелью инструментов. Сюда относятся следующие фигуры:
Rectangle (Прямоугольник) Эта фигура используется для отрисовки прямостороннего прямоугольного четырехугольника. Создав Rectangle, высота и ширина которого равны, можно получить квадрат.
Ellipse (Эллипс) Эта фигура используется для отрисовки эллиптической формы, овала. Ее можно превратить в круг, сделав равными ширину и высоту.
Line (Линия) Эта фигура используется для отрисовки простой прямой линии между двумя точками.
На панели инструментов также можно найти инструменты, используемые для создания фигур произвольной формы:
Pen (Перо) Используется для отрисовки ряда соединенных отрезков, представленных базовым элементом Path (Контур).
Pencil (Карандаш) Используется для отрисовки ряда соединенных элементов, которые могут быть прямыми или кривыми линиями. Blend преобразует отрисованные пользователем контуры в базовый элемент Path.
Все эти визуальные элементы, включая созданные с помощью инструментов Pen и Pencil, представляются одним элементом. И этот элемент может обрабатываться как любой другой объект; т.е. его можно изменять разными способами, включая задание его свойств или анимирование. Например, рассмотрим рис. 2-19, на котором с помощью инструмента Pencil отрисован ряд соединенных кривых с целью создания представления написанного от руки слова Hello (Привет). На панели Objects And Timeline (Объекты и временная шкала) можно увидеть объект, представленный как Path.
РИС. 2 19 Редактирование объекта Path.
Теперь слово Hello, написанное с помощью инструмента Pencil, рассматривается как один объект. Таким образом, вы можете редактировать его свойства, включая Fill, Brush и т.д. Просто выберите объект в представлении Objects And Timeline и внесите соответствующие изменения в окне свойств, как для любого другого объекта.
Размещение и настройка элементов управления
Blend интерпретирует элементы управления абсолютно точно так же, как и визуальные элементы. Вы просто выбираете их на панели инструментов и размещаете на рабочей поверхности. После того, как элемент управления создан на рабочей поверхности, можно редактировать его свойства. Подробно элементы управления обсуждаются в Главе 7, «Элементы управления Silverlight: представления и компоновки».
Единственное, что следует заметить, - на панели инструментов Blend предоставлено два семейства элементов управления. Первое включает текстовые элементы управления: TextBlock (Текстовый блок) и TextBox. Во второе семейство входит ряд базовых элементов управления пользовательского интерфейса: Button, CheckBox (Флажок), ListBox (Список), RadioButton (Переключатель), ScrollBar (Полоса прокрутки), Slider (Ползунок) и GridSplitter (Разделительная полоса).
Наконец, панель инструментов предоставляет возможность добавления элементов управления, не входящих в этот набор. Для этого необходимо выбрать ссылку Asset Library (Библиотека ресурсов) в нижней части панели инструментов. При этом на экран будет выведен диалог Asset Library, как показано на рис. 2-20.
РИС. 2 20 Диалоговое окно Asset Library.
В диалоговом окне Asset Library можно выбирать элементы управления и добавлять их на панель инструментов. Также можно выполнять поиск определенных элементов управления, вводя название в строку поиска. Так, например, если требуется использовать элемент управления MediaElement (Элемент мультимедиа), начните вводить его название. Увидев искомый элемент управления (MediaElement, в данном случае), достаточно выбрать его, и он станет доступен на панели инструментов.
После этого элемент управления можно помещать на рабочую поверхность и работать с его свойствами в редакторе свойств, как это делается для визуальных элементов и компоновочных элементов управления.
Использование Blend для создания анимаций
Подробно создание анимаций будет рассмотрено в Главе 5, но если говорить кратко, анимация создается в Silverlight за счет изменения свойства объекта во времени. Анимации такого типа можно без труда создавать визуально, используя Blend и редактор временной шкалы.
Одна из форм анимации, поддерживаемых Silverlight, - DoubleAnimation (Анимация свойств типа Double), которая используется для изменения числовых свойств, таких как, например, ширина визуального элемента Ellipse. Другой тип, ColorAnimation (Цветовая анимация), используется для изменения цвета свойства Brush.
Например, рассмотрим Ellipse, представленный на рис. 2-21 (который выглядит кругом, потому что его высота и ширина равны). Чтобы визуальными средствами анимировать изменение ширины элемента Ellipse, необходимо добавить новый элемент Storyboard, содержащий эту анимацию.
РИС. 2 21 Рисование круга.
В представлении Objects And Timeline выберите Ellipse и нажмите кнопку + рядом со списком Storyboard в верхней части панели. После принятия в диалоговом окне Create Storyboard (Создание раскадровки) настроек по умолчанию появится редактор временной шкалы. Также вверху окна Blend будет
выведено сообщение Timeline Recording Is On (Ведется запись временной шкалы). Нажмите клавишу F6 для реорганизации рабочего пространства, что упростит работу над анимацией. Экран должен выглядеть примерно так, как показано на рис. 2-22.
Найдите на временной шкале желтую линию. Она обозначает текущее положение курсора воспроизведения на временной шкале. Перетащите его на отметку 2 секунды и щелкните инструмент Record Keyframe (Запись ключевых кадров), располагающийся в верхней части временной шкалы. Он выглядит как шарик с небольшим зеленым знаком плюс (+) снизу справа. На временной шкале на отметке 2 секунды появится маленький овал, как показано на рис. 2-23.
После того, как определен ключевой кадр, любые вносимые изменения в свойства объекта будут записываться в этот ключевой кадр. Продолжим и изменим ширину Ellipse, в то время как желтая линия остается на отметке 2 секунды, обозначая текущее положение на временной шкале. Например, зададим для ширины значение 200 и для свойства Fill значение Red (Красный).
Теперь подвигаем курсор воспроизведения (верхушка вертикально желтой линии на временной шкале) влево-вправо и увидим изменение ширины и цвета круга во времени.
РИС. 2 22 Редактирование временной шкалы.
РИС. 2 23 Добавление ключевого кадра.
А вот XAML-код, сформированный в результате создания анимации визуальными средствами:
<UserControl.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(FrameworkElement.Width)" BeginTime="00:00:00">
<SplineDoubleKeyFrame KeyTime="00:00:02" Value="200"/>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:02" Value="#FFFF2200"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Ellipse Height="100" Width="100" Fill="#FFFFF500" Stroke="#FF000000" x:Name="ellipse"/>
</Grid>
Намного более подробно структура этого XAML будет рассмотрена в Главе 5, но важно обратить внимание на экземпляр элемента Storyboard.TargetName, обозначающий, для какого элемента определена анимация, и экземпляр элемента Storyboard.TargetProperty, обозначающий изменяемое свойство. Как видим, в данном XAML присутствует две анимации: изменяющая ширину целевого объекта и изменяющая его цвет. Во время формирования визуального представления анимации Silverlight использует это описание для вычисления значений свойств в каждом кадре.
Заключение
В данной главе были рассмотрены основы работы с Expression Blend и проведен краткий обзор возможностей, которые он предлагает дизайнеру или разработчику, создающему и реализующему собственные приложения Silverlight. Было показано, как можно использовать Blend для разработки решений и проектов Silverlight, и какие инструменты предлагает Blend IDE для создания и управления визуальными элементами, компоновкой, элементами управления и анимациями в приложении.
Данная глава лишь поверхностно знакомит с тем, что можно делать с помощью Blend, но, возможно, полученные сведения вдохновят читателей на более глубокое его изучение.
Вторая часть набора инструментов взаимодействия дизайнера и разработчика находится в Visual Studio. В Главе 3 будет рассмотрено, как можно использовать этот инструмент, что общего у него с Blend, и какие мощные возможности он обеспечивает разработчикам. Будет показано, как можно создать свое первое Silverlight-приложение - головоломку с перемещением фрагментов.
Глава 3
Использование Visual Studio с
Silverlight 2
В Главе 1, «Введение в Silverlight 2», был представлен Silverlight 2 и его архитектура, благодаря которой можно разрабатывать Silverlight-приложения, используя всю мощь .NET Framework. Было показано, как используется XAML для описания представления элементов пользовательского интерфейса (UI), взаимодействий и анимаций. Кроме того, вы увидели, как Silverlight-приложение может размещаться в браузере и реализовываться с помощью JavaScript, или размещаться в .NET Runtime для браузера и реализовываться на C# или других языках программирования .NET.
Затем в Главе 2, «Использование Expression Blend с Silverlight 2», был более подробно рассмотрен Expression Blend, инструмент для дизайна, используемый для создания приложений Silverlight.
В данной главе этот процесс будет подан с точки зрения разработчика и приведен практический пример использования Microsoft Visual Studio 2008 для построения простой игры-головоломки с перемещением фрагментов (по типу игры в пятнашки). В последующих главах этот пример будет дорабатываться. К концу данной главы вы получите прочное понимание того, как использовать C# и Visual Studio 2008 для построения .NET-приложений.
Установка Visual Studio Tools для Silverlight
Пакет Visual Studio tools for Silverlight (инструменты Visual Studio для Silverlight) включают программу установки, которая обеспечивает установку среды выполнения (для Windows), средств разработки ПО (SDK) Silverlight 2 и инструментов самой Visual Studio в правильной последовательности. Его можно скачать по адресу http://www.silverlight.net.
Пожалуйста, обратите внимание, что для установки этих инструментальных средств необходимо выполнить некоторые предварительные условия:
Должна использоваться финальная версия Visual Studio 2008 с установленным пакетом исправлений SP1. Инструменты не будут работать с бета-версией или версией без SP1. Может использоваться любая редакция Visual Studio 2008.
Должны быть установлены все компоненты Visual Studio для разработки Веб-сайтов.
Должны быть удалены все предыдущие версии среды выполнения Silverlight.
Должны быть удалены все предыдущие версии Silverlight SDK.
Должны быть удалены все предыдущие версии Visual Studio Tools для Silverlight.
Если эти требования не будут выполнены, программа установки даст сбой, и будет выведено диалоговое окно, представленное на рис. 3-1.
РИС. 3 1 Сбой установки инструментов Visual Studio.
Если все предварительные условия выполнены, будет выведено следующее диалоговое окно (рис. 3-2).
РИС. 3 2 Диалоговое окно, указывающее на готовность к установке Visual Studio Tools для Silverlight.
Щелкните Next (Далее), и появится экран с лицензионным соглашением. Сразу после принятия лицензионного соглашения начнется установка. Окно, отображаемое в процессе установки, показано на рис. 3-3.
РИС. 3 3 Установка инструментов Silverlight.
Когда программа установки завершит загрузку и установку, вы получите готовые к работе среду выполнения Silverlight, SDK и Visual Studio Tools. Обратите внимание, что предыдущие версии SDK не интегрируют службу Help (Справка) непосредственно в Visual Studio, но есть файл Readme, расположенный в каталоге \Program Files\Microsoft SDKs\Silverlight\v2.0\Documentation\VS-Help, в котором можно найти инструкции по подключению ее вручную.
Использование Visual Studio для создания приложения Silverlight
Теперь, когда Visual Studio Tools для Silverlight установлены, пора научиться использовать их для проектирования и построения приложений. Рис. 3-4 показывает в действии игру-головоломку на Silver- light. Это приложение полностью написано на C# и XAML и запущено в браузере.
РИС. 3 4 Игра головоломка с перемещением фрагментов.
В последующих разделах будет показано, как использовать Visual Studio 2008 и Silverlight для создания такого приложения на языке программирования C#.
Создание Silverlight-приложения в Visual Studio 2008
Установив Visual Studio, а также все необходимые инструменты и шаблоны для Silverlight, вы сможете создавать Silverlight-приложения. Для этого выберите пункт New Project в меню File. Откроется диалоговое окно New Project (рис. 3-5).
РИС. 3 5 Диалоговое окно New Project Visual Studio 2008.
Убедитесь, что в верхнем правом углу диалога выбран пункт .NET Framework 3.5 (рис. 3-5), и в списке Project Type (Тип проекта) выберите Silverlight. Вы увидите доступные шаблоны Silverlight Application (Приложение Silverlight) и Silverlight Class Library (Библиотека классов Silverlight).
Выберите шаблон Silverlight Application и задайте имя и местоположение своего проекта. Щелкните OK, и Visual Studio запустит Silverlight Application Wizard (Мастер приложений Silverlight) (рис. 3-6).
Этот мастер предлагает несколько вариантов создания и управления Silverlight-приложением. Все Silverlight-приложения в версии 2.0 создаются как пользовательские элементы управления, экземпляры которых затем могут быть созданы и размещены на странице. Таким образом, данное обсуждение сводится к тому, как это сделать.
РИС. 3 6 Мастер приложений Silverlight.
Предлагаются такие опции:
Add A New ASP.NET Web Project To The Solution To Host Silverlight (Добавить в решение новый ASP.NET Веб-проект для размещения Silverlight) Эта опция является опцией по умолчанию и обеспечит создание нового проекта ASP.NET Веб-сайта или Веб-приложения, который будет конфигурирован для размещения и выполнения вашего Silverlight-приложения. Это механизм быстрого создания новых приложений Silverlight (именно то, чем мы занимаемся в этой книге!), так
как он обеспечивает автоматическое формирование кода, необходимого для размещения элемента управления Silverlight на странице, позволяя разработчику сосредоточиться на самом Silverlight- приложении. Используйте панель опций для выбора типа проекта для Веб (это может быть ASP.NET Веб-сайт или ASP.NET Веб-приложение) и задайте ему имя.
Automatically Generate A Test Page To Host Silverlight At Build Time (Сформировать тестовую страницу для размещения Silverlight во время сборки приложения) Эта опция обеспечит создание новой страницы во время выполнения при каждой попытке отладки и тестирования создаваемого приложения. Это особенно полезно, если вы хотите сосредоточиться исключительно на приложении Silverlight и не хотите решать проблемы, связанные с использованием отдельного Веб-проекта. Окончательный же вариант элемента управления будет разворачиваться на сервере, и его экземпляр будет создаваться на Веб-странице.
Link This Silverlight Control Into An Existing Web Site (Подключить этот элемент управления Silverlight к существущему Веб-сайту) Эта опция позволит подключить элемент управления Silverlight в создаваемом решении к существующему Веб-сайту. Для нового проекта эта опция будет недоступна. Она будет доступна для выбора, если приложение Silverlight добавляется в существующее решение, в котором есть Веб-проект.
Примите настройки по умолчанию, как показано на рис. 3-6, и для вас будет создано новое решение Visual Studio, содержащее элемент управления Silverlight и ASP.NET Веб-приложение, в котором будет размещаться этот элемент управления. Структуру проекта можно увидеть на рис. 3-7.
РИС. 3 7 Стандартная структура проекта Silverlight.
Как видно на рис. 3-7, было создано два решения: базовый элемент управления Silverlight
(SlidingBlocks) и Веб-приложение. В следующем разделе вы рассмотрите эти проекты и узнаете, что они включают. После этого перейдем к созданию приложения.
Проект элемента управления Silverlight
Созданный шаблоном базовый проект содержит ряд файлов, включая манифест приложения, XAML- файл приложения с файлом выделенного кода, страницу-пример с файлом выделенного кода, инфор-
мационный файл сборки и некоторые ссылки. Рассмотрим каждый из этих файлов по очереди. В данном разделе представлены некоторые сложные моменты проекта Silverlight, которые, вероятно, особо нетерпеливые читатели захотят пропустить, чтобы быстрее перейти к написанию кода. Однако я бы рекомендовал задержаться и ознакомиться с этой информацией, чтобы понимать все взаимосвязи и зависимости.
Понимание свойств проекта Silverlight
Лучше всего начать с рассмотрения свойств проекта. Для этого щелкните правой кнопкой мыши проект SlidingBlocks в обозревателе решения и выберите Properties. Появится диалоговое окно Project Properties (рис. 3-8).
РИС. 3 8 Диалоговое окно Project Properties Silverlight.
Те, кто знаком с этим окном, заметит, что в нем появилась дополнительная вкладка для Silverlight. Она выбрана на рис. 3-8 и представляет опции Silverlight.
Опции Assembly Name (Имя сборки) по умолчанию присваивается имя проекта. Это имя будет использоваться при компиляции приложения в DLL.
Опции Default Namespace (Пространство имен по умолчанию) по умолчанию также присваивается имя проекта. Если вы ссылаетесь на классы из этого проекта, их имена будут начинаться с имени этого пространства имен.
Опции Startup Object (Объект, с которого начинается запуск проекта) по умолчанию присваивается имя проекта с .App в конце (т.е. SilverlightBlocks.App). Это класс в приложении, который будет выполняться первым. Шаблон определяет этот класс в App.xaml и связанный с ним файл выделенного кода App.xaml.cs, который будет рассматриваться в одном из последующих разделов.
По щелчку кнопки Assembly Information (Сведения о сборке) будет вызван диалог Assembly Information (рис. 3-9). В нем можно определить метаданные своей сборки, включая Title (Название), Description (Описание), Copyright (Авторское право) и Trademark (Торговая марка). Вся эта информация хранится в файле AssemblyInfo.cs и компилируется в приложение Silverlight.
Опция XAP file name (Имя XAP-файла) позволяет задавать файл .xap, в который будут записываться все выходные данные компиляции проекта. Обычно это DLL, содержащая ваш компонент Silverlight и его манифест приложения. Это удобно для Веб-приложений, поскольку компоненту Silverlight для загрузки и использования множества компонентов необходимо сослаться только на один файл (XAP-файл).
РИС. 3 9 Задание сведений о сборке.
Подсказка XAP-файл - это всего лишь ZIP-файл с другим расширением. Если необходимо просмотреть его содержимое, просто переименуйте его с расширением .zip и откройте с помощью любимой утилиты для работы с архивами ZIP. Не забудьте вернуть расширение .xap, когда закончите работу с файлом!
Наконец, предлагается опция для создания самого файла манифеста Silverlight. Этот файл содержит данные по всем элементам пакета, которые будут использоваться приложением Silverlight, таким как дополнительные компоненты или элементы управления, которые необходимы для выполнения приложения. Мы еще будем возвращаться к этому по ходу книги.
Файлы свойств
Первой папкой проекта является папка Properties, содержащая файлы свойств: AppManifest.xml и As- semblyinfo.cs.
AppManifest.xml создается при компиляции проекта. Если проект имеет какие-либо зависимости во время выполнения, такие как внешние элементы управления, ссылки на них размещаются в этом файле.
Файл Assemblyinfo.cs содержит метаданные, которые должны быть скомпилированы в вашу DLL, заданную в диалоговом окне Assembly Information (рис. 3-9). Код в этом файле можно редактировать вручную, но рекомендуется использовать для этого диалоговое окно.
Ссылки
Папка References содержит ссылки на ряд сборок. Это основные сборки Silverlight, которые необходимы для запуска приложения.
mscorlib В эту сборку входят основные типы, используемые приложениями Silverlight.
System В эту сборку входят многие высокоуровневые типы, используемые для разработки и отладки приложений Silverlight, такие как компилятор и классы для отладки и диагностики.
System.Core Эта сборка включает функциональность работы с данными LINQ.
System.Xml В эту сборку входят библиотеки Silverlight для обработки XML.
System.Windows В эту сборку входят основные функциональные возможности Windows и Silver- light, включая элементы управления Silverlight.
System.Windows.Browser В эту сборку входят библиотеки, используемые для взаимодействия с браузером.
System.Net В эту сборку входят классы необходимые для работы с сетью, например, для получения файлов по протоколу HTTP.
В Silverlight также имеется ряд сборок, не входящих в стандартную поставку, которые можно добавлять для обеспечения необходимой функциональности. Некоторые из них будут рассмотрены в данной книге. Примером такой функциональности является Dynamic Language Runtime (Динамическая среда выполнения).
Файлы App.xaml и App.xaml.cs
Файл App.xaml создается интегрированной средой разработки (IDE) при создании проекта Silverlight по шаблону. Обычно он используется для хранения общей информации всего приложения.
App.xaml содержит объявления, определяющие поведение приложения. Вот пример App.xaml, создаваемого шаблоном по умолчанию:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SlidingBlocks.App">
<Application.Resources>
</Application.Resources>
</Application>
Первое, на что следует обратить внимание, - атрибут x:Class, который определяет имя класса, в который будет скомпилирован этот XAML и связанный с ним файл выделенного кода. Как видите, в данном случае это SlidingBlocks.App, который, как вы, возможно, помните из рис. 3-8, был задан в диалоговом окне Project Properties как объект запуска для этого приложения. Таким образом, функциональность запуска проекта Silverlight будет находиться в этом классе.
С помощью атрибута Startup (Запуск) можно задать функцию, которая будет выполняться при запуске приложения. Для этого просто указывается имя необходимой функции, описанной в файле выделенного кода. Также в атрибуте Exit (Выход) можно задать имя функции из файла выделенного кода, которая будет выполняться при завершении приложения.
Далее приведен код стандартного файла выделенного кода, созданного шаблоном:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SlidingBlocks {
public partial class App : Application {
public App()
{
this.Startup += this.Application Startup; this.Exit += this.Application Exit;
this.UnhandledException += this.Application UnhandledException;
InitializeComponent();
}
private void Application Startup(object sender, StartupEventArgs e) {
// Загружаем основной элемент управления this.RootVisual = new Page();
}
private void Application Exit(object sender, EventArgs e) {
}
private void Application UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (!System.Diagnostics.Debugger.IsAttached) {
e.Handled = true;
Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
}
}
private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
{ try { string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight 2 Application " + errorMsg + "\");");
}
catch (Exception)
{
}
}
}
}
Сначала рассмотрим конструктор (это функция с именем, аналогичным имени модуля кода, в данном случае это AppO). Он используется для подключения функций Startup и Exit. Это уже было сделано в файле XAML, поэтому нет необходимости делать это в коде. Однако это демонстрирует замечательную гибкость модели XAML/выделенный код, которая позволяет подключать события во время разработки (задавая их в XAML) или во время выполнения (объявляя их в коде).
Далее можно проверить функции Application Startup и Application Exit. Обратите внимание, что они принимают два параметра: объект, формирующий событие, и объект аргументов. Такая сигнатура функций очень распространена в приложениях Silverlight.
В функции Application Startup происходит присвоение свойству RootVisual (Корневой визуальный элемент) приложения нового объекта Page (Страница). Тем самым объявляется, что UI объекта Page является первым экраном UI, который должно создать это приложение. Если предполагается использовать другие экраны UI, объявленные в XAML, они будут запускаться уже из объекта Page.
Объект Page является XAML-объектом по умолчанию, создаваемым шаблоном для размещения UI вашего приложения, который рассматривается в следующем разделе.
Файлы Page.xaml и Page.xaml.cs
Файл Page.xaml является для приложения UI по умолчанию. При компиляции вместе с ассоциированным с ним файлом выделенного кода он формирует класс Page, экземпляр которого будет объектом Page. Если вспомнить из предыдущего раздела, в качестве значения свойства RootVisual приложения был задан новый объект Page, что обеспечило данному классу UI по умолчанию.
Вот XAML, формируемый по умолчанию для Page.xaml:
<UserControl x:Class="SlidingBlocks.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400"
Height="300">
<Grid x:Name="LayoutRoot" Background="White" >
</Grid>
</UserControl>
Прежде всего, обратите внимание, что контейнером XAML является UserControl. Этого не было в Silverlight 1.0. Как говорилось ранее, при построении приложений Silverlight 2 в Visual Studio, фактически, создаются элементы управления, которые компилируются в DLL и помещаются в XAP, который затем открывает и исполняет Silverlight.
В данном случае, видим, что экземпляр этого UserControl называется SlidingBlocks.Page. SlidingBlocks - это пространство имен (чтобы увидеть это, вернитесь и взгляните на свойства проекта), и Page - имя класса из этого пространства имен.
Объявления xmlns и xmlns:x задают пространство имен по умолчанию и дополнительное пространство имен, соответственно, которые должны использоваться для проверки корректности XAML. Ранее был рассмотрен атрибут x:Class, используемый для описания класса этого элемента управления, который также является примером применения дополнительного пространства имен, запись которого начинается с префикса х:.
Наконец, ширине и высоте присвоены значения по умолчанию: 640 х 480.
Далее идет корневой Grid. В Silverlight 2 корневым элементом должен быть Container (Контейнер), которым в данном случае является Grid под именем LayoutRoot. Соответственно, все элементы дизайна UI будут дочерними элементами этого узла.
Вот выделенный код для данного XAML:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SlidingBlocks {
public partial class Page : UserControl
{
public Page()
{
// Необходима для инициализации переменных InitializeComponent();
}
} }
Те, кто знаком с C#, видят, что этот код очень похож на код, который, возможно, вы использовали ранее. По сути, это стандартный класс Page, унаследованный от типа UserControl. В конструкторе класса выполняется общая настройка с помощью вызова метода InitializeComponentO. В разделе «Написание игры на Silverlight 2» данной главы, в котором мы займемся созданием головоломки с перемещением фрагментов, вы добавите в этот модуль характерный для вашей страницы код.
Веб-проект
Кроме проекта элемента управления, шаблон создает Веб-проект, в котором размещается ваше приложение Silverlight. Этот Веб-проект включает два ASPX-файла: Default.aspx, являющийся пустой Веб-формой, на базе которой можно построить свое приложение; и тестовую страницу
<ИмяПриложения>TestPage.aspx (например, SlidingBlocksTestPage.aspx), которая содержит все необходимое для запуска Silverlight из ASP.NET.
Хотя Silverlight не имеет никаких зависимостей на стороне сервера, ASP.NET предлагает элементы управления, обеспечивающие возможность создания JavaScript и HTML на стороне клиента, необходимых для размещения Silverlight в браузере.
Файл TestPage включает ссылки на эти элементы управления. Далее приведена разметка для ASPX- файла:
<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Register Assembly="System.Web.Silverlight"
Namespace="System.Web.UI.SilverlightControls" TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"style="height:100%;">
<head runat="server">
<title>SlidingBlocks</title>
</head>
<body style="height:100%;margin:0;">
<form id="form1" runat="server" style="height:100%;">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div style="height:100%;">
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/SlidingBlocks.xap" MinimumVersion="2.0.31005.0"
Width="100%" Height="100%" />
</div>
</form>
</body>
</html>
Заметьте, что данная технология является развивающейся, поэтому атрибуты номера версии и открытого ключа могут немного меняться. Если для создания кода вы использовали шаблон, не стоит волноваться, все будет в порядке.
На этой странице используются два элемента управления ASP.NET. Первый -ScriptManager (Диспетчер сценариев), который является артефактом AJAX ASP.NET и превосходным средством управления загрузкой и использованием всех необходимых библиотек JavaScript в соответствующее время и в соответствующем месте.
Второй - элемент управления Silverlight. Обратите внимание, что в качестве параметра он принимает рассмотренный выше XAP. Этот элемент управления будет формировать правильный HTML-код для создания функций DIV и CreateSilverlight.
После запуска этой страницы будет сформировано много кода на HTML и JavaScript. Элемент управления Silverlight создается и получает файл XAP ближе к концу кода. Вот фрагмент кода:
<script type="text/javascript">
//<![CDATA[
Sys.Application.initialize();
Sys.Application.add init(function() {
$create(Sys.UI.Silverlight.Control,
{"source":"ClientBin/SlidingBlocks.xap"}, null, null, $get("Xaml1 parent"));
});
//]]>
</script>
Браузер интерпретирует этот сценарий и создает элемент управления Silverlight. Обратите внимание, что корректную работу элементов управления Silverlight ASP.NET обеспечит ASP.NET. Если экземпляр Silverlight создается не из ASP.NET, по-прежнему могут использоваться сценарии JavaScript, входящие в SDK. Это подробно рассматривается в Главе б, «Элемент управления браузера Silverlight».
Написание игры на Silverlight 2
Silverlight поддерживает модель разделения дизайна и процесса разработки, при которой дизайн представляется с помощью XAML и код, обычно (хотя это не обязательно) на C#, создается в выделенном файле.
В данном примере XAML будет использоваться совсем немного, лишь для размещения Canvas, в котором будут находиться фрагменты рисунка и его полное изображение. Если вернуться к рис. 3-4, эти компоненты можно увидеть слева и справа, соответственно. Обратите внимание, что хотя главным контейнером страницы по умолчанию является Grid, для простоты в этой игре мы будем использовать Canvas.
Создание UI в XAML
Как видно на рис. 3-4, UI этой игры очень прост. Он состоит из области экрана (занимаемой элементом Canvas), в которой располагаются перемещаемые фрагменты собираемого изображения, и области, в которой формируется визуальное представление собранного рисунка.
Вот пример XAML, который обеспечивает отображение Canvas и завершенного рисунка:
<UserControl x:Class="SlidingBlocks.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640"
Height="480" >
<Canvas x:Name="LayoutRoot" >
<Canvas x:Name="GameContainer" />
<Image Source="sl.jpg" Canvas.Left="500"
Height="400" Width="400" Stretch="UniformToFill">
</Image>
</Canvas>
</UserControl>
Как видите, все очень просто. Canvas, в котором будут размещаться фрагменты собираемого изображения, называется GameContainer (Контейнер игры). Изображение, которое будет формировать визуальное представление собранного рисунка, является статическим, таким образом, не нуждается в имени. Изначально оно заполнено изображением sl.jpg из этого же Веб-проекта. Вот и весь дизайн. В следующем разделе займемся кодом.
Написание кода игры
Код игры в данном примере написан на C#. Его без труда можно было бы транслировать на VB.NET, IronPython или любой другой поддерживаемый язык программирования, но в большинстве случаев в данной книге будет использоваться C#.
Инициализация структур данных
Первый шаг в написании кода для этой игры - инициализация структур данных, которые будут использоваться приложением. В данном случае мы собираемся разбить рисунок на 16 фрагментов, 15 из которых будут выставлены на поле в произвольном порядке. Один фрагмент не используется, вместо него оставляем пустое пространство, обеспечивающее возможность перемещения фрагментов по игровому полю.
В Silverlight нельзя создать фрагмент существующего изображения, но можно вырезать его по определенному контуру. Не следует путать вырезание с обрезкой. В первом случае вы указываете, какие части рисунка должны быть отрисованы; во втором - удаляете все, кроме необходимой части изображения. Silverlight не поддерживает обрезку, поэтому приходится вырезать изображение.
Проблема использования вырезания состоит в том, что при его применении остальная часть рисунка остается доступной и может быть активизирована щелчком мыши. Например, если имеется изображе-
ние 400 х 400 и из него вырезается квадратный фрагмент 100 х 100 в позиции (100,100), мы видим квадрат 100 х 100 в позиции (100,100), но объект 400 х 400 никуда не исчез: он стал пустым, но по- прежнему может быть активизирован щелчком мыши. Это не отвечает нашим требованиям для создания головоломки с перемещаемыми фрагментами. Но что можно сделать?
Решение состоит во введении в Canvas изображения, размеры которого соответствуют размерам вырезанного фрагмента, и последующем использовании трансформации транслирования на него, чтобы вырезанная часть изображения располагалась в верхнем левом углу данного Canvas, и, таким образом, Canvas формировал визуальное отображение только вырезанной области.
Итак, для головоломки 4 х 4, образованной 16 блоками необходимо создать 16 изображений и 16 объектов Canvas. Также потребуется как-то представлять поле, чтобы вы знали, какое изображение в каком квадрате находится. Вот код для описания этого:
Canvas[] cI = new Canvas[16];
Image[] i = new Image[16]; int[] board = new int[16];
Создание фрагментов головоломки
Чтобы создать фрагменты головоломки, понадобиться загрузить изображение sl.jpg в каждый элемент массива изображений. Для этого с помощью универсального идентификатора ресурса (uniform resource identifier, URI) мы указываем на необходимое изображение и определяем класс Bitmapimage (из пространства имен System.Windows.Media.Imaging), в который считываются данные по этому URI. И присваиваем этот класс элементу управления изображение:
i[nx].Source = new BitmapImage(uri);
Из конструктора можно вызвать функцию (InitBoard), которая будет использоваться для создания экземпляров фрагментов головоломки:
public Page() {
// Необходимо для инициализации переменных InitializeComponent();
InitBoard();
}
Эту функцию можно увидеть здесь:
void InitBoard() {
Uri uri = new Uri("sl.jpg", UriKind.Relative);
int nx = 0;
for (int ix = 0; ix < 4; ix++)
for (int iy = 0; iy < 4; iy++)
{
nx = (ix * 4) + iy;
i[nx] = new Image();
i[nx].Height = 400;
i[nx].Width = 400;
i[nx].Stretch = Stretch.UniformToFill;
RectangleGeometry r = new RectangleGeometry();
r.Rect = new Rect((ix * 100), (iy * 100), 100, 100);
i[nx].Clip = r;
i[nx].Source = new BitmapImage(uri);
i[nx].SetValue(Canvas.TopProperty, Convert.toDouble(iy * 100 * -1));
i[nx].SetValue(Canvas.LeftProperty, Convert.toDouble(ix * 100 * -1));
cI[nx] = new Canvas();
cI[nx].Width = 100;
cI[nx].Height = 100;
cI[nx].Children.Add(i[nx]);
cI[nx].SetValue(Canvas.NameProperty, "C" + nx.ToString());
cI[nx].MouseLeftButtonDown += new
MouseButtonEventHandler(Page MouseLeftButtonDown);
if (nx < 15)
GameContainer.Children.Add(cI[nx]);
}
// Перемешиваем фрагменты shuffle();
// Отрисовываем поле drawBoard();
}
Не забудьте добавить ссылку на System.Windows.Media.Imaging в начале кода:
using System.Windows.Media.Imaging;
На первый взгляд все это может показаться немного сложным, но при более близком рассмотрении все предельно просто. Задается вложенный цикл для прохождения по осям х и у с диапазоном значений от 0 до 3 . Это, как можно догадаться, используется для организации массива 4x4 для изображений.
Массивы Image и Canvas, используемые для хранения фрагментов, являются одномерными массивами по 16 элементов каждый (при такой структуре для их хранения требуется меньше памяти и кода). Чтобы спроецировать двумерные координаты ix, iy на одномерный массив, необходимо выполнить следующие вычисления:
nx = (ix * 4) + iy;
Для каждого элемента задаются размеры 400 x 400 с помощью значения UniformToFill (Равномерное заполнение) свойства Stretch (Растяжение). Более подробно об использовании изображений рассказывается в Главе 4, «Основы XAML».
Далее вычисляется область вырезания. Для этого используется объект RectangleGeometry (Геометрический элемент прямоугольник):
RectangleGeometry r = new RectangleGeometry(); r.Rect=new Rect((ix*100), (iy*100) ,100,100); i[nx].Clip = r;
Таким образом, определяется прямоугольник с соответствующими координатами (полученными путем умножения ix и iy на 100) соответствующего размера (100 x 100), и он задается как область вырезания для текущего изображения (i[nx]).
Далее изображение загружается в BitmapImage, инициализация которого происходит путем задания URI этого изображения, и помещается в заданное положение. Чтобы изображение, вырезанное в позиции (100,100), появилось в верхнем левом углу, оно должно быть передвинуто на (-100,-100) относительно вырезанной области. Таким образом, свойствам Top (Сверху) и Left (Слева) должно быть задано значение -100 и умножено на значения iy и ix, соответственно.
i[nx].Source = new BitmapImage(uri);
i[nx].SetValue(Canvas.TopProperty, Convert.toDouble(iy * 100 * -1)); i[nx].SetValue(Canvas.LeftProperty, Convert.toDouble(ix * 100 * -1));
Изображения до сих пор не добавлены в родительский Canvas. Это следующий шаг. Canvas необходимо инициализировать, задать его размеры и добавить в него в качестве дочернего элемента соответствующее изображение. Вот код:
cI[nx] = new Canvas();
cI[nx].Width = 100;
cI[nx].Height = 100;
cI[nx].Children.Add(i[nx]);
Теперь мы получили наш Canvas, и он содержит наше вырезанное изображение. Завершаем инициализацию, присваивая Canvas имя (чтобы его можно было отслеживать, когда мы щелкаем его), определяем обработчик событий для описания действий, которые будут выполняться по щелчку пользователя по нему, и, наконец, добавляем его в родительский Canvas. Пока нет необходимости задавать местоположение фрагмента. Это будет сделано после того, как фрагменты будут перемешаны на поле.
Обратите внимание, последнее изображение не добавляется на поле, потому что мы хотим, чтобы осталось свободное пространство.
cI[nx].SetValue(Canvas.NameProperty, "C" + nx.ToString());
cI[nx].MouseLeftButtonDown += new
MouseButtonEventHandler(Page MouseLeftButtonDown);
if(nx<15)
GameContainer.Children.Add(cI[nx]);
Наконец, необходимо перемешать фрагменты и отрисовать игровое поле. Код для реализации этого представлен в следующем разделе.
Перемешиваем фрагменты
Фрагменты головоломки перемешиваются с помощью довольно простого алгоритма перемешивания, который перебирает массив 100 раз, выбирая два случайных элемента каждый раз; если эти два элемента разные, он меняет местами их содержимое. В конце он загружает в последний элемент значение -1, чтобы обозначить пустой квадрат.
Здесь представлен алгоритм перемешивания:
void shuffle()
{
// Инициализируем игровое поле
for (int n = 0; n < 15; n++)
{ board[n] = n;
}
Random rand = new Random(System.DateTime.Now.Second);
for (int n = 0; n < 100; n++)
{
int n1 = rand.Next(15);
int n2 = rand.Next(15);
if (n1 != n2)
{
int tmp = board[n1];
board[n1] = board[n2];
board[n2] = tmp;
}
}
board[15] = -1;
}
Следующий шаг после того, как фрагменты перемешаны, - отрисовка игрового поля.
Отрисовка игрового поля
На данный момент мы имеем все фрагменты головоломки, определенные как элементы Image в элементе Canvas, и массив целых чисел, значение индекса n которого соответствует фрагменту, отображаемому в данном месте. Вы также перемешали этот массив целых чисел, поэтому пришло время отрисовать игровое поле. Это делается следующим образом:
void drawBoard()
{
int nx = 0;
int ny = 0;
for (int n = 0; n < 15; n++)
{
nx = n / 4;
ny = n % 4;
if(board[n]>=0)
{
cI[board[n]].SetValue(Canvas.TopProperty, Convert.toDouble(ny * 100));
cI[board[n]].SetValue(Canvas.LeftProperty, Convert.toDouble(nx * 100));
}
}
}
В данном случае выполняется цикл с изменением индекса от 0 до 14 (в головоломке 15 фрагментов) и вычисление координат x,y для каждого блока в сетке 4x4. Значение x - это просто результат целочисленного деления индекса массива на 4, и значение у - это модуль индекса, деленного на 4. Умножаем эти значения на 100 и получаем необходимые координаты для отрисовки элемента Canvas.
Теперь мы имеем полностью инициализированную игру. Рисунок располагается справа, а игровое поле с перемешанными фрагментами рисунка - слева.
Обработка действий пользователя
Теперь необходимо заняться обработкой действий пользователя. В играх подобного рода предполагается, что пользователь будет щелкать фрагмент изображения, и если этот фрагмент находится рядом с пустой областью, он плавно переместится в эту область, оставляя пустым занимаемое до этого место. Итак, мы должны обработать щечки по элементу Canvas, содержащего фрагмент изображения. Если вернуться к инициализации фрагментов, можно вспомнить такую строку:
cI[nx].MouseLeftButtonDown
+= new MouseButtonEventHandler(Page MouseLeftButtonDown);
Здесь описывается, что по щелчку Canvas будет запускаться обработчик события
Page MouseLeftButtonDown. Этот обработчик события задан для каждого из блоков Canvas.
Код этого обработчика события состоит из двух разделов. Первый определяет, который из Canvas сформировал событие и положение этого Canvas на игровом поле:
void Page MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
Canvas c = sender as Canvas;
int nCanvasID = -1;
int nBoardLoc = -1;
int nEmptyLoc = -1;
for (int i = 0; i < 16; i++) {
if (c == cI[i])
{
nCanvasID = i; break;
}
}
for (int i = 0; i < 16; i++) {
if (board[i] == nCanvasID)
{ nBoardLoc = i;
}
else if (board[i] == -1)
{ nEmptyLoc = i;
} }
Итак, например, вы щелкнули фрагмент, представляющий верхний левый угол полного изображения (блок 0), но в настоящий момент он находится в нижнем левом углу игрового поля (позиция 12). При возникновении события щелчка, выполняется перебор всего массива элементов Canvas, представляющих фрагменты головоломки, до тех пор, пока не будет найден фрагмент, соответствующий Canvas, по которому было произведен щелчок. И здесь вы можете получить индекс этого элемента в массиве, сохранив его в переменной nCanvasID (в нашем гипотетическом примере он равнялся бы 0). После этого, просканировав игровое поле, можно определить местоположение элемента 0 на нем и присвоить значение его позиции переменной nBoardLoc (которое в нашем гипотетическом примере равно 12). И, находясь в этой позиции, найдите местоположение пустой ячейки на игровом поле и сохраните его в nEmptyLoc.
Вторая часть кода проверяет возможность перемещения фрагмента, и, если перемещение возможно, перемещает фрагмент в пустую ячейку и соответствующим образом обновляет игровое поле.
// Прверяем возможность перемещения
if ((nBoardLoc == nEmptyLoc + 1) ||
(nBoardLoc == nEmptyLoc - 1) ||
(nBoardLoc == nEmptyLoc + 4) ||
(nBoardLoc == nEmptyLoc - 4))
{
int nx = nEmptyLoc/4;
int ny = nEmptyLoc%4;
cI[nCanvasID].SetValue(
Convert.toDouble(Canvas.TopProperty, ny * 100)); cI[nCanvasID].SetValue(
Convert.toDouble(Canvas.LeftProperty, nx * 100));
board[nEmptyLoc] = nCanvasID;
board[nBoardLoc] = -1;
checkWinner();
}
else
{
// не делаем ничего
}
}
Для этого сначала проверим местоположение пустой ячейки относительно положения блока, по которому был произведен щелчок. Если они располагаются непосредственно рядом друг с другом (над, под, слева или справа), перемещение возможно. Поскольку игровое поле 4x4 является одномерным массивом, сделать это несложно. Позиции элементов, располагающихся слева и справа от текущего элемента, отличаются от текущей на -1 и +1, соответственно, и позиции элементов сверху и снизу - на -4 и +4, соответственно. Так что если результат проверки фрагментов указывает на пустую ячейку, вы знаете, что можете двигаться.
Чтобы выполнить перемещение, необходимо получить координаты x и у относительно положения пустого фрагмента и задать их как координаты блока, по которому был произведен щелчок. Затем присвоить позиции поля, на которой до этого находилась пустая ячейка, значение Canvas, по которому был произведен щелчок, и позиции поля, на которой до этого располагался Canvas, по которому был произведен щелчок, значение -1, указывая на то, что теперь эта ячейка пуста.
Наконец, вызовем функцию checkWinnerO, чтобы проверить успешность решения головоломки.
Проверка условия выигрыша
Функция checkWinner (Проверка победителя) проверяет успешность решения головоломки. Опять же, все очень просто. Головоломка решена, если каждый n-ный элемент игрового поля равен n, т.е. Canvas 0 имеет индекс 0, Canvas 1- индекс 1 и т.д.
Самый эффективный способ сделать это - предположить, что головоломка решена успешно, и просканировать игровое поле в поисках несоответствия board[n] значению n, что будет свидетельствовать о неверном решении и приводить к завершению цикла. Если все индексы совпадают, у нас есть победитель!
void checkWinner()
{
bool bCompleted = true; for (int n = 0; n < 15; n++) { if (n != board[n]) { bCompleted = false; break;
}
}
if (bCompleted) {
// Игрок выиграл....сделайте для него что-нибудь приятное. }
}
Теперь вы получили все элементы простой игры-головоломки с перемещением фрагментов, написанной на C# для Silverlight 2. И для этого понадобилось всего лишь 100 строк кода. По ходу чтения этой книги данный пример можно расширять, добавляя анимацию перемещения блоков, сохранение лучших результатов, возможность загрузки изображений в приложение и т.д. Нет пределов совершенству!
Заключение
В данной главе мы рассмотрели Visual Studio 2008 и предлагаемые ею различные инструменты и шаблоны для разработки приложений Silverlight с использованием языков программирования .NET. Был детально разобран проект, созданный на базе стандартных шаблонов Silverlight, рассмотрены все его файлы и то, как он используется для разработки и развертывания приложения Silverlight. После этого мы применили теорию на практике и создали полнофункциональную игру-головоломку с перемещением фрагментов, используя XAML и C#. Это позволило почувствовать возможности Silverlight 2, но мы лишь слегка прикоснулись к ним. В Части 2 данной книги, «Программирование в Silverlight 2», будут более глубоко рассмотрены функциональные возможности, доступные в .NET Framework, включая создание собственных элементов управления, работу с сетью и обмен информацией, данные и XML, динамические языки программирования и серверные элементы управления ASP.NET.
Глава 4
Основы XAML
XAML - это ядро приложения Silverlight. Он используется для определения графических ресурсов, взаимодействий, анимаций и временных шкал. XAML основывается на XML, поэтому все описывается в текстовом формате с использованием атрибутов для объявления свойств, методов и событий.
В данной главе будут рассмотрены общие компоненты XAML, используемые для описания визуальных элементов приложения. Во-первых, мы остановимся на формировании компоновки, в том числе на том, как элементы могут размещаться на экране относительно их контейнеров и друг друга. Также рассмотрим разные кисти, используемые для заливки фигур и элементов управления, а также обводки для отрисовки контуров. Затем вы узнаете о контурах и геометрических элементах и о том, как они используются для создания сложных фигур и групп фигур, а также как с их помощью реализовывается вырезание других объектов или заливки. Наконец, будут представлены элементы управления, использующие эти компоненты XAML, включая Canvas, который является основным элементом компоновки Silverlight. Кроме того, мы познакомимся, как использовать элементы управления Glyphs (Глифы) и TextBlock для отображения текста.
Компоновочные свойства XAML
Если говорить кратко, свойства Canvas.Left и Canvas.Top используются для компоновки элементов управления в XAML. Их называют присоединенными свойствами, что всего лишь означает, что они глобально доступны в коде XAML или изменяют свойство, определенное родительским элементом. Кроме того, присоединенное свойство может использоваться для обозначения положения объекта на плоскости относительно оси Z, что определяет очередность отрисовки в случае наложения объектов друг на друга. По умолчанию элемент, отрисовываемый последним (самый нижний в документе XAML), является самым верхним, но с помощью Canvas.ZIndex это положение можно переопределить.
Итак, рассмотрим следующий фрагмент XAML. Он представляет код для Canvas с двумя прямоугольниками. Для определения положения верхнего левого угла этих прямоугольников относительно холста, в котором они располагаются, используются свойства Canvas.Left и Canvas.Top.
<Canvas>
<Rectangle Fill="Red" Width="200" Height="128"Canvas.Left="8" Canvas.Top="8"/>
<Rectangle Fill="Black" Width="280" Height="80" Canvas.Left="40" Canvas.Top="32"/>
</Canvas>
Черный прямоугольник отрисовывается поверх красного, как показано на рис. 4-1.
РИС. 4 1 Компоновка прямоугольников.
Красный прямоугольник находится на расстоянии 8 пикселов от левого края и 8 пикселов от верхней границы родительского холста. Черный сдвинут на 40 пикселов от левого и 32 пиксела от верхнего края. Черный прямоугольник располагается поверх красного, так как он визуализировался последним.
Это положение элементов можно переопределить с помощью свойства ZIndex. ZIndex принимает числовые значения. Объекты с большими значениями ZIndex будут отображаться поверх объектов с меньшими ZIndex, как видно в следующем коде:
<Canvas>
<Rectangle Canvas.ZIndex="2"
Fill="Red" Width="200" Height="128"
Canvas.Left="8" Canvas.Top="8"/>
<Rectangle Canvas.ZIndex="1"
Fill="Black" Width="280" Height="80" Canvas.Left="40" Canvas.Top="32"/>
</Canvas>
Как показано на рис. 4-2, теперь красный прямоугольник располагается поверх черного, чего и следовало ожидать, поскольку значение свойства ZIndex красного прямоугольника больше, чем значение этого свойства для черного прямоугольника.
РИС. 4 2 Изменение порядка расположения элементов относительно оси Z.
Кисти XAML
Кисти в XAML используются для определения того, как отрисовываются и закрашиваются фигуры. В предыдущем примере представлено два прямоугольника, заливка которых выполнена с использованием известных цветов, Red (красный) и Black (черный), соотвественно. Это простые примеры применения кистей. В следующих разделах будут описаны более сложные типы кистей, поддерживаемые XAML.
SolidColorBrush
SolidColorBrush заполняет область сплошным цветом. Для задания цвета может использоваться именованное значение, например Red или Black, или шестнадцатеричные значения, обозначающие интенсивности альфа, красного, зеленого и синего каналов. Например, белый цвет в шестнадцатеричном представлении описывается как #FFFFFFFF, и красный - #FFFF0000.
LinearGradientBrush
LinearGradientBrush (Линейная градиентная кисть) заполняет область линейной градиентной заливкой, определенной в двумерном пространстве. Градиент по умолчанию описывается с использованием нормированного прямоугольника (прямоугольника, верхний левый угол которого имеет координаты (0,0), и нижний правый угол - координаты (1,1)). В этом случае градиент распространяется в направлении от верхнего левого угла к нижнему правому углу. Если для каждой из этих точек задать цвет, Silver- light отобразит плавный переход между ними.
В качестве примера рассмотрим следующее описание прямоугольника:
<Canvas>
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>
Этот фрагмент XAML-кода определяет LinearGradientBrush, распространяющуюся из верхнего левого угла в нижний правый угол прямоугольника. Первая точка градиента, в начале градиента, черная ((#FF000000), и вторая точка градиента, в конце градиента, белая ((#FFFFFFFF). Прорисовку этого прямоугольника можно увидеть на рис. 4-3.
РИС. 4 3 Использование LinearGradientBrush.
Изменение направления распространения градиента
Задавая свойства StartPoint (Начальная точка) и EndPoint (Конечная точка) LinearGradientBrush, можно изменять направление распространения градиента. Чтобы направить градиентную заливку из нижнего левого в верхний правый угол, этим свойствам необходимо задать значения (0,1) и (1,0), соответственно:
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
На рис. 4-4 показано, как этот прямоугольник будет выглядеть на экране.
РИС. 4 4 Изменение направления градиентной заливки.
Добавление точек градиента
В предыдущем примере показано минимально возможное количество точек градиента, которое равно двум. Для управления градиентом можно задавать дополнительные точки градиента и цвета для них. Например, если требуется получить градиентную заливку с изменением цвета от черного к белому и назад к черному, можно определить три точки следующим образом:
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="0.5"/>
<GradientStop Color="#FF000000" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
Первая точка, в позиции 0, черная; вторая, на полпути вдоль линии градиента (в позиции 0,5), белая; и третья точка, в конце градиента в позиции 1, снова черная. Если сформировать визуальное представление этого, можно будет увидеть примерно такой прямоугольник, как представлен на рис. 4-5.
РИС. 4 5 Использование точек градиента.
Позиционирование точек градиента выполняется с помощью параметра Offset (Смещение), поэтому чтобы передвинуть белую секцию данного градиента ближе к верхнему левому углу, необходимо просто изменить значение его свойства Offset так, чтобы оно было ближе к нулю, как показано в данном фрагменте XAML:
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="0.1"/>
<GradientStop Color="#FF000000" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
То, как это меняет вид прямоугольника, можно увидеть на рис. 4-6.
Экспериментируя с позиционированием и направлениями градиента, можно добиться некоторых интересных эффектов. Эти свойства могут использоваться для заполнения фигур или определения контуров, как будет показано далее в данной главе.
РИС. 4 6 Позиционирование точки градиента.
RadialGradientBrush
RadialGradientBrush (Радиальная градиентная кисть) аналогична LinearGradientBrush с точки зрения определения, но она задает круговой градиент, где точка 0 обозначает центр круга, и 1 обозначает внешний край. Проще показать это на примере, рассмотрев такой XAML:
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
Этот код обеспечивает заполнение фигуры градиентной заливкой, начиная от черного цвета в центре и заканчивая белым по краям, как показано на рис. 4-7. Обратите внимание, что вы видите эллипс, так как внешний край прямоугольника белый, и фоновый цвет прямоугольника аналогичен цвету внешней точки градиента.
РИС. 4 7 Заполнение прямоугольника с помощью RadialGradientBrush.
Точки градиента для RadialGradientBrush определяются теми же методами, что и для LinearGradientBrush.
Задание фокуса
При выполнении заливки с использованием RadialGradientBrush, установив свойство GradientOrigin (Центр градиента), можно задавать фокус заливки. Это свойство используется для задания точки начала градиента, которая обычно располагается в центре круга. Несмотря на радиальную природу RadialGradientBrush, фокус задается в прямоугольном нормированном пространстве. Поэтому, если необходимо расположить фокус в верхнем левом углу, задайте GradientOrigin значение (0,0); если желаете расположить его в нижнем правом углу, задайте GradientOrigin значение (1,1). Следующий пример показывает градиентную заливку, фокусная точка которой располагается в нижнем правом углу объекта с координатами (0.7,0.7):
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="0.7, 0.7">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
На рис. 4-8 представлено, как это выглядит.
РИС. 4 8 Задние фокуса RadialGradientBrush.
Изменение SpreadMethod
С помощью свойства SpreadMethod (Метод распространения) можно определять характер повторения градиента. Существует три возможных значения SpreadMethod: Pad (Заполнение), Reflect (Отражение) и Repeat (Повтор). Pad заполняет круг градиентной заливкой соответственно заданным параметрам и является значением по умолчанию. На рис. 4-7 и 4-8 показана прорисовка базовой RadialGradientBrush, для которой задан метод распространения Pad.
Ниже представлен XAML, описывающий прямоугольник, заполненный градиентной заливкой, для свойства SpreadMethod которой задано значение Reflect. Результаты можно увидеть на рис. 4-9.
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<RadialGradientBrush SpreadMethod="Reflect">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
Это приводит к отражению градиента, как видно на рис. 4-9. Для данного градиента определено, что он должен изменяться от черного к белому, но он возвращается опять к черному, как будто отражается. Аналогично, можно использовать метод Repeat для повторения градиента от черного к белому. На рис. 4-10 показан результат этого. Шаблон градиента повторяется с того места, где при обычных условиях он был бы завершен, повторяя переход от черного к белому вплоть до внешних краев прямоугольника.
РИС. 4 9 Использование SpreadMethod со значением Reflect.
РИС. 4 10 Использование SpreadMethod со значением Repeat.
Задание радиуса RadialGradientBrush
Для задания необходимого радиуса градиентной заливки используются свойства RadiusX и RadiusY. Значение по умолчанию для этих свойств - 0,5. Если задать меньшее значение, будет закрашено больше одного круга с учетом поведения прорисовки, которое определяется методом SpreadMethod. Если задать значение, больше 0,5, градиент будет «растянут».
Например, следующий фрагмент XAML-кода определяет RadialGradientBrush, для свойств RadiusX иRadiusY которой задано значение 0,1, и свойство SpreadMethod не задано (т.е. по умолчанию оно принимает значение Pad).
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<RadialGradientBrush RadiusX="0.1" RadiusY="0.1">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
Этот код обеспечит формирование визуального представления прямоугольника, заливка которого выполняется с помощью RadialGradientBrush с радиусом 0,1, поэтому она в пять раз меньше объектов, которые были представлены ранее. Это можно увидеть на рис. 4-11.
РИС. 4 11 Задание радиуса RadialGradientBrush.
В сочетании с методом SpreadMethod можно получить некоторые интересные эффекты. Пример задания значения Reflect для SpreadMethod представлен на рис. 4-12.
РИС. 4 12 Изменение значений радиуса в сочетании с изменением значений SpreadMethod.
Использование ImageBrush
Для заполнения области изображением используется ImageBrush (Кисть-изображение). Согласно поведению, по умолчанию кисть меняет размер соответственно размеру изображения, обеспечивая сохранение его пропорций. Следующий XAML-код обеспечивает заполнение содержимого прямоугольника ImageBrush (Результаты представлены на рис. 4-13):
<Rectangle Width="200" Height="128" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<ImageBrush ImageSource="smily.jpg" />
</Rectangle.Fill>
</Rectangle>
Растягивание изображения
С помощью свойства Stretch (Растяжение) можно определить то, как изображение заполняет закрашиваемую область. Это можно задать с помощью ряда различных режимов растяжения: None (Нет), Uniform (Равномерное), UniformToFill (Равномерное заполнение) и Fill (Заполнение).
Режим None формирует визуальное представление изображения без изменений, в данном случае растяжение не применяется. Значение Uniform обусловливает изменение размеров изображения так, чтобы оно заполняло прямоугольник, но при этом не меняет его пропорции. UniformToFill изменяет размер изображения так, чтобы оно максимально заполняло область вывода, но при этом не меняет его пропорции (обрезая изображение в случае необходимости). Значение Fill обеспечит заполнение изображением всей области вывода с использование независимого масштабирования по осям х и у. Таким образом, изображение будет искажено, но полностью заполнит доступную область.
Все эти варианты в действии можно увидеть на рис. 4-14, на котором представлено четыре прямоугольника, заливка которых выполнена одним и тем же изображением, но с разными режимами растяжения.
РИС. 4 13 Заливка прямоугольника с помощью ImageBrush.
РИС. 4 14 Использование разных режимов свойства Stretch в ImageBrush.
Выравнивание изображения
Выравнивание изображения по осям х и у определяется с помощью свойств AlignmentX и AlignmentY.
Изображение может быть выровнено вдоль оси х по левому краю, по правому краю, по центру и вдоль оси у по верху, центру или низу. Обратите внимание, что если изображение растягивается для
заполнения области, задание выравнивания не будет иметь никакого эффекта; оно имеет смысл, только когда свойству Stretch задано значение None. Далее представлен пример выравнивания изображения по правому краю и низу:
<Rectangle Stroke="Black" Width="200" Height="128" x:Name="r1">
<Rectangle.Fill>
<ImageBrush ImageSource="smily.jpg" Stretch="None" AlignmentX="Right" AlignmentY="Bottom" />
</Rectangle.Fill>
</Rectangle>
Как это выглядит, можно увидеть на рис. 4-15.
РИС. 4 15 Использование image alignment.
VideoBrush
VideoBrush (Видео-кисть) позволяет заполнять область видео-потоком. Более подробно эта кисть будет обсуждаться в Главе 11, «Мультимедиа, рукописный ввод и Deep Zoom», в которой также более полно будет описан элемент управления MediaElement.
Визуальные свойства XAML
Кроме кистей и параметров Canvas, XAML предоставляет множество других свойств для управления представлением объекта. Они позволяют задавать размеры, прозрачность объекта, поведение курсора и обводку.
Использование свойств XAML для задания размеров и местоположения
Размеры в XAML задаются с помощью свойств Height и Width, которые принимают значения типа double. Чтобы создать прямоугольник шириной 100 пикселов и высотой 200 пикселов, например, необходимо было бы написать следующий XAML-код:
<Rectangle Fill="Black" Width="100" Height="200" />
Кроме того, помните, что относительное местоположение объекта задается через точку с помощью свойств Top и Left в родительском элементе.
Рассмотрим следующий XAML:
<Canvas>
<Canvas Canvas.Top="40" Canvas.Left="40">
<Rectangle Canvas.Top="40" Fill="Black" Width="100" Height="200" />
</Canvas>
</Canvas>
Предположим, что самый внешний элемент Canvas является корневым холстом страницы. В результате, Rectangle будет отрисован на расстоянии 80 пикселов от верха страницы, потому что его родительский холст опущен на 40 пикселов вниз, и Rectangle расположен на 40 пикселов вниз от верхнего края своего родителя, что в сумме дает 80 пикселов.
Использование прозрачности
Прозрачность объекта может быть задана двумя способами. Первый - с помощью альфа-канала кисти, которая используется для заливки объекта. Следующий XAML-код обеспечит создание черного прямоугольника поверх рисунка:
<Image Source="smily.jpg" />
<Rectangle Fill="#FF000000" Width="100" Height="200" />
В качестве значения свойства Fill задается черный цвет (потому что красному, зеленому и синему каналам задан 0), и альфа-канал задан непрозрачным (значение #FF). Меняя значение канала альфа, можно сделать прямоугольник полупрозрачным,:
<Image Source="smily.jpg" />
<Rectangle Fill="#77000000" Width="100" Height="200" />
Теперь прямоугольник будет выглядеть серым, и сквозь него будет видно изображение.
Второй метод - использовать свойство Opacity (Непрозрачность), которое принимает значения в диапазоне от 0 (полностью прозрачный) до 1 (полностью непрозрачный). Это свойство применяется в сочетании с определением альфа-канала кисти. Если для заливки фигуры использовать кисть цвета #77000000, например, и затем задать свойству Opacity значение 1, прямоугольник все равно будет непрозрачным. Если задать свойству Opacity значение 0, прямоугольник будет совершенно прозрачным.
Свойство Opacity удобно использовать для анимации прозрачности объекта. Оно позволяет без труда реализовать эффект постепенного исчезновения и появления объекта через DoubleAnimation. Более подробно анимация рассматривается в Главе 5, «Трансформация и анимация XAML».
Поведение курсора
Большинство элементов XAML позволяют использовать свойство Cursor (Курсор) для задания вида курсора при его прохождении по элементу. Это свойства принимает значения перечисления MouseCursor (Курсор мыши):
Arrow (Стрелка) Отображается обычный стандартный курсор-стрелка
Default (Стандартный) Нет предпочтительного курсора; используется курсор родительского элемента, если таковой задан
Hand (Рука) Отображается курсор-рука, обычно используемый для ссылок
IBeam (I-образный) Определяет I-образный курсор; обычно используется для выбора текста
None (Нет) Курсор отсутствует
Wait (Ожидание) Задает значок, который обозначает состояние ожидания
Управление свойством Stroke
Свойство Stroke определяет, как контур фигуры отрисовывается на экране. Обводка фигуры отличается от ее заливки.
Stroke задается с помощью кисти. Далее представлен пример XAML-кода, в котором прорисовка прямоугольника формируется черным контуром, заданным с помощью простой обводки:
<Rectangle Stroke="Black" Canvas.Left="40" Canvas.Top="40" Width="100" Height="200">
По сути, свойство Stroke, в данном случае, использует SolidColorBrush черного цвета (Black). Синтаксически это эквивалентно следующему XAML:
<Rectangle Canvas.Left="40" Canvas.Top="40" Width="100" Height="200">
<Rectangle.Stroke>
<SolidColorBrush Color="Black" />
</Rectangle.Stroke>
</Rectangle>
Используя такой синтаксис (определение кисти в качестве присоединенного свойства Stroke), можно задавать разные типы кистей для отрисовки обводки фигуры. Далее приведен пример применения LinearGradientBrush для обводки прямоугольника:
<Rectangle StrokeThickness="10" Canvas.Left="40"
Canvas.Top="40" Width="100" Height="200">
<Rectangle.Stroke>
<LinearGradientBrush >
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="0.5"/>
<GradientStop Color="#FF000000" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Stroke>
</Rectangle>
Как это выглядит на экране можно увидеть на рис. 4-16.
РИС. 4 16 Использование LinearGradientBrush для определения обводки фигуры.
Задание ширины обводки
Возможно, вы заметили, что в этом примере была задана ширина обводки 10. Это сделано для демонстрации градиентного изменения цвета, поскольку при использовании значения толщины по умолчанию, 1, его просто не было бы видно.
Ширина обводки задается свойством StrokeThickness (Толщина обводки). Оно определяет ширину обводки в пикселах:
<Rectangle StrokeThickness="10" Stroke="Black" Canvas.Left="40" Canvas.Top="40" Width="100" Height="200" />
Задание обводки пунктиром
Свойство StrokeDashArray (Массив длин элементов обводки пунктиром) используется для задания шаблона обводки пунктиром. В сочетании со свойствами StrokeDashCap (Наконечники элементов обводки пунктиром) и StrokeDashOffset (Смещение обводки пунктиром) оно обеспечивает детальное описание обводки пунктиром.
Чтобы обводка прямоугольника была выполнена пунктиром по определенному повторяющемуся шаблону, задается массив значений типа double, которые представляют длины чередующихся штрихов и пробелов. Чтобы определить шаблон пунктира с длиной штриха 4 единицы, за которым следует пробел длиной 1 единица, штрих длиной 2 единицы и пробел длиной 1 единица, свойству StrokeDashArray было бы задано значение (4,1,2,1). Вот пример:
<Rectangle StrokeThickness="10" Stroke="Black" Canvas.Left="40" Canvas.Top="40" Width="100" Height="200" StrokeDashArray="4,1,2,1"/>
На рис. 4-17 показано, как это выглядело бы на экране.
РИС. 4 17 Задание шаблона обводки пунктиром с помощью свойства StrokeDashArray.
Как видим, штрихи обводки имеют прямоугольную форму с нескошенными кромками. Изменить это представление можно с помощью свойства StrokeDashCap. В качестве его значений используется значения перечисления PenLineCap (Наконечники линий):
Flat (Плоский) Это значение по умолчанию; оно определяет, что наконечник не выходит за край линии - аналогично отсутствию наконечника.
Round (Круглый) Задает полукруг, диаметр которого равен толщине линии.
Square (Квадратный) Определяет квадратный наконечник.
Triangle (Треугольный) Определяет равнобедренный треугольный наконечник, базовая длина которого равна толщине обводки.
Далее представлен пример использования StrokeDashCap для задания скругленных штрихов обводки пунктиром:
<Rectangle StrokeThickness="10" Stroke="Black" Canvas.Left="40" Canvas.Top="40" Width="100" Height="200" StrokeDashArray="4,1,2,1" StrokeDashCap="Round"/>
На рис. 4-18 показано, как это будет выглядеть на экране.
РИС. 4 18 Использование свойства StrokeDashCap.
Определение типа соединения линий
Если взглянуть не предыдущие примеры, можно заметить, что штрихи пунктира пересекаются в углах и отрисовываются спрямленными. Это считается соединением линий. С помощью свойства StrokeLineJoin (Соединение линий обводки) можно определять поведение пера при соединении линий. Это свойство принимает перечисление PenLineJoin, которое может содержать одно из следующих трех значений:
Bevel (Скос) Срезает края соединения
Miter (Прямойугол) Сохраняет острые края
Round (Скругление) Скругляет края соединения
Данный XAML-код создает прямоугольник, для которого задан тип соединения линий Bevel:
<Rectangle StrokeThickness="10" Stroke="Black" Canvas.Left="40" Canvas.Top="40" Width="100" Height="200" StrokeLineJoin="Bevel" />
Как это отображается, можно увидеть на рис. 4-19.
РИС. 4 19 Использование StrokeLineJoin для задания срезанных углов.
Фигуры в XAML
XAML поддерживает ряд базовых фигур, которые могут использоваться для создания более сложных объектов. К ним относятся:
Ellipse (Эллипс) Отрисовывает эллипс; круг - это эллипс с равными радиусами по осям X и Y
Rectangle (Прямоугольник) Отрисовывает прямоугольник; квадрат - это прямоугольник с равными размерами по осям X иY
Line (Линия) Отрисовывает прямую линию
Path (Контур) Отрисовывает последовательность соединенных прямых и кривых линий соответственно языку описания контуров
Polygon (Многоугольник) Отрисовывает замкнутую фигуру, образованную рядом соединенных линий
Polyline (Ломаная) Отрисовывает ряд последовательно соединенных прямых
В следующих разделах мы рассмотрим каждую из этих фигур.
Использование объекта Ellipse
Фигура Ellipse используется для отрисовки эллипса или круга. Высота Ellipse определяется вертикальным диаметром (т.е. двойным радиусом по вертикали), его ширина определяется горизонтальным диаметром. Если эти значения равны, XAML сформирует круг. Контур Ellipse отрисовывается с помощью свойства Stroke и закрашивается с помощью Brush.
Использование объекта Rectangle
Rectangle используется для отрисовки прямоугольника или квадрата. Размеры данной фигуры задаются свойствами Width и Height. Если значения этих свойств равны, получаем квадрат. Как и для Ellipse, контур Rectangle отрисовывается с помощью свойства Stroke, для заливки используется Brush.
Используя свойства RadiusX и RadiusY, можно скруглить углы Rectangle. Задавая этим свойствам значения типа double, вы определяете необходимый радиус скругления. По умолчанию они равны 0.0, что указывает на отсутствие скругления. Поскольку свойства RadiusX и RadiusY задаются независимо друг от друга, применяя разные значения для них, можно получить эллиптические скругления.
Далее представлен пример прямоугольника со скругленными углами. Свойству RadiusY задано значение 40, и свойству RadiusX- значение 20. Это указывает на то, что углы будут более пологими в вертикальном направлении:
<Rectangle Fill="Black" Canvas.Left="40" Canvas.Top="40"
Width="100" Height="200" RadiusX="20" RadiusY="40" />
Результаты задания таких значений в действии можно увидеть на рис. 4-20.
РИС. 4 20 Скругление углов прямоугольника.
Использование объекта Line
С помощью объекта Line можно создать простую линию в XAML. Для этого задаются координаты (X1,Y1) и (X2,Y2), и линия отрисовывается между этими точками. Данные координаты задаются относительно верхнеголевого угла области, который определяется свойствами Canvas.Top и Canvas.Left, как обычно. Обратите внимание, что чтобы линия была отрисована, обязательно должна быть определена обводка, хотя бы ее цвет.
Рассмотрим следующий XAML:
<Line X1="40" Y1="40" X2="100" Y2="100" Stroke="Black" />
Это обеспечит отрисовку линии, соединяющей точку (40,40) с точкой (100,100). Однако если добавить свойства Canvas.Top и/или Canvas.Left, линия будет отрисовыватьсясо смещением. Если предположить, что родительский холст не позиционирован, следующий XAML обеспечит создание линии, соединяющей точки (40,140) и (100,200). Если позиционирование присутствует, Silverlight отрисует линию, относительно позиции родительского элемента.
<Line Canvas.Top="100" X1="40" Y1="40" X2="100" Y2="100" Stroke="Black" />
Использование контуров и геометрических элементов
Объект Path отрисовывает последовательность соединенных прямых и кривых линий. Эти прямые и кривые определяются типом геометрического элемента. Здесь будут рассмотрены различные типы геометрических элементов.
EllipseGeometry (Геометрический элемент эллипс) определяет контур как простой эллипс. Например:
<Path Stroke="Black">
<Path.Data>
<EllipseGeometry RadiusX="100" RadiusY="100" />
</Path.Data>
</Path>
Размеры эллипса, образующего контур, задаются в EllipseGeometry с помощью свойств RadiusX и Radiu- sY. Также с помощью атрибута Center (Центр) можно задать центр эллипса. Например:
<Path Stroke="Black">
<Path.Data>
<EllipseGeometry RadiusX="100" RadiusY="100" Center="50,50" />
</Path.Data>
</Path>
LineGeometry (Геометрический элемент прямая) определяет контур как одну линию, начинающуюся в StartPoint, и заканчивающуюся в EndPoint. Эти точки задаются с помощью простых координат х и у, таким образом, верхний левый угол задается как (0,0). Вот пример LineGeometry:
<Path Stroke="Black">
<Path.Data>
<LineGeometry StartPoint="10,10" EndPoint="100,100" />
</Path.Data>
</Path>
RectangleGeometry определяет контур как отдельный прямоугольник. Размеры прямоугольника задаются свойством Rect. Это строка из четырех значений, соответствующих отступу сверху, отступу слева, высоте и ширине прямоугольника. Итак, чтобы отрисовать прямоугольник 100 на 200 пикселов, верхний левый угол которого располагается в точке (0,0), использовался бы следующий Path:
<Path Stroke="Black">
<Path.Data>
<RectangleGeometry Rect="0,0,100,200" />
</Path.Data>
</Path>
Объект PathGeometry (Геометрический элемент контур) используется для задания сложного контура, состоящего из разных сегментов, включая дуги, кривые Безье, прямые линии, кривые Безье высших степеней, поликвадратические кривые Безье и квадратические кривые Безье. Сегменты образуют PathFigure (Форма контура), и один или более объектов PathFigure образуют PathGeometry. PathGeometry также задает начальную точку контура. Если имеется множество сегментов, начальной точкой каждого последующего сегмента будет конечная точка предыдущего сегмента.
Объект ArcSegment
Объект ArcSegment (Сегмент дуга) отрисовывает простую эллиптическую дугу между двумя точками. Дуга описывается рядом разнообразных свойств:
Point (Точка) Задает начальную точку дуги
Size (Размер) Задает радиус дуги по осям x и у
RotationAngle (Угол поворота) Задает угол поворота, т.е. то, насколько сильно дуга закручена вокруг осих
IsLargeArc (Является ли дуга крупной) Определяет, является ли дуга крупной, где крупной считается дуга более 180°
SweepDirection (Направление развертывания) Задает направление отрисовки дуги (Clockwise (По часовой стрелке) или CounterClockwise (Против часовой стрелки))
Вот пример Path с одним дуговым сегментом, в котором демонстрируются данные свойства:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure>
<ArcSegment Point="100,100" Size="200,200"
RotationAngle="10" IsLargeArc="False" SweepDirection="ClockWise" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Объект LineSegment
Добавить прямую линию в PathSegment (Сегмент контура) можно с помощью объекта LineSegment (Сегмент линия). Он просто отрисовывает прямую линию от текущей или начальной точки до точки,
заданной свойством Point. Итак, чтобы отрисовать прямую из точки (100,100) до точки (200,200) и затем еще одну до точки (200,0), создается PathFigure, содержащий несколько линейных сегментов:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="200,200" />
<LineSegment Point="200,0" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Объект PolyLineSegment
Как следует из его имени, с помощью объекта PolyLineSegment (Сегмент ломаная) можно отрисовать ряд прямых, просто задав точки. Первая линия отрисовывается между начальной точкой и первой заданной точкой, вторая - между этой точкой и второй заданной точкой, и т.д.
Далее приведен XAML-код, демонстрирующий PolyLineSegment:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PolyLineSegment
Points="50,50,150,150,250,250,
100,200,200,100,300,300" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Объект BezierSegment
Этот объект позволяет описывать кривую Безье, которая является кривой между двумя точками, определяемой одной или двумя опорными точками. Объект BezierSegment (Сегмент кривая Безье) принимает в качестве параметров три точки, называемые Pointl, Point2 и Point3. В зависимости от того, сколько точек используется, вы получаете разное поведение. Итак, например, если заданы Pointl и Point2, кривая будет сформирована от начальной точки в точку Point2 с использованием Pointl в качестве опорной точки. Если заданы Pointl, Point2 и Point3, кривая формируется от начальной точки в точку Point3, Pointl и Point2 используются как опорные.
Вот пример PathFigure, содержащего BezierSegment:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<BezierSegment Point1="140,120" Point2="100,140" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Объект PolyBezierSegment
Этот объект позволяет задавать группу точек, которые Silverlight интерпретирует в набор опорных точек для группы кривых Безье. Рассмотрим следующий XAML:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PolyBezierSegment>
<PolyBezierSegment.Points>
<Point X="50" Y="50" />
<Point X="150" Y="150" />
<Point X="250" Y="250" />
<Point X="100" Y="200" />
<Point X="200" Y="100" />
<Point X="300" Y="300" />
</PolyBezierSegment.Points>
</PolyBezierSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Как альтернативный вариант, можно задать ряд точек с помощью коллекции точек, хранящейся в виде строки значений, разделенных запятыми:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PolyBezierSegment Points="50,50,150,150,250,250, 100,200,200,100,300,300" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Визуальное представление этого XAML-фрагмента показано на рис. 4-21. В данном случае, начальная точка определена координатами (100,100), это верхняя левая точка всей кривой. Первая кривая Безье заканчивается в точке (250,250), используя точки (50,50) и (150,150) в качестве опорных. Поскольку эти точки эффективно отменяют действие друг друга (они равноудалены от линии, соединяющей точки [100,100] и [250,250]), первая кривая Безье является прямой линией, оканчивающейся в точке (250,250). Вторая кривая Безье начинается в этой точке и заканчивается в точке (300,300) с опорными точками (100,200) и (200,100), благодаря чему она принимает вид петли.
РИС. 4 21 Использование PolyBezierSegment.
Объект QuadraticBezierSegment
Квадратическая кривая Безье - это просто кривая Безье, построенная как обычная квадратическая кривая с использованием единственной опорной точки. QuadraticBezierSegment (Сегмент квадратическая кривая Безье) принимает два объекта Point. Если используется только один объект, он становится конечной точкой кривой. В этом случае контрольной точки нет, и кривая принимает форму прямой линии, соединяющей начальную и заданную конечную точки. Если задается две точки, вторая точка
принимается за конечную точку кривой, а первая точка становится квадратической опортной точкой. Вот пример:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<QuadraticBezierSegment Point1="200,0" Point2="300,100" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Кривая, формируемая данным XAML, представлена на рис. 4-22.
РИС. 4 22 Простая квадратическая кривая Безье.
Объект PolyQuadraticBezierSegment
Как следует из его имени, PolyQuadraticBezierSegment (Сегмент поликвадратическая кривая Безье) является коллекцией соединенных квадратических кривых Безье, определенных и построенных соответственно списку опорных точек аналогично тому, как это описывалось ранее для объекта PolyBezierSegment. Далее представлен пример PolyQuadraticBezierSegment в действии:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PolyQuadraticBezierSegment Points="50,50,150,150,250,250,
100,200,200,100,300,300" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Визуальное представление данного XAML-фрагмента показано на рис. 4-23.
РИС. 4 23 Объект в действии PolyQuadraticBezier.
Данный код обеспечивает построение ряда квадратических кривых Безье. Первая строится между начальной точкой, (100,100), и точкой (150,150) с использованием точки (50,50) в качестве опорной, что в результате дает прямую линию, оканчивающуюся в точке (150,150). Вторая кривая начинается в точке (150,150) и заканчивается в точке (100,200) с опорной точкой (250,250). Это сегмент, в котором кривая разворачивается влево. Третья кривая начинается в точке (100,200) и заканчивается в точке (300,300) с опорной точкой (200,100). На рис. 4-23 это длинная сглаженная кривая, идущая слева направо.
Составные сегменты контура
Каждый из рассмотренных типов сегментов может входить в состав сегмента PathFigure. Кроме того, сегменты PathFigure могут собираться в коллекции в рамках PathGeometry для создания сложного набора сегментов.
Далее приведен пример PathGeometry, в состав которого входят два объекта PathFigure. Первый объект содержит LineSegment, PolyQuadraticBezierSegment и еще один LineSegment. Второй объект включает только один LineSegment.
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="200,200" />
<PolyQuadraticBezierSegment Points="50,50,150,150,250,250,
100,200,200,100,300,300" />
<LineSegment Point="0,0" />
</PathFigure>
<PathFigure>
<LineSegment Point="10,400" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Использование объекта GeometryGroup
В предыдущих разделах были представлены всевозможные геометрические элементы, начиная от самых простых, таких как EllipseGeometry, LineGeometry и RectangleGeometry, до сложных, образованных множеством объектов PathSegment в рамках PathGeometry. Объект GeometryGroup (Группа геометрических элементов) позволяет комбинировать все эти объекты.
Вы просто описываете геометрические элементы, которые хотите включить как коллекцию в этот объект. Далее представлен объект GeometryGroup, содержащий EllipseGeometry, RectangleGeometry, и затем тот же сложный PathGeometry, который использовался в предыдущем разделе:
<Path Stroke="Black">
<Path.Data>
<GeometryGroup>
<EllipseGeometry RadiusX="100" RadiusY="100" Center="50,50" />
<RectangleGeometry Rect="200,200,100,100" />
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="200,200" />
<PolyQuadraticBezierSegment Points="50,50,150,150,250,250,
100,200,200,100,300,300" />
<LineSegment Point="0,0" />
</PathFigure>
<PathFigure>
<LineSegment Point="10,400" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
Рис. 4-24 представляет, как это будет выглядеть.
РИС. 4 24 Использование объекта GeometryGroup для группировки множества геометрических элементов.
Язык описания контуров
Объект Path имеет свойство Data (Данные), в котором может использоваться язык описания контуров для определения сложных контуров. В этом языке используется следующий синтаксис: буква команды, за ней через пробел следует список разделенных запятыми чисел, за которым через пробел идет следующая буква команды. Вот пример:
<Path Stroke="Black" Data="M 100,100 L 200,200" />
В этом экземпляре контур отрисовывается с помощью команды M, обозначающей Move (Перейти), для перехода в точку (100,100) и команды L, обозначающей Line, для построения прямой линии до точки (200,200). Эти команды могут быть заданы либо прописными буквами (например, M), что свидетельствует о применении абсолютных координат, или строчными буквами (например, m), что определяет относительные координаты. Команда M помещает перо в заданную точку без отрисов-
ки линии между точкой, в которой он находится в настоящий момент, и заданной точкой; т.е. перо перемещается в начальную точку. Затем будет проведена линия из точки (100,100) в точку (200,200), при условии отсутствия позиционирования родительского холста. Если родительский холст позиционирован, Silverlight отрисует линию относительно его положения.
Команда L (означающая Line) обеспечивает построение прямой линии от текущей точки в заданную.
Команда H принимает в качестве параметра только одно число и отрисовывает горизонтальную прямую между текущей точкой и заданным значением по оси х.
Команда V принимает в качестве параметра только одно число и отрисовывает вертикальную прямую между текущей точкой и заданным значением по оси у.
Команда C принимает в качестве параметров три точки. Она обеспечивает построение кубической кривой Безье между текущей точкой и третьей из заданных точек. Две первые точки используются как опорные.
Команда Q принимает в качестве параметров две точки и отрисовывает квадратическую кривую Безье между текущей точкой и второй из заданных точек. Первая заданная точка используется как опорная.
Команда S принимает в качестве параметров две точки и отрисовывает сглаженную кубическую кривую Безье между текущей точкой и второй из заданных точек. Для формирования сглаженной кривой используется две опорные точки: текущая точка и первый из двух параметров.
Команда T действует аналогично команде S, за исключением того что она обеспечивает построение сглаженной квадратической кривой Безье.
Команда A принимает пять параметров: размер, угол поворота, isLargeArc, sweepDirection и конечную точку. Эти параметры используются для построения эллиптической дуги.
Команда Z завершает текущий контур, проводя прямую линию между текущей точкой и начальной точкой контура и образуя замкнутую фигуру,.
Вырезание и геометрические элементы в XAML
Элементы XAML могут быть вырезаны по правилу, определяемому типом геометрической формы. Как было показано в предыдущем разделе, эти типы могут быть простыми (EllipseGeometry, LineGeometry или RectangleGeometry), сложными (использующими геометрическую форму, определенную объектом PathGeometry) или группой из этих объектов в составе GeometryCollection.
Чтобы определить метод вырезания объекта, его присоединенному свойству Clip просто задается тип геометрической формы. Следующий пример представляет изображение, вырезанное EllipseGeometry:
<Image Source="smily.jpg" Width="300" Height="300">
<Image.Clip>
<EllipseGeometry Center="150,150" RadiusX="100" RadiusY="100" />
</Image.Clip>
</Image>
Увидеть, как это выглядит, можно на рис. 4-25.
РИС. 4 25 Вырезание объекта геометрической формой.
Элементы управления XAML в Silverlight
Разработчикам на Silverlight доступен ряд элементов управления XAML. К ним относятся:
Canvas
Image
Glyphs
TextBlock
MediaElement
Ко всем этим элементам могут применяться все свойства и операции, обсуждаемые в данной главе выше, такие как вырезание, кисти, компоновка и пр. Первые четыре элемента будут рассмотрены в следующих подразделах. Элемент управления MediaElement подробно рассматривается в Главе 11.
Элемент Canvas
Этот элемент определяет область страницы, в которую могут быть помещены дочерние элементы. Он может использоваться для визуальной группировки элементов, при этом их компоновка и позиционирование выполняются относительно него. Кроме того, объект Canvas может использоваться исключительно как контейнер для других объектов, обеспечивая возможность рассматривать их как единый объект при размещении и обработке событий.
Вот пример организации прямоугольников в группы с использованием элементов Canvas:
<Canvas Width="144" Height="128" Canvas.Left="24" Canvas.Top="8">
<Rectangle Fill="#FF000000" Stroke="#FF000000"
Width="144" Height="64" Canvas.Top="24"/>
<Rectangle Fill="#FF000000" Stroke="#FF000000"
Width="56" Height="128" Canvas.Left="40"/>
</Canvas>
<Canvas Width="152" Height="144" Canvas.Left="24" Canvas.Top="184">
<Rectangle Fill="#FFFF0000" Stroke="#FF000000"
Width="152" Height="72" Canvas.Top="32"/>
<Rectangle Fill="#FFFF0000" Stroke="#FF000000"
Width="64" Height="144" Canvas.Left="48"/>
</Canvas>
Элемент Image
Элемент управления Image используется для определения графического объекта. Он задается Универсальным идентификатором ресурса (URI) изображения, которое может быть растровым в формате jpg или .png.
Далее представлен пример, в котором компоновка изображения задана свойствами Height, Width, Canvas.Left и Canvas.Top и в качестве Source (Источник) изображения задан "smily.jpg":
<Image Width="184" Height="128" Canvas.Left="56" Canvas.Top="32" Source="smily.jpg"/>
Элемент Glyphs
Элемент Glyphs используется для отображения текста с заданным шрифтом. Также он может применяться для представления символов, не связанных с конкретными клавишами, каковыми являются многие графические символы, используемые в шрифтах, включая текст Wingdings или Unicode.
При использовании Glyphs необходимо соблюдать правило: чтобы шрифт мог отображаться, он должен быть установлен на данном компьютере. Таким образом, с Glyphs можно использовать только те шрифты, правами на распространение которых вы обладаете.
Шрифт для элемента Glyphs задается с помощью свойства FontUri (Uri шрифта). Затем свойствами Indices (Индексы) или UnicodeString (Строка Unicode) задаются символы, прорисовку которых нужно создать. В свойстве Indices для описания символов используются их смещения в описании шрифта. Смещения задаются в виде элементов списка, разделенных точками с запятой.
Кроме того, необходимо задать размер шрифта. Для этого используется свойство FontRenderingEmSize (Размер буквы M формируемого шрифта). По желанию можно задать свойство StyleSimulations (Имитация стилей) для имитации стилей шрифтов. Это свойство принимает значения BoldSimulation (Имитация жирного шрифта), ItalicSimulation (Имитация курсива) или BoldItalicSimulation (Имитация жирного курсива), а также значение по умолчанию, None.
Далее приводится пример элемента Glyphs. В нем для отрисовки некоторых символов используется шрифт Webdings и смещения символов.
Примечание Для выполнения данного приложения необходимо, чтобы файл шрифта webdings.ttf располагался на вашем сервере в одном каталоге с приложением Silverlight. Если этот шрифт недоступен, просто замените его другим, имеющимся в наличии, который может формировать прорисовку заданных символов. Важно помнить, что при использовании этой техники в рабочей среде, необходимо иметь разрешение на распространение используемых шрифтов.
<Glyphs Canvas.Top="0" FontUri="webdings.ttf" Indices="133;134;135"
Fill="Black" FontRenderingEmSize="48"/>
Как это будет представлено в Silverlight, показано на рис. 4-26.
РИС. 4 26 Использование объекта Glyphs.
Элемент TextBlock
Это облегченный объект, обеспечивающий отображение одной или множества строк текста, имеющий множество опций форматирования. Он существенно отличается от элемента Glyphs тем, что не требует задания шрифта. Таким образом, представление текста будет одинаковым независимо от используемой операционной системы или браузера.
С помощью свойства FontFamily (Семейство шрифтов) задается семейство шрифтов, которое должно использоваться для формирования визуального представления текста. Silverlight 2, в отличие от Silverlight 1.0, поддерживает все шрифты, установленные в операционной системе, но следующие девять являются встроенными шрифтами:
Arial
Arial Black
Comic Sans MS
Courier New
Georgia
Lucida Grande/Lucida Sans Unicode
Times New Roman
Trebuchet MS
Verdana
Эти шрифты считаются «Веб-безопасными», т.е. в случае их применения результаты будут единообразными, независимо от браузера или операционной системы, используемой для отображения текста. Если вы используете шрифты, не входящие в этот набор и не встроенные в приложение, браузер проверит их наличие в системе, и если найдет их, будет их использовать. Если шрифт не будет найден, и он не встроен в приложение, по правилам замещения шрифтов из предлагаемых системных шрифтов будет выбран наиболее подходящий.
Свойство FontSize (Размер шрифта) используется для задания размер текста, который должен быть отображен, в пикселах. Свойство FontStyle (Стиль шрифта) используется для определения стиля отображаемого шрифта. Ему может быть задано значение Normal (Обычный) или Italic (Курсив).
Свойство FontWeight (Насыщенность шрифта) определяет насыщенность шрифта при его прорисовке. Возможными значениями данного свойства являются: Thin (Тонкий), ExtraLight (Очень светлый), Light (Светлый), Normal, Medium (Средний), SemiBold (Полужирный), Bold (Жирный), ExtraBold (Очень жирный), Black (Черный) или ExtraBlack (Очень черный).
Свойство TextDecorations (Декорирование шрифта) используется для определения того, будет ли текст в TextBlock отображаться с подчерком. Этому значению может быть задано значение Underline (Подчерк) или None.
Свойство TextWrapping (Перенос текста) используется для определения того, будет ли TextBlock выполнять перенос текста. Ему может быть задано значение NoWrap (Без переноса), таким образом, текст будет выведен в одну строку и обрезан по ширине TextBlock, или Wrap (С переносом), тогда текст будет переноситься на новую строку по достижении доступной ширины в горизонтальном направлении. Свойство переноса текста может влиять на размеры текстового поля за счет изменения ширины через ограничение текста и высоты через добавление дополнительных строк. В результате, стандартные свойства Width и Height могут возвращать несоответствующие значения. Поэтому TextBlock предлагает свойства ActualWidth (Фактическая ширина) и ActualHeight (Фактическая высота), которые возвращают реальные значения.
Участки и разрывы строк
Элемент Run (Участок) используется для изменения форматирования или стилевого оформления текста в TextBlock. Если в текстовом поле необходимо задать три разных стиля текста или шрифта, для TextBlock задается первый стиль, и в качестве значения его свойства Text задается необходимый текст. Затем добавляется участок со вторым стилем и текстом, и еще один участок с третьим стилем и текстом. Рассмотрим пример:
<TextBlock FontFamily="Arial" Width="400"
Text="ArialText">
<Run Foreground="Blue" FontFamily="Comic Sans MS" FontSize="24">Large Comic Sans</Run>
<Run Foreground="Teal" FontFamily="Verdana"
FontSize="12" FontStyle="Italic">Italic Verdana</Run> </TextBlock>
В TextBlock загружается текст «ArialTextLarge Comic SansItalic Verdana». Однако поскольку в Run задан текст «Large Comic Sans» с одним шрифтом и стилем, и в следующем Run задан текст «Italic Verdana» с третьими параметрами, на выводе будут представлены все заданные тексты в одну строку в разных форматах. Результаты можно увидеть на рис. 4-27.
РИС. 4 27 Использование переходов в TextBlock.
Разрывы в тексте TextBlock можно создать с помощью элемента LineBreak (Разрыв строки). Для создания разрыва строки этот элемент просто вставляется между элементами Run. Вот предыдущий пример с использованием разрыва строки:
<TextBlock FontFamily="Arial" Width="400"
Text="ArialText">
<Run Foreground="Blue" FontFamily="Comic Sans MS"
FontSize="24">Large Comic Sans</Run>
<LineBreak />
<Run Foreground="Teal" FontFamily="Verdana"
FontSize="12" FontStyle="Italic">Italic Verdana</Run>
</TextBlock>
Рис. 4-28 представляет, как это будет выглядеть на экране. Как видим, разрыв строки выполняется между словами «Sans» и «Italic».
РИС. 4 28 Использование LineBreak в TextBlock.
Заключение
В данной главе подробно рассмотрена настройка визуальных элементов с помощью XAML. Представлены компоновка, позиционирование, заливка, обводки, прозрачность, контуры, геометрические элементы и вырезание - все те возможности, которые позволяют управлять тем, что вы видите в своем пользовательском интерфейсе. Кроме того, вы познакомились с универсальными элементами управления, являющимися контейнерами для других элементов управления, и также используемыми для отображения текста.
Следующая глава будет посвящена использованию XAML для оживления пользовательского интерфейса через введение трансформаций и анимации!
Глава 5
Трансформация и анимация в XAML
В Главе 4, «Основы XAML», вы научились с помощью XAML формировать визуальное представление графических элементов на экране, будь то векторная графика, растровые изображения (с помощью объекта Image) или видео. В данной главе будет рассмотрено, как улучшить представление этих графических элементов с помощью различных типов трансформаций (для изменения их вида) и анимации (для изменения атрибутов объекта во времени). Кроме того, будет представлена анимация по ключевым кадрам и описано их использование при создании более сложного поведения. В завершение мы опять ненадолго вернемся к Expression Blend и покажем, как его можно использовать для создания анимации.
Трансформации
В графике трансформация определяет, как точки из одного координатного пространства отображаются в другом координатном пространстве. Обычно это описывается с помощью матрицы трансформации (transformation matrix), специальной математической структуры, которая обеспечивает простое математическое преобразование из одной системы в другую. Silverlight XAML позволяет абстрагировать это, и в данной книге мы не будем вдаваться в математические детали. Silverlight XAML поддерживает четыре вида трансформации элементов: вращение, масштабирование, наклон и трансляцию (перемещение), а также особый тип трансформации, который позволяет реализовывать собственную матрицу для сочетания трансформаций.
Трансформации реализуются через свойства трансформации. Существует несколько разных типов свойств трансформации, применяемых к разным типам объектов.
Так при использовании типа Brush трансформация определяется либо через свойство Brush.Transform (Трансформация кисти), если необходимо изменить содержимое кисти (например, если вы хотите повернуть изображение, прежде чем использовать его в ImageBrush), либо с помощью свойства Brush.RelativeTransform (Относительная трансформация кисти), которое позволяет трансформировать кисть, используя относительные значения (это пригодиться при закрашивании одной кистью разных областей разных размеров).
Простые трансформации для типа Geometry выполняются с помощью свойства Geometry.Transform. Этот тип не поддерживает относительные трансформации.
Наконец, при использовании элемента пользовательского интерфейса (UI) трансформация задается через свойство RenderTransform. Например, трансформация эллипса будет выполняться с помощью свойства Ellipse.RenderTransform.
В следующем разделе будут рассмотрены разные типы трансформаций и показано использование этих свойств для конкретных типов объектов.
Вращение с помощью RotateTransform
RotateTransform позволяет поворачивать элемент на заданный угол вокруг заданной центральной точки. Угол поворота задается свойством Angle (Угол) в градусах. Примем за начало отсчета (0 градусов) горизонтальный вектор, направленный вправо. Пусть вращение выполняется по часовой стрелке, тогда вертикальный вектор, указывающий вниз, является результатом поворота на 90 градусов.
Координаты центра трансформации задаются свойствами CenterX и CenterY. По умолчанию центр трансформации имеет координаты 0.0, таким образом, ось вращения по умолчанию находится в верхнем левом углу контейнера.
Рассмотрим пример XAML-кода, в котором выполняется вращение TextBlock с помощью RenderTransform, содержащего RotateTransform, который определяет поворот на 45 градусов:
<TextBlock Width="320" Height="40"
Text="This is the text to rotate" TextWrapping="Wrap">
<TextBlock.RenderTransform>
<RotateTransform Angle="45" />
</TextBlock.RenderTransform>
</TextBlock>
Как это выглядит, представлено на рис. 5-1.
РИС. 5 1 Использование свойства RotateTransform.
Как видите, поворот этого текста был выполнен относительно центральной точки с координатами (0,0), т.е. верхнего левого угла.
В следующем XAML показано, как использовать CenterX и CenterY для выполнения вращения вокруг другой точки. В данном случае, поворот выполняется вокруг точки (100,200):
<TextBlock Width="320" Height="40"
Text="This is the text to rotate" TextWrapping="Wrap" >
<TextBlock.RenderTransform>
<RotateTransform Angle="45" CenterX="100" CenterY="200" />
</TextBlock.RenderTransform>
</TextBlock>
Результаты этой трансформации представлены на рис. 5-2.
РИС. 5 2 Вращение вокруг другой центральной точки.
Масштабирование с помощью ScaleTransform
ScaleTransform используется для изменения размера объекта в направлении по горизонтальной оси, вертикальной оси или в обоих направлениях.
При выполнении масштабирования объекта необходимо задать, по крайней мере, одну из осей масштабирования и то, на сколько должен быть изменен масштаб объекта по этой оси. Для масштабирования объекта по горизонтальной оси, оси х, используется свойство ScaleX, и для масштабирования по вертикальной оси, оси у, используется свойство ScaleY. Эти свойства принимают значения типа double, которые представляют, во сколько раз должен быть изменен объект в направлении по заданной оси. Следовательно, значения, больше 1, будут увеличивать объект. Например, если свойству ScaleX задать значение 2, это обеспечит увеличение размера объекта по горизонтали в два раза. Значения, меньше 1, но больше 0, будут обусловливать уменьшение объекта. Например, использование значения 0,5 приведет к уменьшению размера объекта вдвое в заданном направлении.
Итак, рассмотрим XAML-код, который обеспечивает создание красного прямоугольника шириной 96 пикселов и высотой 88 пикселов:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000" Width="96" Height="88" Canvas.Left="112" Canvas.Top="72" />
На рис. 5-3 показано, как это выглядит в Silverlight.
РИС. 5 3 Представление прямоугольника в Silverlight.
Чтобы применить к этому объекту ScaleTransform, используется RenderTransform и задается трансформация ScaleTransform. Вот соответствующий XAML:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="96" Height="88" Canvas.Left="112" Canvas.Top="72">
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="2" />
</Rectangle.RenderTransform>
</Rectangle>
На рис. 5-4 показано, как это выглядит в Silverlight.
РИС. 5 4 Масштабирование с помощью ScaleTransform.
Можно заметить, что в результате применения ScaleTransform прямоугольник вытянулся вправо. Это произошло, потому что не был задан центр масштабирования. Для задания центра масштабирования используются свойства CenterX, для масштабировании по горизонтали, и CenterY, для масштабирования по вертикали. Эти свойства определяют координаты центра масштабирования. Эти координаты задаются относительно верхнего левого угла прямоугольника. Координата по умолчанию - 0, т.е. изменение размера будет происходить вправо и вниз.
Если свойству CenterX задать положительное значение (например, 50), масштабирование будет выполняться относительно точки X, смещенной на 50 пикселов вправо от левого края прямоугольника. В результате этого будет создаваться впечатление, что прямоугольник сместился на некоторое число пикселов (в зависимости от коэффициента масштабирования) относительно исходного положения. Это объясняется тем, что масштабирование выполняется относительно заданного центра, и левая часть прямоугольника увеличивается точно также, как и правая. Аналогичные результаты в вертикальном направлении можно получить, задавая ScaleY и CenterY. Рассмотрим пример:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="96" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="2" CenterX="50"/>
</Rectangle.RenderTransform>
</Rectangle>
Как в результате этого изменяется прямоугольник, можно увидеть на рис. Рис. 5-5.
РИС. 5 5 Масштабирование относительно центра масштабирования.
Перемещение объекта с помощью TranslateTransform
Трансляция (translation) - это трансформация путем перемещения объекта на плоскости из одного места в другое. Описывается она путем задания векторов, которые определяют перемещение объекта от-
носительно осей х и у. Для этого используются свойства X и Y. Чтобы передвинуть элемент на две единицы по горизонтали (объект будет двигаться вправо), свойству X задается значение 2. Чтобы переместить элемент влево, используется отрицательное значение, например, -2. Аналогично, для перемещения объекта по вертикали применяется свойство Y. Задание ему положительных значений обусловит перемещение объекта вниз по экрану, тогда как отрицательные значения обеспечат перемещение объекта вверх.
Рассмотрим пример трансформации трансляцией, которая обеспечивает перемещение уже знакомого нам красного прямоугольника вверх и влево через задание свойств X и Y. Эти значения образуют вектор , определяющий трансформацию.
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="96" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<TranslateTransform X="-50" Y="-50"/>
</Rectangle.RenderTransform>
</Rectangle>
Результаты этой трансформации представлены на рис. 5-6. Прямоугольник переместился вверх и влево относительно его исходного положения (рис. 5-3).
РИС. 5 6 Использование свойства TranslateTransform.
Наклон объекта с помощью свойства SkewTransform
Наклон объекта подразумевает его поступательное пропорциональное изменение вдоль одной из осей. В результате квадрат или прямоугольник превращается в параллелограмм. Этот визуальный эффект очень полезен при создании впечатления трехмерного изображения на плоскости.
Можно задавать наклон под определенным углом вдоль оси х или у и относительно определенного центра. Конечно, все это можно комбинировать и наклонять объект относительно обеих осей одновременно.
Рассмотрим XAML-код, обеспечивающий наклон прямоугольника вдоль оси х на 45 градусов:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="96" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<SkewTransform AngleX="45"/>
</Rectangle.RenderTransform>
</Rectangle>
Результат представлен на рис. 5-7.
РИС. 5 7 Наклонение прямоугольника с помощью SkewTransform.
Имитация трехмерного изображения с помощью SkewTransform
Наклон используется для создания эффекта трехмерного изображения. Ниже представлен пример XAML-кода, в котором используется три прямоугольника, два из которых наклонены по оси х, и один - по оси у, что создает впечатление трехмерного изображения:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="88" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<SkewTransform AngleX="45"/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="88" Height="88" Canvas.Left="80" Canvas.Top="168">
<Rectangle.RenderTransform>
<SkewTransform AngleX="45"/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="88" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<SkewTransform AngleY="45"/>
</Rectangle.RenderTransform>
</Rectangle>
Результаты этого представлены на рис. 5-8.
РИС. 5 8 Имитация трехмерного изображения с помощью SkewTransform.
Определение собственных трансформаций с помощью
MatrixTransform
Все трансформации по сути своей осуществляются путем совокупного изменения координатного пространства объекта с помощью матрицы трансформации. Все представленные до этого в данной главе трансформаций широко известны и хорошо описаны.
Математика матриц и реализация трансформаций выходят за рамки рассмотрения данной книгой, но ради синтаксической полноты мы рассмотрим здесь, как их можно определять в Silverlight XAML.
Обратите внимание, что матрица, используемая в MatrixTransform, является аффинной. Это означает, что последний столбец матрицы всегда (0 0 1), и, таким образом, задаются только первые два столбца. Для этого используется свойство Matrix (Матрица), которое принимает строковое значение, образованное значениями первых двух столбцов, записанными через пробелы. Ниже приведен пример:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="96" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<MatrixTransform Matrix="1 0 1 2 0 1" />
</Rectangle.RenderTransform>
</Rectangle>
На рис. 5-9 продемонстрирован результат применения этой матрицы - растянутый и наклоненный прямоугольник.
РИС. 5 9 Использование MatrixTransform.
Сочетание трансформаций
Как было представлено в предыдущем примере, с помощью аффинной матрицы и MatrixTransform можно создавать сложные трансформации. Однако не все хорошо разбираются в математике матриц. Поэтому применяется другая техника - сочетание трансформаций с помощью элемента Trans- formGroup (Группа трансформаций), который просто позволяет задавать несколько трансформаций. Объект подвергается комбинированному эффекту от всех трансформаций вместе взятых. Рассмотрим пример:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000"
Width="96" Height="88" Canvas.Left="80" Canvas.Top="80">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.2" ScaleY="1.2" />
<SkewTransform AngleX="30" />
<RotateTransform Angle="45" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
В этом примере комбинируются ScaleTransform, который обеспечивает увеличение размера фигуры вдоль обеих осей на 20%, наклон на 30 градусов по оси х и поворот на 45 градусов. Результаты этой трансформации представлены на рис. 5-10.
РИС. 5 10 Сочетание трансформаций с помощью TransformGroup.
Анимация
Слово анимация буквально означает «оживить что-то». Таким образом, с помощью анимации вы можете вдохнуть жизнь в созданные вами объекты, меняя их атрибуты, такие как цвет, размер, прозрачность и другие свойства, во времени и в ответ на действия пользователя.
В XAML анимация элемента осуществляется за счет изменения одного или более его свойство во времени. Это время определяется с помощью временной шкалы. Например, чтобы элемент пересек экран за 5 секунд, необходимо было бы задать временную шкалу длительностью 5 секунд, которая обеспечила бы изменение свойства Canvas.Left от 0 до значения ширины экрана. В следующих разделах будут обсуждаться все доступные типы анимации и отличия анимации этих свойств с использованием ключевых кадров.
Прежде чем переходить к различным типа анимации, вы должны познакомиться с механизмами анимаций, которые включают Triggers (Триггеры), EventTriggers (Триггеры событий) и Storyboards (Раскадровки). Сначала рассмотрим эти концепции, а затем уже углубимся в различные типы анимации.
Использование триггеров и триггеров событий
Анимации в Silverlight выполняются в ответ на некоторое событие, которое определяется с помощью триггера. В настоящее время Silverlight XAML поддерживает только один тип триггеров - EventTrigger. Каждое свойство UI имеет коллекцию Triggers, которая используется для определения одного или более триггеров (т.е. одного или более EventTriggers).
Итак, первый шаг в добавлении анимации в элемент - создание его коллекции триггеров. Затем в эту коллекцию необходимо будет добавить, по крайней мере, один триггер события. Например, первый шаг при анимации прямоугольника, определение коллекции триггеров, выглядит следующим образом:
<Rectangle x:Name="rect" Fill="Red" Canvas.Top="100"
Canvas.Left="100" Width="100" Height="100">
<Rectangle.Triggers>
</Rectangle.Triggers>
</Rectangle>
Далее необходимо определить EventTrigger, который будет добавлен в эту коллекцию. В данном EventTrigger с помощью свойства RoutedEvent (Отслеживаемое событие) задается событие, в ответ на возникновение которого будет запускаться анимация. В Главе б, «Элемент управления браузера Silver-
light», подробно рассматриваются все события, поддерживаемые каждым из объектов в XAML, но обратите внимание, что RoutedEvent поддерживает только событие Loaded (Загружен).
Чтобы реализовать анимацию, которая будет запускаться после загрузки прямоугольника, EventTrigger необходимо описать следующим образом:
<EventTrigger RoutedEvent="Rectangle.Loaded">
</EventTrigger>
Вот фрагмент XAML-кода, запускающий эту анимацию:
<Rectangle x:Name="rect" Fill="Red" Canvas.Top="100" Canvas.Left="100" Width="100" Height="100">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Следующий шаг - создать анимацию, которая будет использоваться. Анимации размещаются в раскадровках, которым посвящен следующий раздел.
Использование BeginStoryboard и Storyboard
BeginStoryboard (Начать раскадровку) - это триггерное действие, содержащее объект Storyboard. В объектах Storyboard находятся описания анимации. При описании анимации эти объекты просто встраиваются в определение EventTrigger. Вот как это было бы выполнено для примера с прямоугольником, с которым мы работаем в этой главе:
<Rectangle x:Name="rect" Fill="Red" Canvas.Top="100" Canvas.Left="100" Width="100" Height="100">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Определение параметров анимации
Теперь, когда среда анимации задана, можно приступать к описанию самой анимации. В основе анимации лежит изменение свойства во времени. Возможна анимация трех разных типов свойств:
Свойства типа double анимируются с помощью DoubleAnimation или DoubleAnimationUsingKeyFrames (Анимация свойств типа Double с использованием ключевых кадров). Этот метод используется для анимации свойств со значением типа double, например, таких размеров, как Canvas.Left, или таких визуальных атрибутов, как Opacity.
Свойства типа точка анимируются с помощью PointAnimiation (Анимация точки) или PointAnimationUsingKeyFrames (Анимация точки с использованием ключевых кадров). Этот метод используется для анимации свойств со значениями, определенными как точка. Например, сегменты прямых или кривые описывают с помощью точек.
Свойства типа цвет анимируются с помощью ColorAnimation или ColorAnimationUsingKeyFrames (Цветовая анимация с использованием ключевых кадров). Этот метод используется для анимации свойств, содержащих значения цвета, например, фона или обводки элемента.
Анимация каждого из этих типов свойств выполняется от значения, заданного атрибутом From (От) (или его текущего значения, если этот атрибут не задан), до значения, заданного атрибутом To (До), или на значение, заданное атрибутом By (На).
Задание объекта анимации
Объект, к которому должна применяться анимация, задается свойством Storyboard.TargetName (Имя цели) данного типа анимации. В это свойство передается имя объекта, которое в описании объекта задано свойством x:Name (Имя). Кроме того, с помощью Storyboard.TargetProperty (Целевое свойство) задается анимируемое свойство. Заметьте, что составное или присоединенное свойство (такое как Can- vas.Left) заключается в круглые скобки. Итак, например, чтобы задать анимацию свойства типа Double для свойства Canvas.Left прямоугольника rect, необходимо написать следующий XAML:
<DoubleAnimation Storyboard.TargetName="rect" Storyboard.TargetProperty="(Canvas.Left)" />
Задание продолжительности
Для определения времени перехода анимируемых свойств от одного значения к другому используется свойство Duration (Продолжительность). Оно определяется в формате ЧЧ:ММ:СС, где продолжительность 5 секунд записывается 00:00:05, или сокращенно - 0:0:5. Рассмотрим пример:
<DoubleAnimation Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" Duration="0:0:5" />
Задание момента начала
Если вы не хотите, чтобы анимация начиналась сразу после загрузки, можно ввести задержку с помощью свойства BeginTime (Момент начала). Для него используется такой же синтаксис, как и для Duration.
<DoubleAnimation Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" BeginTime="0:0:5" />
Использование свойства SpeedRatio
Можно настроить поведение анимации, умножая ее продолжительность на коэффициент скорости. Для этого используется свойство SpeedRatio (Коэффициент скорости). Например, в предыдущем случае была задана продолжительность 5 секунд. Задав SpeedRatio равным 2, можно изменить скорость воспроизведения, и анимация будет длиться 10 секунд. Или можно ускорить анимацию до 1 секунды, задавая SpeedRatio равным 0,2.
<DoubleAnimation Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" SpeedRatio="2" Duration="0:0:5" />
Использование свойства AutoReverse
Анимация Silverlight обеспечивает возможность возвращения свойств, измененных в ходе анимации, к исходным значениям. Например, если значение типа double изменяется от 0 до 500 за определенный промежуток времени, свойство AutoReverse (Автоматическая перемотка) заставит анимацию выполниться в обратном направлении, от 500 к 0.
Обратите внимание, что если задана продолжительность анимации 5 секунд, и свойству AutoReverse задано значение true, продолжительность всей анимации будет 10 секунд. Далее представлен пример XAML со свойством AutoReverse:
<DoubleAnimation Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" AutoReverse="True" Duration="0:0:5" />
Задание свойства RepeatBehavior
Существует ряд опций, посредством которых можно управлять поведением анимации по завершении ее выполнения. Задаются они с помощью свойства RepeatBehavior (Поведение повтора). Это свойство может принимать три типа значений:
Время в секундах. После прохождения этого промежутка времени на временной шкале, анимация будет запускаться повторно.
Значение Forever (Постоянно) определяет постоянное повторение.
Определенное количество повторений. Для этого задается число, определяющее число повторений, за которым следует символ x. Например, если необходимо повторить анимацию три раза, задается значение 3х.
Далее представлен полный XAML-код для анимации перемещения прямоугольника из точки 100 в точку 500 и назад в 100 по оси х с последующим троекратным повторением:
<Rectangle x:Name="rect" Fill="Red"
Canvas.Top="100" Canvas.Left="100" Width="100" Height="100">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation RepeatBehavior="3x"
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" To="500" Duration="0:0:5" AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Рассмотрим каждый из этих типов анимации немного более подробно. Сначала обратимся к атрибутам, необходимым для анимации каждого из типов, а затем перейдем к использованию анимации по ключевым кадрам.
Анимация значения с помощью DoubleAnimation
Объект DoubleAnimation позволяет задавать, как значения типа double изменяется со временем. Анимация вычисляется как линейная интерполяция между значениями свойства в разные моменты времени.
При анимации свойств типа double задается значение в начале анимации, с помощью свойства From, и его абсолютное конечное значение, с помощью свойства To, или относительное конечное значение, посредством свойства By.
Например, чтобы изменить свойство Canvas.Left элемента от 100 (расположение рядом с левым краем экрана) до 500, можно задать свойству From значение 100 и 500 свойству To или 400 свойству By. Обратите внимание, что в случае задания обоих свойств, To имеет преимущество над By. Также если прямоугольник уже находится в определяемой From позиции, это свойство задавать не надо.
Предыдущий пример XAML-кода реализует это поведение. Прямоугольник располагается в позиции с Canvas.Left равным 100. DoubleAnimation определяет для To значение 500. Следовательно, анимация обеспечит изменение значения от 100 до 500, что обусловит перемещение прямоугольника по экрану вправо.
Анимация цвета с помощью ColorAnimation
Поведение ColorAnimation очень близко поведению DoubleAnimation. Этот тип используется для изменения значения color элемента во времени. Анимация вычисляется как линейная интерполяция между значениями color в заданный промежуток времени.
При анимации цвета значение в начале анимации задается свойством From. Если это свойство не задано, за исходный принимается текущий цвет. Атрибут To определяет конечный цвет. Также можно задать атрибут By, тогда конечный цвет будет получен путем суммирования значения цвета, заданного в From (или исходного цвета), и цвета, заданного By.
Анимация цветовых свойств не означает анимацию содержимого свойства, потому что содержимым свойства обычно является кисть, а не цвет. Поэтому, например, если необходимо анимировать цвет
заливки прямоугольника, целевым свойством анимации является не его свойство Fill, а свойство Color кисти SolidBrush, которая используется для выполнения заливки.
Далее представлен пример анимации цвета прямоугольника. Цвет меняется от черного к белому в течение 5 секунд:
<Rectangle x:Name="rect" Canvas.Top="100" Canvas.Left="100"
Width="100" Height="100" Fill="Black">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="rect"
Storyboard.TargetProperty=
"(Shape.Fill).(SolidColorBrush.Color)"
To="#00000000" Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Как видите, в этом фрагменте XAML целевым свойством является свойство Color кисти SolidColorBrush, закрашивающей фигуру. Это типовой синтаксис XAML, используемый при работе с такими составными свойствами.
Анимация точки с помощью PointAnimation
Для изменения во времени значения, определенного как точка, используется тип PointAnimation. Анимация вычисляется как линейная интерполяция между значениями в заданный промежуток времени.
Аналогично тому, как это делалось для анимации цвета и объектов типа Double, исходное значение задается с помощью свойства From и конечное значение задается как относительное (используя By) или как абсолютное (используя To). Далее представлен пример анимации конечной точки кривой Безье:
<Path Stroke="Black" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<QuadraticBezierSegment x:Name="seg"
Point1="200,0" Point2="300,100" />
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard>
<PointAnimation Storyboard.TargetName="seg"
Storyboard.TargetProperty="Point2"
From="300,100" To="300,600" Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
В данном случае кривая Безье описывается начальной точкой (100,100), конечной точкой (300,100) и опорной точкой (200,0). Задано, что анимация запускается после загрузки контура и обеспечивает перемещение конечной точки кривой (Point2) от точки (300,100) в точку (300,600) в течение 5 секунд.
Использование ключевых кадров
Все рассматриваемые до сих пор типы анимации: ColorAnimation, DoubleAnimation и PointAnimation, - выполнялись путем изменения заданного свойства во времени с использованием линейной интерполяции. Например, при изменении значения типа double от 100 до 500 за 5 секунд, его приращение составляет 80 единиц в секунду.
Каждый из этих переходов может быть определен рядом промежуточных этапов, называемых ключевыми кадрами(key frames). Для изменения линейного поведения анимации от начального свойства к конечному используется один или более ключевых кадров. Затем задается, какой стиль анимации должен быть применен между различными точками.
Ключевые кадры определяются с помощью опорных моментов (key times). Это моменты, задаваемые относительно начала анимации и определяющие время окончания ключевого кадра. Итак, представим, что необходимо создать анимацию продолжительностью 9 секунд с тремя ключевыми кадрами, расположенными через равные промежутки времени друг от друга. Первый ключевой кадр можно задать в конце третьей секунды (0:0:3), второй - в конце шестой (0:0:6), и третий - в конце девятой (0:0:9). Вы не задаете продолжительность опорного момента, вы задаете время окончания каждого ключевого кадра.
В качестве еще одного примера возьмем анимацию объектов типа Double, с разделением промежутка 100 - 500 на две равные части. Анимация должна двигаться очень быстро первую половину пути и очень медленно вторую половину. Все перемещение должно занять 6 секунд. Поскольку средней точкой между 100 и 500 является 300, начало ключевого кадра определяем в точке 300. Указываем, что перемещение из начальной точкой в среднюю точку должно занять 1 секунду, используя опорный момент 0:0:1. Затем задаем продолжительность перемещения из средней точки в конечную точку равным 5 секундам, используя второй опорный момент, 0:0:6. Теперь элемент будет мгновенно перескакивать из начальной в среднюю точку и затем медленно проходить остальную часть пути.
В предыдущем примере оба сегмента анимации используют линейную интерполяцию. Для обеспечения дополнительной гибкости существует еще два типа ключевых кадров: ключевой кадр дискретной анимации, который мгновенно «перебрасывает» значение от одного значения к другому, и ключевой кадр сглаженной анимации, который обеспечивает плавное изменение значения, используя для определения интерполяции кривую второго порядка. (В следующих разделах будет рассмотрено описание анимации с использованием ключевых кадров для объектов типа Double. Аналогичные принципы применяются для анимации Point и Color.)
В наименованиях типов анимации с использованием ключевых кадров используется постфикс UsingKeyFrames (с использованием ключевых кадров). То есть для описания анимации объектов типа Double с ключевыми кадрами будет использоваться тип DoubleAnimationUsingKeyFrames, для которого будут заданы цель и свойство (точно так же, как это делалось для DoubleAnimation). DoubleAnimationUsingKeyFrames включает описания ключевых кадров. (И как я уже говорил, то же самое касается PointAnimationUsingKeyFrames и ColorAnimationUsingKeyFrames.)
Использование линейных ключевых кадров
Стандартным методом анимации изменения значений свойства является линейная интерполяция, при которой общая величина изменения равномерно распределяется по времени, отведенному на изменение. Другой способ - определение линейных шагов между кадрами с помощью LinearKeyFrame (Линейный ключевой кадр), в котором используется все та же линейная интерполяция, но между ключевыми кадрами, поэтому можно создавать эффекты ускорения/замедления.
Рассмотрим следующий пример анимации. В нем используется DoubleAnimationUsingKeyFrames. В этом случае определяются два ключевых кадра. Один кадр описывает линейную интерполяцию для изменения Canvas.Left от 0 до 300 за 1 секунду, второй - линейную интерполяцию для изменения Canvas.Left от 300 до 600 за 8 секунд. В результате создается эффект быстрого перемещения прямоугольника в первой половине пути и медленного движения во второй. Аналогичные принципы применяются для LinearPointKeyFrame и LinearColorKeyFrame.
<Rectangle Fill="#FFFF0000" Stroke="#FF000000"
Width="40" Height="40" Canvas.Top="40" x:Name="rect">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" >
<LinearDoubleKeyFrame KeyTime="0:0:1" Value="300" />
<LinearDoubleKeyFrame KeyTime="0:0:9" Value="600" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Использование ключевых кадров дискретной анимации
Если необходимо изменить свойство от одного значения к другому, но без применения линейной интерполяции, можно использовать ключевой кадр дискретной анимации. Он заставит объект «перескочить» на заданное значение в заданное время ключевого кадра. Далее показан тот же пример, что был представлен выше, но с использованием ключевого кадра дискретной анимации. За 1 секунду анимации прямоугольник перепрыгнет полпути на экране. Остальные 8 секунд анимации он будет проходить оставшийся отрезок пути.
<Rectangle Fill="#FFFF0000" Stroke="#FF000000"
Width="40" Height="40" Canvas.Top="40" x:Name="rect">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Canvas.Left)" >
<DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="300" />
<DiscreteDoubleKeyFrame KeyTime="0:0:9" Value="600" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Аналогичные принципы применяются для DiscretePointKeyFrame и DiscreteColorKeyFrame.
Использование ключевых кадров сглаженной анимации
Для изменения свойства от одного значения к другому с использованием нелинейно изменяемого значения, обеспечивающим ускорение и замедление, применяется ключевой кадр сглаженной анимации. Для этого задается квадратическая кривая Безье. Тогда скорость изменения свойства от одного значения к другому определяется параллельной проекцией этой кривой.
Чтобы представить это, возьмем наглядный пример: солнце стоит прямо над головой, вы посылаете футбольный мяч в дальнюю часть поля. Проследите за тенью мяча. Пока он летит вверх, кажется, что тень движется с ускорением. Когда он достигает верхней точки, тень замедляет ход. Когда мяч начинает падать, скорость тени опять начинает возрастать до тех пор, пока мяч не упадет на землю.
Теперь представьте, что ваша анимация - это тень мяча, а плавная линия - это траектория мяча. Траектория, плавная линия или сплайн, описывается с помощью KeySpline (Опорная сглаженная линия). KeySpline определяет опорные точки квадратической кривой Безье. Кривая нормализована, так что первая точка кривой находится в 0, вторая - в 1. Для описания параболической дуги, именно по такой траектории падает мяч, KeySpline будет включать два нормализованных значения через запятую.
Описать кривую, по которой двигается мяч, можно с помощью сглаженной линии, используя KeySpline, например 0.3,0 0.6,1. Здесь задается первая (0.3,0) и вторая (0.6,1) точки кривой. В результате будет создан эффект быстрого ускорения анимации в первой трети пути, затем перемещение будет происходить с постоянной скоростью до прохождения примерно двух третей траектории мяча, и затем оставшуюся часть пути движение будет замедляться, имитируя падения мяча на землю.
Далее представлен пример использования KeySpline для описания сглаженной кривой при моделировании такого движения с помощью анимации DoubleAnimationUsingKeyFrames:
<Ellipse Fill="#FF444444" Stroke="#FF444444"
Width="40" Height="40" Canvas.Top="40" x:Name="ball">
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="ball"
Storyboard.TargetProperty="(Canvas.Left)" >
<SplineDoubleKeyFrame KeyTime="0:0:5"
KeySpline="0.3,0 0.6,1" Value="600" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
В этом примере выполняется анимация эллипса. Его перемещение по экрану моделирует движение тени мяча, если смотреть на нее сверху.
Анимация и Expression Blend
Анимацию можно создавать графически в Expression Blend. Он формирует за вас XAML-код, применяя различные типы анимации автоматически.
В Blend для сайта, созданного для Silverlight 1, выберите в меню Window пункт Animation Workspace (Рабочая область анимации). При этом откроются инструменты для графического проектирования временных шкал. При редактировании свойств, которые должны меняться, используя визуальный редактор, будет формироваться XAML-код анимации. Это можно увидеть на рис. 5-11.
Внизу экрана представлена панель Objects And Timeline. В ней можно добавить временную шкалу и затем визуально вводить ключевые кадры. Чтобы добавить новую временную шкалу, щелкните кнопку + на панели Objects And Timeline (рис. 5-12).
РИС. 5 11 Expression Blend в режиме Animation Workspace.
РИС. 5 12 Добавление новой временной шкалы.
Если щелкнуть кнопку +, откроется диалоговое окно, в котором будет предложено ввести имя создаваемой раскадровки. Диалог Create Storyboard (Создание раскадровки) показан на рис. 5-13. В данном случае я изменил предлагаемое по умолчанию имя Storyboard1 на Timelinel и убрал флажок Create As Resource (Создать как ресурс).
РИС. 5 13 Создание раскадровки.
При использовании Blend для сайта для Silverlight 1 анимацию можно создавать на уровне Canvas или как Resource (Ресурс). В первом случае анимации запускаются в ответ на триггеры, располагающиеся на холсте. Далее представлен пример XAML, созданного Blend из диалогового окна Create Storyboard, в котом пользователь обозначил, что не хочет создавать анимацию как Resource:
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard x:Name="Timeline1"/>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
Обратите внимание, что если бы пользователь установил флажок Create As Resource (рис. 5-13), Storyboard был бы создан в <Canvas.Resources>, и его пришлось бы запускать из JavaScript. В приложении для Silverlight 2 анимация сразу создается как ресурс. Более подробно остановимся на этом в Главе 6.
Представление Objects And Timeline изменится, в нем будет отображена только что созданная временная шкала. Это можно увидеть на рис. 5-14.
РИС. 5 14 Панель Objects And Timeline с новой временной шкалой.
На рис. 5-14 вертикальная линия на нулевой отметке времени обозначает текущее время. (В Blend эта линия будет желтой.) Чтобы добавить ключевой кадр, просто перетащите эту линию на тот момент, куда необходимо вставить ключевой кадр, и щелкните кнопку Record Keyframe (Записать ключевой кадр). Эта кнопка находится сразу над временной шкалой слева от 0:00:000 на рис. 5-14.
Перетащите линию на 4-секундную отметку и добавьте ключевой кадр. Добавленный ключевой кадр будет отображаться как небольшой овал на временной шкале, как показано на рис. 5-15.
РИС. 5 15 Добавление ключевого кадра.
Установив временную шакалу на отметку 4 секунды и добавив ключевой кадр, можно перейти к редактированию цвета, местоположения, прозрачности или формы прямоугольника. Blend сам проведет соответствующие вычисления для облегчения создания анимации. В качестве примера на рис. 5-16 показан тот же прямоугольник, что мы видели на рис. 5-11, но с измененными заливкой и размерами.
РИС. 5 16 Задание изменений в ключевом кадре.
Вероятно, вы заметили, что если перемещать индикатор временной шкалы, можно предварительно просмотреть полученную анимацию и увидеть, как она выглядит в каждый отдельно взятый момент времени. На рис. 5-17 показано, как наш прямоугольник выглядит на второй секунде опорного времени. Для этого мы просто перетащили желтую вертикальную линию на отметку 2 секунды.
Ниже представлен полный XAML-код, сформированный Blend при создании анимации графическими средствами для сайта для Silverlight 1:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480"
Background="White"
x:Name="Page">
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard x:Name="Timeline1">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="141"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.Y)">
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="163"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[2].(RotateTransform.Angle)">
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="35.107"/>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:04" Value="#FF9D0B0B"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rect" Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="1.7"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="rect"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="1.549"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Rectangle Width="87" Height="69" Fill="Red" Stroke="#FF000000"
Canvas.Top="41" RenderTransformOrigin="0.5,0.5" x:Name="rect">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
РИС. 5 17 Предварительный просмотр анимации.
Заключение
В данной главе вы узнали, как в Silverlight XAML описываются трансформации и анимации. Были представлены различные типы трансформации, используемые для вращения, изменения размеров или наклонения объекта, а также произвольные трансформации с использованием аффинной матрицы. Затем были рассмотрены анимации и их запуск с помощью триггера XAML. Показано, как анимация меняет значения свойств со временем, и представлены типы XAML, поддерживающие анимацию значений: double, point и color. Также мы научились использовать ключевые кадры для более тонкой настройки анимации. Наконец, вы познакомились со средством графического создания анимации, Expression Blend, и увидели, как просто в Blend создавать анимации визуально.
В Главе б будет рассмотрен сам элемент управления Silverlight и более подробно описан полный набор его свойств, методов и событий.
Глава 6
Элемент управления браузера
Silverlight
В данной главе будет подробно рассмотрены вопросы разработки решений для Silverlight с использованием XAML-кода и JavaScript. Мы исследуем, как объект подключаемого модуля Silverlight размещается в браузере, а также полную модель свойств, методов и событий, поддерживаемую этим элементом управления. Также будут рассмотрены поддержка событий загрузки и ошибок, а также обработка параметризации и контекста. Будет показан стандартный обработчикошибок, предоставляемый Silver- light, и то, как его можно переопределить собственными обработчиками ошибок. Мы детально остановимся на объекте Downloader, предоставляемом Silverlight, и выясним, как он может использоваться для динамического введения содержимого в приложение. Наконец, будет рассмотрена модель программирования элементов пользовательского интерфейса (UI), составляющих модель элементов управления XAML, и показано использование их методов и событий в модели программирования JavaScript.
Размещение Silverlight в браузере
Для использования и создания приложений Silverlight не требуется никакого специального программного обеспечения, кроме самого подключаемого модуля Silverlight и файла Silverlightjs, который обеспечивает загрузку и установку подключаемого модуля для клиентов, не имеющих его. Создавать сайты на Silverlight можно, используя любое ПО для разработки Веб-сайтов, начиная от Notepad, до Eclipse, Expression Web или Expression Blend, - выбор за вами.
Данный раздел представляет базовое руководство по тому, как начать использовать Silverlight. До сих пор в этой книге всю сложную работу за вас выполнял шаблон Expression Blend или Microsoft Visual Studio, но теперь пришло время узнать, как самостоятельно создать и запустить простое приложение Silverlight, не используя никаких других инструментов, кроме Windows Explorer и Notepad.
Первый и самый важный файл, который нам понадобится, - стандартный файл Silverlightjs. Он доступен в Silverlight Software Development Kit (SDK), который можно скачать на Веб-сайте http://www.microsoft.com/silverlight.
Далее необходимо создать HTML-файл, который будет ссылаться это этот JavaScript-файл. Элемент управления Silverlight будет размещаться на этой странице. Вот пример:
<HTML>
<HEAD>
<script type="text/javascript" src="Silverlight.js" />
</HEAD>
<BODY>
</BODY>
</HTML>
Файл Silverlightjs включает методы createObject и createObjectEx, с помощью которых могут создаваться экземпляры Silverlight. Разница между этими методами в том, что createObjectEx может использовать JavaScript Object Notation (JSON)1 для сериализации параметров.
Эти функции принимают набор параметров, используемых для создания экземпляра элемента управления. Данные параметры представлены в табл. 6-1.
таблица 6 1 Параметры методов createObject и createObjectEx
1Объектная нотация JavaScript (прим, переводчика).
Имя параметра
Описание
source
Задает источник XAML-кода или XAP-приложения, который формируется элементом управления. Это может быть ссылка на файл (т.е. "source.xap"), URI (т.е., http://server/generatexaml.aspx) или ссылка на встроенный XAML, содержащийся в DIV (т.е., #xamlcontent для DIV под именем xamlcontent).
parentElement
Это имя DIV, в котором находится элемент управления Silverlight на вашей HTML-странице.
ID
Это уникальный ID, присваиваемый вами экземпляру элемента управления Silverlight.
width
Ширина элемента управления в пикселах или в процентном соотношении.
height
Высота элемента управления в пикселах или в процентном соотношении.
background
Определяет цвет фона элемента управления. Задание цветов подробно рассматривается в разделе «SolidColorBrush» Главы 4, «Основы XAML». Можно использовать ARGB-значение, например #FFAA7700, или именованный цвет, например Black.
framerate
Задает максимально допустимую частоту кадров анимации. Значение по умолчанию равно 24.
isWindowless
Может принимать значения true или false, значение по умолчанию - false. Если задано true, визуальное представление содержимого Silverlight формируется позади HTML- содержимого, так что HTML-содержимое может отображаться поверх его.
enableHtmlAccess
Определяет возможность доступа к содержимому, располагающемуся в элементе управления Silverlight, из DOM1 браузера. Значение по умолчанию - true.
inplaceInstallPrompt
Silverlight имеет два режима установки. Установка inplace (на месте) включает принятие лицензии на ПО и прямую загрузку элемента управления без перехода с сайта, на котором он будет размещаться. При установке indirect (непрямая) пользователю приходится переходить на сайт Microsoft для загрузки Silverlight и уже там принимать лицензионное соглашение и скачивать элемент управления. С помощью этого свойства задается, какой из методов будет использоваться. Значение true обеспечивает пользователю прямую inplace установку; значение false приводит к использованию непрямой установки.
version
Задает минимально необходимую поддерживаемую версию Silverlight.
onLoad
Задает функцию, вызов которой будет происходить при загрузке элемента управления.
onError
Задает функцию, вызов которой будет происходить в случае возникновения ошибки.
onFullScreenChange
Это событие формируется при изменении свойства FullScreen (Во весь экран) элемента управления Silverlight.
onResize
Это событие формируется при изменении свойства ActualWidth или ActualHeight элемента управления Silverlight.
initParamsЗадает определяемый пользователем набор параметров для
элемента управления. Более подробно это рассматривается в разделе «Обработка параметров» далее в данной главе.
userContextЗадает уникальный идентификатор, который может передаваться
как параметр в функцию обработки события onLoad. Более подробно это рассматривается в разделе «Ответ на события загрузки страницы» далее в данной главе.
Пожалуйста, обратите внимание, что при создании экземпляра элемента управления свойства width, height, background, framerate, isWindowless, enableHtmlAccess, version и inplaceInstallPrompt задаются в массиве свойств, и onLoad и onError - в массиве событий.
Ниже приведен один из примеров метода createObject
Silverlight.createObject(
"Scene.xaml",
document.getElementById("SilverlightControlHost"),
"mySilverlightControl",
{
width:'300',
height:'300',
inplaceInstallPrompt:false,
background:'#D6D6D6',
isWindowless:'false',
framerate:'24',
version:'2.0'
},
{
onError:null,
onLoad:null
},
пи11);Теперь вернемся к нашей HTML-странице и настроим ее, чтобы она могла обрабатывать этот элемент управления Silverlight. Как видите, при задании имени компонента Silverlight необходимо было задать родительский DIV под именем SilverlightControlHost, в котором этот компонент будет размещаться. DIV задается через его свойство ID. Вот полный HTML-код:
<html>
<head>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript">
function createSilverlight() {
Silverlight.createObject(
"Page.xaml",
document.getElementById("SilverlightControlHost"),
"mySilverlightControl",
{
width:'300',
height:'300',
inplaceInstallPrompt:false, background:'#D6D6D6', isWindowless:'false', framerate:'24', version:'2.0'
},
{ onError:null, onLoad:null }, null);
}
</script>
</head>
<body>
<div id="SilverlightControlHost">
<script type="text/javascript">
createSilverlight();
</script>
</div>
</body>
</html>
Наконец, элементу управления Silverlight необходим файл с исходным XAML-кодом. В данном примере используется XAML-файл Scene.xaml.
Далее представлен простой XAML-файл, содержащий с надписью TextBlock «Hello, World!» (Здравствуй, мир!):
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480"
Background="White"
x:Name="Page">
<TextBlock Text="Hello, World!"></TextBlock>
</Canvas>
Вот все, что необходимо для настройки и подготовки к работе приложения Silverlight. По мере добавления функциональности в приложение код будет усложняться, но эти три файла - HTML-страница для размещения элемента управления, XAML-файл и Silverlightjs, - как правило, присутствуют в каждом проекте.
Использование тега Object напрямую
В предыдущем примере экземпляр элемента управления Silverlight создавался с помощью функции Sil- verlight.createObject, находящейся в Silverlightjs. Но существует возможность создать экземпляр подключаемого модуля Silverlight напрямую, без применения это функции. Сделать это позволяет стандартный тег <object>, имеющий дочерний элемент <param> для задания параметров. Вот пример реализации:
<object data="data:application/x-silverlight,"
type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="Page.xaml"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="2.0.31005.0" />
</object>
Примечание Пожалуйста, обратите внимание на различие типов MIME в Silverlight 2 RTW и ранее использованных бета-версиях, так как в Beta 2 использовался тип MIME «application/x-silverlight-2-b2». Если возникают проблемы с распознанием объекта Silverlight браузером, убедитесь, что этот параметр задан правильно, соответственно используемой версии Silverlight. Для Silverlight 2 RTW тип MIME «application/x- silverlight-2».
Замечательная особенность тега <object> в том, что он является наращиваемым, в том смысле, что если создать экземпляр исходного <object>не удалось, браузер на этом месте сформирует визуальное представление следующей части HTML, при условии что HTML располагается до закрывающего тега </object>. Поэтому, если Silverlight не установлен, на его место на экране без труда можно поставить простой баннер.
Рассмотрим пример:
<object data="data:application/x-silverlight,"
type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="Page.xaml"/> <param name="onerror" value="onSilverlightError" /> <param name="background" value="white" />
<а href="..." style="text-decoration: none;">
<img src="..." alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object>
В данном случае в объект встроена гиперссылка (тег <a>), поэтому если Silverlight не установлен в системе, этот тег обеспечит ссылку, по которой можно будет перейти на сайт загрузки Microsoft.
Данный подход исключительно полезен, если требуется встроить Silverlight в Веб-сайт, где JavaScript недоступен.
Реакция на события загрузки страницы
Обработчик событий JavaScript задается для управления событиями загрузки страницы с помощью параметра onLoad (после загрузки), представленного в табл. 6-1. Он запускается после полной загрузки XAML-содержимого элемента управления Silverlight. Обратите внимание, что если для какого-либо XAML-элемента UI будет определено аналогичное событие, оно будет сформировано до формирования события onLoad элемента управления Silverlight. Кроме того, у элемента управления есть доступное только для чтения свойство IsLoaded (Загружен), которое устанавливается непосредственно перед формированием события onLoad.
При использовании обработчика события onLoad функция JavaScript должна принимать три параметра: первый - ссылка на элемент управления, второй - пользовательский контекст, и третий - ссылка на корневой элемент XAML. Рассмотрим пример:
function handleLoad(control, userContext, rootElement) { ...
}
Обработка параметров
При вызове функции createObject для создания экземпляра Silverlight в нее можно передавать параметры с помощью свойства initParams (Параметры инициализации). Это свойство строкового типа, поэтому если необходимо задать несколько значений, они могут указываться через запятую в виде строки с разделяющими запятыми. Синтаксический разбор такой строки в JavaScript не представляет большого труда. Далее представлен пример описания элемента управления Silverlight с тремя параметрами:
function createSilverlight() {
Silverlight.createObject(
"Scene.xaml",
document.getElementById("SilverlightControlHost"), "mySilverlightControl", { width:'300', height:'300', inplaceInstallPrompt:false, background:'#D6D6D6', isWindowless:'false', framerate:'24', version:'2.0'
}, { onError:null, onLoad:handleLoad
},
"pl, p2, p3", // Список параметров null);
}
В данном случае параметры pl, р2 и р3 заданы как строка с разделяющими запятыми. В JavaScript есть строковый метод split (разделить), который позволяет разбивать строки с разделяющими запятыми в массив значений.
Далее представлен пример обработчика событий onLoad, который использует этот метод для разделения списка параметров в массив строк и для отображения каждого из них в окне предупреждения:
function handleLoad(control, userContext, rootElement) {
var params = control.initParams.split(",");
for (var i = 0; i< params.length; i++) {
alert(params[i]);
} }
Пользовательский контекст
В элемент управления Silverlight может передаваться дополнительный параметр - параметр контекста. Он включается непосредственно в событие onLoad как второй параметр. Обычно для него используется имя userContext (Пользовательский контекст). Его поведение абсолютно аналогично представленным ранее параметрам: он имеет значение, которое может быть запрошено после формирования визуального представления элемента управления. Однако, как правило, пользовательский контекст используется не как параметр элемента управления, а как переменная ссылочного типа для различия элементов управления, хотя ничто не мешает задавать его для параметризации вашего элемента управления.
Далее представлен пример страницы, на которой размещаются три элемента управления Silverlight. Обратите внимание, что переменные имени и контекста заданы в этой странице-хосте и передаются как параметры в JavaScript, создающий элемент управления Silverlight:
<html>
<head>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript">
function handleLoad(control, userContext, rootElement)
{
alert(userContext);
}
function createSilverlight(parentElement, cid, context) {
Silverlight.createObject(
"Page.xaml",
document.getElementById(parentElement), cid, {
width:'300', height:'300', inplaceInstallPrompt:false, background:'#D6D6D6', isWindowless:'false', framerate:'24', version:'2.0'
},
{
onError:null, onLoad:handleLoad
},
"p1,p2,p3",
context,
null);
}
</script>
</head>
<body>
<div id="SilverlightControlHost1">
<script type="text/javascript">
createSilverlight("SilverlightControlHost1", "ctrl1","the first control");
</script>
</div>
<div id="SilverlightControlHost2">
<script type="text/javascript">
createSilverlight("SilverlightControlHost2", "ctrl2","the second control");
</script>
</div>
<div id="SilverlightControlHost3">
<script type="text/javascript">
createSilverlight("SilverlightControlHost3", "ctrl3","the third control");
</script>
</div>
</body>
</html>
HTML-страница имеет обработчик события onLoad, который представлен здесь:
<script type="text/javascript">
function handleLoad(control, userContext, rootElement)
{
alert(userContext);
}
</script>
Он принимает параметр userContext и отображает значение контекста в окне предупреждения. Как это выглядит на экране, показано на рис. 6-1, на котором HTML-страница представляет контекст первого элемента управления
РИС. 6 1 Вывод на экран пользовательского контекста.
Реакция на события, возникающие в случае ошибки на странице
Silverlight предоставляет несколько методов обработки ошибок в зависимости от типа ошибки. Ошибки возникают в случаях, когда синтаксический анализатор XAML сталкивается с проблемой, загрузка не завершается соответствующим образом, возникает ошибка времени выполнения и если описанным в XAML-документе обработчикам событий не поставлены в соответствие JavaScript-функции.
При инициализации элемента управления с помощью обработчика событий onError задается функция JavaScript, которая будет вызываться при возникновении ошибки. Однако если такая функция не будет задана (или если она задана как null), то никакого уведомления об ошибке не будет происходить, и будет отображаться пустая серая область на месте элемента управления Silverlight. Но в проектах, созданных из Expression Blend, описывается стандартный обработчик ошибок.
Стандартный обработчик событий
Стандартный обработчик событий JavaScript обеспечит вывод на экран сообщения об ошибке с основными деталями возникшей ошибки Silverlight, включая код и тип ошибки, а также сообщение с указанием конкретной проблемы и имени вызванного метода.
Далее представлен пример неправильно сформированного XAML-документа, в котором сделана ошибка в имени закрывающего тега элемента TextBlock, он ошибочно назван </TextBlok>:
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock>Hello, World!</TextBlok>
</Canvas>
Если используется обработчик, созданный Expression Blend по умолчанию, он обеспечит вывод на экран сообщения об ошибке Silverlight, как показан на рис. 6-2.
ParserError- wfc: element type match
File: Pagejtaml line 3 character 37
РИС. 6 2 Сообщение об ошибке.
Использование собственного обработчика ошибок
Можно использовать собственный обработчик ошибок. Для этого свойству onError элемента управления Silverlight необходимо задать специальную функцию обработчика ошибок. Она должна будет принимать два параметра: объект отправителя события и аргументы события, описывающие детали возникшей ошибки.
Существует три типа аргументов события. Первый тип - базовый объект ErrorEventArgs (Аргументы ошибки), содержащий тип сообщения об ошибке и код. Свойство errorType (Тип ошибки) определяет тип ошибки в виде строки, содержащей значения RuntimeError (Ошибка времени выполнения) или ParserError (Ошибка синтаксического анализатора). На основании этой информации используется один из двух производных типов ошибок.
При обработке в XAML ошибки синтаксического разбора используется объект ParserErrorEventArgs (Аргументы ошибки синтаксического анализатора). Оно содержит ряд свойств:
Свойство charposition (позиция символа) содержит позицию символа, в котором возникла ошибка.
Свойство linenumber (номер строки) содержит номер строки, в которой возникла ошибка.
Свойство xamlFile (xaml-файл) определяет файл, в котором возникла ошибка.
Свойство xmlAttribute (xaml-атрибут) определяет xml-атрибут, в котором возникла ошибка.
Свойство xmlElement (xaml-элемент) определяет xml-элемент, в котором возникла ошибка.
Ошибки времени выполнения определяются в объекте RuntimeErrorEventArgs (Аргументы ошибки времени выполнения). Этот объект также включает ряд свойств:
Свойство charPosition определяет позицию символа, в котором возникла ошибка.
Свойство lineNumber определяет строку, в которой возникла ошибка.
Свойство methodName (имя метода) определяет метод, связанный с этой ошибкой.
Рассмотрим, как ошибку можно перехватить собственным обработчиком ошибок. Прежде всего, создается метод createSilverlight(), выполняющий настройку обработчика ошибок:
function createSilverlight()
{
Silverlight.createObject(
"Scene.xaml",
document.getElementById("firstControl"),
"agc1",
{
width:'300',
height:'300',
inplaceInstallPrompt:false,
background:'#D6D6D6',
isWindowless:'false',
framerate:'24',
version:'2.0'
},
{
onError:handleError,
onLoad:null
}, null);
}
Далее представлен HTML-файл, который вызывает этот измененный метод создания элемента управления Silverlight и содержит функцию handleError, заданную как обработчик ошибок в атрибуте onError:
<html>
<head>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="createSilverlight.js"></script>
<script type="text/javascript">
function handleError(sender, errorArguments)
{
var strError = "Error Details: \n";
strError+= "Type: " + errorArguments.errorType + "\n";
strError+= "Message: " + errorArguments.errorMessage + "\n";
strError+= "Code: " + errorArguments.errorCode + "\n";
// Мы знаем (в данном случае), что это ошибка синтаксического анализатора.
// Чтобы обработчик ошибок был более универсальным,
// тип ошибки должен определяться до вызова
// свойств аргументов определенного типа.
strError+= "Xaml File: " + errorArguments.xamlFile + "\n";
strError+= "Xaml Element: " + errorArguments.xmlElement + "\n";
strError+= "Xaml Attribute: " + errorArguments.xmlAttribute + "\n";
strError+= "Line: " + errorArguments.lineNumber + "\n";
strError+= "Position: " + errorArguments.charPosition + "\n";
alert(strError);
}
</script>
</head>
<body>
<div id="firstControl">
<script type="text/javascript">
createSilverlight();
</script>
</div>
</body>
</html>
Если при выполнении этого кода возникает ошибка, на экран будет выведено окно предупреждения с содержимым ошибки. На рис. 6-3 приведен пример собственного окна предупреждения.
РИС. 6 3 Использование собственного обработчика ошибок.
Свойства элемента управления Silverlight
Элемент управления Silverlight имеет ряд свойств, некоторые из которых уже обсуждались в разделе «Размещение Silverlight в браузере». Свойства могут задаваться не только при инициализации элемента управления, но также с помощью сценария. Элемент управления разделяет свойства на три типа: непосредственные свойства, свойства содержимого и свойства настроек. Непосредственные свойства - это свойства самого элемента управления, которые доступны посредством синтаксиса control.имясвойства. Доступ к свойствам содержимого и настроек осуществляется посредством синтаксиса control.content.имясвойства и contraLsettings.имясвойства, соответственно1.
Непосредственные свойства
Ниже перечислены поддерживаемые непосредственные свойства:
initParams В этом свойстве хранятся параметры инициализации, передаваемые в элемент управления. Оно может быть задано только как часть инициализации элемента управления.
isLoaded Это свойство принимает значение true после загрузки элемента управления; в противном случае, оно имеет значение false. Является доступным только для чтения.
source Это XAML-содержимое, визуальное представление которого должно быть сформировано. Это может быть ссылка на файл, URI службы, формирующей XAML, или (в случае присутствия префикса #) DIV, содержащий XAML-код в блоке сценария.
Свойства содержимого
Для организации доступа к свойствам содержимого используется синтаксис control.content.имясвойства. Например, если необходимо обратиться к свойству actualHeight, используется синтаксис con- trol.content.actualHeight. Доступны следующие свойства содержимого:
actualHeight Возвращает высоту области отображения элемента управления Silverlightin в пикселах. Возвращаемое значение зависит от ряда критериев. Во-первых, от того, как высота элемента управления была задана изначально. Вспомним, что это может быть процентное соотношение или абсолютное значение в пикселах. В первом случае, свойство actualHeight возвращает текущую высоту элемента управления, но если пользователь изменит размеры браузера, ее значение изменится. Если высота задана абсолютным значением, будет возвращено это значение. При использовании элемента управления в полноэкранном режиме, это свойство будет возвращать разрешающую способность экрана по вертикали.
actualWidth Возвращает ширину экрана. Возвращаемое значение зависит от ряда критериев и аналогично параметру actualHeight.
fullScreen Переключает режим отображения элемента управления Silverlight между встроенным и полноэкранным режимами. По умолчанию имеет значение false, что обозначает встроенный режим. Когда этому свойству задано значение true, элемент управления Silverlight будет отображаться во весь экран.
Свойства настроек
Элемент управления Silverlight также имеет ряд свойств, которые определены как свойства настроек. Доступ к этим свойствам осуществляется посредством синтаксиса control.settings.имясвойства:
background Это свойство задает цвет фона элемента управления Silverlight. Может принимать значения в нескольких форматах, включая именованный цвет (например, Black), 8-разрядные зна-
1При использовании функции CreateObject имена большинства свойств используются с маленькой буквы, но при программном обращении к ним во время выполнения первая буква в имени свойства должна быть большой. Это касается всех трех типов свойств (прим, научного редактора).
чения Red/Green/Blue (RGB) с или без альфа-канала и 16-разрядные RGB-значения с или без альфаканала.
enableFrameRateCounter (Счетчик частоты кадров включен) Если задано значение true, Silverlight будет отображать текущую частоту кадров (в кадрах в секунду) в строке состояния браузера. Значение по умолчанию - false.
enableHtmlAccess (Html-доступ включен) Если задано значение true, XAML-содержимое становится доступным из DOM браузера. Значение по умолчанию - true.
enableRedrawRegions (Перерисовка областей включена) Если задано значение true, отображаются области объекта подключаемого модуля, перерисовываемые в каждом кадре. Это полезный инструмент оптимизации приложения. Значение по умолчанию - false.
maxFrameRate (Максимальная частота кадров) Определяет максимальную генерируемую частоту кадров. По умолчанию принимает значение 24 и имеет абсолютный максимум 64.
version (версия) Сообщает об используемой в настоящий момент версии элемента управления Silverlight. Это строка, содержащая до четырех разделенных точками целых чисел: основной, дополнительный номера версий, номер сборки и номер редакции, - хотя обязательными являются только первые два значения (основной и дополнительный номер версии).
windowless Это свойство определяет режим отображения элемента управления: безоконный или оконный. Если задано значение true, используется безоконный режим, т.е. содержимое Silverlight отображается на странице «за» HTML-содержимым.
Методы элемента управления Silverlight
Элемент управления Silverlight имеет ряд методов, которые могут использоваться для управления его поведением и функционированием. Аналогично группам свойств Silverlight, методы Silverlight тоже сгруппированы в «семейства» методов. В настоящее время поддерживаются один непосредственный метод и три метода содержимого. Что есть что, будет представлено в следующих разделах, включая примеры, демонстрирующие синтаксис этих методов и способ доступа к ним.
Метод createFromXaml
Метод createFromXaml (создать из Xaml) является методом содержимого Silverlight, позволяющий задавать XAML-содержимое, которое динамически добавляется в элемент управления Silverlight. Этот метод принимает два параметра. Первый - строка, содержащая XAML, который будет использоваться, и второй - параметр namescope (область имен). Если второй параметр имеет значение true (значением по умолчанию является false), в предоставленном XAML будут созданы уникальные ссылки x:Name, которые не будут конфликтовать с именами существующих XAML-элементов.
Для createFromXaml существует ограничение: в добавляемом XAML должен быть всего один корневой узел. Поэтому, если необходимо добавить несколько элементов, убедитесь, что все они располагаются в одном узле, включающем элемент Canvas.
Кроме того, createFromXaml не добавляет XAML в элемент управления Silverlight до тех пор, пока он не будет добавлен в дочерний элемент одного из элементов Canvas элемента управления. Итак, при вызове createFromXaml вы получаете ссылку на узел, и эта ссылка затем используется для добавления этого узла в дерево визуального представления. Рассмотрим пример:
function handleLoad(control, userContext, sender) {
var xamlFragment = '<TextBlock Canvas.Top="60" Text="A new TextBlock" />';
textBlock = control.content.createFromXaml(xamlFragment);
sender.children.add(textBlock);
}
Здесь создается XAML-код для элемента управления TextBlock с текстом «A new TextBlock» (Новый TextBlock). Этот XAML-код затем используется для создания XAML-узла в содержимом элемента управ-
ления. Когда это будет выполнено, Silverlight возвратит ссылку на TextBlock. Эта ссылка добавляется в дерево визуального представления элемента управления Silverlight и используется для прорисовки TextBlock.
Метод createFromXamlDownloader
Метод createFromXamlDownloader (создать из загрузчика Xaml) является методом содержимого, используемым в паре с объектом Downloader (Загрузчик), который будет рассмотрен в данной главе позже. Этот метод принимает два параметра. Первый параметр - ссылка на объект Downloader, который загружает XAML-код или пакет, содержащий XAML-код. Второй параметр - имя пакета загружаемого содержимого, который должен использоваться. Если это .zip-файл, задается имя файла, содержащегося в .zip-архиве, в котором находится XAML-код, который предполагается использовать. Если загруженное содержимое не в пакете .zip, в качестве значения этого параметра должна быть задана пустая строка.
Метод createObject
Метод createObject (создать объект) является непосредственным методом, предназначенным для создания одноразового объекта для определенной функции. В Silverlight единственным таким поддерживаемым объектом является Downloader. Более подробно остановимся на этом в данной главе позже.
Метод findName
Этот метод содержимого позволяет выполнять поиск узла в XAML-коде по атрибуту x:Name. Если findName (найти имя) находит узел с заданным именем, он возвращает ссылку на него, в противном случае, возвращается null.
Объект Downloader
Элемент управления Silverlight предоставляет объект, который обеспечивает возможность загружать дополнительные элементы, используя функциональность асинхронной загрузки. Это позволяет скачивать отдельные ресурсы или ресурсы в виде .zip-архива.
Свойства объекта Downloader
Объект Downloader поддерживает следующие свойства:
downloadProgress (показатель процесса загрузки) Это свойство обеспечивает нормализованное значение (между 0 и 1), которое представляет объем загруженного содержимого в процентном соотношении к его общему размеру, где значение 1 эквивалентно 100% загрузки.
status (состояние) Это свойство принимает код состояния HTTP для текущего состояния процесса загрузки. Возвращает стандартный код состояния HTTP, например, «404» для «Not Found» (не найден) или «200» для «OK».
statusText (текст состояния) Это свойство принимает текст состояния HTTP для текущего состояния процесса загрузки. Он соответствует коду состояния для свойства status. Для успешного запроса status будет равен «200», и statusText будет «OK». Для получения дополнительной информации по кодам состояния HTTP посмотрите стандартные коды HTTP, опубликованные W3C (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).
uri Это свойство содержит URI объекта, к которому в настоящий момент обращается загрузчик.
Методы объекта Downloader
Объект Downloader поддерживает следующие методы:
abort (отменить) Отменяет текущую загрузку и возвращает все свойства в исходное состояние.
getResponseText (получить текст ответа) Возвращает строковое представление загруженных данных. Принимает обязательный параметр, который используется для указания именованного блока в загружаемом пакете.
open (открыть) Запускает сеанс загрузки. Принимает три параметра. Первый - команду действия. Набор команд HTTP задокументирован W3C; однако, Silverlight поддерживает только GET (Получить). Второй параметр - URI ресурса, который должен будет загружаться.
send (отправить) Выполняет запрос загрузки, который был запущен командой open.
События объекта Downloader
Объект Downloader поддерживает следующие события:
completed (завершен) Это событие формируется по завершении загрузки. Оно принимает два параметра. Первый - объект, сформировавший это событие (в данном случае, сам элемент управления downloader), и второй - набор аргументов события (eventArgs).
downloadProgressChanged (показатель процесса загрузки изменился) Это событие формируется в ходе загрузки. Оно формируется при каждом изменении показателя процесса загрузки (значение которого меняется от 0 до 1) на 0,05 (5%) или более, а также когда он достигает значения 1,0 (100%). По достижении 1,0 также формируется событие completed.
Использование объекта Downloader
Объект Downloader позволяет выполнять доступ к ресурсам сети из JavaScript. Пожалуйста, обратите внимание, что этот объект будет работать, только если приложение Silverlight выполняется с Вебсервера, и будет формировать ошибку в случае загрузки страницы просто из файловой системы.
Объект Downloader создается методом createObject, предоставляемым элементом управления Silverlight. Рассмотрим пример:
<script type="text/javascript">
function handleLoad(control, userContext, sender) {
var downloader = control.createObject("downloader");
}
</script>
Следующий шаг - запустить сеанс загрузки. Для этого с помощью метода open объекта Downloader объявляется URI файла и вызывается метод send для начала загрузки. Далее представлен пример, в котором выполняется загрузка файла фильма movie.wmv:
function handleLoad(control, userContext, sender) {
var downloader = control.createObject("downloader");
downloader.open("GET","movie.wmv");
downloader.send();
}
Для отслеживания процесса загрузки и момента ее завершения понадобится создать соответствующие обработчики событий. Далее представлена та же функция, но в нее были внесены необходимые дополнения:
function handleLoad(control, userContext, sender) {
var downloader = control.createObject("downloader");
downloader.addEventListener("downloadProgressChanged","handleDLProgress");
downloader.addEventListener("completed","handleDLComplete");
downloader.open("GET","movie.wmv");
downloader.send();
}
Теперь можно применить эти обработчики событий. В данном примере событие downloadPro- gressChanged связано с функцией JavaScript handleDLProgress, и событие completed - с функцией JavaScript handleDLComplete. Эти функции представлены в данном фрагменте кода:
function handleDLProgress(sender, args) {
var ctrl = sender.getHost();
var t1 = ctrl.content.findName("txt1");
var v = sender.downloadProgress * 100;
t1.Text = v + "%";
}
function handleDLComplete(sender, args) { alert("Download complete");
}
Примечание Объект Downloader может использоваться только для приложений, размещенных на Вебсервере. В случае попытки его использования со страницы, загружаемой из файловой системы, будет сформирована ошибка.
Программирование элементов UI
XAML предоставляет ряд визуальных элементов для создания UI. Все они были перечислены и подробно рассмотрены в Главах 4 и 5. К элементам UI относятся Canvas, Ellipse, Glyphs, Image, Line, MediaElement, Path, Polygon, Polyline, Rectangle, Run, Shape, TextBlock и другие.
Каждый из этих элементов поддерживает полнофункциональный набор методов и событий, которые будут перечислены и рассмотрены в следующих нескольких разделах.
Кроме того, Silverlight 2 обладает богатым набором элементов управления. Они используются из .NET- кода для создания насыщенных UI, которые подробно обсуждаются в Главе 7, «Элементы управления Silverlight: представления и компоновки».
Методы элементов UI
Элементы UI предоставляют функции, которые могут вызываться из JavaScript. Эти функции позволяют манипулировать элементами UI для создания сложных сценариев взаимодействия с приложением и являются общими для всех элементов UI.
Методы AddEventListener и RemoveEventListener
Метод AddEventListener (Добавить обработчик события) используется для привязки к элементу UI обработчика события во время выполнения. Это полезно для разделения дизайна и разработки: разработчик ничего не добавляет непосредственно в XAML, создаваемый дизайнером, а вводит код обработки события в файл (или блок) JavaScript. События элементов UI, которые могут обрабатываться, обсуждаются в данной главе позже.
Далее представлен пример привязки обработчика события во время выполнения. Здесь добавляется обработчик события, который отслеживает щелчок мыши и определяет, что событие должно обрабатываться функцией JavaScript handleMouse (обработка мыши). Эта функция, как большинство обработчиков событий, принимает два параметра: аргументы отправителя и события. Поскольку обрабатывается событие мыши, данная функция принимает экземпляр объекта MouseEventArgs (Аргументы события мыши), предоставляющий координаты х и у положения мыши в момент формирования события:
<script type="text/javascript">
function handleLoad(control, userContext, sender) {
sender.addEventListener("mouseLeftButtonDown",handleMouse);
function handleMouse(sender, mouseEventArgs) {
alert(mouseEventArgs.getPosition(null).x + ":" + mouseEventArgs.getPosition(null).y);
}
</script>
Вы можете уничтожить подключение во время выполнения, используя метод RemoveEventListener (Удалить обработчик события). В него можно передать либо целочисленный маркер, который был возвращен addEventListener, либо имя события.
Метод findName
Этот метод используется для выполнения поиска именованного объекта в дереве элементов XAML. Он возвращает ссылку на заданный объект, если он существует; в противном случае, он возвратит null. Например, рассмотрим код XAML:
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="400" Width="400">
<TextBlock Canvas.Top="0" x:Name="txt1" Text="TextBlock1" />
<TextBlock Canvas.Top="20" x:Name="txt2" Text="TextBlock2" />
<TextBlock Canvas.Top="40" x:Name="txt3" Text="TextBlock3" /> </Canvas>
В этом коде с помощью свойства x:Name задается три элемента TextBlock: txt1, txt2 и txt3. Теперь с помощью метода findName можно найти именованный узел, получить ссылку на него и, используя эту ссылку, редактировать его. В данном случае, все это выполняется в обработчике события handleLoad (обработка загрузки).
<script type="text/javascript">
function handleLoad(control, userContext, sender) {
var t1 = sender.findName("txt1"); t1.Text = "TextBlock1 has changed"; } </script>
Организация доступа к элементу управления с помощью метода GetHost
Элементы UI предоставляют метод GetHost (Получить хост). Он может использоваться для доступа к элементу управления Silverlight, в котором располагается данный элемент. Это особенно полезно, если требуется запросить у объекта некоторые сведения, например, номер версии.
Организация доступа к родительскому элементу с помощью метода getParent
Возможны случаи, когда требуется обратиться к родителю элемента UI. Получение ссылки на элемент управления Silverlight и затем использование findName для получения родителя является очень неэффективным способом, поэтому предоставляется метод getParent (Получить родителя). В случае успешного выполнения он возвращает ссылку на родительский элемент; в противном случае, возвращается null.
Использование методов GetValue и SetValue
Доступ к обычным свойствам всегда можно организовать с помощью традиционного синтаксиса с использованием точки (объект.имясвойства), но для поддержки присоединенных свойств существует альтернативная методика с использованием метода GetValue (Получить значение). Например, если необходимо обратиться к свойству Canvas.Top, вы не можете сделать это через o6beKm.Canvas.Top. В этом случае должен использоваться синтаксис o6beKm.GetValue("Canvas.Top"). GetValue также может использоваться для доступа к неприсоединенным (простым) свойствам как эквивалент нотации с использованием точки.
Аналогично, можно применять метод SetValue (Задать значение) для задания значения, как простого, так и присоединенного свойства. Этот метод принимает два параметра. Первый - имя свойства, и второй - присваиваемое значение. Рассмотрим пример:
var t1 = ctrl.content.findName("txt1");
t1.setValue("Canvas.Top",20);
Примечание Для доступа и задания значений присоединеных свойств можно также применять синтаксис с квадратными скобками. Например, tl["Canvas.Top"] = 20.
Использование SetFontSource
Элемент TextBlock поддерживает дополнительный метод SetFontSource (Задать источник шрифта), который позволяет использовать в TextBlock загруженный шрифт. Итак, если для отображения текста вы хотите использовать новый шрифт - например, если необходимо поддерживать набор иностранных символов (такой как используется для языков Восточной Азии), - вы можете скачать этот шрифт с помощью объекта Downloader и передать этот объект в метод SetFontSource. После этого TextBlock сможет использовать данный шрифт. Для применения этого метода необходимо обладать правами на распространение шрифта (или его подмножества).
Далее приведен пример использования метода SetFontSource. В данном случае, имеется XAML- документ, описанный с помощью Expression Blend, в котором есть некоторый текст на китайском языке:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Background="White">
<TextBlock x:Name="myTextBlock" Width="152" Height="64"
Canvas.Left="184" Canvas.Top="56" Text="№@^7 " TextWrapping="Wrap" MouseLeftButtonDown="handleIt" /> </Canvas>
В Silverlight 2 имеется стандартный шрифт для этих символов. Если требуется отображать их особым шрифтом, который, вероятно, недоступен на всех пользовательских компьютерах, можно скачать этот шрифт с помощью объекта Downloader. В приведенном выше XAML-коде был описан обработчик события handleIt. Вот эта функция:
// Обработчик события для инициализации и выполнения запроса на скачивание файла шрифта. function handleIt(sender, eventArgs) {
// Извлекаем ссылку на элемент управления. var control = sender.getHost();
// Создаем объект Downloader.
var downloader = control.createObject("downloader");
// Добавляем событие Completed.
downloader.addEventListener("Completed", "onCompleted");
// Инициализируем запрос Downloader. downloader.open("GET", "MyFontName.TTF");
// Выполняем запрос Downloader. downloader.send();
}
Данный код обеспечивает создание объекта загрузки. Этот объект скачивает шрифт и описывает обработчик события onCompleted (по завершении), который будет обрабатывать событие Completed, формируемое по завершении загрузки. Это событие будет задавать в качестве источника шрифта для TextBlock дополнительный шрифт, и тогда Silverlight будет формировать визуальное представление китайских иероглифов, используя этот новый источник шрифта.
// Обработчик события Completed.
function onCompleted(sender, eventArgs) {
// Извлекаем объект TextBlock.
var myTextBlock = sender.findName("myTextBlock");
// Добавляем файлы шрифтов, содержащиеся в загруженном объекте
// в коллекцию шрифтов типа TextBlock.
myTextBlock.setFontSource(sender);
// Задаем свойству FontFamily удобное для пользователя имя шрифта. myTextBlock.fontFamily = "Simhei";
}
События элементов UI
Элементы UI поддерживают ряд событий, которые могут быть ассоциированы с функциями JavaScript либо через AddEventListener для добавления их во время выполнения, либо путем использования соответствующего атрибута XAML для добавления их во время разработки. Например, чтобы ассоциировать событие MouseLeftButtonDown (Нажатие левой кнопки мыши) с помощью JavaScript, применяется метод AddEventListener:
t1.addEventListener("MouseLeftButtonDown", handleMouseDown);
Чтобы ассоциировать событие в XAML, можно использовать атрибут, имя которого аналогично имени рассматриваемого события (например, «MouseLeftButtonDown»). Рассмотрим пример:
<TextBlock Canvas.Top="0" x:Name="txt1" Text="Status" MouseLeftButtonDown="handleMouseDown"/>
Элемент UI поддерживает следующие события:
GotFocus (Получение фокуса) Это событие формируется, когда элемент получает фокус мыши.
KeyDown (Нажатие клавиши) Это событие возникает для элемента, находящегося в фокусе, при нажатии клавиши. Обработчик данного события принимает два параметра. Первый параметр, sender (отправитель), представляет ссылку на объект, сформировавший событие. Второй параметр - объект KeyEventArgs, имеющий ряд собственных свойств. Одно из них -key (клавиша), является целым значением, представляющим нажатую клавишу. Это значение не является характерным для операционной системы, и соответствия между ним и конкретными клавишами можно найти в Silverlight SDK. Другое свойство - platformKeyCode (код клавиши для конкретной ОС) относится к операционной системе. Кроме фактической клавиши, предоставляются Булевы свойства shift и ctrl. Они показывают, были ли нажаты клавиши Shift и Ctrl. (Обратите внимание, что это событие не формируется, когда Silverlight выполняется в полноэкранном режиме.)
KeyUp (Удерживаемая клавиша отпущена) Это событие возникает для элемента, находящегося в фокусе, когда удерживаемая клавиша отпускается. Оно предусматривает все те же два параметра, что и событие KeyDown. (Заметьте, что это событие не формируется, когда Silverlight выполняется в полноэкранном режиме.)
Loaded Это событие формируется, когда содержимое Silverlight загружено в элемент управления Silverlight и проведен его синтаксический разбор, но перед формированием его визуального представления.
LostFocus (Потеря фокуса) Это событие, противоположное GotFocus: оно формируется, когда объект теряет фокус.
MouseEnter (Вход курсора мыши) Это событие формируется, когда курсор мыши входит в границы объекта.
MouseLeave (Выход курсора мыши) Это событие, противоположное MouseEnter: оно формируется, когда курсор мыши покидает область, ограничивающую объект.
MouseLeftButtonDown Это событие возникает при нажатии пользователем левой кнопки мыши, когда курсор находится над элементом UI.
MouseLeftButtonUp (Удерживаемая левая кнопка мыши отпущена) Это событие возникает при отпускании удерживаемой левой кнопки мыши.
MouseMove (Перемещение мыши) Это событие формируется при перемещении курсора по элементу UI.
Реализация перемещения элементов методом «Drag-and-Drop»
С помощью обработчиков событий мыши и методов Silverlight CaptureMouse (Перехватывать события мыши) и ReleaseMouseCapture (Приостановить перехват событий мыши) можно реализовать перемещение элементов методом «drag-and-drop», или перетаскиванием, в Silverlight.
Прежде всего, давайте рассмотрим XAML-документ, содержащий несколько фигур, которые могут перемещаться по холсту методом «drag-and-drop». Обработчики событий мыши (MouseLeftButtonDown, MouseLeftButtonUp и MouseMove) в этих фигурах связаны с функциями onMouseDown, onMouseUp и onMouseMove, соответственно.
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="400" Width="400">
<Ellipse Canvas.Top="0" Height="10" Width="10" Fill="Black"
MouseLeftButtonDown="onMouseDown"
MouseLeftButtonUp="onMouseUp" MouseMove="onMouseMove" />
<Ellipse Canvas.Top="20" Height="10" Width="10" Fill="Black"
MouseLeftButtonDown="onMouseDown" MouseLeftButtonUp="onMouseUp" MouseMove="onMouseMove"/>
<Ellipse Canvas.Top="40" Height="10" Width="10" Fill="Black"
MouseLeftButtonDown="onMouseDown" MouseLeftButtonUp="onMouseUp" MouseMove="onMouseMove"/>
<Ellipse Canvas.Top="60" Height="10" Width="10" Fill="Black"
MouseLeftButtonDown="onMouseDown" MouseLeftButtonUp="onMouseUp" MouseMove="onMouseMove"/>
</Canvas>
Теперь, рассмотрим каждую функцию-обработчик события в отдельности. Сначала обратимся к обработчику события MouseDown (Нажатие кнопки мыши). При перетягивании элемент управления должен «владеть» событиями мыши, таким образом, используется метод captureMouse. Также необходимо запоминать исходные точки перед перетягиванием, эта информация также будет сохраняться обработчиком события. Наконец, с помощью булевой переменной isMouseDown (кнопка мыши нажата) мы обозначаем, что кнопка мыши нажата.
var beginX;
var beginY;
var isMouseDown = false;
function onMouseDown(sender, mouseEventArgs) {
beginX = mouseEventArgs.getPosition(null).x;
beginY = mouseEventArgs.getPosition(null).y;
isMouseDown = true;
sender.captureMouse();
}
Операция «drag-and-drop» заключается в перемещении элемента с помощью мыши. Поэтому, когда возникает событие MouseMove, текущие координаты курсора мыши запоминаются, чтобы затем использоваться для определения того, куда должен быть перемещен элемент.
Текущие х- и у-координаты курсора мыши получаем из объекта mouseEventArgs. В примере выполняется перетягивание объекта Ellipse, т.е. он является sender. Задать его свойства Top и Left можно, добавляя приращение координат к исходным х- и у-координатам.
Также заметьте, что событие onMouseMove будет сформировано независимо от того, выполняется ли перетягивание или нет, поэтому для проверки используется событие isMouseDown. (Помните, оно было задано в предыдущем обработчике события MouseDown.)
function onMouseMove(sender, mouseEventArgs) {
if (isMouseDown == true)
{
var currX = mouseEventArgs.getPosition(null).x;
var currY = mouseEventArgs.getPosition(null).y;
sender["Canvas.Left"] += currX - beginX;
sender["Canvas.Top"] += currY - beginY;
beginX = currX;
beginY = currY;
} }
Наконец, когда кнопка мыши отпущена, будет приостановлено отслеживание событий мыши и переменная isMouseDown возвращена в исходное состояние. Эллипс останется на новом месте.
function onMouseUp(sender, mouseEventArgs) {
isMouseDown = false;
sender.releaseMouseCapture();
}
На рис. 6-4 показано 4 эллипса, для которых активирована возможность перемещения методом «drag- and-drop». На рис. 6-5 показано размещение этих эллипсов после перетягивания.
РИС. 6 4 Четыре эллипса, для которых активирована возможность перемещения методом «drag and drop».
РИС. 6 5 Перемещение эллипсов методом «drag and drop».
Заключение
В данной главе рассмотрена объектная модель Silverlight и возможность ее использования при программировании на JavaScript. Вы узнали, как разместить элемент управления Silverlight в браузере, включая то, как инициализировать его и задать исходное состояние с помощью его модели свойств. Было показано, как элемент управления может быть настроен с помощью контекста и специальных параметров. Также представлена полная поддерживаемая им модель свойств, методов и событий. Кроме того, вы научились реализовывать собственный обработчик событий и использовать основной стандартный обработчик событий.
Мы рассмотрели, как добавлять в элемент управления внешнее содержимое с помощью объекта Downloader, и как перехватывать события, которые он формирует, для обеспечения обратной связи о процессе загрузки. Вы познакомились с предлагаемыми XAML элементами UI, с предоставляемыми ими методами, событиями и свойствами и возможностями их программирования.
Теперь, когда вы познакомились с Silverlight и его возможностями, пришло время переходить на следующий уровень и изучить богатый и мощный набор элементов управления и модель программирования, предлагаемые Silverlight 2. И начнем мы это в следующей главе с базового набора элементов управления Silverlight.
Глава 7
Элементы управления Silverlight: представления и компоновки
Silverlight 2 поставляется с двумя основными сборками, в которых содержатся элементы управления для использования в ваших приложениях. Это core controls (основные элементы управления) и extended controls (дополнительные элементы управления). Они являются дополнением к пространству имен Sys- tem.Windows.Forms, содержащему базовые элементы управления.
В данной главе будут представлены следующие основные элементы управления и описаны возможности их использования в Silverlight:
Button
CheckBox
HyperlinkButton
Image
ListBox
RadioButton
TextBlock
TextBox
Мы рассмотрим специальные свойства, методы и события, предоставляемые каждым из этих элементов управления, а также свойства, методы и события, общие для всех элементов управления. Изложенная в данной главе информация не должна быть единственным источником при работе с любым из данных элементов управления, но здесь приводится достаточно базовых сведений, чтобы подтолкнуть вас и помочь начать самостоятельные эксперименты с ними.
Элемент управления Button
В Silverlight кнопка реализуется с помощью элемента управления Button. Кнопка реагирует на ввод пользователя с таких устройств ввода, как мышь, клавиатура или стилус, формируя событие Click (Щелчок). Условия формирования кнопкой события Click могут быть настроены несколькими способами. Они задаются свойством ClickMode (Режим щелчка), которое может принимать значения Hover (Наведение), Press (Нажатие) и Release (Отпустить). Эти значения определяют момент формирования события Click. В первом случае, Hover, оно формируется при наведении курсора мыши на кнопку. Во втором случае, Press, оно формируется при нажатии кнопки мыши в момент, когда курсор находится на Button. В третьем случае, Release, это событие возникает, когда пользователь нажал и отпустил кнопку мыши при наведенном на Button курсоре.
<Canvas x:Name="LayoutRoot" Background="White">
<Button x:Name="b1" ClickMode="Hover"
Content="Button1" Click="Button Click"></Button>
<Button x:Name="b2" Canvas.Top="40" ClickMode="Press"
Content="Button2" Click="Button Click"></Button>
<Button x:Name="b3" Canvas.Top="80" ClickMode="Release" Content="Button3" Click="Button Click"></Button>
</Canvas>
Как видите, для всех этих кнопок определен обработчик события Click и одна и та же функция, Button Click, для каждой из них.
Вот код обработки этого события на языке С#:
private void Button Click(object sender, RoutedEventArgs e) {
Button b = (Button)sender; string strTest = b.Name;
}
Этот код построен по типичному шаблону обработчика события. Он принимает объект отправителя, содержащий ссылку на элемент управления, который сформировал событие (в данном случае, одну из кнопок), и набор аргументов, связанных с этим событием (RoutedEventArgs), который включает метаданные о событии.
Вы заметите, что в данном экземпляре объявлен только один обработчик события. Это делает код аккуратным и понятным. Конечно, вы захотите выяснить, какой из элементов сформировал событие, для этого пригодится отправитель.
Отправитель - это объект типа Object, поэтому чтобы извлечь из него характерные для кнопок свойства, его просто приводят к типу Button. В данном случае, после приведения этого объекта к типу Button мы можем получить его имя. Если запустить приложение сейчас, можно будет увидеть три кнопки и то, как свойство ClickMode, ассоциированное с каждой из этих кнопок, обусловливает их разное поведение!
Дополнительным очень полезным свойством является IsEnabled (Активирован). Если ему задано значение false, кнопка отображается на экране, но выглядит неактивной и не формирует события.
Надпись на кнопке задается свойством Content (Содержимое). В качестве его значения может быть задан простой текст, который будет отображаться как название кнопки. Однако Button также является контейнером, поэтому ее содержимое можно настроить с помощью XAML.
Вот пример кнопки (ужасно некрасивой), содержимое которой описано с помощью XAML:
<Button x:Name="b1" Click="Button Click" Width="100" Height="100">
<Canvas>
<Ellipse Fill="Green" Width="50" Height="50"></Ellipse>
<TextBlock Text="Hello"></TextBlock>
</Canvas>
</Button>
Как видите, это обеспечивает чрезвычайную гибкость в представлении кнопок, что позволяет создавать разнообразные кнопки в Веб-приложениях, например, такие как можно увидеть на панели инструментов Microsoft Office 2007.
Элемент управления CheckBox
CheckBox - это элемент управления, предоставляющий пользователю опцию для выбора. Обычно он представляется в виде прямоугольника, в котором пользователь может установить или убрать флажок. Он используется, когда имеется ряд опций на выбор и можно выбрать несколько из них.
При установлении флажка CheckBox формирует событие Checked (Установлен), при снятии флажка формируется событие Unchecked (Снят). Также CheckBox формирует событие Click при каждом щелчке по нему. Аналогично элементу управления Button, CheckBox имеет свойство ClickMode, которому может быть задано значение Hover, Press или Release, определяющее условия формирования события.
CheckBox может быть флажком с тремя состояниями (поддерживается неопределенное состояние). Это определяется свойством IsThreeState (Три состояния). Если это состояние включено, и пользователь переводит CheckBox в неопределенное состояние, свойству IsChecked присваивается значение null.
Значение CheckBox можно получить с помощью свойства IsChecked. Необходимо быть осторожным с тем, когда CheckBox находится в режиме с тремя состояниями, поскольку, если CheckBox в неопределенном состоянии, свойство IsChecked возвращает значение null.
Аналогично элементу управления Button, CheckBox является контейнером. Он имеет свойство Content, с помощью которого можно задавать простую строку текста, которая будет отображаться как надпись
рядом с флажком, или можно разместить XAML-код в дочернем теге <Content>, для получения более насыщенного эффекта.
Вот пример каждого из вариантов:
<StackPanel>
<CheckBox Checked="CheckBox Checked" Unchecked="CheckBox Unchecked" IsThreeState="True" Content="Test1">
</CheckBox>
<CheckBox Checked="CheckBox Checked" Unchecked="CheckBox Unchecked" IsThreeState="True">
<CheckBox.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="The Caption"></TextBlock>
<Image Source="..."/>
</StackPanel>
</CheckBox.Content>
</CheckBox>
</StackPanel>
При обработке событий Clicked, Checked и Unchecked, в качестве sender будет выступать объект, который необходимо привести к типу CheckBox, чтобы получить доступ к свойствам флажка.
Ниже приведен пример:
private void CheckBox Checked(object sender, RoutedEventArgs e) {
CheckBox c = (CheckBox)sender;
bool b = (bool)c.IsChecked;
}
private void CheckBox Unchecked(object sender, RoutedEventArgs e) {
CheckBox c = (CheckBox)sender; bool b = (bool)c.IsChecked;
}
Элемент управления HyperlinkButton
HyperlinkButton (Гиперссылка) обеспечивает на странице элемент с возможностью щелчка по нему для перехода по URI, заданному свойством NavigateUri (Uri перехода).
Например:
<HyperlinkButton Content="Microsoft"
NavigateUri="http://www.microsoft.com" />
HyperlinkButton - это элемент управления с содержимым, т.е. он может иметь простое свойство Content, содержащее текст, который будет отображаться для гиперссылки, или его содержимое может быть намного более насыщенным и более привлекательным.
Например, если вы хотите, чтобы гиперссылка выглядела как рисунок, это очень просто реализовать, используя дочерний элемент <Hyperlink.Content>, в котором может располагаться изображение. Например:
<HyperlinkButton NavigateUri="http://www.silverlight.net" >
<HyperlinkButton.Content>
<Image Source="sl.jpg"/>
</HyperlinkButton.Content>
</HyperlinkButton>
Теперь, когда приложение будет запущено, вы получите изображение, щелчок по которому обеспечит переход по заданному URL.
Свойство TargetName определяет, где будет открываться содержимое, располагающееся по заданному URL. Для вывода на экран содержимого URL доступны следующие опции:
blank Открывает новое окно браузера без имени.
self Замещает текущую HTML-станицу новым содержимым. Если HTML-станица отображается во фрейме, замещается только содержимое рамки.
top Замещает текущую HTML-станицу новым содержимым. Даже если HTML-станица отображается во фрейме, меняется содержимое всего окна браузера.
parent Замещает всю HTML-станицу.
Если используется фреймовая структура, можно задавать имя используемого фрейма.
Вот пример, определяющий, что когда пользователь выбирает этот элемент управления, должно открываться новое окно браузера:
<Grid x:Name="LayoutRoot" Background="White">
<HyperlinkButton NavigateUri="http://www.silverlight.net"
TargetName=" blank" >
<HyperlinkButton.Content>
<Image Source="sl.jpg"/>
</HyperlinkButton.Content>
</HyperlinkButton>
</Grid>
Обратите внимание, что событие Click для HyperlinkButton будет формироваться перед переходом по заданному URI. Это может быть очень полезным, потому что обеспечивает завершение любой предварительной обработки перед загрузкой нового содержимого.
Далее рассмотрим пример с использованием события Click. Обратите внимание, что NavigateUri задано значение http://www.microsoft.com, но фактически страница переходит по адресу http://www.silverlight.net, потому что Click выполняется раньше перехода и меняет значение NavigateUri.
Во-первых, рассмотрим XAML:
<HyperlinkButton NavigateUri="http://www.microsoft.com"
TargetName=" blank" Click="HyperlinkButton Click" >
<HyperlinkButton.Content>
<Image Source="sl.jpg"/>
</HyperlinkButton.Content>
</HyperlinkButton>
И теперь обратим внимание на выделенный С#-код, в котором обрабатывается событие HyperlinkButton Click:
private void HyperlinkButton Click(object sender, RoutedEventArgs e) {
HyperlinkButton h = (HyperlinkButton)sender;
string strTest = h.NavigateUri.AbsoluteUri;
if (strTest == "http://www.microsoft.com/") {
h.NavigateUri = new Uri("http://www.silverlight.net");
}
}
При выполнении этого кода вы увидите, что несмотря на то, что для HyperlinkButton определен один URL, в ходе обработки события Click ему будет задан другой URL, и переход будет выполнен по новому URL.
Элемент управления Image
Элемент управления Image используется для отображения изображений. Он может принимать форматы файлов .bmp, jpg и .png. Путь к изображению задается свойством Source. Например:
<Image Source="sl.jpg" />
Примечание Если в коде дается ссылка на неподдерживаемый формат, или Source задан несоответствующим образом, будет сформировано событие ImageFailed (Ошибка изображения).
Если фактические размеры изображения отличаются от заданных для элемента управления Image (т.е. если имеется элемент Image размером 100 х 100 и в него загружается jpg-изображение 2000 х 2000 пикселов), управлять поведением отображения можно с помощью свойства Stretch. Оно может принимать следующие значения:
Fill Изменяет размеры изображения соответственно размерам области вывода, используя независимое масштабирование по осям х и у.
Uniform Изменяет размеры изображения так, чтобы оно поместилось в элемент управления Image , но при этом сохраняет пропорции изображения.
UniformToFill Изменяет размеры изображения так, чтобы оно полностью заполнило область вывода, обрезая его в случае необходимости.
None Отображает изображение как есть, что приводит к его обрезке, если оно не помещается в элемент Image.
Часто изображение необходимо задать не во время разработки, указывая URI в XAML-коде, а определить его во время выполнения, возможно, как результат обращения к базе данных или чего-либо подобного. В таких случаях в качестве источника для элемента управления Image используется класс BitmapImage (пространства имен System.Windows.Media.Imaging). Далее приведен пример того, как это делается.
Сначала XAML:
<Image x:Name="theImage"/>
Затем в файле выделенного C# кода необходимо подключить пространство имен:
using System.Windows.Media.Imaging;
И вот код, который обеспечит загрузку изображения по URL при загрузке страницы:
public Page(){
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page Loaded);
}
void Page Loaded(object sender, RoutedEventArgs e) {
Uri uri = new Uri("sl.jpg",UriKind.Relative); theImage.Source = new BitmapImage(uri);
}
В данном случае создается новый объект Uri с использованием пути к изображению. Второй параметр в конструкторе - опция, определяющая, как должен вычисляться Uri. Используемый URI может быть относительным (в этом случае поиск заданного ресурса будет вестись в том же каталоге, в котором располагается компонент), абсолютным (в этом случае поиск заданного ресурса будет вестись напрямую, поэтому местоположение должно указываться с применением синтаксиса http://cepeep/pecypc) или комбинацией первых двух.
Когда Uri создан, он может использоваться для создания нового BitmapImage, который определяется как источник для элемента управления Image.
Элемент управления ListBox
Элемент управления ListBox используется для представления содержимого в виде упорядоченного списка. Это достаточно гибкий элемент управления, так что элементы списка могут создаваться из содержимого любого типа, но обычно список образуется элементами ListBoxItem (Элемент списка), как в следующем примере:
<ListBox x:Name="theList" SelectionChanged="ListBox SelectionChanged">
<ListBoxItem Content="1"/>
<ListBoxItem Content="2"/>
<ListBoxItem Content="3"/>
<ListBoxItem Content="4"/>
<ListBoxItem Content="5"/>
</ListBox>
Возможность выбора элементов, образующих ListBox, пользователем реализуется посредством события SelectionChanged (Выбранный элемент изменен) и свойства SelectedItem (Выбранный элемент). В предыдущем фрагменте XAML-кода обработкой события SelectionChanged занимался обработчик метода ListBox SelectionChanged. Вот код:
private void ListBox SelectionChanged(
object sender, SelectionChangedEventArgs e) {
ListBoxItem x = theList.SelectedItem as ListBoxItem; string strTest = x.Content.ToString();
}
Обратите внимание, что свойство SelectedItem возвращает object, а не ListBoxItem, потому что (как упоминалось ранее) в ListBox могут размещаться разные типы содержимого. Поэтому, в данном случае, SelectedItem приводится к ListBoxItem.
Помните, что в ListBox может располагаться разное содержимое. Далее приведен пример, когда ListBox включает составные элементы, образованные компонентами StackPanel, каждый из которых содержит Rectangle, Image и TextBlock.
<ListBox x:Name="theList" SelectionChanged="ListBox SelectionChanged">
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Black" Height="100" Width="100"></Rectangle>
<Image Height="100" Width="100" Source="sl.jpg"/>
<TextBlock Text="Item 1"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Black" Height="100" Width="100"></Rectangle>
<Image Height="100" Width="100" Source="sl.jpg"/>
<TextBlock Text="Item 2"></TextBlock>
</StackPanel>
</ListBox>
Как будет выглядеть этот ListBox, можно увидеть на рис. 7-1.
РИС. 7 1 ListBox со сложными элементами.
Содержимое таких сложных элементов, как представленью здесь, можно получить следующим образом: с помощью SelectedItem получить контейнер (в данном случае, StackPanel) и затем извлечь из него необходимое содержимое. Например:
StackPanel s = theList.SelectedItem as StackPanel;
TextBlock t = s.Children[2] as TextBlock;
string strTest = t.Text;
Элемент управления RadioButton
Элемент управления RadioButton, подобно CheckBox используется для фиксирования выбора пользователя. Однако отличается от CheckBox тем, что обычно применяется в ситуациях, когда пользователь должен выбрать единственный вариант из ряда предлагаемых опций.
Один из способов управления набором опций с возможностью единственного выбора - задать элементы управления RadioButton, соответствующие опциям, как элементы одного уровня в контейнере. Рассмотрим пример:
<StackPanel Orientation="Vertical" Background="Yellow">
<RadioButton Content="Option 1" IsChecked="true" ></RadioButton>
<RadioButton Content="Option 2"></RadioButton>
<RadioButton Content="Option 3"></RadioButton>
<RadioButton Content="Option 4"></RadioButton>
<StackPanel Orientation="Vertical" Background="White">
<RadioButton Content="Option 5" IsChecked="true"></RadioButton>
<RadioButton Content="Option 6"></RadioButton>
<RadioButton Content="Option 7"></RadioButton>
<RadioButton Content="Option 8"></RadioButton>
</StackPanel>
</StackPanel>
В данном XAML-коде имеется два контейнера StackPanel, один из которых расположен в другом. Первый контейнер содержит опции 1, 2, 3, и 4; второй - опции 5, б, 7 и 8. В результате, пользователь может выбрать только одну из опций от 1 до 4 и только одну из опций от 5 до 8. Как это работает представлено на рис. 7-2.
РИС. 7 2 Использование элемента управления RadioButton.
Кроме того, опции можно сгруппировать, задавая для каждого RadioButton свойство GroupName (Имя группы). В предыдущем примере в StackPanel располагались опции 1 -4, и Silverlight разрешал пользователю приложения выбирать только одну из них.
Если потребовалось бы разделить этот набор опций на две группы, чтобы пользователь мог выбирать одну из опций 1 и 2, и одну из опций 3 и 4, вместо контейнера можно было бы использовать группы RadioButton.
<StackPanel Orientation="Vertical" Background="Yellow">
<RadioButton Content="Option 1" IsChecked="true"
GroupName="G1" ></RadioButton>
<RadioButton Content="Option 2" GroupName="G1" />
<RadioButton Content="Option 3" GroupName="G2" />
<RadioButton Content="Option 4" GroupName="G2" />
<RadioButton Content="Option 5" GroupName="G3"
IsChecked="true" />
<RadioButton Content="Option 6" GroupName="G3" />
<RadioButton Content="Option 7" GroupName="G3" />
<RadioButton Content="Option 8" GroupName="G3" />
</StackPanel>
Как это выглядит в действии, можно увидеть на рис. 7-3.
РИС. 7 3 Использование элемента управления RadioButton с группами.
Аналогично элементам управления Button и CheckBox, RadioButton имеет свойство ClickMode, определяющее, какое действие пользователя приводит к формированию события Click. Его возможными значениями являются: Hover, при котором событие формируется уже от того, что пользователь проводит курсором по элементу управления; Press, при котором событие формируется по щелчку кнопки мыши по элементу управления; и Release, при котором кнопка мыши должна быть нажата, а потом отпущена, при нахождении курсора мыши на кнопке выбора. Также аналогично элементу управления CheckBox, состояние выбора отдельного RadioButton может быть проверено с помощью свойства IsChecked.
Элемент управления TextBlock
Элемент управления TextBlock используется в приложениях Silverlight для отображения текста.
В самом простом случае, для отображения текст достаточно применить TextBlock с заданным свойством Text. Например:
<TextBlock Text="1234"></TextBlock>
Размер текста можно менять, задавая свойство FontSize (в пикселах). Используемый шрифт определяется свойством FontFamily например, XAML-код для вывода текста шрифтом Arial Black размером 20 выглядел бы так:
<TextBlock Text="1234" FontFamily="Arial Black" FontSize="20" />
Свойство FontStyle определяет, как будет выведен текст, курсивом или обычным шрифтом. Чтобы текст отображался курсивом, свойству FontStyle задается значение Italic:
<TextBlock Text="1234" FontFamily="Arial Black"
FontSize="20" FontStyle="Italic"></TextBlock>
Чтобы использовать обычный шрифт, можно задать свойству FontStyle значение Normal или просто оставить его незаданным.
Разрывы строк и использование разных шрифтов для отображения текста реализуется с помощью подэлементов TextBlock: <LineBreak> и <Run>. Как следует из его имени, <LineBreak> создает разрывы в тексте с переносом остального текста на новую строку.
Однако TextBlock не является элементом управления для представления содержимого, как некоторые из элементов управления, которые были представлены в данной главе ранее. Поэтому если необходимо представить текст иначе, чем все остальное содержимое свойства Text, используется элемент управления Run:
<TextBlock Width="400" Text="My first text">
<LineBreak/>
<Run>My Second Text</Run>
<LineBreak/>
<Run>My Third Text</Run>
<LineBreak/>
<Run>My Fourth Text</Run>
</TextBlock>
Замечательное качество элемента управления Run в том, что он поддерживает те же свойства шрифта, размера, цвета и т.д., что и TextBlock. Таким образом, он предоставляет тот же уровень управления его содержимым, что и TextBlock. Это означает, что текст TextBlock и текст, отображаемый с помощью Run, полностью согласованы.
Одно из отличий Silverlight 2 от Silverlight 1.0 в том, что TextBlock в Silverlight 2 больше не ограничен девятью шрифтами, встроенными в Silverlight. Silverlight 2 руководствуется правилами замещения системных шрифтов, поэтому если шрифт представлен в системе, текст будет отображен этим шрифтом; если шрифт недоступен в системе, будет использоваться резервный шрифт, определенный операционной системой.
Итак, рассмотрим пример некоторого XAML, созданного для отображения TextBlock, в котором содержится текст, представленный шрифтом Webdings, а также некоторый текст на китайском языке и иврите:
<StackPanel Orientation="Vertical" Background="Yellow">
<TextBlock Width="400" Text="My first text">
<LineBreak/>
<Run FontFamily="Webdings">My Second Text</Run>
<LineBreak/>
<Run>®ft№AS№&W</Run>
<LineBreak/>
<Run>T3nn лл'эп лтр'лррклш^л лт^тлр! ц'т
</Run>
</TextBlock>
</StackPanel>
Как это выглядит, можно увидеть на рис. 7-4. Данная новая возможность абсолютно упростила разработку Silverlight-приложений с многоязычным пользовательским интерфейсом.
РИС. 7 4 Использование специальных шрифтов в Silverlight.
Элемент управления TextBox
Элемент управления TextBox обеспечивает пользователям область для ввода текста. В самой простой форме TextBox предоставляет область, в которую пользователь может ввести одну строку текста. Например:
<StackPanel>
<TextBox />
<TextBox />
</StackPanel>
Это очень простой StackPanel, содержащий два элемента управления TextBox. На рис. 7-5 показано, как это будет выглядеть. В текстовые поля введены некоторые значения для демонстрации того, как пользователь мог бы заполнять TextBox в приложении.
РИС. 7 5 Простые элементы управления TextBox.
Чтобы эти элементы управления TextBox могли принимать многостроковый ввод, понадобится сделать две вещи. Во-первых, необходимо задать высоту или поместить их в контейнер, обеспечивающий им нестандартную высоту. Затем свойству AcceptsReturn (Допускаются символы возврата каретки) потребуется задать значение True, благодаря чему эти элементы управления смогут принимать символы возврата каретки. Что будет получено в результате, можно увидеть на рис. 7-6.
рис. 7 6 Элементы управления TextBox настроенные для многострокового ввода текста пользователем.
Свойство Text такого TextBox будет возвращать объект типа String, в котором каждая строка будет отделена символом '\r'.
Каждый раз при изменении текста в TextBox формируется событие TextChanged (Текст изменен). Заметьте, это происходит после каждого нажатия клавиши, поэтому если необходимо отслеживать все изменения, как одно событие, возможно, лучше будет перехватывать событие LostFocus и работать с текстом из него.
Элементы управления TextBox автоматически принимают ввод через Редактор метода ввода (Input Method Editor, IME) для поддержки иностранных языков. Если в системе установлена поддержка различных клавиатур и языков , IME будет работать в Silverlight 2 точно так же, как для любого другого элемента управления HTML. Это можно видеть на рис. 7-7, где в одном TextBox используются разные языки IME - изумительно!
РИС. 7 7 Элемент управления TextBox с текстом на разных языках.
В данном случае, свойство Text возвратит строку с использованием кодировки Unicode со всеми символами и V' в качестве разделителей строк.
Элементы управления TextBox позволяют выбирать подстроки Text и также обеспечивают возможность настроить то, как выглядит выбранный текст. Для задания или возвращения выбранного в настоящий момент текста используется свойство SelectedText (Выбранный текст). Начало выбранной под-
строки можно получить с помощью свойства SelectionStart (Начало выбранной подстроки), ее длину - с помощью свойства SelectionEnd (Конец выбранной подстроки). При любом изменении выбора подстроки формируется событие SelectionChanged (Выбранный элемент изменен). Рассмотрим следующий пример:
Во-первых, XAML-код:
<TextBox Height="100" AcceptsReturn="True"
Text="ABCDEFGHIJKLMNOPQRSTUVWXYZ" SelectionChanged="TextBox SelectionChanged">
</TextBox>
Здесь определяется событие SelectionChanged, для которого определен обработчик события TextBox SelectionChanged. Рассмотрим:
private void TextBox SelectionChanged(object sender, RoutedEventArgs e) {
TextBox t = sender as TextBox;
int st = t.SelectionStart;
int ln = t.SelectionLength; string strT = t.SelectedText;
}
В данном случае, переменная st типа int содержит индекс начального символа выбранной подстроки (отсчитываемой от нуля), ln - длина выбранной подстроки, и strT- строка, содержащая выбранную подстроку. Итак, например, если выбрана подстрока, как показано на рис. 7-8, st будет равна 9, ln равна 8, и strT будет равна JKLMNOPQ.
РИС. 7 8 Выбор подстроки текста.
Также в TextBox можно использовать разные шрифты, точно так же как это делается в TextBlock. Подробно об этом рассказывалось в разделе «Элемент управления TextBlock» в этой главе ранее.
Общие свойства, события и методы
В предыдущих разделах были подробно рассмотрены базовые элементы управления Silverlight с акцентированием внимания на их особых свойствах, методах и событиях. Однако существует ряд функциональных возможностей, общих для всех или большинства этих элементов управления, и вы должны познакомиться с ними, прежде чем начнете разработку собственных приложений Silverlight.
Обработка фокуса
Элементы, которые могут принимать ввод, формируют события GotFocus и LostFocus. Это важное дополнение в Silverlight 2, потому что в Silverlight 1.0 только корневой элемент управления Silverlight мог принимать эти события.
События GotFocus и LostFocus формируются каждый раз, когда пользователь переходит на или покидает элемент управления, либо наводя курсором мыши, либо используя клавишу Tab. Оба этих события являются событиями, передающимися вверх по иерархии (bubbling events). Это означает, что элемент управления принимает событие, но не обрабатывает его. Событие передается его родителю и так далее вверх по иерархии до тех пор, пока не будет перехвачено обработчиком события.
Обработка событий мыши
Элементы управления Silverlight формируют несколько событий мыши:
MouseEnter Это событие формируется при входе курсора мыши в область отображения элемента управления.
MouseLeave Это событие формируется, когда курсор мыши покидает область отображения элемента управления.
MouseLeftButtonDown Это событие формируется при нажатии пользователем левой кнопки мыши, когда курсор находится над элементом управления.
MouseLeftButtonUp Это событие формируется при отпускании удерживаемой левой кнопки мыши, когда курсор находится над элементом управления.
MouseMove Это событие формируется при перемещении курсора по элементу управления.
Кроме перечисленных событий для обеспечения максимального контроля могут использоваться методы CaptureMouse и ReleaseMouseCapture. Когда для элемента управления вызывается метод CaptureMouse , все события мыши будут направляться в этот элемент управления независимо от того, находится ли курсор мыши в его границах или нет. Метод ReleaseMouseCapture, как следует из его имени, возвращает механизм перехвата событий в нормальное состояние. Эти методы очень полезны для реализации перемещения объектов методом «drag-and-drop». Рассмотрим пример.
Использование событий мыши для реализации перемещения объектов методом «Drag-and-drop»
Ниже представлен XAML-документ, обеспечивающий отрисовку эллипсов на странице. Обратите внимание, что для всех эллипсов определены одни и те же обработчики событий мыши:
<UserControl x:Class="MouseEvents.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontFamily="Trebuchet MS" FontSize="11"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Canvas Width="400" Height="300" Background="Wheat">
<Ellipse Canvas.Top="0" Fill="Black" Width="20" Height="20" MouseLeftButtonDown="Ellipse MouseLeftButtonDown" MouseLeftButtonUp="Ellipse MouseLeftButtonUp" MouseMove="Ellipse MouseMove" />
<Ellipse Canvas.Top="40" Fill="Black" Width="20" Height="20" MouseLeftButtonDown="Ellipse MouseLeftButtonDown" MouseLeftButtonUp="Ellipse MouseLeftButtonUp" MouseMove="Ellipse MouseMove" />
<Ellipse Canvas.Top="80" Fill="Black" Width="20" Height="20" MouseLeftButtonDown="Ellipse MouseLeftButtonDown" MouseLeftButtonUp="Ellipse MouseLeftButtonUp" MouseMove="Ellipse MouseMove" />
<Ellipse Canvas.Top="120" Fill="Black" Width="20" Height="20" MouseLeftButtonDown="Ellipse MouseLeftButtonDown" MouseLeftButtonUp="Ellipse MouseLeftButtonUp" MouseMove="Ellipse MouseMove" />
</Canvas>
</Grid>
</UserControl>
Теперь рассмотрим выделенный код. Во-первых, нам необходимы переменные для сохранения х и у координат курсора мыши в момент начала перемещения методом «drag-and-drop» и еще одна переменная для обозначения того, удерживается ли кнопка мыши в настоящий момент.
double beginX = 0;
double beginY = 0; bool isMouseDown = false;
Если курсор находится над любой из кнопок, и нажимается кнопка мыши, выполняется функция Ellipse MouseLeftButtonDown.
private void Ellipse MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Ellipse b = sender as Ellipse;
beginX = e.GetPosition(this).X;
beginY = e.GetPosition(this).Y;
isMouseDown = true; b.CaptureMouse();
}
Отправителем является универсальный объект, поэтому, прежде всего, необходимо привести его к типу эллипс. После этого используем аргумент MouseButtonEventArgs (Аргументы событий кнопки мыши) для получения текущих координат х и у и задания их как начальных значений. Затем, поскольку кнопка мыши удерживается нажатой, ее перемещения должны отслеживаться, поэтому переменной isMouseDown задается значение True. Наконец, мы хотим отслеживать события мыши для этого эллипса (любого из заданных) таким образом, чтобы даже если пользователь уводит курсор мыши с этого эллипса, он продолжал получать события.
Итак, поскольку пользователь двигает мышью, должно формироваться событие MouseMove. Оно обрабатывается функцией-обработчиком события Ellipse MouseMove:
private void Ellipse MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown)
{
Ellipse b = sender as Ellipse;
double currX = e.GetPosition(this).X;
double currY = e.GetPosition(this).Y;
b.SetValue(Canvas.LeftProperty, currX); b.SetValue(Canvas.TopProperty, currY); } }
Это событие будет формироваться при прохождении курсора мыши по эллипсу, независимо оттого, выполняется ли перемещение этого эллипса или нет. Но нас интересуют только варианты, когда пользователи перетягивает эллипс, а это, по определению, означает, что переменная isMouseDown имеет значение True. В этом случае мы получаем текущие координаты курсора мыши и используем их для задания присоединенных свойств Top и Left эллипса. В результате будет создан эффект перетягивания эллипса соответственно координатам курсора мыши.
Наконец, при отпускании удерживаемой кнопки мыши формируется событие MouseLeftButtonUp, перехватываемое функцией Ellipse MouseLeftButtonUp:
private void Ellipse MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Ellipse b = sender as Ellipse;
isMouseDown = false;
b.ReleaseMouseCapture();
}
Это обеспечивает возвращение переменной isMouseDown к исходному значению, и элемент управления, отслеживающий события мыши, прекращает делать это. В результате восстанавливается обычное
поведение мыши, а эллипс остается передвинутым в другое место. Все это в действии можно увидеть на рис. 7-9 и 7-10.
На рис. 7-9 показано, как приложение выглядит в исходном состоянии. Если пользователь наведет курсор мыши на любой из эллипсов и затем нажмет кнопку мыши и продолжит перемещение, эллипс начнет двигаться за курсором. Таким образом, пользователь может менять расположение эллипсов на экране методом «drag-and-drop». Это представлено на рис. 7-10
Кроме событий мыши, существуют события клавиатуры, которые могут формироваться для многих элементов управления. Подробнее об этом рассказывается в следующем разделе.
РИС. 7 9 Приложение, реализующее перемещение объектов методом «Drag and drop».
РИС. 7 10 Перемещение элементов управления методом «drag and drop».
Использование клавиатуры
Кроме элемента управления TextBox, который предлагает пользователю возможность ввода текста с клавиатуры, многие элементы управления формируют события KeyDown и KeyUp, которые могут использоваться для перехвата ввода с клавиатуры. Событие KeyDown формируется при каждом нажатии клавиши, когда фокус находится на элементе. Функция-обработчик этого события принимает универсальный объект-отправитель и объект KeyEventArgs, который может использоваться для извлечения информации о нажатой клавише. Он имеет свойство key, возвращающее объект Key с информацией о клавише. Это платформонезависимое свойство, поэтому оно лучше всего подходит для использования
в приложениях Silverlight. KeyEventArgs предлагает также еще одно свойство, PlatformKeyCode (Код клавиши на данной платформе), которое может использоваться со свойством key для получения кодов клавиш, используемых в конкретной операционной системе.
Кроме того, статическое свойство Keyboard.Modifers возвращает значение ModifierKeys (Модифицирующие клавиши), которое может использоваться для определения того, какая из модифицирующих клавиш (Alt, Control, Shift, Windows или Apple) была нажата. Просто используйте побитовое И на возвращенное значение свойства для проверки искомой модифицирующей клавиши (например, Shift).
Заключение
В данной главе были представлены некоторые базовые элементы управления Silverlight (Button, CheckBox, HyperlinkButton, Image, ListBox, RadioButton, TextBlock и TextBox) и показано, как они могут использоваться для создания приложений Silverlight. Кроме того, дан обзор свойств, методов и событий, общих для всех элементов управления, что поможет вам начать использовать элементы управления представления и компоновочные элементы управления в Silverlight.
В следующей главе рассматриваются расширенные элементы управления Silverlight и рассказывается, как они могут использоваться для расширения круга возможностей ваших приложений.
Глава 8
Элементы управления Silverlight: расширенные элементы управления
В Главе 7, «Элементы управления Silverlight: представления и компоновки», был представлен набор элементов управления Silverlight и проведен обзор таких основных элементов управления, как TextBox и CheckBox. Однако для современных насыщенных интерактивных приложений (RIAs) необходимы намного более сложные элементы управления, такие как таблицы с данными, календари и т.д. В данной главе вы научитесь использовать эти элементы управления в своих Silverlight приложениях. Некоторые из этих элементов управления, такие как DataGrid (Таблица с данными), заслуживают отдельной книги, поэтому не ожидайте получить здесь полный API этих элементов управления. Однако в данной главе предоставлено достаточно сведений об этих расширенных элементах управления, которые позволят понимать, что происходит при их использовании. Располагая этими знаниями, можно продолжать экспериментировать и изучать эти элементы управления уже самостоятельно.
Элемент управления DataGrid
Элемент управления DataGrid разработан для облегчения задачи по отображению данных в формате таблицы. Это сетка данных, а не просто сетка, потому что она может быть связана с источником данных. Более подробно отображение данных рассматривается в Главе 10, «Создание взаимодействующих с сервером приложений в Silverlight», но чтобы вы могли осознать мощь DataGrid, некоторые из методик работы с ним будут использованы здесь.
При добавлении элемента управления DataGrid в окно редактирования XAML, получаем такой XAML- код:
<UserControl
xmlns:my="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data" x:Class="SilverlightApplication1.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<my:DataGrid></my:DataGrid>
</Grid>
</UserControl>
Пока что DataGrid не может делать практически ничего, поэтому добавим в него два свойства: имя и AutoGenerateColumns (Столбцы формируются автоматически), которое обеспечит автоматическое создание необходимых столбцов данных при привязке сетки к DataGrid. Вот как выглядит XAML для DataGrid после этих дополнений:
<my:DataGrid x:Name="GrdHeadline" AutoGenerateColumns="True">
</my:DataGrid>
Вот и все, что требуется для подготовки DataGrid к использованию связанных данных. Прежде чем переходить к остальным свойствам, методам и событиям этого элемента управления, давайте выполним простую привязку данных. Будем использовать RSS-канал по адресу http://feeds.reuters.com/reuters/oddlyEnoughNews?format=xml.
Итак, в начале Page.xaml.cs добавляем ссылку на System.Net:
using System.Net;
Далее необходимо настроить объект WebClient (Веб-клиент) на чтение данных по этому URI и добавить обработчик события для обработки завершения загрузки данных. Для этого в конструктор Page добавляем следующий код:
WebClient client = new WebClient();
Uri uri =
new Uri("http://feeds.reuters.com/reuters/topNews?format=xml");
client.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(
client DownloadStringCompleted);
client.DownloadStringAsync(uri);
Теперь по завершении загрузки данных будет запускаться обработчик события
client DownloadStringCompleted. В этой функции будет использоваться специальный класс типа NewsHeadline (Заголовок новостей). Вот код этого класса:
public class NewsHeadLine {
public string strHead { get; set; } public string strLine { get; set; } }
client DownloadStringCompleted использует библиотеки System.Xml.Linq, поэтому понадобится добавить ссылку на них. Для этого щелкните правой кнопкой мыши References и выберите Add Reference. На вкладке .NET вы увидите библиотеку System.Xml.Linq, как показано на рис. 8-1. Выберите ее и щелкните OK.
Чтобы код скомпилировался, в нем должна быть указана эта библиотека. Для этого просто добавляем данное выражение в начало Page.xaml.cs:
using System.Xml.Linq;
Итак, получаем код обработчика событий client DownloadStringCompleted:
void client DownloadStringCompleted(
object sender, DownloadStringCompletedEventArgs e) {
XDocument xmlHeadlines = XDocument.Parse(e.Result);
var headlines = from story in xmlHeadlines.Descendants("item") select new NewsHeadLine {
strHead = (string)story.Element("title"), strLine = (string)story.Element("link") };
GrdHeadline.ItemsSource = headlines; }
Этот код обеспечивает синтаксический разбор данных, возвращаемых в результате запроса к сервису (хранящихся в e.Result), в объект XDocument. После этого с помощью Linq данные выбираются из XDocument и создается коллекция заголовков. Затем эта коллекция присваивается как значение свойству ItemsSource (Источник элементов) элемента управления DataGrid. Результаты представлены на рис. 8-2.
РИС. 8 1 Добавление ссылки на System.Xml.Linq.
РИС. 8 2 Образец коллекции заголовков, созданный при выполнении элемента управления DataGrid.
В DataGrid возможны два режима выбора: одиночный, при котором можно выбирать по одной строке, и множественный, при котором при удержании клавиш Ctrl и/или Shift может быть выбрано несколько строк.
Эти режимы задаются с помощью свойства SelectionMode (Режим выбора), которое принимает значения DataGridSelectionMode.Single для одиночного выбора и DataGridSelectionMode.Extended для множественного.
При использовании единичного режима выбранный элемент сохраняется в SelectedItem. Если этот объект типа object, перед использованием он должен быть приведен к соответствующему типу. Вы видели, что сетка заполнялась элементами определенного нами класса NewsHeadLine.
Итак, для единичного выбора выбранные данные могут быть получены следующим образом:
NewsHeadLine theHeadline = GrdHeadline.SelectedItem as NewsHeadLine;
Когда установлен режим множественного выбора, можно использовать свойство SelectedItems, возвращающее коллекцию списков. Это очень просто сделать, вот код:
string strHead;
string strLink;
System.Collections.IList listOfItems = GrdHeadline.SelectedItems;
foreach(NewsHeadLine newsHead in listOfItems) {
strHead = newsHead.strHead; strLink = newsHead.strLine;
}
В данном случае, свойство SelectedItems возвращает System.Collections.IList. После этого можно перебрать его элементы, извлекая каждый из объектов NewsHeadline и получая его данные.
При использовании любой таблицы, и DataGrid здесь не исключение, всегда полезно сделать ее более удобной для восприятия путем использования цветных полос, т.е. чередовать закрашенную и незакрашенную строки попеременно разными цветами или оттенками. В данном случае, чтобы сделать DataGrid полосатым, можно использовать свойства RowBackground (Фон строки) и AlternatingRowBack- ground (Чередующийся фон строки). В качестве значений этим свойствам задается цвет кисти следующим образом:
GrdHeadline.RowBackground =
new SolidColorBrush(Colors.LightGray);
GrdHeadline.AlternatingRowBackground = new SolidColorBrush(Colors.Yellow);
Результат такого форматирования можно увидеть на рис. 8-3.
РИС. 8 3 Чередование цветов строк.
Возможно, вы обратили внимание, что столбцы добавляются в том порядке, в котором данные определены в классе NewsHeadLine. Однако порядок вывода данных на экран можно менять. Настройку по умолчанию можно переопределить свойством DisplayIndex (Индекс отображения). Например, в нашем DataGrid два столбца. В первом выводятся заголовки, во втором - ссылки. Их можно поменять местами следующим способом:
GrdHeadline.Columns[0].DisplayIndex = 1;
GrdHeadline.Columns[1].DisplayIndex = 0;
Более широкие возможности управления визуальным представлением данных в сетке предоставляет шаблон данных. Шаблон данных - это XAML, определяющий то, как должны быть организованы данные, включая привязку к конкретным полям. Например, в предыдущих примерах вывода каждая ячейка таблицы была связана с определенным элементом RSS-канала. Чтобы вывести два поля RSS-канала в одной ячейке, необходимо использовать шаблон данных. Рассмотрим следующий XAML:
<UserControl
xmlns:my="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data"
x:Class="DataGrid.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<my:DataGrid x:Name="GrdHeadline" AutoGenerateColumns="True">
<my:DataGrid.Columns>
<my:DataGridTemplateColumn>
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="123"></TextBlock>
<TextBlock Text="{Binding strHead}"></TextBlock>
<TextBlock Text="{Binding strPubDate}"></TextBlock>
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
<my:DataGridTemplateColumn>
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding strLine}"></TextBlock>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
</my:DataGrid.Columns>
</my:DataGrid>
</Grid>
</UserControl>
В этом XAML столбцы DataGrid заданы заранее с помощью элемента <my:DataGrid.Columns>. Мы можем переопределить шаблон для столбцов по умолчанию, когда в ячейке выводится одно поле, задавая для каждой ячейки <my:DataGridTemplateColumn.CellTemplate>, в котором имеется код, описывающий, как должна отображаться ячейка.
Как видите, описано только две ячейки, поэтому данная таблица, независимо от количества полей данных, будет иметь только два столбца. Первый столбец, определенный шаблоном первой ячейки, будет представлен элементом StackPanel, содержащим три текстовых поля, в которых выводятся заданное в коде «123», связанное с данными свойство strHead класса NewsHeadline и связанное с данными свойство strPubDate того же класса NewsHeadline. StackPanel выводит эти поля друг над другом.
Второй столбец, описанный шаблоном второй ячейки, является простым TextBlock, связанным с полем strLine. Возможно, вы заметили, что здесь появилось еще одно поле, strPubDate, которого не было в исходном примере класса, поэтому описание класса и код привязки необходимо обновить. Вот новое описание класса:
public class NewsHeadLine
{
public string strHead { get; set; }
public string strLine { get; set; }
public string strDescription { get; set; } public string strPubDate { get; set; } }
И вот новый код привязки данных, который обеспечивает привязку дополнительных полей:
void client DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
XDocument xmlHeadlines = XDocument.Parse(e.Result);
var headlines = from story in xmlHeadlines.Descendants("item") select new NewsHeadLine {
strHead = (string)story.Element("title"), strLine = (string)story.Element("link"), strDescription = (string)story.Element("description"), strPubDate = (string)story.Element("pubDate") };
GrdHeadline.ItemsSource = headlines; }
Чтобы увидеть новые данные, необходимо внести еще одну небольшую коррективу - изменить высоту строки. Сейчас в ней может отображаться только одна строка текста, в результате чего содержимое первой ячейки будет обрезано по вертикали. Также понадобиться отключить автоматическое определение столбцов, потому что мы хотим переопределить поведение привязки данных DataGrid по умолчанию. Это обеспечивает следующий код (поместите его в конструктор Page):
GrdHeadline.AutoGenerateColumns = false;
GrdHeadline.RowHeight = 60;
Теперь, после выполнения этого кода, на экран будет выведен DataGrid с ячейками, соответствующими заданным шаблонам (рис. 8-4). Выглядит не очень красиво, но замечательно иллюстрирует возможности управления представлением данных в элементе управления DataGrid.
РИС. 8 4 Использование шаблона данных для определения визуального представления данных.
Элемент управления DataGrid обладает богатейшим API, который заслуживает отдельной книги. Однако того, что было рассказано о нем на этих нескольких страницах, достаточно, чтобы понять, какую невероятную гибкость он обеспечивает. Вы сможете использовать эту базовую информацию для перехода на следующий уровень при создании собственных приложений Silverlight!
Элементы управления Calendar и DatePicker
Возможность использования дат в приложениях Silverlight обеспечивается элементами управления Calendar (Календарь) и DatePicker (Элемент выбора дат). Элемент управления Calendar выводит на экран дни заданного месяца или месяцы заданного года и предоставляет кнопки со стрелками для перемещения по месяцам или годам. DatePicker сочетает это представление с текстовым полем, в которое пользователь может вводить дату в соответствующем формате, или выпадающим списком, в котором можно выбрать определенную дату.
Рассмотрим сначала элемент управления Calendar. Он прост, поэтому удобно начинать с него:
<UserControl
xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" x:Class="cal.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<my:Calendar x:Name="cal"></my:Calendar>
</Grid>
</UserControl>
Это обеспечит отображение Calendar в стандартном представлении месяца с выделенным соответственно сегодняшнему числу днем. Посмотрите на рис. 8-5. Как видите, этот снимок экрана был создан 24 ноября в понедельник.
РИС. 8 5 Использование элемента управления Calendar.
Месяц отображаемой даты задается свойством DisplayDate (Отображаемая дата). Например, следующий код обеспечивает выбор даты 1 января 2009 года:
DateTime d = new DateTime(2009, 1, 1); cal.DisplayDate = d;
Это обеспечит отображение выбранного месяца, но без указания конкретного дня. Посмотрите на календарь, представленный на рис. 8-6.
РИС. 8 6 Изменение отображаемой даты.
Сравните рис. 8-6 и рис. 8-5. Можно заметить, что на рис. 8-6 дата не выбрана. При задании отображаемой даты выбранная дата была обнулена, поэтому свойство SelectedDate (Выбранная дата) имеет значение null. Если вы выберете какой-то день на экране, свойству SelectedDate будет присвоено это значение (типа DateTime), или дату можно задать в коде через все то же свойство SelectedDate. Например:
DateTime s = new DateTime(2009, 1, 31); cal.SelectedDate = s;
Как это выглядит, можно увидеть на рис. 8-7. Теперь на отображаемом календаре выбрана дата, 31 января.
Коллекция BlackoutDates (Недоступные даты) позволяет задавать диапазон дат, которые не могут быть выбраны. Эта коллекция содержит тип CalendarDateRangeCollection (Коллекция диапазона дат календаря), в который могут добавляться диапазоны дат. Все даты, попадающие в этот диапазон, будут отображаться неактивными и, таким образом, не могут быть выбраны. Свойства SelectableDateStart (Начало дат, доступных для выбора) и SelectableDateEnd (Конец дат, доступных для выбора) задают диапазон отображаемых дат. Например, с помощью этих свойств можно обеспечить вывод на экран календарь, содержащий диапазон отображаемых дат и диапазон (обычно поддиапазон) дат, доступных для выбора.
РИС. 8 7 Использование свойства SelectedDate.
Элемент управления DatePicker сочетает эту функциональность с текстовым полем. Свойство Text этого поля содержит все, что пользователь вводит в качестве даты. Если невозможно выполнить синтаксический разбор введенных пользователем данных, формируется ошибка TextParseError (Ошибка синтаксического разбора текста).
Справа от текстового поля можно увидеть значок, выбор которого обеспечивает отображение элемента управления Calendar для выбора даты. Когда пользователь щелкает этот значок, формируется событие CalendarOpened (Календарь открыт). Когда пользователь закрывает его, формируется событие CalendarClosed (Календарь закрыт). Элементы управления Calendar и DatePicker обеспечивают базовые средства для создания приложений, в которых ввод основывается на датах и которые могут отображать информацию календаря.
Элементы управления RepeatButton и ToggleButton
Элемент управления RepeatButton (Кнопка повтора) предоставляет кнопку, при нажатии которой формируется множество событий щелчка. Частота формирования событий определяется свойством Delay (Задержка), оно задается в миллисекундах. Например, рассмотрим следующий XAML:
<RepeatButton x:Name="rpt" Delay="100"
Content="0" Click="rpt Click">
</RepeatButton>
В этом фрагменте задается код кнопки повтора rpt с задержкой 100 миллисекунд, содержимое которой по умолчанию равно 0. Обработка щелчка пользователя находится в обработчике событий rpt Click. Вот код этого обработчика событий:
private void rpt Click(object sender, RoutedEventArgs e) { int n = Convert.ToInt16(rpt.Content);
n++;
rpt.Content = n.ToString();
}
Когда пользователь щелкает кнопку, текущее значение свойства Content извлекается, преобразовывается в целое число, увеличивается на единицу и опять присваивается как значение свойства Content. В результате надпись на кнопке увеличивается, пока пользователь удерживает кнопку мыши нажатой над RepeatButton. Это может использоваться как способ контроля при обработке множества повторяющихся действий. Например, для различных типов счетчиков, реализованных таким образом, что пользователю предоставляется кнопка со стрелкой, и, пока он удерживает ее, значение увеличивается.
Во всех остальных отношениях, RepeatButton является обычной кнопкой, поэтому все детали о его использовании можно найти в Главе 7, в которой рассматривается универсальный элемент управления Button.
ToggleButton (Выключатель) - это кнопка, которая, будучи нажатой, остается в этом состоянии до тех пор, пока по ней не щелкнут снова. Этот элемент управления сочетает в себе переключатель и обычную кнопку. Свойства элемента управления ToggleButton подобны используемым в переключателях и обычных кнопках: ToggleButton тоже имеет свойство IsChecked, с помощью которого можно извлекать его текущее значение, и свойство IsThreeState, которое посредством значения Null позволяет задавать третье состояние, среднее между обычным и нажатым.
Как и стандартный элемент управления Button (Глава 7), RepeatButton и ToggleButton являются элементами управления с содержимым, т.е. могут использоваться для отображения сложного содержимого и создания кнопок с изображениями, видеокнопок и многого другого для ваших приложений Silverlight.
Элемент управления ScrollViewer
Элемент управления ScrollViewer является контейнером для отображения информации. Он предоставляет горизонтальную и вертикальную полосы прокрутки, что обеспечивает возможность пользователю перемещать область отображения и просматривать все содержимое, если его размеры превышают размеры контейнера. Наличие полос прокрутки определяется свойствами HorizontalScrollBarVisibility (Видимость горизонтальной полосы прокрутки) и VerticalScrollBarVisibility (Видимость вертикальной полосы прокрутки). По умолчанию, если содержимое превышает размеры ScrollViewer, отображается вертикальная полоса прокрутки; горизонтальная полоса прокрутки не отображается независимо от содержимого. Рассмотрим следующий пример XAML:
<UserControl x:Class="sviewer.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<ScrollViewer>
<Image Source="mix08 1280.jpg" Stretch="None" />
</ScrollViewer>
</Grid>
</UserControl>
В данном случае ScrollViewer является единственным дочерним элементом управления на рабочей поверхности размером 400 х 300, поэтому его размеры также будут 400 х 300. В нем располагается изображение размером 1280 х 1024. Результат можно увидеть на рис. 8-8.
РИС. 8 8 Использование элемента управления Scrollviewer.
Как видно на рис. 8-8, отображается только закрашенная серым область, потому что видна только левая часть изображения. Горизонтальная полоса прокрутки отсутствует, так что мы не можем переместиться вправо к цветной части рисунка.
Но если в описание Scrollviewer в XAML добавить HorizontalScrollBarVisibility="True", пользователь сможет увидеть все остальное изображение. Вот этот XAML-код:
<ScrollViewer HorizontalScrollBarVisibility="Visible">
<Image Source="mix08 1280.jpg" Stretch="None" />
</ScrollViewer>
Результаты представлены на рис. 8-9.
РИС. 8 9 Использование Scrollviewer с горизонтальной полосой прокрутки.
Подсказка Можно также переопределить видимость вертикальной полосы прокрутки. По умолчанию она видимая, но ее можно отключить (т.е. она не будет отображаться), задав свойству VerticalScrollBarVisibility значение Hidden.
Элемент управления Slider
Элемент управления Slider обеспечивает пользователю возможность выбирать значение из заданного диапазона, передвигая вертикальный элемент (называемый бегунком (thumb)) вдоль линии, начиная от наименьшего значения в диапазоне, заканчивая наибольшим значением. Доступ к значению обеспечивается через свойство Value (Значение), возвращающее величину типа Double.
Элемент управления Slider можно настроить множеством способов. Например, свойства Minimum (Минимум) и Maximum (Максимум) используются для определения минимального и максимального значений диапазона. Если необходимо, чтобы пользователь выбирал значение из диапазона чисел от О до 100, задайте свойству Minimum значение 0 и свойству Maximum значение 100.
Еще одно свойство, связанное с элементом управления Slider, - Orientation (Ориентация), которое используется для определения направления перемещения бегунка. Ему может быть заданы значения Horizontal (Горизонтально) или Vertical (Вертикально).
Когда свойству Orientation задано значение Horizontal, по умолчанию перемещение Slider от наименьшего к наибольшему значению реализуется в направлении слева направо, и снизу вверх, если Orientation задано значение Vertical. Эти стандартные настройки можно переопределить свойством IsDirectio- nReversed (Обратное направление), задание значения True которому обеспечит изменение направления возрастания значений в Slider.
Кроме того, можно перемещать бегунок, щелкая на полосе перемещения типового элемента управления Slider. Каждый щелчок обеспечивает изменение значения на определенную величину. Это поведение определяется свойством LargeChange (Быстрое перемещение), задание числового значения, которому обеспечивает увеличение или уменьшение значения бегунка на заданную величину.
Далее приведен пример элемента управления Slider в XAML:
<Slider x:Name="sldr" Maximum="100"
Orientation="Vertical"
IsDirectionReversed="True"
LargeChange="10">
</Slider>
Создаваемый здесь Slider будет вертикальным с наименьшим значением сверху, наибольшим - снизу. Он обеспечит возможность, перетягивая бегунок, выбирать значения в диапазоне от 0 до 100. Также пользователь сможет увеличивать значения на 10, щелкая полосу перемещения.
Заключение
В данной главе мы продолжили изучение набора элементов управления Silverlight. Много внимания было уделено DataGrid, его свойствам, методам и событиям, поскольку это важный элемент управления, обеспечивающий приложениям функциональность, аналогичную электронным таблицам. При обсуждении DataGrid представлен код, предлагаемый Silverlight для упрощения привязки данных, а также рассмотрены шаблоны данных и их использование для компоновки таблиц. Кроме того, вы познакомились с другими расширенными инструментами, доступными в Silverlight, включая элементы управления Calendar, DatePicker, ScrollViewer и Slider.
На этом мы завершаем обзор элементов управления Silverlight и в следующей главе займемся созданием собственных элементов управления.
Глава 9
Создание собственного элемента управления Silverlight
В Главе 7, «Элементы управления Silverlight: представления и компоновки», был представлен краткий обзор использования Microsoft Visual Studio для создания приложений Silverlight на C#. В Главе 8, «Элементы управления Silverlight: расширенные элементы управления», описаны некоторые элементы управления, доступные в Silverlight. Вероятно, на данный момент, вас интересует, какие еще элементы управления доступны в базовом наборе. Но есть два варианта: элементы управления можно либо покупать, либо создавать самостоятельно. Есть множество производителей элементов управления; подробнее о них можно узнать на сайте http://www.silverlight.net. Однако, используя Silverlight, можно создавать собственные элементы управления для Silverlight. В данной главе предлагается практический подход к построению таких элементов управления.
Создание проекта
Итак, начнем. Первый шаг - создание нового проекта Silverlight в Visual Studio. Делаем это, выбирая опцию New Project в меню File (рис. 9-1).
РИС. 9 1 Создание проекта нового элемента управления.
Как видно на рис. 9-1, этот проект будет называться CircleControl (Элемент управления круг). Если вернуться к Главе 4, «Основы XAML», вы увидите, что XAML не предлагает фигуры Circle (Круг), но в нем есть Ellipse со свойствами, определяющими ширину и высоту. Мы унаследуем фигуру от Ellipse, но вместо ширины и высоты применим свойство Radius (Радиус), что позволит Silverlight отрисовывать круг.
Щелкните OK, и откроется Мастер приложений Silverlight (рис. 9-2). Примите настройки по умолчанию, и Visual Studio создаст все необходимое для приложения Silverlight. Подробнее о приложениях Silverlight и каждом из составляющих их файлов рассказывается в Главе 3, «Использование Visual Studio с Silverlight 2». Теперь все готово для следующего шага - добавления самого элемента управления.
РИС. 9 2 Мастер приложений Silverlight Application Wizard.
Добавление шаблона элемента управления
Элемент управления Silverlight создается точно также, как любой другой проект: с использованием XAML и, если необходимо, некоторого выделенного кода. Применяемый шаблон обеспечивает создание тестового проекта, который включает файл App.xaml для кода приложения и файл Page.xaml основного UI. Создаваемый элемент управления будет добавлен в Page.xaml. Совсем скоро вы увидите, как это делается.
Сначала создадим сам элемент управления. Щелкнем правой кнопкой мыши на проекте (в данном случае, CircleControl), выберем Add и затем New Item (Новый элемент). Появится диалоговое окно Add New Item (Добавление нового элемента), как показано на рис. 9-3.
РИС. 9 3 Добавление нового элемента управления Silverlight.
В этом диалоговом окне из предлагаемых категорий выбираем Silverlight, выбираем шаблон Silverlight User Control и присваиваем ему имя. После этого щелкаем Add.
Будет создан базовый UserControl. Вот как выглядит XAML для элемента управления Circle в проекте
CircleControl:
<UserControl x:Class="CircleControl.Circle"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" >
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>
Обратите внимание на использование пространств имен. Для x:Class, который определяет объект для Silverlight, задано значение CircleControl.Circle. Поскольку круг будет иметь только один визуальный элемент, унаследованный от базового типа Ellipse, в сетку LayoutRoot необходимо добавить следующее:
<Grid x:Name="LayoutRoot" Background="White">
<Ellipse x:Name="BaseEllipse"></Ellipse>
</Grid>
Написание кода элемента управления
Код элемента управления очень прост. Circle - это UserControl, формирующий визуальное представление заданного XAML, который содержит Ellipse. К этому требуется добавить свойство Radius, определяющее радиус Circle, и свойство FillColor (Цвет заливки), обеспечивающее возможность закрашивать круг. UserControl не предоставляет свойство Fill, поэтому его придется реализовать самостоятельно.
Вот этот код. Он должен находиться в файле выделенного кода с расширением .cs, поэтому если элемент управления назван Circle.xaml, этот файл будет называться Circle.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace CircleControl
{
public partial class Circle : UserControl
{
public Circle()
{
// Необходимо для инициализации переменных
InitializeComponent();
}
public double Radius
{
get
{
return BaseEllipse.Width / 2;
} set
{
BaseEllipse.Width = value * 2;
BaseEllipse.Height = value * 2;
}
}
public SolidColorBrush Fill
{
get
{
return (SolidColorBrush)BaseEllipse.Fill;
} set
{
BaseEllipse.Fill = (SolidColorBrush)value;
}
}
}
}
Как видите, все очень просто. Свойство Radius типа double возвращает в методе get ширину BaseEllipse (Базовый эллипс), деленную на 2. Для типа Ellipse всегда задаются ширина и высота, и, естественно, радиус круга является половиной ширины или высоты фигуры.
Аналогично, задавая значение Radius, вы хотите, чтобы ширина и высота базового Ellipse были в два раза больше радиуса. Это выполняется в методе set свойства.
Чтобы определить свойство Fill, необходимо привести входящее значение к типу SolidColorBrush и задать его в качестве значения Fill. Чтобы возвратить значение Fill базового эллипса, приводим его к SolidColorBrush . Все очень просто!
Теперь, когда мы получили элемент управления, можно реализовать его в приложении. Если вспомнить Главу 3, стандартный шаблон в качестве UI по умолчанию для приложения задает Page.xaml. Итак, добавим наш элемент управления туда.
Прежде всего, необходимо добавить ссылку на пространство имен нашего элемента управления. В данном случае, проект называется CircleControl, и его пространство имен имеет такое же имя. Точные сведения о пространстве имен можно найти в свойствах проекта. Для этого щелкните проект правой кнопкой мыши и выберите Properties, чтобы открыть диалог Project Properties. Это подробно обсуждалось в Главе 3.
Ваше исходное объявление UserControl в Page.xaml должно выглядеть аналогично следующему фрагменту кода.
Примечание В некоторых версиях Visual Studio Tools для <UserControl> применяется <Grid>, в некоторых - <Canvas>. В данном случае для демонстрационных целей используется <Canvas>, но не будет никаких проблем, если вы возьмете <Grid>, потому что оба этих элемента управления являются контейнерами.
<UserControl x:Class="CircleControl.Page"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:circ="clr-namespace:CircleControl"
Width="640"
Height="480">
<Canvas x:Name="LayoutRoot">
</Canvas>
</UserControl>
Теперь, когда пространство имен объявлено, можно добавить ссылку на элемент управления. Заметьте, что для данного пространства имен префиксом XML объявлен circ, поэтому, когда вы начинаете вводить его в редакторе, функция IntelliSense предлагает этот тег. Это показано на рис. 9-4.
РИС. 9 4 IntelliSense и пространства имен специальных элементов управления.
Функция IntelliSense также обеспечит выбор имени элемента управления и доступных для него свойств (в данном случае, это все свойства пользовательского элемента управления плюс описанные ранее Fill и Radius). На рис. 9-5 представлен выбор свойства Radius в IntelliSense.
РИС. 9 5 IntelliSense и свойства специального элемента управления.
Вот пример Page.xaml с объявлением пространства имен и описанием двух кругов:
<UserControl x:Class="CircleControl.Page"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:circ="clr-namespace:CircleControl"
Width="640"
Height="480" >
<Canvas x:Name="LayoutRoot">
<circ:Circle Fill="Black" Radius="100"
Canvas.Left="0" Canvas.Top="50"></circ:Circle>
<circ:Circle Fill="Red" Radius="50"
Canvas.Left="0" Canvas.Top="50"></circ:Circle>
</Canvas>
</UserControl>
Как это выглядит, можно увидеть на рис. 9-6.
РИС. 9 6 Использование элемента управления Circle на странице.
Итак, мы взяли существующий проект, добавили в него шаблон элемента управления, на основании которого построили элемент управления для отображения круга. Все это замечательно, но в данном случае возможности повторного использования элемента управления очень ограничены. Вот для этого пригодятся проекты библиотеки классов Silverlight, которые будут рассмотрены в следующем разделе.
Создание библиотек классов Silverlight
Среди шаблонов Visual Studio для Silverlight 2 есть шаблон, позволяющий создавать библиотеку классов, которую можно без труда использовать в других проектах. Эта библиотека классов может включать элементы управления Silverlight. В данном разделе на простом примере создания элемента управления Square (Квадрат) будет продемонстрировано добавление элементов управления в библиотеку.
Прежде всего, откроем Visual Studio и выберем New Project в меню File. Появится диалоговое окно New Project. Создайте в нем новый проект библиотеки классов Silverlight и присвойте ему соответствующее имя. Пример этого можно увидеть на рис. 9-7.
РИС. 9 7 Создание новой библиотеки классов Silverlight.
При этом будет создан проект библиотеки классов, как показано на рис. 9-8. Это обычный проект библиотеки классов Visual Studio, поэтому если вы знакомы с разработкой на C#, ваши навыки пригодятся и в Silverlight 2.
Чтобы добавить новый элемент управления Silverlight, щелкните правой кнопкой мыши на проекте, выберите Add и затем выберите New Item, как делали это ранее (если необходимо освежить память, вернитесь к рис. 9-3), и назовите его SquareControl (Элемент управления квадрат).
Теперь можете редактировать XAML и код элемента управления, выполняя те же шаги, что и ранее. Вот пример XAML для элемента управления Square:
Примечание Некоторые версии Visual Studio Tools создают Grid вместо Canvas под именем LayoutRoot. В данном разделе используется Canvas, но он может быть без проблем заменен на Grid.
<UserControl x:Class="SquareLib.SquareControl"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="640"
Height="480" >
<Canvas x:Name="LayoutRoot" >
<Rectangle x:Name="rootControl"></Rectangle>
</Canvas>
</UserControl>
РИС. 9 8 Проект библиотеки классов в Visual Studio.
Аналогично представленному ранее элементу управления Circle, Square тоже создается на базе существующего элемента управления XAML. В данном случае используется Rectangle, который мы назовем rootControl (Корневой элемент управления). Вот код на C#, реализующий элемент управления Square:
using System;
using System.Net;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SquareLib
{
public partial class SquareControl : UserControl
{
public SquareControl()
{
// Необходимо для инициализации переменных InitializeComponent();
}
public double Size
{
get
{ return rootControl.Width;
} set { rootControl.Width = value; rootControl.Height = value;
}
}
public SolidColorBrush Fill
{
get
{ return (SolidColorBrush)rootControl.Fill;
} set {
rootControl.Fill = (SolidColorBrush)value;
}
}
}
}
Компиляция этого решения обеспечит создание библиотеки классов, которая может быть включена в другие проекты.
Чтобы использовать эту библиотеку классов, необходимо просто создать новый проект и добавить в него ссылку на нее. Итак, создадим новый проект Silverlight. Для этого в диалоговом окне New Project (File, New Project) выберем шаблон Silverlight Project.
Стандартный шаблон создает решение с двумя проектами: элемент управления Silverlight и Веб-сайт ASP.NET для его размещения.
Проект Silverlight Control позволяет добавлять ссылку, щелкнув правой кнопкой мыши папку References и выбрав Add Reference (рис. 9-9).
РИС. 9 9 Добавление ссылки на ваш проект Silverlight.
Через открывшееся диалоговое окно можно перейти в каталог, в котором располагается DLL, скомпилированная из вашего проекта библиотеки классов. Она должна располагаться в подкаталоге ClientBin. Добавьте ссылку, и ее можно будет увидеть в списке ссылок. Если ваша библиотека классов имеет какие- либо зависимости, они также будут представлены в этом списке. На рис. 9-10 показана ссылка на сборку SquareLib, после ее удачной компиляции.
РИС. 9 10 Использование вашей специальной ссылки.
Теперь можно вернуться к Page.xaml и добавить ссылку на пространство имен, что позволит использовать элементы управления из этой сборки. В этом очень поможет функция IntelliSense Visual Studio. В начале файла XAML, где описываются пространства имен, добавьте новый атрибут xmlns и задайте для него префикс (например, sq, как показано на рис. 9-11). IntelliSense предоставит список доступных сборок или схем. Вам просто надо выбрать имя необходимой сборки. В данном случае, это SquareLib, поэтому выбирайте ее. Обратите внимание, что ваш список сборок может выглядеть иначе, чем представленный на рис. 9-11.
РИС. 9 11 IntelliSense и пространства имен XML.
Выполнив все это, вы получите ссылку на соответствующе пространство имен и сборку. Их можно увидеть здесь:
<UserControl x:Class="SquareCLHost.Page"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sq="clr-namespace:SquareLib;assembly=SquareLib" Width="640"
Height="480" >
<Canvas x:Name="LayoutRoot">
</Canvas>
</UserControl>
Поскольку для этого пространства определен префикс sq, добавлять элементы управления из него можно посредством IntelliSense, используя этот префикс.
Итак, например, если в рамках элемента LayoutRoot ввести символ < для открытия узла XML, в выпадающем списке среди предлагаемых опций вы увидите sq:. Если вставить его в код, вы получите список доступных классов, как показано на рис. 9-12.
РИС. 9 12 IntelliSense для библиотеки классов специального элемента управления.
Наконец, приведем пример XAML с несколькими экземплярами SquareControl:
<UserControl x:Class="SquareCLHost.Page"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sq="clr-namespace:SquareLib;assembly=SquareLib" Width="640"
Height="480" >
<Canvas x:Name="LayoutRoot" >
<sq:SquareControl Size="10" Canvas.Top="10"
Canvas.Left="10" Fill="Red"></sq:SquareControl>
<sq:SquareControl Size="10" Canvas.Top="20"
Canvas.Left="20" Fill="Green"></sq:SquareControl>
<sq:SquareControl Size="10" Canvas.Top="30"
Canvas.Left="30" Fill="Yellow"></sq:SquareControl>
<sq:SquareControl Size="10" Canvas.Top="40"
Canvas.Left="40" Fill="Blue"></sq:SquareControl>
</Canvas>
</UserControl>
Заключение
В данной главе представлена гибкая модель расширяемости, предлагаемая Silverlight 2. Вы научились добавлять элементы управления в приложения и инкапсулировать функциональность в элемент управления для упрощения повторного использования. Также было показано, как с помощью шаблона библиотеки классов Silverlight можно создавать элементы управления, компилируемые в сборки .NET, на которые могут ссылаться и использовать другие проекты.
На основании полученных знаний вы можете приступать к созданию собственных элементов управления или дорабатывать стандартные элементы управления, о которых рассказывалось в Главах 7 и 8.
В Главе 10, «Создание взаимодействующих с сервером приложений в Silverlight», мы перейдем к немного более сложным вопросам и рассмотрим, как в Silverlight 2 реализуется работа с сетью и связь.
Глава 10
Создание взаимодействующих с сервером приложений в Silverlight
В данной главе вы узнаете, как можно создавать взаимодействующие с сервером приложения, используя Silverlight. Глава разделена на три основных раздела. В первом мы обратимся к архитектуре Silverlight, и вы увидите, как дизайн в ней отделен от реализации, что позволяет создавать сервисы на Personal Hypertext Processor (PHP) или Java, генерирующие XAML, который формирует визуальное представление вашего Silverlight-приложения. Во втором разделе рассматривается сам браузер и его использование для подключения к удаленным сервисам с помощью технологии AJAX. В последней части представлены некоторые классы, доступные в .NET, включая WebClient и WebRequest, и показано их использование для получения данных с сервера и отображения в приложении Silverlight.
Подключение приложений с помощью XAML
Одним из свойств Silverlight, делающим его таким мощным инструментом, является то, что XAML - это XML и, таким образом, он может быть сформирован сервером. В примерах, которые были представлены до сих пор, XAML статичен: документ создается дизайнером в каком-нибудь инструменте, таком как Expression Blend. Однако вы не ограничены лишь статическим XAML и можете создавать целый ряд разнообразнейших сценариев, динамически формируя XAML и передавая его пользователям в ответ на запрос или переход приложения в определенное состояние.
Например, требуется создать приложение прогноза погоды. При использовании статического XAML для этого пришлось бы создать сложную систему, которая периодически формировала бы различные XAML-документы для каждого из местоположений пользователей, а пользователи запрашивали бы и загружали соответствующие документы. Намного проще создать шаблон приложения и заполнять поля подстановки в UI приложения, используя сведения, полученные с сервера.
Серверные приложения могут создаваться на разных языках программирования. В этом разделе обсуждаются PHP и Java. Будет рассмотрено, как XAML генерируется в каждом из этих языков, сначала в общем, а затем на конкретном примере с использованием сведений прогноза погоды.
Silverlight и PHP
PHP (можно скачать на сайте http://www.php.net) - простой, но при этом мощный язык написания сценариев, который может использоваться для создания XAML шаблона. Он обычно принимает PHP-код в качестве входных данных и создает Веб-страницы на выходе. Так же динамически можно формировать XAML. Если вы не знакомы с PHP, далее представлены базовые приемы работы с ним.
Ваша первая PHP-страница
PHP может использоваться для динамического формирования Веб-страниц на основании входных параметров. Так, например, рассмотрим страницу, созданную с использованием этого HTML-кода:
<HTML> <HEAD> </HEAD> <BODY> <H1>Hello, World!</H1> </BODY>
</HTML>
Это представляется как простая HTML-страница с фразой «Hello, World!», которую можно увидеть на рис. 10-1.
РИС. 10 1 Простая Веб страница «Hello World!».
С помощью PHP эту простую страницу можно сформировать динамически. В данном случае, страница принимает параметр, и препроцессор PHP подставляет его. Ниже представлен PHP-код:
<HTML>
<HEAD>
</HEAD>
<BODY>
<H1>Hello, <?php echo($ REQUEST['name']);?>!</H1>
<BODY>
</HTML>
Здесь показан код разметки HTML со встроенным PHP-кодом, извлекающим параметр URL name и записывающий его в выходной поток с помощью команды echo. Итак, если вы перейдете на эту страницу, передавая ей значение name, процессор PHP динамически создаст разметку страницы. Например, на рис. 10-2 показано, как будет представлен на экране следующий параметр URL:
http://localhost/phptext/Hello.php?name=Laurence
РИС. 10 2 Динамическое формирование страниц на PHP.
Учебный пример PHP и XAML
Тот же принцип может применяться и к XAML. Не составит большого труда создать в Expression Blend XAML-шаблон представления содержимого и использовать его на PHP-странице. Если необходимо представить повторяющееся содержимое, такое как список, для отображения можно использовать PHP-цикл.
Лучше всего продемонстрировать это на примере. PHP (наряду с Apache, MySQL и Linux) является основным элементом знаменитого набора LAMP, поэтому давайте рассмотрим, как создать приложение PHP/MySQL, которое могло бы выполняться на любом Веб-сервере или операционной системе, поддерживающей LAMP. (Аббревиатура расшифровывается как Linux, Apache, MySQL и PHP.) Фактически мы будем создавать приложение «Windows IIS MySQL PHP», сокращенно WIMP, что означает «бесхарактерный человек, тряпка» - совершенно никудышнее название.
Создание базы данных на стороне сервера
В данном случае, MySQL используется для создания базы данных имен и адресов на стороне сервера. MySQL можно скачать по адресу http://www.mysql.com. Там можно найти бесплатную версию продукта, идеально подходящую для экспериментов.
Кроме этого, предлагается набор инструментов GUI, таких как MySQL Administrator и MySQL Query Browser, для построения и заполнения баз данных. Инструкции по применению этих инструментальных средств выходят за рамки рассмотрения данной книгой, однако исчерпывающую документацию можно найти на Веб-сайте http://www.MySQL.com.
На рис. 10-3 показан MySQL Table Editor (Редактор таблиц MySQL) и его использование для описания простой таблицы имен и адресов.
РИС. 10 3 Описание таблицы имен и адресов в MySQL.
Редактировать содержимое таблицы можно в MySQL Query Browser (Обозреватель запросов MySQL). Просто щелкните кнопку Edit (Редактировать) внизу UI приложения (рис. 10-4) и можно вводить имя и адрес, как показано на рис. 10-4.
РИС. 10 4 Добавление данных в таблицу с помощью MySQL Query Browser.
Теперь у нас есть данные, которые можно отображать с помощью PHP. Пора связать их с XAML- шаблоном. В следующем разделе мы научимся создавать шаблон в Expression Blend.
Создание XAML-шаблона
Теперь, когда у нас есть данные, подумаем о том, как представить их, используя XAML. Expression Blend - замечательный визуальный редактор для XAML. На рис. 10-5 приведен пример XAML-шаблона, который может использоваться для вывода на экран данных адреса и имени из таблицы.
РИС. 10 5 Создание XAML шаблона в Expression Blend.
Полученный в результате XAML представляет коллекцию объектов Canvas, Rectangle и TextBlock. Полный код XAML-шаблона, представленного на рис. 10-5, приводится в Листинге 10-1. Обратите внимание, что корневым узлом этого XAML является Canvas, а все элементы UI располагаются в другом Canvas , который и будет повторяться при отображении множества записей.
ЛИСТИНГ 10 1 XAML шаблон приложения для вывода адресов
<Canvas
xmlns=http://schemas.microsoft.com/client/2007
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
Width="640" Height="480"
Background="#FF460608">
<Canvas Width="352" Height="128" Canvas.Left="10" Canvas.Top="8" >
<Rectangle Fill="#FF693B3D" Stroke="#FF000000" StrokeThickness="0"
RadiusX="16" RadiusY="16" Width="352" Height="128" Canvas.Top="1"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0" RadiusX="8"
RadiusY="8" Width="336" Height="40" Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175"
StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtName" Width="312" Height="24"
Canvas.Left="16" Canvas.Top="16" FontFamily="Arial Unicode MS"
FontSize="18" FontWeight="Normal" Foreground="#FFFFFFFF"
Text="User Name" TextWrapping="Wrap"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="336" Height="23"
Canvas.Left="8" Canvas.Top="48">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175"
StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtAddr1" Width="312" Height="24"
FontFamily="Arial Unicode MS" FontSize="12" FontWeight="Normal"
Foreground="#FFFFFFFF" Text="Address1"
TextWrapping="Wrap" Canvas.Left="14" Canvas.Top="48"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="336"
Height="23" Canvas.Left="8" Canvas.Top="71">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175"
StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtAddr2" Width="312" Height="24" FontFamily="Arial Unicode MS" FontSize="12" FontWeight="Normal" Foreground="#FFFFFFFF"
Text="Address2" TextWrapping="Wrap" Canvas.Left="15" Canvas.Top="72"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0" RadiusX="8" RadiusY="8" Width="168" Height="23" Canvas.Left="176" Canvas.Top="94">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175"
StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="168"
Height="23" Canvas.Left="8" Canvas.Top="94">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175"
StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtCity" Width="144" Height="24" FontFamily="Arial Unicode MS" FontSize="12"
FontWeight="Normal" Foreground="#FFFFFFFF" Text="City" TextWrapping="Wrap" Canvas.Left="15" Canvas.Top="96"/>
<TextBlock x:Name="txtState" Width="144" Height="24" FontFamily="Arial Unicode MS" FontSize="12"
FontWeight="Normal" Foreground="#FFFFFFFF" Text="State" TextWrapping="Wrap" Canvas.Left="182" Canvas.Top="96"/> </Canvas>
</Canvas>
Свойству Canvas.Top второго Canvas (далее называемого контейнером) задано значение 8 пикселов и свойству Height задано значение 128 пикселов. Следовательно, если под первым экземпляром этого контейнера необходимо разместить другие экземпляры, для второго контейнера Canvas.Top должен быть определен как 136 (128 + 8), для следующего - 264 (128 + 128 + 8) и т.д.
Все элементы UI размещаются в контейнере и все они должны иметь в XAML уникальные имена. Как видите, в этом примере XAML имя каждого TextBlock определятся атрибутом x:Name. При клонировании контейнера XAML должен обеспечивать уникальные имена для этих узлов. Алгоритм присваивания имен будет прост - в конце каждого имени будет добавляться индекс элемента. Итак, например, записанное в шаблоне значение x:Name txtState для первой строки базы данных превратиться в txtState1, для второй строки - txtState2, и т.д.
Как будет показано в следующем разделе, размножить эти элементы в PHP очень просто.
Формирование XAML из PHP и MySQL
Синтаксический разбор страницы выполняет PHP. Это означает, что когда сервер получает запрос на страницу, PHP записывает форматированные данные в буфер ответов. Когда PHP встречает специальный открывающий тег (<?php), он передает обработку синтаксическому анализатору PHP. Анализатор выполняет код, выявляемый процессором PHP, пока не встретит закрывающий тег (?>). Это делает связку MySQL и PHP идеальным сочетанием для отображения содержимого, формируемого по шабло-
ну. Шаблон для формирования содержимого просто помещается в файл с расширением .php, а там, где требуется вставить некоторые связанные с данными поля подстановки, добавляется необходимая PHP-логика, заключенная в открывающий и закрывающий теги (<?php и ?>, соответственно).
PHP-код может содержать циклы. Если после выражения цикла следует некоторое содержимое, оно будет выведено многократно. В теле цикла могут присутствовать открывающий/закрывающий теги PHP. Например, можно сделать следующее:
<?php
for($i = 0; $i<100; $i ++)
{ // Открывающая скобка цикла
// Выходим из PHP, хотя цикл еще не закрыт! ?>
<H1>My Text Line is <?php echo $i; ?></H1>
<?php
} // Теперь закрываем наш цикл ?>
Это обеспечит повторение HTML-содержимого (текста, заключенного в элемент <H1>) 100 раз. Как видите, не обязательно заключать весь текст в теги <?php... ?>. Это полезное свойство при объединении PHP и XAML.
В XAML холст-контейнер может быть помещен в цикл:
<?php
for($i = 0; $i<100; $i ++)
{ // Открывающая скобка цикла
// Выходим из PHP, хотя цикл еще не закрыт!
?>
<Canvas>
...
</Canvas>
<?php
} // Теперь закрываем наш цикл ?>
Выполнение этого кода обеспечит запись XAML 100 раз! Это делает PHP мощным языком описания шаблонов для Silverlight.
Возвращаясь к нашему примеру, рассмотрим, как установить подключение к базе данных, выполнить запрос к ней и записать то количество XAML-элементов Canvas, которое соответствует числу возвращенных результатов. Также отредактируем содержимое элементов TextBlock холста-контейнера, чтобы они отображали информацию, полученную из базы данных, а также обеспечим уникальность имен TextBlock.
В итоге должна получиться PHP-страница, формирующая XAML, который будет использоваться как источник для элемента управления Silverlight. Но чтобы было немного интересней, изменим PHP и введем параметр state (штат), который обеспечит возвращение сведений только для людей, проживающих в заданном штате. Это превратит наш код в настоящий динамический генератор XAML.
Во-первых, необходимо, чтобы Silverlight распознавал вывод PHP как XML. Для этого задаем тип MIME содержимого вывода. Это делается в PHP с помощью команды header (заголовок):
header('Content-type: text/xml');
Извлечение параметра строки запроса (т.е. http://server/script.php?param = value) в PHP обеспечивается массивом $ REQUEST. Итак, чтобы прочитать значение параметра State, используем следующий код:
$State=$ REQUEST['State'];
В PHP версии 4.x имеется встроенный набор команд MySQL. Для версий 5.x и выше набор команд MySQL должен задаваться как расширение. Независимо от используемой версии, синтаксис PHP аналогичен.
Подключение к серверу localhost с использованием имени пользователя user и пароля password выполняется с помощью команды mysql connect:
$con = mysql connect("localhost", "user", "password");
На сервере может располагаться несколько баз данных. Для выбора необходимой базы данных используется команда mysql select db:
mysql select db("test", $con); // "test" имя базы данных
Затем, чтобы выполнить запрос к этой базе данных, используется команда mysql query, в которую передается строка, содержащая фактический запрос SQL. Результат запроса будет представлять собой массив массивов значений. Приведем пример:
$sqlString = "SELECT * from addresses";
$result = mysql query($sqlString);
Затем массив mysql fetch array разбивается на строки. С помощью цикла while можно обойти каждую строку, как показано в следующем примере:
while($row = mysql fetch array($result)) { ...
}
таким образом, исходя из данного сценария, получаем такой алгоритм действий:
Задаем тип MIME text/xml.
Принимаем входной параметр (штат).
Записываем начальный тег «корневого» Canvas.
Используем входной параметр для построения запроса.
Выполняем запрос и получаем результирующее множество.
Для каждой строки результирующего множества:
Создаем XAML-шаблона.
Заполняем атрибуты Text элементов TextBlock данными из соответствующих полей базы данных.
Заполняем атрибуты x:Name уникальными ID, полученными на основании порядкового номера строки.
Закрываем тег «корневого» Canvas.
Код PHP-страницы полностью приведен в листинге 10-2. Разметка PHP в блоке XAML выделена жирным шрифтом.
ЛИСТИНГ 10 2 PHP код для формирования XAML
<?php
header('Content-type: text/xml');
$State=$ REQUEST['State']; ?>
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480"
Background="#FF460608" >
<?php $height=128;
$top=8;
$i=0;
$con = mysql connect("localhost", "root", "root");
mysql select db("test",$con);
$sqlString = "SELECT * from addresses";
if($State!="")
{
$sqlString = $sqlString . " WHERE State = '" . $State . "'";
}
$result = mysql query($sqlString);
while($row = mysql fetch array($result))
{
?>
<Canvas Width="352" Height="128" Canvas.Left="10"
Canvas.Top="<?php echo($top + ($height*$i)); ?>" >
<Rectangle Fill="#FF693B3D" Stroke="#FF000000"
StrokeThickness="0" RadiusX="16" RadiusY="16"
Width="352" Height="128" Canvas.Top="1"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="336" Height="40"
Canvas.Left="8" Canvas.Top="8">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175" StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtName<?php echo $i; ?>" Width="312" Height="24"
Canvas.Left="16" Canvas.Top="16"
FontFamily="Arial Unicode MS" FontSize="18"
FontWeight="Normal" Foreground="#FFFFFFFF"
Text="<?php echo($row['Name']); ?>"
TextWrapping="Wrap"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="336"
Height="23" Canvas.Left="8" Canvas.Top="48">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175" StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtAddr1<?php echo $i; ?>" Width="312"
Height="24" FontFamily="Arial Unicode MS" FontSize="12"
FontWeight="Normal" Foreground="#FFFFFFFF"
Text="<?php echo($row['Address1']); ?>" TextWrapping="Wrap"
Canvas.Left="14" Canvas.Top="48"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="336" Height="23"
Canvas.Left="8" Canvas.Top="71">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175" StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtAddr2<?php echo $i; ?>" Width = "312"
Height="24" FontFamily="Arial Unicode MS"
FontSize="12" FontWeight="Normal"
Foreground="#FFFFFFFF"
Text="<?php echo($row['Address2']); ?>" TextWrapping="Wrap"
Canvas.Left="15" Canvas.Top="72"/>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="168" Height="23"
Canvas.Left="176" Canvas.Top="94">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175" StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Stroke="#FF000000" StrokeThickness="0"
RadiusX="8" RadiusY="8" Width="168"
Height="23" Canvas.Left="8" Canvas.Top="94">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.518,0.175" StartPoint="0.515,0.825">
<GradientStop Color="#FF460608" Offset="0"/>
<GradientStop Color="#FF841316" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtCity<?php echo $i; ?>" Width = "144"
Height="24" FontFamily="Arial Unicode MS"
FontSize="12" FontWeight="Normal" Foreground="#FFFFFFFF" Text="<?php echo($row['City']); ?>" TextWrapping = "Wrap" Canvas.Left="15" Canvas.Top="96"/>
<TextBlock x:Name="txtState<?php echo $i; ?>" Width="144" Height="24" FontFamily="Arial Unicode MS" FontSize="12" FontWeight="Normal" Foreground="#FFFFFFFF"
Text="<?php echo($row['State']); ?>"
TextWrapping="Wrap" Canvas.Left="182" Canvas.Top="96"/>
</Canvas>
<?php
$i++;
}
?>
</Canvas>
Создание PHP-страницы для отображения Silverlight
Как было показано в предыдущем разделе, сервер выводит содержимое напрямую, пока не встречает открывающий тег (<?phpY Встретив этот тег, сервер обращается к интерпретатору PHP, который выполняет код, заключенный в открывающий и закрывающий теги (?>).
PHP-код обычно используется для создания динамического HTML-кода. Поскольку Silverlight отображается с помощью HTML, HTML-страница просто редактируется: в нее добавляются теги PHP, и меняется имя файла с добавлением расширения.php. Итак, чтобы реализовать отображение Silverlight, используя PHP, необходимо, чтобы страница, включающая Silverlightjs и createSilverlightjs, вызывала createSilverlight для создания экземпляра элемента управления Silverlight.
Мы хотим, чтобы пользователь мог выбирать имена и адреса в базе данных по штату. Таким образом, эта страница должна принимать параметр и применять его при создании содержимого Silverlight с использованием XAML-источника, сформированного PHP, который был представлен в предыдущем разделе. К счастью, это очень просто сделать в PHP. Чтобы вывести на экран, сформированный XAML, необходимо всего лишь присвоить в качестве значения свойства content элемента управления Silverlight Uniform Resource Indicator (URI)1 вашего приложения. Silverlight будет подключаться к серверу по этому URI, принимать результирующий XAML и формировать его визуальное представление.
Далее представлен полный код примера PHP-страницы, формирующей HTML:
<html xmlns="http://www.w3.org/1999/xhtml"> <head>
<title>SilverlightJSApplication2</title>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="createSilverlight.js"></script>
<script type="text/javascript">
function handleLoad(control, userContext, rootElement) {
<?php
if(!isset($_REQUEST['State']))
$State="";
else
$State=$_REQUEST['State'];
?>
control.source = "http://localhost/phptest/xaml.php?State=<?php echo($State) ?>";
}
</script>
</head>
<body>
<div id="SilverlightControlHost">
<script type="text/javascript">
Унифицированный индикатор ресурса (прим, переводчика).
createSilverlight();
</script>
</div>
</body>
</html>
На рис. 10-6 и 10-7 показано, как эта PHP-страница отображается в браузере с использованием Silver- light для адресов в Нью-Йорке (NY в базе данных) и Вашингтоне (WA).
РИС. 10 6 Содержимое, сформированное приложением PHP для адресов в Нью Йорке.
РИС. 10 7 Содержимое, сформированное приложением PHP для адресов в Вашингтоне.
Silverlight и Java
Язык программирования Java компилируется в байт-код, который либо интерпретируется, либо компилируется методом Just-In-Time (JIT) и вызывается во время выполнения на виртуальной машине. Это делает его идеально подходящим для серверных сред, особенно когда в центре обработки данных представлены различные операционные системы. Java поддерживается практически всеми основными операционными системами.
Существует много способов создания серверных приложения на Java и ее версии для предприятий, называемой обычно J2EE или просто JEE. Один из методов - Серверные страницы Java (Java Server Pages, JSP), концепция которых аналогична PHP, в которых для разметки необходимого вывода используется код, выполняющийся во время выполнения. Итак, для создания таких страниц используется
стандартная разметка HTML, но в нее помещаются теги JSP, которые будут выполняться при отображении страницы. Другой способ - использование Сервлета (Servlet) Java, который является приложением, выполняющимся на сервере и принимающим параметры через HTTP.
Открытость Silverlight позволяет создавать приложения, объединяющие в себе Silverlight и Java. Для построения страниц, включающих содержимое Silverlight, может использоваться технология JSP и серверные технологии, такие как сервлеты, идеально подходят для формирования XAML, отображаемого браузером.
Чтобы продемонстрировать создание приложений Silverlight в среде Java, поработаем с обеими технологиями. Сначала рассмотрим, как построить JSP-страницу для размещения элемента управления Silverlight. Затем создадим сервлет для генерирования XAML, визуальное представление которого будет формировать элемент управления Silverlight.
Создание сервлета для генерирования XAML
Сервлет - это приложение, расширяющее класс HttpServlet из пространства имен javax.servlet. Он предоставляет две функции, doGet и doPost, используемые для перехвата команд HTTP-GET и HTTP-POST, соответственно. Каждая из этих функций принимает объекты HTTPRequest (HTTP-запрос) и HTTPResponse (HTTP-ответ). Первый используется для получения сведений запроса, второй управляет ответом. Как правило, параметры считываются из объекта HTTPRequest, выходные данные записываются в объект HTTPResponse. Далее представлен пример этих функций:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Обрабатываем GET }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Обрабатываем POST }
В типовом шаблоне проектирования создается вспомогательная функция, принимающая объекты запроса и ответа, и затем методы doGet и doPost вызывают эту функцию. С этой точки зрения, код будет выполняться один и тот же, независимо от метода вызова сервлета.
В данном примере сервлет принимает XAML-документ как шаблон и использует прикладные программные интерфейсы (API) XML в Java для обработки документа, заполняя его результатами запроса к базе данных.
Далее представлен простой XAML-документ, используемый в этом учебном примере:
<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="200" Height="80"
Background="#FF000000">
<TextBlock x:Name="txtName" Width="200" Height="24"
Canvas.Left="24" Canvas.Top="8" Foreground="#FFEFB9B9" Text="Name" TextWrapping="Wrap"/>
<TextBlock x:Name="txtCity" Width="200" Height="24"
Canvas.Left="24" Canvas.Top="40" Foreground="#FFEFB9B9" Text="City" TextWrapping="Wrap"/>
<TextBlock x:Name="txtCountry" Width="200" Height="24"
Canvas.Left="24" Canvas.Top="72" Foreground="#FFEFB9B9" Text="Country" TextWrapping="Wrap"/>
</Canvas>
Данный XAML включает три элемента TextBlock. Сервлет выполняет запрос к таблице Customers (Покупатели) базы данных Northwind и заполняет элементы TextBlock результатами запроса. Запрос принимает в качестве параметра ID покупателя и использует его для извлечения соответствующей записи покупателя, в которой нас интересуют имя покупателя, город проживания и страна.
Если у вас еще нет используемой в этом примере базы данных Northwind, ее можно скачать на сайте Microsoft Developer Network (MSDN). База данных Northwind Traders является примером базы данных, которая предоставляется Microsoft свободно для SQL Server. Она содержит базу сведений о фиктивном Интернет-магазине и является полезным источником тестовых данных для таких примеров, какой рассматривается здесь.
Чтобы заполнить элементы TextBlock, необходимо найти их в XAML-документе. При использовании в Java XML API для поиска узлов по XPath понадобится задать префикс стандартного пространства имен для элементов. Так позже вы заметите, что ссылки на элементы стандартного пространства имен (<TextBlock>, например) формируются с использованием добавляемого во время выполнения префикса стандартного пространства имен (т.е. <d:TextBlock>).
Итак, в Java мы будем использовать API XML для поиска узла, который необходимо редактировать, по имени. Например, TextBlock, содержащий сведения о стране, называется txtCountry. Таким образом, для формирования XAML нашего приложения вспомогательная функция должна выполнять следующие шаги:
Принять входной параметр. Если он null, присвоить ему значение по умолчанию.
Задать text/xml в качестве выходного типа MIME.
Создать объект для XML-документа и загрузить в него XAML-файл шаблона. В этом примере XAML хранится в документе Template.xml.
Открыть базу данных SQL Server и выполнить запрос к таблице Northwind Customers для поиска покупателя, соответствующего входному параметру.
Необходимо будет прочитать максимум одну строку, читаем ее.
Используем XPath для узла ContactName (Имя контакта), чтобы найти его, и замещаем его содержимое значением поля ContactName, полученным из базы данных.
Используем XPath для узла City (Город), чтобы найти его, и замещаем его содержимое значением поля City, полученным из базы данных.
Используем XPath для узла Country (Страна), чтобы найти его, и замещаем его содержимое значением поля Country, полученным из базы данных.
Записываем XML в поток HTTP-ответа.
Имейте в виду этот алгоритм, рассматривая код листинга 10-3, в котором показана вспомогательная функция, используемая сервлетом для генерирования XAML.
ЛИСТИНГ 10 3 Java код для генерирования XAML
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { try { String strID = request.getParameter("ID"); if(strID==null) strID="ALFKI";
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
response.setContentType("text/xml");
PrintWriter out = response.getWriter();
DocumentBuilder builder = factory.newDocumentBuilder();
String uri = getServletContext().getRealPath("template.xml");
Document doc = builder.parse(uri);
DOMSource domSource = new DOMSource(doc);
StreamResult streamResult = new StreamResult(out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
XPathFactory xpFactory = XPathFactory.newInstance();
XPath xpath = xpFactory.newXPath();
xpath.setNamespaceContext(new DefaultNameSpaceContext());
String strContactName="";
String strCity="";
String strCountry="";
java.lang.Class.forName
("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection c = java.sql.DriverManager.getConnection
("jdbc:sqlserver://localhost\\SQLEXPRESS;databasename=Northwind;
user=javauser;password=javauser;");
String SQL =
"Select ContactName, City, Country
from Customers where CustomerID = ?";
PreparedStatement pstmt = c.prepareStatement(SQL);
pstmt.setString(1, strID);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
strContactName = rs.getString("ContactName");
strCity=rs.getString("City");
strCountry=rs.getString("Country");
String strXPath = "//d:TextBlock[@x:Name='txtName']";
XPathExpression expr = xpath.compile(strXPath);
Object result = expr.evaluate(doc,XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
Node ndeT1 =
nodes.item(0).getAttributes().getNamedItem("Text");
ndeT1.setNodeValue(strContactName);
strXPath = "//d:TextBlock[@x:Name='txtCity']";
expr = xpath.compile(strXPath);
result = expr.evaluate(doc,XPathConstants.NODESET);
nodes = (NodeList) result;
ndeT1 =
nodes.item(0).getAttributes().getNamedItem("Text");
ndeT1.setNodeValue(strCity);
strXPath = "//d:TextBlock[@x:Name='txtCountry']";
expr = xpath.compile(strXPath);
result = expr.evaluate(doc,XPathConstants.NODESET);
nodes = (NodeList) result;
ndeT1 =
nodes.item(0).getAttributes().getNamedItem("Text");
ndeT1.setNodeValue(strCountry);
}
rs.close();
pstmt.close();
serializer.transform(domSource, streamResult);
out.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
Результаты выполнения этого сервлета (на сервере приложений Tomcat) представлены на рис. 10-8.
Отображение Silverlight из JSP
Чтобы получить JSP-страницу, создается HTML-страница и затем те ее части, в которых должна выполняться логика страницы, дополняются с помощью разметки JSP. В данном случае мы хотим отображать Silverlight-приложение. Обычно это делается путем импорта библиотек сценариев Silverlightjs и create- Silverlight.js с последующим вызовом createSilverlight в именованном элементе DIV.
Однако наша JSP-страница будет немного более функциональной: она сможет принимать параметр и использовать его для построения элемента исходного XAML, созданного ранее. Для этого пишем код на Java и встраиваем его с помощью тегов JSP <% и %>. Полный код JSP-страницы представлен в листинге 10-4.
ЛИСТИНГ 10 4 JSP код для отображения содержимого Silverlight
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="js/silverlight.js"></script>
<script type="text/javascript"
src="js/createSilverlight.js"></script>
<script type="text/javascript">
function handleLoad(control, userContext, rootElement) {
<%
String strValue="";
if (request.getParameter("ID") == null) { strValue = "ALFKI";
} else {
strValue = request.getParameter("ID");
} %> control.source = "http://localhost:8084/ScreenCast2/XamlSource?ID=<% out.print(strValue); %>"; } </script>
<title>JSP Page</title>
</head>
<body>
<h1>Silverlight JSP Page</h1>
<div id="slContent">
<script type="text/javascript"> createSilverlight();
</script>
</div>
</body>
</html>
На рис. 10-9 и 10-10 показано, как эта страница выглядит. Заметьте, что параметр AROUT передается в JSP-страницу в строке запроса первой страницы, тогда как ALFKI передается во вторую страницу.
РИС. 10 9 Выполнение JSP с параметром ID AROUT.
РИС. 10 10 Выполнение JSP с параметром ID ALFKI.
Использование JavaScript для создания приложений, взаимодействующих с сервером
Silverlight приложение выполняется в браузере, поэтому JavaScript, и в частности AJAX, могут использоваться для создания взаимодействующих с сервером Silvelight-приложений. В данном разделе рассматриваются методы, применяемые для этого, включая получение данных от серверного приложения с помощью AJAX и введение их в собственное приложение Silverlight, а также использование ASP.NET AJAX для связи с Веб-сервисом, приема данных с сервера и формирования их представления в Silver- light.
Использование AJAX
Мы собираемся создать простое приложение, формирующее данные, которые будут перехватываться AJAX-вызовом и передаваться в Silverlight для отображения. Для этого сначала необходимо создать серверное приложение, которое при вызове будет возвращать текущее время на сервере.
Создание серверного приложения для получения текущего времени
Для начала создадим новое Веб-приложение ASP.NET. Добавим в него новый универсальный обработчик ServerTime.ashx. Отредактируем код этого обработчика так, чтобы он возвращал текущее системное время в виде обычного текста. Вот полный код ASHX:
using System;
using System.Collections;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
namespace AJAXSample {
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1 1)] public class ServerTime : IHttpHandler {
public void ProcessRequest(HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Write(System.DateTime.Now.ToShortTimeString());
}
public bool IsReusable
{ get {
return false;
}
}
}
}
При выполнении этот ASHX передаст текущее системное время в браузер, как показано на рис. 10-11.
РИС. 10 11 Выполнение обработчика ServerTime.
Теперь рассмотрим, как можно получить эти данные и отобразить в Silverlight.
Создание клиентского приложения для отображения времени
При создании нового Silverlight-приложения с использованием JavaScript в Microsoft Visual Studio будет создано приложение с простой кнопкой, которая выглядит, как представлено на рис. 10-12. Изменим это приложение так, чтобы при загрузке страницы оно обращалось к серверу для получения времени, используя только что созданный нами обработчик ASHX, и затем выводило это время на кнопке.
РИС. 10 12 Базовое приложение Silverlight.
Сделать это очень просто. Добавьте следующий AJAX-код в блок сценария:
var xmlHttp;
function getLatestTime() {
xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET","http://localhost:42395/ServerTime.ashx",true);
xmlHttp.onreadystatechange = handleAJAXCallback;
xmlHttp.send(null);
}
Если вы не знакомы с AJAX, не волнуйтесь, он достаточно прост. Первая строка создает новый объект XMLHttpRequest, который является основой всего, что делает AJAX. Обратите внимание, что мы стараемся не усложнять код, поэтому для более старых браузеров синтаксис создания объекта xmlHttp будет другим. После этого открывается URI универсального обработчика ServerTime, который был создан нами ранее.
Подсказка Чтобы этот фрагмент кода работал на вашем компьютере, не забудьте заменить URL в предыдущем фрагменте кода соответствующим URL вашего приложения.
Далее объявляется функция-обработчик события изменения свойства readyState (Состояние готовности) объекта AJAX. В этом случае формируется событие onreadystatechange (обратите внимание на чувствительность к регистру; событие должно быть записано строчными буквами), и обработчик события располагается в функции handleAJAXCallback (Обработка обратного вызова AJAX), которую вы увидите через мгновение. Наконец, вызывается функция send( объекта xmlHttp для установления сетевого соединения.
Функция handleAJAXCallback вызывается при каждом изменении свойства readyState объекта xmlHttp. Существует пять различных состояний:
0—Запрос еще не инициализирован.
1—Запрос инициализирован.
2—Запрос отправлен.
3—Запрос обрабатывается.
4—Запрос завершен.
Нас интересует состояние, свидетельствующее о завершении запроса, поэтому проводим проверку состояния 4. Вот код:
function handleAJAXCallback() {
if((xmlHttp.readyState == 4) && (xmlHttp.status ==200)) {
var SL = document.getElementById("silverlightPlugIn");
SL.content.findName("txt").Text = xmlHttp.responseText;
} }
Этот код проверяет значение свойства readyState и HTTP-код состояния (в свойстве status). Если они равны 4 и 200, соответственно (т.е. соединение было успешным), приложение находит в XAML элемент txt и задает в качестве его значение текст ответа. Обратите внимание, что в случае использования базового шаблона XAML, TextBlock с надписью на кнопке не имеет имени, поэтому не забудьте присвоить ему имя txt, чтобы гарантировать работоспособность этого кода. Свойство responseText (Текст ответа) объекта xmlHttp содержит данные, возвращенные с сервера. В данном случае, это текущее время на сервере.
И последнее, необходимо обеспечить вызов сценария при загрузке страницы. Для этого мы задаем сценарий onLoad в теге <BODY> страницы. Приведем пример:
<body onload="getLatestTime();">
Как все это выглядит, можно увидеть на странице рис. 10-13.
РИС. 10 13 Использование AJAX для обновления приложения Silverlight.
Это полезная техника для создания высоко-динамичных сайтов на Silverlight с использованием технологий, ориентированных на стандарты. Также показано, что Silverlight не связан с инфраструктурой сервера Microsoft и может размещаться и обновляться с любого сервера.
В следующем разделе будут рассмотрены Веб-сервисы ASP.NET и то, как с помощью ASP.NET AJAX организовать взаимодействие между ним и Silverlight.
Использование ASP.NET AJAX и Веб-сервисов
При создании Веб-сервиса с использованием ASP.NET можно пометить его как используемый в JavaScript, имея в виду, что этот Веб-сервис может автоматически сгенерировать JavaScript-прокси. Этот прокси использует JavaScript Object Notation (JSON), позволяя без труда передавать по сети сложные типы данных, не обращая внимания на вопросы совместимости. Итак, давайте создадим Вебсервис и посмотрим, как можно с помощью JavaScript извлекать данные из него и помещать в Silver- light.
В Visual Studio создаем новое приложение и добавляем в него Веб-сервис ASMX. Будем использовать этот Веб-сервис для формирования текущего времени в двух форматах: коротком и длинном. Для этого создадим класс, содержащий две строки, что обеспечит нам структурированный объект с данными. Вот как он выглядит:
public class DateData {
public string strShortTime;
public string strLongTime;
}
Теперь напишем код класса Веб-сервиса, который будет возвращать текущее время в двух форматах с помощью представленного выше класса. Обратите внимание, что класс обозначен как Sys- tem.Web.Script.Services.ScriptService.Тем самым мы указываем инфраструктуре ASP.NET пометить его как сервис, который может использоваться из JavaScript:
using System;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1 1)]
[System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService {
public Service () {
}
[WebMethod]
public DateData getTime(){
DateData dReturn = new DateData();
dReturn.strLongTime = System.DateTime.Now.ToLongTimeString();
dReturn.strShortTime = System.DateTime.Now.ToShortTimeString(); return dReturn;
}
}
При выполнении этого сервиса добавление /js в конце URI обеспечит формирование JavaScript- прокси. Поэтому для работы с этим Веб-сервисом можно либо использовать HTML-страницу, которая включает этот сценарий, либо ASP.NET-страницу с ScriptManager, ссылающимся на этот сервис. Применим здесь второй метод.
Создадим в решении ASP.NET-страницу и добавим в нее элемент управления ScriptManager. В ScriptManager необходимо добавить ссылку на только что созданный вами Веб-сервис. Делаем это с помощью тега <Services>. Вот пример:
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Service.asmx" InlineScript="true" />
</Services>
</asp:ScriptManager>
Далее добавляем на страницу Silverlight, как обычно. Но сначала взгляните на XAML, визуальное представление которого будет формировать Silverlight. В демонстрационных целях я сделал его максимально простым:
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Canvas.Top="0" x:Name="txtShort"></TextBlock>
<TextBlock Canvas.Top="20" x:Name="txtLong"></TextBlock>
</Canvas>
Добавляем этот код в страницу и создаем экземпляр объекта Silverlight, как обычно. Вот код, который может быть добавлен в раздел <body> разметки ASP.NET:
<div id="silverlightPlugInHost">
<script type="text/javascript"> Silverlight.createObjectEx({ source: 'Scene.xaml', parentElement: document.getElementById('silverlightPlugInHost'), id: 'silverlightPlugIn', properties: { width: '100%', height: '100%', background:'white', version: '1.0' }, events: { onLoad: handleLoad }, context: null
});
</script>
В этом коде необходимо обратить внимание на две вещи. Во-первых, источник задан как Scene.xaml, поэтому убедитесь, что при вызове своего XAML-файла используете именно это имя. Во-вторых, событие handleLoad определено как событие, формируемое, когда содержимое Silverlight загружено, и сформировано его визуальное представление.
Итак, рассмотрим это событие handleLoad:
function handleLoad() {
Service.getTime(onSuccess, onFailed,"");
}
Веб-сервис назван Service, и JavaScript-прокси принимает его имя. Таким образом, JavaScript-прокси можно вызывать, используя синтаксис ИмяКласса.ВебМетод. Наш Веб-метод назывался getTime (Получить время), поэтому просто вызываем Service.getTime. JavaScript-прокси для общения с Вебсервисом использует AJAX, и, поскольку AJAX применяет механизм обратного вызова, должны быть описаны функции обратного вызова в случае успеха и неудачи (или истечения времени ожидания). Итак, в данном случае, задаются функции обратного вызова onSuccess (В случае успеха) и onFailed (В случае неудачи), соответственно. Третий параметр - это параметр контекста, который может быть пустым.
Вот функции onSuccess и onFailed:
function onSuccess(result) {
var sl = document.getElementById("silverlightPlugIn");
sl.content.findName("txtShort").Text = result.strShortTime; sl.content.findName("txtLong").Text = result.strLongTime;
}
function onFailed(result) {
alert("Timed out");
}
Эти функции принимают возвращенное в параметре result (результат) значение. Мы используем JSON, поэтому это структурированный объект, так что значениями полей result.strShortTime и re- sult.strLongTime будут строки, содержащие время в укороченном и удлиненном форматах, соответственно. Нам осталось только найти элементы TextBlock по их именам и задать им соответствующие значения.
Взаимодействие и данные в .NET
При использовании .NET в Silverlight 2 взаимодействие с сервисами реализовывается посредством двух основных классов: WebClient и WebRequest (Веб-запрос). Как будет показано далее, эти классы обеспечивают гибкие средства доступа к данным. Кроме того, вы увидите, как в Silverlight можно использовать классы Windows Communication Foundation и ADO.NET Data Services (службы данных ADO.NET).
Класс WebClient
Класс WebClient является простейшим классом удаленного взаимодействия для Silverlight. При его использовании задается Uri содержимого, доступ к которому необходимо организовать, и затем для загрузки данных вызывается метод DownloadStringAsync (Загрузить строку асинхронно) или OpenReadA- sync (Открыть для чтения асинхронно). Первый используется для получения строковых данных, второй - для получения любых данных в виде потока. Для возвращения результатов выполнения этих методов потребуется функция обратного вызова, DownloadStringCompleted (Загрузка строки завершена) или OpenReadCompleted (Чтение завершено), соответственно.
Попробуем все это на практике. Создадим приложение Silverlight и, как делали это ранее, добавим универсальный обработчик в Веб-приложение и используем его для возвращения текущего времени на сервере. Для этого просто изменим ProcessRequest (Обработать запрос) следующим образом:
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Write(System.DateTime.Now.ToLongTimeString());
}
Теперь в Page.xaml.cs можно использовать класс WebClient для общения с сервером. Для этого добавьте в начало своего кода ссылку на пространство имен System.Net:
using System.Net;
Теперь, чтобы использовать класс WebClient, необходимо будет просто применить следующий код. Обратите внимание, что при написании кода этого приложения я использовал Cassini, поэтому работал с портом 65144. Вы можете использовать другой порт при выполнении своего приложения, поэтому не забудьте внести в код соответствующие изменения или настройте Cassini на использование конкретного порта.
public Page() {
InitializeComponent();
WebClient cl = new WebClient();
Uri uri = new Uri("http://localhost:65144/WebClientTest Web/Time.ashx");
cl.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(cl DownloadStringCompleted); cl.DownloadStringAsync(uri);
}
Для события DownloadStringCompleted объявлена функция-обработчик cl DownloadStringCompleted, поэтому по завершении передачи данных будет вызываться эта функция. Рассмотрим ее:
void cl DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{ txtTime.Text = e.Result;
}
Как видите, функция получает объект аргументов (в виде класса DownloadStringCompletedEventArgs), в котором имеется свойство Result, содержащее возвращенную строку.
WebClient имеет еще несколько полезных атрибутов: свойство IsBusy (Занят), которое возвращает true, если асинхронная передача данных еще не завершена, и метод CancelAync, который может использоваться для отмены выполняющихся асинхронных транзакций. Если это происходит, свойству Cancelled (Отменен) соответствующего обработчика (DownloadStringCompleted или OpenReadCompleted) присваивается значение true.
Класс WebRequest
Немного больше возможностей, включая использование Silverlight в качестве клиентской части стандартного шаблона HTTP-форм (с HTTP-POST), предоставляет класс WebRequest. Он действительно полезен с точки зрения обеспечения возможности взаимодействия, потому что методика HTTP-POST широко используется во всех серверных технологиях, так что клиентскую часть на HTML можно заменить Silverlight-приложением без всяких изменений серверной части кода.
Итак, например, объединим серверный компонент, принимающий запрос HTTP post к трем текстовым полям, t1, t2 и t3. Начнем с создания Silverlight-приложения и добавим универсальный обработчик в Веб-проект. Отредактируем метод обработчика ProcessRequest так, чтобы он принимал значения формы через HTTP-POST. Вот как реализовать прием трех строк из запроса HTTP-POST:
public void ProcessRequest (HttpContext context) {
string str1 = "";
string str2 = "";
string str3 = "";
if (context.Request.HttpMethod == "POST") {
str1 = context.Request.Form["t1"];
str2 = context.Request.Form["t2"];
str3 = context.Request.Form["t3"];
}
context.Response.ContentType = "text/plain";
context.Response.Write("OK");
}
Обычно в таких случаях используется HTML-форма с тремя элементами управления TextField (t1, t2 и t3) и кнопкой Submit (Отправить) для передачи этих данных. То же самое можно сделать в Silverlight. Вот XAML для простой формы ввода данных:
<UserControl x:Class="WebRequestTest.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.265*"/>
<ColumnDefinition Width="0.735*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.037*"/>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="0.05*"/>
<RowDefinition Height="0.106*"/>
<RowDefinition Height="0.054*"/>
<RowDefinition Height="0.09*"/>
<RowDefinition Height="0.563*"/>
</Grid.RowDefinitions>
<TextBox Margin="0,0,25,0" Grid.Column="1"
Grid.Row="1" x:Name="t1" />
<TextBox Margin="0,0,25,0" Grid.Column="1"
Grid.Row="3" x:Name="t2" />
<TextBox Margin="0,0,25,0" Grid.Column="1"
Grid.Row="5" x:Name="t3"
/>
<TextBlock Margin="8,0,0,0" Grid.Row="1"
Text="Field 1" TextWrapping="Wrap"/>
<TextBlock Margin="8,0,8,0" Grid.Row="3"
Text="Field 2" TextWrapping="Wrap"/>
<TextBlock Margin="8,0,8,0" Grid.Row="5"
Text="Field 3" TextWrapping="Wrap"/>
<Button Height="36" HorizontalAlignment="Left" Margin="0,26.9,0,0" VerticalAlignment="Top" Width="77" Grid.Column="1" Grid.Row="6"
Content="Submit" x:Name="b" Click="b Click" />
</Grid>
</UserControl>
Как эта форма выглядит, можно увидеть на рис. 10-14.
РИС. 10 14 Форма ввода данных на Silverlight.
Пользователь вводит текст в трех полях и затем нажимает кнопку Submit. При этом формируется событие b Click. Вот код обработки этого события:
private void b Click(object sender, RoutedEventArgs e) {
Uri uri = new Uri(
"http://localhost:22602/WebRequestTest Web/SubmitForm.ashx");
WebRequest rq = WebRequest.Create(uri);
rq.Method = "POST";
rq.ContentType = "application/x-www-form-urlencoded";
rq.BeginGetRequestStream(new AsyncCallback(RequestReady), rq); rq.BeginGetResponse(new AsyncCallback(ResponseReady), rq);
}
При использовании класса WebResponse сначала необходимо задать вызываемый URI. Это выполняется с помощью объекта Uri; он указывает на сайт, содержащий обработчик форм. Затем этот URI передается в метод Create (Создать) WebRequest для установления связи. Также задается используемый Method (Метод). Это может быть метод HTTP-Verb, такой как POST или GET. В данном случае, выполняется отправка данных формы, поэтому должен применяться POST.
Далее необходимо задать соответствующий тип содержимого. Опять же, поскольку используется форма, этим типом будет application/x-www-form-urlencoded. Все эти действия выполняются соответственно Веб-стандартам, поэтому возможные варианты значений можно найти в любом хорошем справочнике во Веб.
Наконец, должен быть задан поток запроса. Это поток, потому что предполагается запись данных в запрос. Вы должны задать метод асинхронного обратного вызова, который будет выполняться после завершения Request, а также ссылку на сам объект запроса. Кроме того, требуется перехватывать ответ
формы, поэтому вызывается BeginGetResponse (Начать прием ответа) для начала настройки потока и задается обратный вызов, который будет выполняться, когда поток ответа готов.
В методе обратного вызова, который вызывается, когда поток запроса готов, можно выполнить запись в поток, используя объект StreamWriter (объект записи в поток). В данном случае, записывается несколько параметров. Согласно протоколу HTTP они должны быть разделены символами &: t1=3HQ4eHue1&t2=3Ha4eHue2&t3=3Ha4eHue3.
Итак, теперь осталось лишь записать имя параметра и свойство Text полей ввода:
void RequestReady(IAsyncResult aR){
WebRequest rq = aR.AsyncState as WebRequest;
Stream rqStream = rq.EndGetRequestStream(aR);
StreamWriter w = new StreamWriter(rqStream);
w.Write("t1=" + t1.Text + "&");
w.Write("t2=" + t2.Text + "&");
w.Write("t3=" + t3.Text ); w.Flush();
}
Как было показано в универсальном обработчике событий, после того как сервер получает данные, он записывает OK для обозначения состояния. По завершении записи ответа вызывается метод обратного вызова ResponseReady (Ответ готов).
void ResponseReady(IAsyncResult aR) {
WebRequest rq = aR.AsyncState as WebRequest; using(WebResponse rs = rq.EndGetResponse(aR)) using (Stream rpStream = rs.GetResponseStream()) {
StreamReader rdr = new StreamReader(rpStream); string postStatus = rdr.ReadToEnd();
} }
Этот код просто извлекает поток ответа из результата асинхронного вызова и читает его до конца. В данном случае, это просто состояние, но так можно извлекать ответы с сервера для каждого поля.
Как видите, применяя данную методику, довольно просто создавать Silverlight-клиентские приложения заменяющие традиционные HTTP-формы!
Использование SyndicatedFeed для организации доступа к RSS и ATOM
Двумя наиболее популярными типами данных, доступными в Интернете, являются каналы RSS и ATOM, обычно используемые в блогах или на новостных сайтах. Silverlight предлагает класс SyndicatedFeed (Информационный канал), с помощью которого можно без труда организовать доступ к этим данным.
SyndicatedFeed очень прост в использовании. Рассмотрим на примере. Но, прежде чем продолжить, остановимся на мгновение на междоменном доступе в Silverlight. При организации доступа к содержимому, находящемуся на других сайтах (не на том, который обслуживает содержимое Silverlight), .NET-классы ищут на сервере файл Crossdomain.xml. Если они находят его, то проводят синтаксический разбор междоменных правил, чтобы выяснить, имеют ли они право на доступ к содержимому. Если они не находят этот файл, они формируют ошибку. Поэтому помните об этом, прежде чем использовать SyndicatedFeed для доступа к данным, или можете столкнуться с проблемами. В сети можно найти много информации о Crossdomain.xml, потому что он де факто является стандартным способом обеспечения междоменного доступа для разных технологий.
Для данного примера мы буем просто использовать статический XML-документ Doc.rss, хранящийся на сервере.
Прежде чем приступать к написанию кода, убедитесь в наличие соответствующих ссылок, которые обеспечивают возможность использовать SyndicatedFeed, потоковую передачу данных и XML.
using System.Net;
using System.Xml;
using System.IO;
using System.ServiceModel.Syndication;
Чтобы создать эту ссылку, вероятно, придется добавить ссылку на System.ServiceModel.Syndication.
Следующее, что необходимо сделать до написания кода, - сформировать представление данных в XAML.
<UserControl x:Class="RSSClient.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas x:Name="LayoutRoot" Width="400"
Height="300" Background="White">
<ItemsControl x:Name=" rssTitles">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock FontWeight="Bold"
Text="{Binding Title.Text}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</UserControl>
Здесь в XAML используется объект ItemsControl (Элементы), который в сочетании с ItemTemplate (Шаблон элемента) обеспечит базовую функцию повторения. Этот объект связывается с данными с помощью DataTemplate (Шаблон данных), определяющего, что элемент управления TextBlock связан с данными RSS-канала по Title.
Возвращаясь к С#-коду, теперь можно создать объект WebClient для загрузки RSS-документа. После того, как RSS-документ будет загружен, его можно будет прочитать с помощью элемента управления SyndicatedFeed. Вот код для создания WebClient, выполняющего доступ к RSS-документу:
public Page() {
InitializeComponent();
WebClient client = new WebClient();
Uri uri = new Uri("doc.rss",UriKind.Relative);
client.OpenReadCompleted +=
new OpenReadCompletedEventHandler(client OpenReadCompleted);
client.OpenReadAsync(uri);
}
Здесь задается функция обратного вызова (client OpenReadCompleted), которая вызывается по завершении загрузки. Вот код этой функции:
void client OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e) {
XmlReader r = XmlReader.Create(e.Result);
SyndicationFeed feed = SyndicationFeed.Load(r);
rssTitles.ItemsSource = feed.Items;
}
Здесь создается XmlReader (объект чтения Xml), который считывает результаты обратного вызова и передает их в SyndicationFeed. Также SyndicationFeed содержит соответствующие коллекции, включая коллекцию Items (Элементы). Эта коллекция содержит (кроме всего прочего) Title для элемента RSS, таким образом, задавая свойство ItemsSource элемента ItemsControl коллекции rssTitles, мы выполняем привязку данных, и заголовки будут формироваться Silverlight. Результаты представлены на рис. 10-15.
РИС. 10 15 Просмотр данных RSS с использованием SyndicationFeed и привязки данных.
Выходя за рамки таких простых каналов, как RSS и ATOM, Silverlight предоставляет возможность использования таких расширенных сервисов, как ASMX и Веб-сервисы WCF. Это будет рассмотрено в следующем разделе.
Silverlight и WCF
Пространство имен System.ServiceModel содержит классы, используемые Silverlight для работы с Вебсервисами . В данном разделе мы поэтапно рассмотрим процесс создания простого сервиса в WCF и его использование в Silverlight.
Создадим новое приложение Silverlight и добавим новый класс в Веб-проект. Назовем его Person (Человек), и будет создан класс Person.cs. Он будет использоваться для передачи данных между сервисом и клиентом. Для этого необходимо обозначить этот класс как DataContract (Контракт данных) между WCF и Silverlight и пометить каждый его элемент, с которым должен будет работать Silverlight, атрибутом DataMember (Элемент данных).
Обратите внимание, что понадобится включить System.Runtime.Serialization. Рассмотрим код:
[DataContract] public class Person {
public Person(string strName, string strAge) {
Name = strName;
Age = strAge;
}
[DataMember]
public string Name { get; set; }
[DataMember]
public string Age { get; set; } }
Сюда также входит конструктор, используемый для инициализации свойств Name и Age (Возраст).
Далее необходимо добавить в проект шаблон WCF Service (WCF-сервис). Присвоение ему имени PersonService обеспечит создание файлов PersonService.cs и IPersonService.cs. Файл IPersonService.cs будет отвечать за создание интерфейса, определяющего контракт сервиса. В нем необходимо будет определить метод сервиса, возвращающий список людей. Сделать это несложно: просто пометьте интерфейс атрибутом ServiceContract и метод, доступный для вызова, атрибутом OperationContract (Контракт операции).
[ServiceContract] public interface IPersonService {
[OperationContract]
Person[] getPeople();
}
Реализация сервиса выполняется в классе PersonService.cs. В нем должны быть реализованы, по крайней мере, методы, описанные в OperationContract. Рассмотрим пример:
public class PersonService : IPersonService {
public Person[] getPeople()
{
Person[] people = {
new Person("Derek Snyder","32"), new Person("Yoshi Latimer","19"), new Person("Mark Steel","31")
}; return people;
} }
Здесь создается и возвращается вызывающей стороне массив объектов Person, названный people (люди). Silverlight может выполнить привязку к такой коллекции элементов. Прежде, чем двигаться дальше, необходимо убедиться, что WCF правильно сконфигурирован для выполнения базового HTTP- связывания1, которое будет использоваться клиентом Silverlight. Это выполняется в файле Web.config. Найдите следующий код в узле <serviceModel> и убедитесь, что связывание задано как basicHttpBinding (Базовое HTTP-связывание):
<service behaviorConfiguration="PersonServiceBehavior" name="PersonService">
<endpoint address=""
binding="basicHttpBinding" contract="IPersonService"> <identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
Протестируйте работоспособность сервиса, щелкнув правой кнопкой мыши файл PersonService.svc и выбрав в контекстном меню View In Browser (Просмотр в браузере). Если все хорошо, на экране вы увидите примерно следующее (рис. 10-16):
РИС. 10 16 Выполнение WCF сервиса.
Если сервис работает правильно, можно добавлять ссылку на него в проект Silverlight. Опять же, все просто: щелкаем правой кнопкой мыши узел References в Solution Explorer и выбираем в контекстном
''Использование базовых Веб сервисов по протоколу SOAP 1.1 (прим, научного редактора).
меню Add Service Reference (Добавить ссылку на сервис). Появится диалоговое окно Add Service Reference, как показано на рис. 10-17. Введите адрес сервиса и щелкните кнопку Go (Перейти). Это обеспечит создание прокси-классов для сервиса.
РИС. 10 17 Добавление ссылки на сервис.
Прокси будет создан в пространстве имен, заданном в диалоговом окне. В данном случае, используется имя PSProxy, который через мгновение вы увидите в коде.
Прежде всего, необходим XAML для определения уровня представления. Это XAML с привязкой к данным, который связывается с результатами вызова сервиса:
<ItemsControl x:Name=" itemTitles">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold" Text="{Binding Name}" />
<TextBlock Text=" : "></TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding Age}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Как видите, здесь имеется два элемента TextBlock, которые связаны со значениями Name и Age. Рассмотрим вызов сервиса и то, как он используется для передачи данных в это содержимое Silverlight:
Binding binding = new BasicHttpBinding();
EndpointAddress endPoint = new EndpointAddress
("http://localhost:25101/PersonService Web/PersonService.svc");
PSProxy.PersonServiceClient client = new
PSProxy.PersonServiceClient(binding, endPoint);
client.getPeopleCompleted += new
EventHandler<PersonService.PSProxy.getPeopleCompletedEventArgs> (client getPeopleCompleted);
client.getPeopleAsync();
Здесь создается новый класс BasicHttpBinding под именем binding (что соответствует тому, что вы задавали в Web.config для этого сервиса) и EndpointAddress (Адрес конечной точки), указывающий на сам сервис. Затем создается новый экземпляр клиента сервиса (который был сформирован для вас автоматически при создании ссылки на сервис) и описывается функция обратного вызова. Наконец, выполняется вызов функции getPeopleAsync, которая обеспечивает асинхронный вызов метода сервиса. По завершении выполнения метода сервиса, запускается функция обратного вызова.
Функция обратного вызова получает аргументы, содержащие массив объектов Person, формируемый методом сервиса. Это коллекция, которую можно связать с ItemsControl, представленным ранее. Посмотрим на код:
void client getPeopleCompleted(object sender,
PersonService.PSProxy.getPeopleCompletedEventArgs e) {
itemTitles.ItemsSource = e.Result;
}
Результаты этого представлены на рис. 10-18.
РИС. 10 18 WCF клиент на Silverlight.
Все эти примеры очень просты, но я надеюсь, что они иллюстрируют различные доступные сценарии создания взаимодействующих с сервером приложений и обеспечивают базовые сведения, которые пригодятся при написании реального кода для Silverlight-приложений!
Заключение
В данной главе представлены различные стратегии создания взаимодействующих с сервером приложений на Silverlight. Вы увидели, как XAML может использоваться в качестве инструмента взаимодействия из приложений на базе PHP и Java и как Silverlight может использоваться для связи с этими приложениями. Затем мы рассмотрели AJAX и познакомились с тем, как использовать AJAX и JavaScript для получения данных от серверных приложений, и как открытая природа дерева визуального отображения Silverlight позволяет передавать эти данные в элемент управления Silverlight для дальнейшего отображения. Наконец, вы познакомились с некоторыми новыми классами, предлагаемыми Silver- light 2 для работы с сетью и связи. Рассмотрены классы WebClient и WebRequest. Также вы научились создавать приложения для использования WCF-сервисов через прокси.
В следующей главе будут представлены некоторые ориентированные на потребителя технологии Silverlight 2, включая элементы управления для мультимедийного содержимого, элемент управления, обеспечивающий возможность использования ваших приложений на компьютерах с перьевым вводом, и новый элемент управления, обеспечивающий в Silverlight-приложениях функциональность Deep Zoom.
Глава 11
Мультимедиа, рукописный ввод и Deep Zoom
В предыдущих главах вы познакомились с основными элементами управления, используемыми для создания насыщенных интерактивных Интернет-приложений. В данной главе будет рассмотрено три элемента управления, предоставляющие специальную функциональность. Сначала будет представлен элемент управления MediaElement, который обеспечивает API для управления аудио- и видеоданными, позволяя тем самым создавать замечательные мультимедийные приложения. Затем вы рассмотрите элемент управления InkPresenter (Элемент отображения рукописного ввода), который позволяет вводить рукописное или рисованное содержимое посредством рукописных примечаний, т.е. обеспечивает возможность использования приложения на компьютерах с перьевым вводом. Наконец, вашему вниманию будет представлен достаточно новый элемент управления Silverlight 2, MultiScaleImage (Масштабируемое изображение), который добавляет в ваши приложения новое измерение - возможность глубокого масштабирования.
Элемент управления MediaElement
Одно из наиболее важных применений Silverlight в Веб - обеспечение поддержки мультимедиа следующего поколения, которое может воспроизводиться на разных платформах. Для этого Silverlight поддерживает элемент управления MediaElement, которому посвящен данный раздел. В нем поэтапно рассматривается процесс создания простого медиаплейера, обеспечивающего возможность прогрессивной загрузки и воспроизведения видеоданных. Кроме того, вы научитесь закрашивать поверхности с помощью видео-кисти, что позволит добавлять интересные графические эффекты. Элемент управления MediaElement поддерживает следующие форматы:
Видео
WMV1: Windows Media Video 7
WMV2: Windows Media Video 8
WMV3: Windows Media Video 9
WMVA: Windows Media Video Advanced Profile, не-VC-1
WMVC1: Windows Media Video Advanced Profile, VC-1
Аудио
WMA7: Windows Media Audio 7
WMA8: Windows Media Audio 8
WMA9: Windows Media Audio 9
MP3: ISO/MPEG Layer 3
Моно или стерео
Частоты дискретизации от 8 до 48 кГц
Скорости передачи двоичных данных от 8 до 320 Кбит/с
Переменная скорость передачи двоичных данных
Кроме этих форматов, элемент управления MediaElement также поддерживает списки воспроизведения ASX и протоколы http, https и mms.
Если говорить о потоковой передаче видео- и/или аудио, MediaElement поддерживает потоковое вещание и потоковую передачу по запросу от Windows Media Server. Если для URI задан протокол mms, потоковая передача включена; в противном случае, загрузка и воспроизведение файла будут осуществляться путем прогрессивной загрузки, при которой воспроизведение начинается только после заполнения буфера воспроизведения и затем эти два процесса выполняются параллельно.
Если определен протокол http или https, происходит обратное. MediaElement сначала делает попытку выполнить прогрессивную загрузку, и уже в случае неудачи пытается применить потоковую передачу файла.
Использование элемента управления MediaElement
Элемент управления MediaElement в базовой конфигурации настроить очень просто, но он имеет множество расширенных функций, освоив которые, вы сможете реализовывать довольно интересные сценарии. Но, прежде чем бегать, надо научиться ходить, поэтому сначала обратимся к решению самых обычных задач с помощью MediaElement.
Простое воспроизведение видео с помощью элемента управления MediaElement
Чтобы начать работу с элементом управления MediaElement, добавьте его на свою страницу и задайте в качестве значения его атрибута Source URL видеофайл, который хотите воспроизвести. Рассмотрим пример XAML-кода Silverlight 2 приложения:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SilverlightApplication5.Page" Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White">
<MediaElement Source="balls.wmv" />
</Grid>
</UserControl>
Это обеспечит автоматическую загрузку и воспроизведение видеоданных. Размер области воспроизведения мультимедиа определяется следующими правилами:
Если заданы свойства Height и Width элемента управления MediaElement, MediaElement использует их.
Если задано одно из этих свойств, элемент управления MediaElement растянет мультимедиа, сохраняя пропорции изображения.
Если не заданы ни Height, ни Width, элемент управления MediaElement будет воспроизводить видео в стандартных размерах. Если они превышают размер области просмотра элемента управления Silverlight, MediaElement обрежет видео соответственно размеру области просмотра.
Рассмотрим пример. Используемая в данной главе (и доступная для скачивания на Веб-сайте компании) видеозапись balls.wmv имеет размер 480 х 360. Если указать MediaElement воспроизводить это видео и не задать его Height и Width, воспроизводимое видеоизображение будет размером 480 х 360. Если у UserControl выставить размер 200 х 200, на экране будет видна только часть видеоизображения размером 200 х 200 пикселов, начиная от верхнего левого угла. Обрезанная таким образом часть видео представлена на рис. 11-1.
РИС. 11 1 Видеоизображение, обрезанное по размеру элемента управления Silverlight.
Размеры элемента управления MediaElement
Как было показано в предыдущем разделе, размер MediaElement важен при воспроизведении видео. Если размеры элемента управления не заданы, и видеоизображение превышает размеры элемента управления Silverlight, оно будет обрезано.
Управление шириной и высотой самого MediaElement осуществляется через его свойства Height и Width. При формировании визуального представления элемента управления, мультимедиа будет растягиваться (или сжиматься) так, чтобы поместиться в элемент управления. Если заданный размер элемента управления мультимедиа больше элемента управления Silverlight, изображение будет обрезано размерами элемента управления Silverlight.
Далее представлен пример элемента управления MediaElement, для которого заданы размеры 200 х 200. На рис. 11-2 можно увидеть, как будет отображаться видео:
<MediaElement Source="balls.wmv" Height="200" Width="200" />
РИС. 11 2 Отображение видео после задания размеров MediaElement.
Растяжение мультимедиа
В предыдущем примере видеоизображение сворачивалось до размера элемента управления MediaElement (200 х 200). Как видно на рис. 11-2, размер видеоизображения (исходный размер которого, как вы помните, 480 х 360 пикселов) меняется так, чтобы оно поместилось в MediaElement, но с сохранением его пропорций. Это может привести к появлению черных полей вверху и внизу видеоизображения, создавая эффект просмотра широкоформатного видео. Переопределить это поведение можно с помощью свойства Stretch элемента управления MediaElement. Это свойство принимает четыре разных значения:
None Растяжения нет. Если MediaElement больше размера видеоизображения, видеоизображение
будет отображаться в центре области отображения. Если MediaElement меньше, будет видна центральная часть видеоизображения. Например, возьмем видео размером 480 х 360. Если размер MediaElement - 200 х 200, и Stretch задано значение None, будет отображаться центральная область видеоизображения размером 200 х 200, как показано на рис. 11-3.
РИС. 11 3 Эффект задания свойству Stretch значения None.
Uniform Это режим растяжения по умолчанию, он обеспечивает сохранение пропорций видеоизображения и добавление полей вверху, внизу или по бокам в случае необходимости.
UniformToFill Это значение обеспечивает растяжение видео с сохранением его пропорций. При этом часть видеоизображения, не поместившаяся в область отображения, обрезается. Так, например, если ширина видео больше его высоты (например, 480 х 360) и оно должно отображаться в окне 200 х 200, видеоизображение будет обрезано, чтобы поместиться в окне просмотра (до меньшего квадрата, в данном случае). Результат этого можно увидеть на рис. 11-4. Если сравнить его с рис. 11-2, можно заметить, что видео обрезано.
РИС. 11 4 Использование режима растяжения UniformToFill.
Fill Это режим растяжения обеспечивает заполнение MediaElement видеоизображением с изменением его пропорций в случае необходимости. На рис. 11-5 показано отображение видео, когда свойству Stretch задано значение Fill. Как видно в этом случае, для заполнения области просмотра видеоизображение растянуто по вертикали.
РИС. 11 5 Использование значения Fill свойства Stretch.
Прозрачность видеоизображения
Регулировать прозрачность MediaElement позволяет свойство Opacity. Это нормализованное свойство, т.е. значение 0 эквивалентно полной прозрачности, 1 - полной непрозрачности, все остальные значения в этом диапазоне представляют разные степени прозрачности. Видеоизображение будет отображаться с заданной прозрачностью, при этом элементы, находящиеся позади элемента мультимедиа на экране, будут видны.
Далее представлен пример XAML, обеспечивающий отображение красного прямоугольника и MediaElement . Для MediaElement задана прозрачность 0,5, что делает видеоизображение полупрозрачным. Поскольку визуальное представление MediaElement формируется вторым, он размещается ближе в направлении по оси Z и располагается поверх прямоугольника. На рис. 11-6 можно увидеть результат выполнения этого примера.
<Rectangle Fill="Red" Height="100" Width="200" />
<MediaElement Source="balls.wmv" Height="200"
Width="200" Stretch="Fill" Opacity="0.5" />
РИС. 11 6 Применение свойства Opacity для видеоизображения.
Использование трансформаций с элементом управления
MediaElement
Подробно трансформации рассматриваются в Главе 5, «Трансформация и анимация в XAML», здесь хотелось бы отметить лишь то, что трансформации могут применяться и к элементу управления MediaElement . При этом отображаемое видео также трансформируется. Это может привести к созданию некоторых очень интересных эффектов. Например, далее представлен MediaElement, к которому применена трансформация наклонение:
<MediaElement Source="balls.wmv" Height="200" Width="200" Stretch="Fill" >
<MediaElement.RenderTransform>
<SkewTransform AngleX="45"/>
</MediaElement.RenderTransform>
</MediaElement>
Как это выглядит, можно увидеть на рис. 11-7.
РИС. 11 7 Наклонение видео с помощью SkewTransform.
Расположение содержимого поверх видеоизображения
Silverlight позволяет размещать содержимое, включая текст и графические элементы, поверх видеоизображения. Это можно сделать либо с помощью свойств ZOrder (Z-порядок) элементов пользовательского интерфейса (UI) (смотрите Главу 1, «Введение в Silverlight 2»), либо просто размещать элементы UI в том же месте, что и элемент мультимедиа, и объявлять их в XAML после него. Далее представлен пример MediaElement, и Canvas с прямоугольником и текстовым блоком, который перекрывает видеоизображение:
<MediaElement Source="balls.wmv" Height="200" Width="200" Stretch="Fill" />
<Canvas Margin="20,140,0,0">
<Rectangle Fill="Red" Height="40" Width="160" />
<TextBlock>Subtitle on Video</TextBlock>
</Canvas>
На рис. 11-8 показано, как это будет выглядеть на экране.
РИС. 11 8 Отображение содержимого поверх видео.
Вырезание мультимедиа геометрическими формами
В Главе 4, «Основы XAML» были рассмотрены вырезание и геометрические элементы. Эти возможности также могут применяться к MediaElement, для которого с помощью фигур или контуров можно определить контур вырезания. Например, следующий XAML в качестве контура вырезания для MediaElement определяет эллипс:
<MediaElement Source="balls.wmv" Height="200" Width="200" Stretch="Fill" >
<MediaElement.Clip>
<EllipseGeometry RadiusX="100" RadiusY="75" Center="100,75"/>
</MediaElement.Clip>
</MediaElement>
Результаты представлены на рис. 11-9.
РИС. 11 9 Вырезание мультимедиа геометрическими формами.
Автоматическое воспроизведение
По умолчанию, если задан источник, MediaElement автоматически воспроизводит мультимедиа. Этим поведением можно управлять посредством свойства AutoPlay (Автоматическое воспроизведение). По умолчанию его значение true, но его можно переопределить и задать false. Можно воспроизвести мультимедиа позже, используя метод Play (Воспроизвести). Этот и другие методы и события, используемые при программировании элемента мультимедиа, рассматриваются в следующем разделе.
Управление воспроизведением звука
С помощью свойства IsMuted (Без звука) элемента управления MediaElement можно определить, будет ли аудиозапись сопровождать воспроизведение или нет. Это свойство Булевого типа, и если задать ему значение true, звук будет отключен.
Кроме того, с помощью свойства Volume (Громкость) можно управлять громкостью звука. Оно принимает нормализованное значение, где 0 эквивалентно отсутствию звука, 1 - полной громкости, и промежуточные значения представляют относительные уровни громкости. Итак, например, значение 0,43 обозначало бы воспроизведение звука с громкостью, составляющей 43% от полной громкости.
Наконец, балансом звука можно управлять с помощью свойства Balance (Баланс), которое принимает значения в диапазоне от -1 до +1. Значение -1 приводит к смещению баланса звука полностью влево, т.е. левый динамик будет воспроизводить звук со 100% громкостью, и в правом динамике будет 0% громкости. Значение +1 обеспечивает прямо противоположный эффект - баланс звука будет полностью смещен вправо, при этом правый динамик будет воспроизводить звук со 100% громкостью. Значение 0 обеспечивает равномерное распределение громкости между двумя динамиками.
Например, свойству Balance задано значение 0,8, тогда правый динамик будет воспроизводить звук с 80% громкостью и левый динамик - с 20%. Если используется значение -0,8, левый динамик будет воспроизводить звук с громкостью 80%, и правый динамик - с громкостью 20%.
Далее представлен некоторый XAML, определяющий, что звук не выключен, общая громкость составляет 50% и что баланс звука смещен вправо:
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200"
Stretch="Fill" IsMuted="False" Volume="0.5" Balance="0.8" />
Программирование MediaElement
MediaElement предлагает насыщенную модель программирования, которая позволяет управлять воспроизведением методами Play, Stop (Остановить) и Pause (Приостановить). Также вы имеете возможность взаимодействовать с видео, отслеживая процесс буферизации и загрузки, а также отвечать на маркеры, размещенные в видеофайле. Кроме того, можно обработать события для перехвата, такие как поведение мыши.
Базовые элементы управления воспроизведением
Основными методами управления видео являются Play, Stop и Pause. Если свойству AutoPlay элемента управления MediaElement задано значение false, для начала воспроизведения видео необходимо применить Play. Даже если AutoPlay задано значение true, и воспроизведение начинается автоматически, с помощью этих методов его можно остановить или приостановить. Далее представлен пример XAML, в котором имеется элемент мультимедиа и три простых элемента управления воспроизведением, реализованных как элементы TextBlock:
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200" Stretch="Fill" />
<Canvas Canvas.Top="160">
<Rectangle Fill="Black" Width="200" Height="24" Opacity="0.7"/>
<TextBlock Foreground="White" Canvas.Left="20">Play</TextBlock>
<TextBlock Foreground="White" Canvas.Left="80">Stop</TextBlock>
<TextBlock Foreground="White" Canvas.Left="140">Pause</TextBlock>
</Canvas>
На рис. 11-10 показано, как эти элементы управления будут выглядеть на видеоизображении.
РИС. 11 10 Добавление элементов управления в видеоизображение.
Для создания элементов управления вы задаете имя функции, которая должна выполняться в ответ на событие мыши, используя атрибут самого элемента управления видео. Намного более подробно обработка событий Silverlight с помощью JavaScript рассматривается в Главе б, «Элемент управления браузера Silverlight». Однако, в данном случае, просто требуется начать, остановить или приостановить воспроизведение видео, когда пользователь щелкнет соответствующий текстовый блок. Это реализуется путем обработки события MouseLeftButtonDown текстового блока, которое ассоциируется с функциями, воспроизводящими, приостанавливающими или останавливающими воспроизведение.
При программировании на JavaScript необходимо обеспечить, чтобы эти функции были доступны со страницы, на которой размещается элемент управления Silverlight. Итак, они могут быть реализованы либо путем использования элементов JavaScript на странице, либо в файле js, который включен в страницу с помощью элемента JavaScript, свойству Src которого задано соответствующее значение.
Если для сведения воедино содержимого XAML используется Expression Blend, он обеспечивает для Page.xaml псевдо-файл выделенного кода Page.xaml.js. Это идеальное место для реализации функциональности JavaScript.
Создадим проект Silverlight 1.0 Site. Далее представлен XAML, описывающий похожий UI, как был создан в предыдущем примере, но с объявлениями обработчиков событий:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="640" Height="480" Background="White" x:Name="Page">
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200" Stretch="Fill" />
<Canvas Canvas.Top="160">
<Rectangle Fill="Black" Width="200" Height="24" Opacity="0.7"/>
<TextBlock MouseLeftButtonDown="doPlay"
Foreground="White"
Canvas.Left="20">Play</TextBlock>
<TextBlock MouseLeftButtonDown="doStop" Foreground="White"
Canvas.Left="80">Stop</TextBlock>
<TextBlock MouseLeftButtonDown="doPause" Foreground="White"
Canvas.Left="140">Pause</TextBlock>
</Canvas> </Canvas>
Теперь можно написать кода на JavaScript для начала, остановки и приостановки воспроизведения. Вот этот код:
function doPlay(sender, args) {
var meVid = sender.findName("vid"); meVid.Play();
}
function doStop(sender, args) {
var meVid = sender.findName("vid"); meVid.Stop();
}
function doPause(sender, args) {
var meVid = sender.findName("vid"); meVid.Pause();
}
Когда функция JavaScript определяется как обработчик события, она должна принимать два параметра. Первый, sender, - это объект, который формирует событие. Второй, args, содержит аргументы, которые включаются как часть события.
Теперь в этой JavaScript-функции необходимо получить ссылку на объект MediaElement, управление которым осуществляется. Выполняется это с помощью метода findName объекта sender. Хотя отправителем является текстовый блок, который щелкнул пользователь, выполнение его метода findName все равно обеспечит выполнение поиска по всему XAML-документу до тех пор, пока не будет найден элемент vid (который был создан путем применения атрибута x:Name к нашему объекту MediaElementY Если вернуться к XAML, можно увидеть, что в MediaElement был элемент x:Name со значением vid, так что поиск должен быть успешным. Ссылка на соответствующий объект MediaElement будет сохранена в переменной JavaScript meVid. Теперь для управления воспроизведением осталось просто вызывать методы Play, Stop или Pause для этого объекта.
При создании проекта приложения для Silverlight 2 и использовании .NET все даже еще проще: не надо использовать findName для доступа к элементу, и ему уже присвоено имя vid, так что код будет выглядеть так:
private void doPlay(object sender, MouseButtonEventArgs e) {
vid.Play();
}
private void doPause(object sender, MouseButtonEventArgs e) {
vid.Pause(); }
private void doStop(object sender, MouseButtonEventArgs e) {
vid.Stop();
}
Управление буферизацией и загрузкой
При использовании прогрессивной загрузки видео подсистема мультимедиа определяет, сколько видеоданных необходимо кэшировать, прежде чем будет возможно воспроизведение. Итак, в зависимости от того, какая полоса пропускания необходима для загрузки видео, и какая полоса пропускания доступна, создается буфер для размещения объема видеоданных, достаточного для начала воспроизведения, в ходе которого загрузка видео продолжается в фоновом режиме.
Когда буфер полон на 100%, начинается воспроизведение. Воспроизведение может прерываться при изменении состояния связи и дозагрузки буфера. Silverlight позволяет отслеживать это поведение с помощью события BufferingProgressChanged (Показатель процесса буферизации изменился) и свойства BufferingProgress (Показатель процесса буферизации). Используя эти событие и свойство, можно показывать пользователям текущее состояние буферизации или выполнять логику для улучшения взаимодействия с пользователем (UX) как результат условий буферизации. Например, в условиях плохого соединения буферизация может не превышать 50%. Вы можете перехватить это значение и предоставить соответствующую обратную связь своему клиенту.
Для управления буферизацией задайте в MediaElement обработчик событий, определяющий функцию для обработки события BufferingProgressChanged:
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200" Stretch="Fill" BufferingProgressChanged="doBuff"/>
<TextBlock x:Name="txtBuff"></TextBlock>
Таким образом, функция doBuff будет выполняться каждый раз при изменении наполненности буфера. Это событие тесно связано со свойством BufferingProgress. Данное свойство принимает значения в диапазоне от 0 до 1, где 0 соответствует пустому буферу, и 1 - полному. Событие будет формироваться при изменении наполнения буфера на 5% (т.е. 0,05) или более и когда буфер заполнен полностью.
Далее представлен код, который может использоваться для ответа на это событие и обеспечения обратной связи о текущем состоянии буфера пользователям.
Сначала JavaScript-версия:
function doBuff(sender, args) {
var theText = sender.findName("txtBuff");
var meVid = sender.findName("vid");
var prog = meVid.BufferingProgress * 100; prog = "Buffering % " + prog;
theText.Text = prog;
}
И вот, как это было бы сделано в выделенном коде .NET (на C#):
private void doBuff(object sender, RoutedEventArgs e) {
double prog = vid.BufferingProgress * 100; txtBuff.Text = "Buffering % " + prog;
}
Если у вас не видно текст с отображением буферизации в Silverlight-приложении, обратите внимание на используемый элемент компоновки. Если вы использовали <Grid>, текст может находиться под
«кнопками» Play, Stop и Pause. В этом случае задайте для текстовых блоков небольшой отступ с помощью свойства Margin.
Можно переопределить автоматическую буферизацию, задавая конкретную продолжительность буферизованного видео. Например, если необходимо всегда иметь 10-секундный буфер видео и, таким образом, снизить риск прерывания воспроизведения из-за повторной синхронизации буфера при ухудшении состояния связи, можно задать свойство BufferingTime (Размер буфера). В качестве его значения задается временной диапазон. Так, например, чтобы задать 10-секундный буфер, BufferingTime задается значение 0:0:10, как показано в следующем примере:
<MediaElement x:Name="vid" Source="balls.wmv"
Height="200" Width="200" Stretch="Fill"
BufferingProgressChanged="doBuff" BufferingTime="0:0:10"/>
<TextBlock x:Name="txtDown"></TextBlock>
Если прогрессивная загрузка недоступна или не поддерживается, придется загружать весь видеофайл целиком и только потом начинать его воспроизведение. В этом случае событие DownloadPro- gressChanged и свойство DownloadProgress могут использоваться для получения состояния загрузки. Принципы работы с ними аналогичны функциям буферизации. Дале представлен XAML, определяющий событие DownloadProgressChanged:
<MediaElement x:Name="vid" Source="balls.wmv"
Height="200" Width="200" Stretch="Fill"
BufferingProgressChanged="doBuff"
BufferingTime="0:0:10"
DownloadProgressChanged="doDown"/>
<TextBlock x:Name="txtDown"></TextBlock>
И теперь код функции doDown , обрабатывающей это событие. Опять же, сначала рассмотрим JavaScript-версию:
function doDown(sender, args) {
var theText = sender.findName("txtDown");
var meVid = sender.findName("vid");
var prog = meVid.DownloadProgress * 100;
prog = "Downloading % " + prog; theText.Text = prog;
}
И вот .NET-версия:
private void doDown(object sender, RoutedEventArgs e) {
double prog = vid.DownloadProgress * 100; txtBuff.Text = "Downloading % " + prog;
}
Управление текущим состоянием видео
Silverlight представляет свойство CurrentState (Текущее состояние) и связанное с ним событие Cur- rentStateChanged (Текущее состояние изменилось), которое может использоваться для ответа на изменение состояния мультимедиа.
Действительными состояниями свойства CurrentState являются:
Buffering (Буферизация) Буфер не заполнен на 100%, поэтому воспроизведение приостановлено до полного заполнения буфера.
Closed (Закрыто) Мультимедиа закрыто.
Error (Ошибка) Возникла проблема с загрузкой, буферизацией или воспроизведением мультимедиа.
Opening (Открывается) Мультимедийный файл найден, и буферизация или загрузка должны
вот-вот начаться.
Paused (Приостановлено) Воспроизведение приостановлено.
Playing (Воспроизводится) Идет воспроизведение мультимедиа.
Stopped (Остановлено) Воспроизведение остановлено.
Вот как событие CurrentStateChanged элемента управления MediaElement определяется в XAML:
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200"
Stretch="Fill" CurrentStateChanged="doState" BufferingTime="0:0:10" />
Здесь задается функция doState, которая будет вызываться в ответ на изменение текущего состояния. Далее представлен пример такой JavaScript-функции, которая использует значение свойства CurrentState элемента управления MediaElement в окне уведомления:
function doState(sender, args) {
var meVid = sender.findName("vid");
alert(meVid.CurrentState);
}
В C#, вместо окна уведомления MessageBox, для вывода содержимого свойства Currentstate на экран можно использовать TextBlock:
private void doState(object sender, RoutedEventArgs e) {
txtBuff.Text = vid.CurrentState.ToString();
}
Управление положением курсора воспроизведения
Для управления текущим положением курсора воспроизведения используются свойства NaturalDuration (Номинальная продолжительность) и Position (Положение) элемента мультимедиа. После того, как свойство CurrentState устанавливается в значение Opened, становится возможным получение значения и свойства NaturalDuration. Продолжительность видео в секундах можно получить с помощью Natu- ralDuration.Seconds и потом преобразовать это значение в часы, минуты и секунды.
В этом примере событие CurrentStateChanged элемента управления MediaElement ассоциировано с функцией doState (из предыдущего примера). Однако теперь эта функция перехватывает значение свойства NaturalDuration. В JavaScript-версии используется вспомогательная функция convertDT для преобразования возвращаемого значения в строку. Рассмотрим код на JavaScript:
function doState(sender, args) {
var meVid = sender.findName("vid");
var txtStat = sender.findName("txtStat");
var datetime = new Date(0, 0, 0, 0, 0, meVid.naturalDuration.Seconds)
durationString = convertDT(datetime);
txtStat.Text = durationString.toString();
}
function convertDT(datetime) {
var hours = datetime.getHours();
var minutes = datetime.getMinutes();
var seconds = datetime.getSeconds();
if (seconds < 10) {
seconds = "0" + seconds;
}
if (minutes < 10) { minutes = "0" + minutes;
}
var durationString;
if (hours > 0) {
durationString = hours.toString() + ":" + minutes + ":" + seconds;
}
else {
durationString = minutes + ":" + seconds;
}
return durationString;
}
Далее следует замечательный пример того, как .NET Framework в Silverlight 2 существенно упрощает разработку: все это может быть реализовано одной строкой кода на C#:
private void doState(object sender, RoutedEventArgs e)
{
txtStat.Text = vid.NaturalDuration.ToString();
}
Вот XAML, в котором используется представленная выше функция:
<Canvas x:Name="sample9" Opacity="1">
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200" Stretch="Fill" CurrentStateChanged="doState" BufferingTime="0:0:10" />
<TextBlock x:Name="txtStat"></TextBlock>
</Canvas>
Получить текущее положение курсора воспроизведения можно с помощью свойства Position. В этом примере позиция выводится в текстовом блоке при приостановке воспроизведения (Для тестирования можете оставить в XAML-коде три «кнопки» Play, Stop и Pause и соответствующие им обработчики событий doPlay и doStop с предыдущего примера, но закомментировать тело функции doState). Необходимый код на JavaScript для функции doPause выглядел бы примерно так:
function doPause(sender, args) {
var meVid = sender.findName("vid");
meVid.Pause();
var txtStat = sender.findName("txtStat");
var datetime = new Date(0,0,0,0,0, meVid.Position.Seconds);
positionString = convertDT(datetime); txtStat.Text = positionString.toString(); }
И, как и ранее, эквивалентный код на C# намного проще:
private void doPause(object sender, MouseButtonEventArgs e) {
vid.Pause();
txtStat.Text = vid.Position.ToString();
}
Использование маркеров временной шкалы мультимедиа
Маркер временной шкалы - это элемент метаданных, ассоциированный с конкретной точкой на временной шкале мультимедиа. Обычно эти маркеры создаются и кодируются в мультимедиа заранее с помощью такого ПО, как Expression Encoder, и часто применяются для установления в видео поисковых меток.
Silverlight поддерживает эти маркеры и формирует событие MarkerReached (Маркер достигнут) при встрече с маркером в ходе воспроизведения. Это событие можно перехватывать и использовать как триггер для действий, которые должны выполняться при достижении данной отметки.
Далее представлен фрагмент XAML, в котором с помощью атрибута MarkerReached задается обработчик события встречи с маркером, JavaScript-функция handleMarker:
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200" MarkerReached="handleMarker" />
Среди аргументов данного события имеется объект marker (маркер). Он содержит объект TimeSpan (Диапазон времени) с меткой времени, в которой установлен маркер. В предыдущем разделе, «Управление положением курсора воспроизведения», представлен пример преобразования объекта TimeSpan в формат, удобный для восприятия пользователем. Также marker содержит свойство Type (Тип).
Его значением является строка, которую задает человек, кодирующий видео. Наконец, имеется параметр Text, допускающий в качестве своего значения текст в свободном формате и обычно используемый для описания параметра. Далее представлен JavaScript-код для чтения всех трех параметров и создания строки, отображаемой в окне уведомления:
function handleMarker(sender, args)
{
var strMarkerStatus = args.marker.time.seconds.toString();
strMarkerStatus += " : ";
strMarkerStatus += args.marker.type;
strMarkerStatus += " : ";
strMarkerStatus += args.marker.text;
alert(strMarkerStatus);
}
Код на C# очень похож на предыдущий; заметьте, что args типа TimeLineMarkerRoutedEventArgs:
private void handleMarker(object sender, TimelineMarkerRoutedEventArgs e)
{
string strMarkerStatus = e.Marker.Time.ToString();
strMarkerStatus += " : ";
strMarkerStatus += e.Marker.Type;
strMarkerStatus += " : ";
strMarkerStatus += e.Marker.Text;
}
Как это выглядит, можно увидеть на рис. 11-11.
РИС. 11 11 Перехват маркеров временной шкалы в Silverlight.
Маркеры временной шкалы можно добавлять в медиафайл также динамически, используя код на Silverlight. При этом поисковые метки можно задавать через процентное соотношение положения метки к общей продолжительности файла, например.
Далее представлен пример, в котором XAML для MediaElement определяет функцию handleOpen (Обработка открытия), выполняющуюся при открытии файла мультимедиа. Она вставляет новый объект временной шкалы в видео на 10-секундной отметке. Этот элемент не сохраняется в видео постоянно, только до завершения сеанса.
<MediaElement x:Name="vid" Source="balls.wmv"
Height="200" Width="200"
MarkerReached="handleMarker"
MediaOpened="handleOpened" />
Обработчик должен создать новый элемент временной шкалы в XAML и добавить его в коллекцию маркеров MediaElement. В данном случае, задается маркер временной шкалы на отметке 10 секунд, для которого Type определен как 'My Temp Marker' (мой временный маркер) и Text - 'Dynamically Added Marker' (Динамически добавляемый маркер).
Вот как это выглядело бы в JavaScript:
function handleOpened(sender, args) {
var marker =
sender.getHost().content.createFromXaml(
"<TimelineMarker Time='0:0:10'" +
" Type='My Temp Marker' Text='Dynamically Added Marker' />");
sender.markers.add(marker);
}
И вот аналогичный код в .NET:
private void handleOpened(object sender, RoutedEventArgs e) {
TimelineMarker t = new TimelineMarker();
t.Time = new TimeSpan(0, 0, 0, 10);
t.Type = "My Temp Marker";
t.Text = "Dynamically Added Marker";
vid.Markers.Add(t);
}
Коллекцию маркеров MediaElement составляют объекты TimeLineMarker (Маркер временной шкалы), поэтому для введения нового маркера просто создается новый объект TimeLineMarker, задаются его свойства Time, Type и Text, и этот объект добавляется в коллекцию. Silverlight имеет достаточно развитую логику и знает, когда должно быть сформировано событие, исходя из заданного Time, поэтому при создании новых маркеров нет необходимости добавлять их в порядке расположения на временной шкале.
Теперь, когда MediaElement достигает 10-секундной отметки при воспроизведении, появляется диалоговое окно уведомления, как показано на рис. 11-12.
РИС. 11 12 Использование динамически добавляемого маркера.
Закрашивание поверхностей видеоизображением с помощью VideoBrush
Особенно замечательная возможность Silverlight - использование видео для заливки поверхности с помощью VideoBrush. Сделать это очень просто. Во-первых, необходим элемент мультимедиа, который загрузит видео. Он должен быть скрыт и не должен принимать события мыши. Для этого его прозрачность задается равной 0 и свойству IsHitTestVisible (Объект виден для механизма обработки кликов) присваивается значение false. Также элементу мультимедиа должно быть задано имя посредством свойства x:Name. Рассмотрим пример:
<MediaElement x:Name="vid" Source="balls.wmv" Opacity="0" IsHitTestVisible="False" />
Теперь объект VideoBrush можно применять к любому объекту точно так же, как любую другую кисть. В качестве источника кисти задается MediaElement (вот почему ему обязательно должно быть присвоено имя). Также можно задать свойство Stretch для управления визуальными эффектами кисти.
Например, здесь представлен TextBlock, для закрашивания Foreground которого используется Video
Brush:
<TextBlock FontFamily="Verdana" FontSize="80" FontWeight="Bold" TextWrapping="Wrap" Text="Video">
<TextBlock.Foreground>
<VideoBrush SourceName="vid"/>
</TextBlock.Foreground>
</TextBlock>
Silverlight теперь будет формировать визуальное представление текста, используя VideoBrush. На рис. 11-13 показано, как это будет выглядеть.
РИС. 11 13 Использование VideoBrush для закрашивания текста.
Элемент управления InkPresenter
Как было показано в данной книге до сих пор, Silverlight расширяет возможности следующего поколения Веб-приложений, предоставляя инструменты для добавления насыщенных видео, аудио, векторной графики, анимации и других элементов, которые улучшают UX. Рукописные примечания - создание рукописного или нарисованного от руки содержимого с использованием устройств, разработанных для этих целей, - еще один замечательный способ сделать приложения еще более интерактивными и индивидуальными. Обеспечиваемая Silverlight поддержка программирования рукописного содержимого приносит эту функциональность в Веб. В данном разделе мы рассмотрим поддержку рукописных примечаний в Silverlight.
Существует несколько разных типов устройств, которые могут использоваться для приложений с поддержкой рукописных примечаний:
Ввод с помощью пера Обычно преобразователи графической информации, вводимой пером поддерживаются Планшетными ПК (Tablet PC), но существуют также настольные компьютеры, которые поддерживают подключение внешних планшетов. Эти устройства используют возможности ввода с помощью пера, предоставляемые в Silverlight. Они создают Ink (Рукописный фрагмент), который может быть интегрирован в Веб-страницы Silverlight, таким образом, обеспечивая поддержку рукописного ввода, рисования, рукописных примечаний и прочих форматов ввода в Веб.
Сенсорный ввод Сенсорные экраны широко применяются в интерактивных терминалах или других местах, где использование стилуса или клавиатуры было бы слишком громоздким или неуместным. Рукописные примечания в Silverlight обеспечивают поддержку сенсорных экранов, что позволяет создавать насыщенные Интернет-приложения с возможностью сенсорного ввода.
Ввод посредством мыши Имитировать рукописный ввод, подобный вводу пером Планшетного ПК, можно с помощью мыши. Однако такой ввод будет иметь боле низкое разрешение по сравнению с использованием пера настоящего Планшетного ПК.
Пример рукописных примечаний в Silverlight
На сайте http://silverlight.net предлагается замечательный пример приложения, поддерживающего рукописные примечания. Это приложение для чтения книг можно найти по адресу http://silverlight.net/samples/1.0/Page-Turn/default.html и увидеть на рис. 11-14.
Данное приложение демонстрирует, как можно загружать источник данных и просматривать изображения и другие ресурсы, имитируя перелистывание страниц книги. Оно расширено возможностью введения рукописных примечаний, что позволяет комментировать изображения, и добавляемые комментарии остаются связанными с изображением. Пример страницы с комментарием показан на рис. 11-15.
РИС. 11 14 Пример PageTurn на Silverlight.
РИС. 11 15 Комментирование изображения в Silverlight.
Классы рукописного ввода в Silverlight для разработчиков на JavaScript
Поддержка рукописного ввода в Silverlight очень проста. Каждый раз при проведении устройством ввода по экрану формируется один или более объектов StylusPoint (Штрих стилуса). Эти объекты объединяются в коллекцию StylusPointCollection (Коллекция штрихов стилуса), которая формирует основу Stroke. Обводки собираются в коллекцию StrokeCollection (Коллекция обводок). Эта коллекция составляет список графических элементов, используемых для создания рукописного ввода, визуальное предоставление которого формирует InkPresenter. Итак, если взглянуть на рис. 11-15, буква «С» в слове COOL - это обводка, образованная рядом точек, объединенных в StrokeCollection. Обе буквы «О», буква «L», линия и точка в восклицательном знаке, и линии, образующие стрелку и круг, - все это обводки. Каждая из этих обводок является участником коллекции StrokeCollection в InkPresenter, и каждая из них образована объектами StylusPoint, входящими в состав коллекции StylusPointCollection соответствующей обводки. Каждый из этих типов предоставляет объектно-ориентированный интерфейс со свойствами и методами, обеспечивающими возможность их программирования. Рассмотрим основные типы и некоторые их свойства и методы.
Тип StrokeCollection
Объект InkPresenter имеет свойство Strokes типа StrokeCollection. Эта коллекция, в свою очередь, содержит все метаданные, необходимые для представления рукописного ввода пользователя.
Свойства StrokeCollection
При использовании JavaScript для программирования Silverlight, StrokeCollection предоставляет свойство Count (Количество), которое возвращает количество обводок, находящихся в коллекции в настоящий момент.
Методы StrokeCollection
StrokeCollection предоставляет следующие методы:
Add (Добавить) Позволяет добавлять новую обводку в коллекцию.
Clear (Очистить) Очищает коллекцию обводок, что приводит к немедленному повторному формированию визуального отображения (т.е. удалению рукописного фрагмента, созданного ранее).
GetBounds (Получить границы) Возвращает прямоугольник (в виде структуры Rect), который представляет блок, ограничивающий обводки.
GetItem(индекс) (Получить элемент) Обеспечивает извлечение обводки, хранящейся под заданным индексом.
HitTest (Проверка совпадения) Если этот метод передается в StylusPointCollection, он возвращает подмножество обводок в StrokeCollection, которые пересекаются с данными штрихами.
Insert (Вставить) Аналогичен Add за исключением того, что позволяет вставлять новые обводки в коллекцию по заданному индексу.
Remove (Удалить) Обеспечивает удаление заданного элемента из StrokeCollection.
RemoveAt (Удалить по) Обеспечивает удаление элемента из StrokeCollection по заданному индексу.
Тип Stroke
Представленный в предыдущем разделе StrokeCollection - это коллекция объектов Stroke. Объект Stroke представляет коллекцию штрихов обводки; каждый штрих соответствует одному движению стилуса: стилус опускается (stylus-down), стилус перемещается (stylus-move), стилус поднимается (stylus-up). Эти объекты, в свою очередь, обладают собственным набором свойств и методов.
Свойства Stroke
Объект Stroke предоставляет следующие свойства:
DrawingAttributes (Атрибуты рисования) Каждая обводка имеет собственную независимую высоту, ширину, цвет и цвет контура. Эти параметры задаются посредством типа DrawingAttributes. Чтобы использовать этот тип, создается экземпляр объекта DrawingAttributes, задаются значения свойств, и новый объект DrawingAttributes добавляется в обводку.
StylusPoints (Штрихи стилуса) Это StylusPointCollection, содержащий коллекцию объектов StylusPoint, образующих обводку. StylusPoint обсуждается в следующем разделе.
Методы Stroke
Объект Stroke обладает следующими методами для работы с рукописным вводом:
GetBounds Возвращает ограничивающий прямоугольник Stroke в виде структуры Rect.
HitTest Если передать этот метод в StylusPointCollection и если какой-либо из этих штрихов пересекает Stroke, метод возвратит true; в противном случае, возвращается false.
Тип StylusPointCollection
Эта коллекция объединяет в себе объекты StylusPoint. Она используется для хранения штрихов стилуса для Stroke или, в некоторых случаях, может передаваться в такие методы, как HitTest, для выявления пересечения обводок.
Свойства StylusPointCollection
StylusPointCollection предоставляет свойство - Count, которое возвращает количество штрихов стилуса в данной коллекции.
Методы StylusPointCollection
Объект StylusPointCollection имеет следующие методы:
Add Этот метод позволяет добавлять новый StylusPoint в конец коллекции.
AddStylusPoints (Добавить штрихи стилуса) Этот метод позволяет добавлять существующий объект StylusPointCollection в конец данной коллекции.
Clear Этот метод удаляет все объекты StylusPoint из коллекции.
GetItem Этот метод получает заданный StylusPoint из коллекции. Используется со значением типа integer, представляющим индекс интересующего элемента, например, getItem(5).
Insert Этот метод вставляет новый StylusPoint в коллекцию по заданному индексу.
Remove Этот метод удаляет заданный StylusPoint из коллекции.
RemoveAt Этот метод удаляет из коллекции StylusPoint по заданному индексу.
Тип StylusPoint
Тип StylusPoint представляет отдельный штрих, создаваемый, когда пользователь выполняет ввод с помощью устройства рукописного ввода: пера, мыши или сенсорного экрана. Штрих предоставляет ряд свойств и методов.
Свойства StylusPoint
StylusPoint предоставляет следующие свойства:
Свойство Name позволяет задавать имя штриха. Это уникальный идентификатор. Когда штрихи формируются в процессе ввода пользователем, имена им не присваиваются.
Свойство PressureFactor (Коэффициент нажима) обозначает нажим, с которым пользователь водит пером или касается экрана при формировании штриха. При использовании мыши применяется
нажим по умолчанию. Это значение типа double в диапазоне от 0.0 до 1.0, значение по умолчанию - 0,5. На основании коэффициента нажима можно менять высоту и ширину Stroke программно через свойство DrawingAttributes, чтобы предоставить обратную связь пользователю.
Координаты обводки можно получить с помощью свойств X и Y. Они измеряются в пикселах.
Аргументы событий мыши и рукописный ввод
При использовании рукописного ввода формируемые устройством ввода события трактуются как события мыши, и аргументы, получаемые обработчиками событий, будут типа MouseEventArgs.
Объект MouseEventArgs содержит методы, которые позволяют запрашивать сведения об устройстве ввода (является ли оно мышью, стилусом или каким-то другим устройством) и коллекцию объектов StylusPoint, связанную с этим событием.
Обратите внимание, что это тот же объект MouseEventArgs, который используется с событиями MouseEnter, MouseLeave, MouseLeftButtonDown, MouseLeftButtonUp и MouseMove.
Свойства MouseEventArgs
Объект MouseEventArgs предоставляет следующие свойства Булевого типа: ctrl и shift. Они принимают значение true, если пользователь удерживает соответствующую клавишу при формировании события.
Методы MouseEventArgs
Объект MouseEventArgs предоставляет следующие методы:
Метод GetPosition (Получить положение) принимает в качестве параметра элемент и возвращает объект Point, который представляет координаты х и у курсора мыши относительно этого элемента. Если вызов метода осуществляется без параметра, Point содержит координаты относительно положения элемента управления, сформировавшего событие.
Метод GetStylusInfo (Получить сведения о стилусе) возвращает объект StylusInfo (Сведения о стилусе), содержащий информацию о состоянии стилуса. StylusInfo имеет следующие свойства:
IsInverted (Инвертированный): Если перо инвертировано, это указывает на то, что пользователь хочет использовать его для удаления штрихов, а не для их отрисовки. Это свойство возвращает true в этом случае.
DeviceType (Тип устройства): Возвращает строку, содержащую тип устройства -"Mouse", "Stylus" или "Touch".
Метод GetStylusPoints возвращает копию штрихов стилуса, добавленных в коллекцию с момента формирования последнего события мыши. Это будет объект типа StylusPointCollection.
Программирование для рукописного ввода в Silverlight
При написании приложений инструментами Microsoft под термином рукописный ввод (Ink) обычно подразумевается надпись или рисунок от руки, создаваемый пользователем с помощью описанных ранее устройств рукописного ввода, таких как цифровое перо, сенсорный экран или мышь. При использовании в приложении Silverlight эти устройства обеспечивают заполнение объекта StrokeCollection отдельными объектами Stroke. В свою очередь, Stroke выполняет запись действий устройства, например пера, к которым относятся действия: перо опускается (pen-down), перо перемещается (penmove) и перо поднимается (pen-up). Stroke может представлять точку, прямую линию или кривую. Это осуществляется с помощью объекта StylusPointCollection, который содержит объекты StylusPoint, создаваемые преобразователем графической информации, связанным с пером, сенсорным экраном или мышью. Атрибуты рукописного ввода содержаться в классе DrawingAttributes.
Как говорилось, Silverlight принимает элементы рукописного ввода с помощью класса InkPresenter. Это подкласс элемента Canvas, который также содержит коллекцию обводок в StrokeCollection. При добав-
лении обводок в StrokeCollection, InkPresenter автоматически формирует их визуальное представление, используя соответствующие DrawingAttributes.
Обычно InkPresenter добавляется в XAML приложения во время разработки дизайна, но объекты Stroke, составляющие StrokeCollection, будут добавляться во время выполнения с помощью JavaScript.
Далее представлен пример использования перекрывающего изображение InkPresenter на странице:
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Image Source="sushi.jpg" Width="600" Height="400"></Image>
<InkPresenter
x:Name="inkEl"
Background="transparent" Width="600" Height="400" MouseLeftButtonDown="inkMouseDown" MouseMove="inkMouseMove"
MouseLeftButtonUp="inkMouseUp"/>
</Canvas>
InkPresenter определяет обработчики событий MouseLeftButtonDown, MouseMove и MouseUp. Мы рассмотрим, как это делается в JavaScript, для чего создадим простое приложение для рукописного ввода. Затем далее в этом разделе то же самое будет сделано на C#. Сходство необыкновенное! Для этих событий понадобятся функции-обработчики действий «начало рукописного ввода», «рукописный ввод» и «прекращение рукописного ввода».
Примечание Хотя рукописный ввод может быть выполнен пером, с помощью сенсорного экрана или мыши, в документации API используется термин «Мышь».
Прежде чем перейти к функциям-обработчикам событий JavaScript, требуется выполнить некоторые вспомогательные операции по объявлению глобальных переменных, необходимых для поддержки этих действий:
var theInk;// Ссылка на модуль отображения рукописного ввода
var newStroke; // Ссылка на обводку
var theControl; // Ссылка на элемент управления Silverlight
function handleLoad(control, userContext, rootElement) {
// Событие Load возвращает ссылку на элемент управления, // но другие обработчики событий нет. Поэтому мы собираемся // создать ссылку на элемент управления здесь theControl = control;
// Здесь мы создадим ссылку на элемент рукописного ввода theInk = control.content.findName("inkEl");
}
Эти вспомогательные переменные для InkPresenter, текущей обводки и самого элемента управления Silverlight будут использоваться функциями, поддерживающими описанные выше действия рукописного ввода. При загрузке элемент управления Silverlight запускает функцию handleLoad. В качестве параметра она принимает ссылку на элемент управления Silverlight, но поскольку реализованные нами обработчики событий мыши не делают этого, данную ссылку необходимо сохранить в handleLoad. В ходе выполнения handleLoad можно также получить ссылку на InkPresenter, проведя его поиск по имени (in- kEl). Тогда не придется вызывать getHost для получения ссылки на родительский элемент UI, чтобы найти InkPresenter, при каждом выполнении обработчика событий.
Теперь можно приступать к рассмотрению обработчиков событий. Сначала разберемся, что происходит при формировании события MouseLeftButtonDown, результатом чего является выполнение функции inkMouseDown (Нажатие кнопки мыши при рукописном вводе). Мы будем отслеживать перемещения мыши аналогично тому, как это происходило при обработке перемещения методом «drag-and- drop», что рассматривалось в Главе б. При получении входных данных от мыши создается новый объект Stroke, содержащий объект DrawingAttributes, который определяет визуальные характеристики этой обводки. В представленном здесь примере DrawingAttributes будет обеспечивать следующие парамет-
ры обводки: Width - 2, Height -2, цвет заливки - White (Белый), и цвет контура - White. Тип MouseEventArgs в Silverlight поддерживает метод getStylusPoints, как было показано ранее в этой главе, который принимает InkPresenter в качестве единственного параметра. Этот метод возвращает тип StylusPointCollection, который используется в методе AddStylusPoints обводки. Теперь можно добавить обводку в StrokesCollection InkPresenter. Посмотрим на код:
function inkMouseDown(sender,args)
{
// Перехватываем событие мыши.
theInk.CaptureMouse();
// Создаем новую обводку.
newStroke = theControl.content.createFromXaml('<Stroke/>');
// Задаем новый элемент атрибутов рисования для обводки.
// Он, как следует из его имени, определяет внешний вид обводки
var da = theControl.content.CreateFromXaml('<DrawingAttributes/>'); newStroke.DrawingAttributes = da;
// Теперь, когда обводка имеет атрибуты рисования, // зададим их значения...
newStroke.DrawingAttributes.Width = 2;
newStroke.DrawingAttributes.Height = 2;
newStroke.DrawingAttributes.Color = "White";
newStroke.DrawingAttributes.OutlineColor = "White";
newStroke.StylusPoints.AddStylusPoints(args.GetStylusPoints(theInk)); theInk.Strokes.Add(newStroke);
}
Теперь перемещение курсора мыши по холсту в состоянии отрисовки обводки (т.е. когда newStroke не null) означает добавление новых штрихов в эту обводку и отображается в виде следа, оставляемого мышью. Вот код, реализующий это:
// Добавляем новые штрихи в Stroke, с которым работаем в данный момент.
function inkMouseMove(sender,args) {
if (newStroke != null)
{
newStroke.StylusPoints.AddStylusPoints(args.GetStylusPoints(theInk));
} }
Наконец, по завершении отрисовки обводки, когда вы отпускаете кнопку мыши (или отрываете перо от экрана), формируется событие MouseLeftButtonUp. После этого требуется очистить обводку и прекратить отслеживание мыши. После того, как переменной newStroke задается значение null, движение мыши (или пера) по экрану больше не будет обеспечивать добавление штрихов в обводку, и, следовательно, обводка не будет отрисовываться. Рассмотрим код:
function inkMouseUp(sender,args) {
// Задаем newStroke значение null newStroke = null;
// Прекращаем отслеживать перемещения мыши theInk.releaseMouseCapture();
}
На рис. 11-16 показан пример приложения до добавления в него рукописного примечания. На рис. 1117 представлено то же приложение с рукописным примечанием, которое было отрисовано с помощью мыши или пера.
РИС. 11 16 Выполнение приложения Silverlight с возможностью рукописного ввода.
РИС. 11 17 Приложение Silverlight с возможностью рукописного ввода с рукописным примечанием.
В предыдущем примере было продемонстрировано, как программировать рукописный ввод, используя Silverlight и JavaScript. Конечно же, то же самое можно сделать с помощью управляемого кода. Вот полный выделенный код на C#, обеспечивающий создание такого же приложения:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Ink;
namespace NetInkSample
{
public partial class Page : UserControl
{
Stroke newStroke;
public Page()
{
InitializeComponent();
}
private void inkEl MouseLeftButtonDown(
object sender, MouseButtonEventArgs e)
{
inkEl.CaptureMouse();
// Создаем новую обводку.
newStroke = new Stroke();
DrawingAttributes da = new DrawingAttributes();
newStroke.DrawingAttributes = da;
newStroke.DrawingAttributes.Width=2;
newStroke.DrawingAttributes.Height=2;
newStroke.DrawingAttributes.Color=Colors.White;
newStroke.DrawingAttributes.OutlineColor=Colors.White;
newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkEl));
inkEl.Strokes.Add(newStroke);
}
private void inkEl MouseMove(object sender, MouseEventArgs e) {
if (newStroke != null)
{
newStroke.StylusPoints.Add(
e.StylusDevice.GetStylusPoints(inkEl));
}
}
private void inkEl MouseLeftButtonUp( object sender, MouseButtonEventArgs e) { newStroke = null;
inkEl.ReleaseMouseCapture();
}
}
}
И в XAML-коде, соответственно, необходимо сделать изменения:
<Image Source="sushi.jpg" Width="600" Height="400"></Image>
<InkPresenter x:Name="inkEl" Background="transparent"
Width="600" Height="400"
MouseLeftButtonDown="inkEl MouseLeftButtonDown" MouseMove="inkEl MouseMove"
MouseLeftButtonUp="inkEl MouseLeftButtonUp"/>
Кроме демонстрации гибкости Silverlight, который позволяет разрабатывать приложения как на языке сценариев JavaScript, так и на компилируемых языках программирования .NET, это также показывает простоту перехода от JavaScript к .NET, что позволяет без труда обновить существующие Silverlight- приложения на JavaScript до Silverlight 2 и перейти к управляемому коду.
Реализация Deep Zoom с помощью элемента управления
MultiScaleImage
Deep Zoom - достаточно новая технология, введенная в Silverlight 2 и обеспечивающая новый уникальный способ работы с изображениями в приложениях. Она реализована в XAML посредством элемента MultiScalelmage, который, как следует из его имени, предоставляет возможность управлять размером и масштабом изображений, а Silverlight, в свою очередь, обеспечивает огромное виртуальное пространство, в котором эти изображения могут отрисовываться.
Лучше всего возможность Deep Zoom рассмотреть на примере. На рис. 11-18 представлена иллюстрация к детскому научному проекту.
РИС. 11 18 Изображение в Deep Zoom.
Пока что ничего сверхъестественного, казалось бы, обычная фотография. Так чем же вызван весь этот шум вокруг Deep Zoom? В этом приложении можно менять масштаб изображения, прокручивая колесо мыши. Итак, на рис. 11-19 представлен другой вид этого изображения. Я уменьшил масштаб, чтобы показать весь рисунок. Теперь можно увидеть первое изображение относительно всей фотографии.
РИС. 11 19 Исходное изображение в другом масштабе.
Посмотрите внимательно на апельсин на рис. 11-19. В его центре можно увидеть изображение с рис. 11-18. Увеличьте масштаб, и вы опять получите изображение, представленное на рис. 11-20.
РИС. 11 20 Еще более глубокое масштабирование.
Как видите, все второе изображение - не более чем пиксел на третьем (оно находится в зрачке глаза на рис. 11-20), а размер первого изображения всего несколько пикселов на втором рисунке. По этим нескольким статическим рисункам сложно оценить возможность Deep Zoom должным образом. Deep Zoom, действительно, надо увидеть, чтобы поверить и понять, почему эта технология называется Deep Zoom™ она позволяет организовывать изображения так, что вы можете увеличивать и уменьшать масштаб изображений, размещая их на гигантских холстах.
Использование редактора Deep Zoom
Но как создать приложение, которое позволит уменьшать и увеличивать масштаб изображений таким образом? Базовое приложение для этого написать довольно просто. Возьмем элемент управления MultiScalelmage и ассоциируем его с файлом, содержащим метаданные изображений. Этот файл создается в редакторе Deep Zoom, который можно загрузить в Центре загрузки Microsoft. Редактор Deep Zoom представлен на рис. 11-21.
РИС. 11 21 Редактор Deep Zoom.
Этот инструмент выполняет простую последовательность операций, включающую Import (Импорт), за которым следует Compose (Компоновка) с последующим Export (Экспорт). Итак, начинаем с вкладки Import, щелкаем Add Image (Добавить изображение), чтобы выбрать изображение, и повторяем этот
шаг для всех изображений, которые вы хотите использовать. На рис. 11-21 можно увидеть, что выбраны три изображения.
Следующий шаг - Compose, который осуществляется с помощью опций на вкладке Compose. На этой вкладке изображения размещаются на соответствующих поверхностях. Вы можете менять масштаб изображений, что разместить в них другие изображения. Например, на рис. 11-22 можно увидеть, что я взял одно из изображений и увеличил его масштаб так, что на экране виден только глаз.
РИС. 11 22 Компоновка изображений для просмотра с разными уровнями увеличения в редакторе Deep Zoom.
Теперь, следующее изображение с его нормальным разрешением будет помещено на данное, масштаб которого увеличен. Итак, если посмотреть на рис. 11-22, вы увидите, куда вставлено второе изображение (в зрачок глаза). Позже, при выполнении приложения, увидеть это изображение можно будет, только увеличив первое. На рис. 11-23 показано, куда помещается второе изображение на первом.
РИС. 11 23 Добавление нового изображения на увеличенное первое.
Это простой пример, мы просто добавили одно изображение, которое можно увидеть, только увеличив первое. Deep Zoom позволяет создавать намного боле сложные приложения, данный пример лишь дает представление о возможностях этой технологии. Теперь мы готовы перейти к третьему этапу- экспорту. Для этого будем использовать закладку Custom вкладки Export редактора Deep Zoom (рис. 11-24).
РИС. 11 24 Экспорт метаданных Deep Zoom.
Чтобы экспортировать метаданные изображений, скомпонованных в Deep Zoom, необходимо присвоить имя проекту, выбрать в качестве Output type (Тип результата) - «Images» (Изображения), в качестве Image Settings (Настройки изображения) - «Export as Composition» (Экспортировать как композицию) и экспортировать проект в заданный каталог. При этом в выходном каталоге будут созданы два файла и папка. Один из файлов называется SparseImageSceneGraph.xml и является конфигурационным файлом, который определяет каждое изображение и его местоположение на других изображениях с разными уровнями увеличения. Например, рассмотрим граф сцены для XAML с двумя изображениями:
<?xml version="1.0"?>
<SceneGraph version="1">
<AspectRatio>1.33333333333334</AspectRatio>
<SceneNode>
<FileName>C:\Code\SLBook\Chapter11\DZCSample
\source images\dzcsample\DSCN2961.JPG</FileName>
<x>0</x>
<y>0</y>
<Width>1</Width>
<Height>1</Height>
<ZOrder>1</ZOrder>
</SceneNode>
<SceneNode>
<FileName>C:\Code\SLBook\Chapter11\DZCSample
\source images\dzcsample\DSCN2959.JPG</FileName>
<x>0.451782754964542</x>
<y>0.313488814592021</y>
<Width>0.00099432659277551</Width>
<Height>0.00099432659277551</Height>
<ZOrder>2</ZOrder>
</SceneNode>
</SceneGraph>
Как видите, это довольно простой XAML-код. В нем указывается соотношение сторон основного изображения (полученное, исходя из размеров первого изображения), и каждое изображение превращается в SceneNode (Узел сцены). Первое изображения является первым SceneNode. Оно располагается в позиции (0,0) и является нормализованным изображением, т.е. его ширина и высота принимаются за 1. Размеры и расположение всех остальных изображений устанавливаются относительного первого.
Второе изображение размещается в точке с координатами 0,45 по оси х и 0,31 по оси у. Его размер составляет, примерно, 0,00099 размеров первого изображения. Таким образом, если увеличить первое изображение, примерно, в 10000 раз, можно будет увидеть второе изображение. Его Z-порядок равен 2 (Z-порядок первого изображения - 1), т.е. он будет отрисовываться поверх первого изображения.
Кроме того, редактор Deep Zoom разделяет изображение на равные фрагменты, поэтому при масштабировании рисунка загружается не все изображение, а лишь просматриваемые фрагменты, что очень эффективно при работе с большими изображениями. При просмотре изображения в маленьком масштабе, вы видите все фрагменты уменьшенными. Они обладают некоторым запасом разрешения для масштабирования. При увеличении масштаба изображения до пределов разрешающей способности (или выше), вы будете видеть лишь часть рисунка, т.е. только фрагменты, представляющие видимую часть изображения, обеспечивая, таким образом, экономное использование пропускного канала и сокращая время загрузки.
Другой экспортируемый файл будет называется dzc output.xml. В нем содержатся все сведения о фрагментах и их положении относительно основного изображения. Он будет располагаться в каталоге, созданном редактором Deep Zoom, в котором вы также найдете ряд подпапок с изображениями.
Первый проект Deep Zoom
Чтобы использовать Deep Zoom, создадим новое приложение Silverlight. Прежде чем делать что-либо еще, необходимо скомпилировать приложение. При этом будет создан каталог ClientBin в проекте Вебприложения. Сделав это, закройте решение.
Теперь в Windows Explorer скопируйте каталог, содержащий файл dzc output.xml и подпапки с фрагментированными изображениями, в папку ClientBin Веб-приложения. Сделав это, вновь откройте решение. Solution Explorer вашего проекта будет выглядеть примерно так, как показано на рис. 11-25.
РИС. 11 25 Добавление данных Deep Zoom в Веб приложение.
Теперь, чтобы сформировать визуальное представление содержимого Deep Zoom, необходимо просто добавить MultiScalelmage в Page.xaml и в качестве значения его свойства Source задать путь к файлу dzc output.xml (в данном случае, этот файл располагается в /dzcsample/dzc output.xml), а также необходимые ширину и высоту. Посмотрим, как будет выглядеть ваш Page.xaml:
<UserControl x:Class="DZCSampleApp.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas>
<MultiScaleImage Source="dzcsample/dzc_output.xml"
Height="300" Width="400" />
</Canvas>
</UserControl>
Итак, при выполнении этого приложения элемент управления MultiScalelmage будет формировать визуальное представление верхнего элемента в SceneGraph, увеличивая его от оригинального масштаба изображения до заданных ширины и высоты (в данном случае, 400 х 300).
Как видите, в приложении нет автоматической реализации управления мышью, поэтому мы не можем перемещаться по изображению или менять его масштаб. Как это делается, будет рассмотрено в следующем разделе
Использование мыши и логических координат в Deep Zoom
Как и все остальные элементы управления Silverlight, MultiScaleImage может объявлять функции для обработки событий. Например, для перемещения изображения используются обычные события мыши: MouseLeftButtonDown, MouseLeftButtonUp и MouseMove, - и обрабатываются они так же, как это делается при перемещении любого элемента методом «drag-and-drop». Сначала, рассмотрим XAML для MultiScaleImage, определяющий эти события:
<UserControl x:Class="DeepZoomSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480">
<Canvas>
<MultiScaleImage x:Name="dz" Source="dzcsample/dzc_output.xml" MouseLeftButtonDown="MultiScaleImage MouseLeftButtonDown" MouseLeftButtonUp="MultiScaleImage MouseLeftButtonUp" MouseMove="MultiScaleImage MouseMove" Height="480" Width="640"></MultiScaleImage>
</Canvas>
</UserControl>
И теперь рассмотрим каждый из этих обработчиков событий более подробно. Прежде всего, есть код, общий для них всех, который обеспечивает отслеживание текущего состояния мыши и просматриваемых в настоящий момент координат MultiScaleImage:
bool dragging = false;
double dx = 0;
double dy = 0;
Point p0;
Point p1;
Point pLast;
Теперь посмотрим, что происходит, когда пользователь щелкает изображение кнопкой мыши:
private void MultiScaleImage MouseLeftButtonDown(
object sender, MouseButtonEventArgs e) {
dragging = true;
p0 = dz.ElementToLogicalPoint(new Point(0, 0));
p1 = dz.ElementToLogicalPoint(new Point(640, 480));
dx = 0;
dy = 0;
double x = e.GetPosition(null).X;
double y = e.GetPosition(null).Y;
pLast = dz.ElementToLogicalPoint(new Point(x, y));
}
Предполагается, что пользователь удерживает кнопку мыши и двигает мышью, поэтому задаем Буле- вому свойству dragging (перетягивание) значение true. Теперь необходимо получить текущие координаты видимой части изображения. Вспомним, что для верхнего изображения задана позиция (0,0), или x = 0 and y = 0, и его высота и ширина заданы равными 1. Это логические координаты и логические размеры.
В Silverlight логические координаты верхнего левого угла и нижнего правого угла окна можно получить с помощью метода ElementToLogicalPoint (Логическая точка элемента), передав в него физические координаты. Итак, представим, что изображение было увеличено и немного передвинуто. Теперь если вызвать этот API для физической точки (0,0), т.е. верхнего левого угла видимой в данный момент части изображения, будет возвращена логическая точка, представляющая положение это точки на полном изображении. Чтобы получить координаты нижнего правого угла, делаем то же самое для точки, координаты которой соответствуют ширине и высоте физического экрана (в данном случае, 640 х 480).
Мы хотим отслеживать изменение размеров относительно осей х и у, поэтому задаем переменным dx и dy значение 0. Зачем это сделано, станет понятно через мгновение.
Кроме того, необходимо получать логические координаты курсора мыши. Для этого вызывается API ElementToLogicalPoint, в него передается текущее положение мыши (которое можно получить из объекта MouseEventArgs, передаваемого в эту функцию) и возвращаемые результаты сохраняются в переменной pLast.
Итак, что происходит, когда пользователь начинает перетягивание, удерживая кнопку мыши нажатой? Мы хотим получить эффект перемещения по изображению. Вот код, реализующий это:
private void MultiScaleImage MouseMove(
object sender, MouseEventArgs e) {
if (dragging) {
if (e!=null) {
double x = e.GetPosition(null).X;
double y = e.GetPosition(null).Y;
Point pCurrent = dz.ElementToLogicalPoint(new Point(x, y)); if (pLast!=null) {
dx += (pCurrent.X - pLast.X);
dy += (pCurrent.Y - pLast.Y);
Point origin = new Point(p0.X - dx, p0.Y - dy); dz.ViewportOrigin = origin;
} pLast = pCurrent;
}
} }
Событие MouseMove формируется независимо оттого, удерживается кнопка мыши или нет, поэтому для обозначения перетягивания используем переменную dragging. Итак, если пользователь выполняет перетягивание, и MouseEventArgs не null, будет выполняться весь остальной код.
В данном случае, мы извлекаем текущие координаты мыши и сохраняем их логические эквиваленты (полученные с помощью метода ElementToLogicalPoint элемента управления) в точке pCurrent. Теперь если pLast не null, значит, пользователь выполняет перетягивание, и мышь переместилась относительно ее предыдущего положения. Итак, чтобы получить изменение логических координат, произошедшее в результате перемещения мыши из предыдущей точки в текущую, мы просто вычисляем разницу (дельту) между предыдущими и текущими координатами относительно обеих осей (х и у). После этого задаем для свойства Origin (Начало отсчета) элемента управления MultiScaleImage исходные координаты с учетом дельта по х и у. Это обеспечит эффект «перемещения» изображения при перемещении мышью, хотя мы, по сути, просто изменяем координаты верхнего левого угла отображаемой части изображения. По завершении перемещения необходимо просто задать положение Last (Последний) как Current, чтобы, когда пользователь вновь начнет двигать мышью, вычисления производились относительно этой точки, а не той, в которой пользователь нажмет кнопку мыши.
Наконец, необходимо, чтобы после того, как пользователь отпустит кнопку мыши, все вернулось в исходное состояние. Сделать это довольно просто. Рассмотрим код:
private void MultiScaleImage MouseLeftButtonUp( object sender, MouseButtonEventArgs e) {
dragging = false;
p0 = new Point();
p1 = new Point(); pLast = new Point(); dx = 0;
dy = 0;
}
Эти три простые функции обеспечивают пользователю возможность перетягивать изображение и перемещаться по нему независимо от степени его увеличения. В следующем разделе будет показано, как с помощью колеса мыши увеличивать и уменьшать изображение и, таким образом, открывать части изображения, скрытые при других степенях увеличения.
Создание функциональности масштабирования с использованием колеса мыши
Проблемой при создании приложений Deep Zoom является то, что стандартным средством изменения масштаба, де факто, является колесо мыши, но Silverlight и .NET не обрабатывают события колеса мыши. Что же можно сделать? Существует два варианта. Первый - использовать JavaScript вместо C#, потому что браузер может перехватывать перемещения колеса мыши и формировать события в ответ на его прокручивание. Второй вариант - использовать браузер как мост к Silverlight, т.е. браузер должен будет перехватывать событие и затем информировать .NET об этом. Вся дальнейшая обработка будет осуществляться в .NET. Все намного проще, чем кажется!
Прежде всего, необходимо обеспечить возможность использования API браузера в Silverlight, поэтому не забудьте включить в код следующую строку:
using System.Windows.Browser;
Затем в конструкторе Page элемент управления должен быть зарегистрирован как поддерживающий сценарии. Методы элементы управления, обозначенные как ScriptableMember (Участник, поддерживающий сценарии), доступны из JavaScript. Вот как это делается:
public Page() {
InitializeComponent();
HtmlPage.RegisterScriptableObject("MySilverlightObject", this); }
Далее требуется перехватывать события колеса мыши на этой странице. Для этого сначала добавляем вызов handleLoad в тег <Body>, чтобы обеспечить выполнение JavaScript-кода при формировании визуального представления страницы:
<body style="height:100%;margin:0;" onload="handleLoad();">
...
</body>
Затем в JavaScript-функции handleLoad задается событие:
function handleLoad() { window.onmousewheel = document.onmousewheel = onMouseWheel; if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', onMouseWheel, false);
} }
Тем самым определяем, что JavaScript-функция onMouseWheel (При прокручивании колеса мыши) будет выполняться при любом прокручивании колеса мыши.
function onMouseWheel() {
if(!event) {
event = window.event;
}
var slPlugin = $get("Xaml1");
slPlugin.content.MySilverlightObject.dz_MouseWheel( event.clientX, event.clientY, event.wheelDelta);
}
Эта функция просто принимает ссылку на элемент управления Silverlight (в данном случае, при создании ему присваивается имя Xaml1) и затем вызывает функцию выделенного кода, определенную для него. Для вызова используется синтаксис <ИмяКомnонентa>.content.<ИмяOбъектa>.<ИмяФункции>.
<ИмяКомпонента> - это переменная, определенная в JavaScript как ссылка на объект Silverlight.
<ИмяОбъекта> - это имя, заданное для объекта при его регистрации (ее можно увидеть в конструкторе PageQ).<ИмяФункции> - это имя вызываемой функции. Эта функция должна быть соответствующим образом описана, чтобы JavaScript «видел» ее. В данном случае, вызывается функция dz MouseWheel, рассмотрим ее:
[ScriptableMember]
public void dz MouseWheel(double x, double y, int delta) {
double dZoomFactor=1.33;
if (delta < 0)
dZoomFactor= 1/1.33;
Point pz = dz.ElementToLogicalPoint(new Point(x, y)); dz.ZoomAboutLogicalPoint(dZoomFactor, pz.X, pz.Y);
}
Прежде всего, как видите, она обозначена ScriptableMember, т.е. JavaScript может видеть и вызывать ее. Функция JavaScript передает текущие координаты мыши и дельта, возникающие в результате изменения масштаба. Дельта будет иметь положительное значение при прокручивании колеса вперед и отрицательное значение при прокручивании назад.
Масштабный коэффициент каждого прокручивания колеса задан равным 33% (но он может быть любым), таким образом, переменной dZoomFactor (Масштабный коэффициент) задается значение 1.33 при увеличении и 1/1.33 при уменьшении масштаба.
Далее требуется, чтобы изменение размеров происходило вокруг текущего положения курсора мыши на изображении. Это очень просто сделать, преобразовав координаты курсора мыши в логическую точку с помощью метода ElementToLogicalPoint элемента управления MultiScaleImage. Имея координаты и коэффициент масштабирования, вызываем метод ZoomAboutLogicalPoint (Масштабирование вокруг логической точки), чтобы обеспечить изменение размеров MultiScaleImage.
Коллекции в Deep Zoom
Кроме возможности увеличения и уменьшения изображения, можно также создавать коллекции изображений и работать с ними в масштабируемой среде.
Возможно, вы заметили, что при экспорте изображений из редактора Deep Zoom всегда предлагалась опция Create Collection (Создать коллекцию). Как следует из ее имени, эта опция обеспечивает создание коллекции изображений. Посмотрим на рис. 11-26. Как видите, я разместил в рабочей области множество изображений. Теперь давайте посмотрим, как их можно экспортировать в виде коллекции.
Для работы с изображениями коллекции Silverlight предлагает коллекцию SubImages (Множество изображений). Обратите внимание, что при формировании визуального представления страницы полный набор изображений не будет загружаться, поэтому эта коллекция будет пустой в этот момент. Чтобы иметь возможность работать с коллекцией, необходимо описать событие ImageOpenSucceeded (Изображение открыто успешно). Это событие будет формироваться в случае успешной загрузки и отображения.
РИС. 11 26 Создание коллекции Deep Zoom.
Рассмотрим XAML:
<MultiScaleImage x:Name="dz"
Source="dzcsample/dzc_output.xml"
ImageOpenSucceeded="dz ImageOpenSucceeded" Height="480" Width="640">
</MultiScaleImage>
В этот момент коллекция SubImages будет заполнена и может использоваться для работы с отдельными рисунками, ее составляющими. Рассмотрим пример изменения месторасположения изображений:
private void dz ImageOpenSucceeded(object sender, RoutedEventArgs e) {
int nImages = dz.SubImages.Count;
for (int lp = 0; lp < nImages; lp++) {
dz.SubImages[lp].ViewportOrigin = new Point(lp*0.1, lp*0.1);
}
}
Как видите, процесс абсолютно аналогичен тому, который использовался ранее для работы с одним рисунком. В данном случае, каждое изображение перемещается путем использования SubImages[lp,], где lp - это переменная цикла, которая может принимать значения от 0 до числа, соответствующего количеству изображений в коллекции. Результаты представлены на рис. 11-27. Обратите внимание на разницу между этой и исходной компоновками, которая представлена на рис. 11.26.
РИС. 11 27 Компоновка коллекции изображений.
Заключение
В этой длинной главе представлены три наиболее мощных элемента управления, предлагаемые Silver- light 2. Сначала был подробно рассмотрен элемент управления MediaElement и то, как можно использовать Silverlight для воспроизведения и трансформации видео- и/или аудиосодержимого, включая программирование прозрачности, маркеры, динамические маркеры и т.д. Затем вы познакомились с рукописными примечаниями и устройствами, поддерживающими их, а также тем, как Silverlight может обеспечить поддержку рукописного ввода на Веб-страницах. Наконец, вашему вниманию была представлена технология Deep Zoom и реализация этой новой возможности в Silverlight. Вы научились создавать сцены и коллекции, расширенные функциональностью глубокого масштабирования.
Глава 12
Стили и шаблоны в Silverlight 2
Silverlight предлагает множество элементов управления, они были рассмотрены в нескольких предыдущих главах, а также возможность создания собственных элементов управления. Все поставляемые элементы управления Silverlight уже по умолчанию выглядят гармонично и насыщенно, но если возникнет необходимость изменить их стандартный вид соответственно собственному дизайну, Silverlight 2 предлагает мощные возможности стилевого оформления и шаблонов, которые могут использоваться для изменения представления вашего приложения.
Понимание стилевого оформления
Чтобы понять, что такое стилевое оформление, рассмотрим простой пример использования кнопки в Silverlight-приложении. Далее представлен XAML для элемента управления Button:
<Canvas Background="LightBlue">
<Button x:Name="btn" Content="Click Me!" Width="140"></Button>
</Canvas>
Это обеспечит отображение кнопки в стандартном стиле Silverlight (серебристого цвета, как будто с подсветкой сверху), как можно увидеть на рис. 12-1.
РИС. 12 1 Базовая кнопка Silverlight.
Как было показано в Главе 7, «Элементы управления Silverlight: представления и компоновки», и в Главе 8, «Элементы управления Silverlight: расширенные элементы управления», многие элементы управления Silverlight, включая Button, являются элементами управления с содержимым, т.е. могут формировать визуальное представление XAML-содержимого. В случае с Button это означает, что он может включать кое-что более интересное, чем просто строка «Click Me!» (Щелкни меня!), и что в него можно добавлять некоторую функциональность, обеспечивающую пользователю более широкие возможности при взаимодействии с этим элементом управления.
Например, создадим кнопку с изображением. Для этого используем изображение как содержимое кнопки. Например:
<Canvas Background="LightBlue">
<Button Canvas.Left="40" Canvas.Top="40" x:Name="btn" Width="60" Height="80"> <Button.Content>
<StackPanel Orientation="Vertical">
<Image Source="icon.jpg" Height="48" Width="48">
</Image>
<TextBlock Text="Click!"></TextBlock>
</StackPanel>
</Button.Content>
</Button>
</Canvas>
Как это выглядит на экране, представлено на рис. 12-2.
РИС. 12 2 Кнопка, использующая XAML содержимое.
Вас не устраивает стандартный шрифт и цвет надписи на кнопке, и вы хотите еще больше изменить ее внешний вид? Сделать это в XAML довольно просто. Можно задать свойства, включающие семейство шрифтов, размер, насыщенность и т.д., настраивающие внешний вид кнопки. Например, посмотрим на обновленный TextBlock:
<TextBlock Text="Click!" FontFamily="Comic Sans Ms"
Foreground="MediumBlue" FontSize="20">
</TextBlock>
Также добавим несколько других реализаций кнопки. В XAML это сделать довольно просто, потому что можно просто скопировать первую кнопку, а затем задать свойства расположения. Пример представлен на рис. 12-3.
РИС. 12 3 Несколько экземпляров элемента управления Button.
Выглядит славно и очень просто реализуется, но использование такого подхода приведет к разрастанию XAML и, что еще хуже, большому количеству повторяющегося кода, что усложнит проверку, отладку, обслуживание и обновление приложения.
Возьмем элементы управления TextBlock. Для каждого из них явно объявлены свойства FontFamily, Foreground и FontSize, несмотря на то, что всем им задано одно и то же значение. А что, если требуется изменить какое-то из этих значений. Придется просматривать каждый элемент управления один за другим, чтобы обновить их все.
Вот где возникает необходимость в стилях. Давайте рассмотрим, как вынести некоторые из этих данных в стиль.
Создание стиля
Стиль создается в разделе <Resources> (Ресурсы) контейнера. Здесь может быть создан один или более стилей, для которых задается имя стиля и тип объекта, к которому будет применяться стиль. Например, чтобы создать стиль TextBlockStyle (Стиль текстового блока) для элемента управления TextBlock, используется такой XAML:
<Style TargetType="TextBlock" x:Key="TextBlockStyle"> </Style>
Для стиля задается тип элемента управления, к которому он может применяться. Однако то, что этот стиль предполагается для TextBlock, не означает, что все экземпляры TextBlock будут использовать его. Вы не ограничены одним стилем для одного типа. В стиле должен быть задан тип элемента управления, для которого предназначен стиль и Key (Ключ) стиля. Таким образом, можно иметь множество разных описаний стилей для элемента управления TextBlock с разными Key. Тогда, задавая свойство Style (Стиль) для разных TextBlock, вы просто выбираете тот стиль, который желаете применить к тому или иному TextBlock, по имени. Это будет продемонстрировано через мгновение, но сначала рассмотрим настройку стиля свойств TextBlock.
Это выполняется с помощью Setter (Установщик). Setter - это тег XAML, определяющий свойство и значение, которое необходимо задать этому свойству.
Далее представлен XAML, используемый ранее для задания свойств Text, FontFamily, Foreground и FontSize элемента TextBlock:
<TextBlock Text="Click!" FontFamily="Comic Sans Ms" Foreground="MediumBlue" FontSize="20">
</TextBlock>
И вот теперь стиль, который делает то же самое:
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="FontFamily" Value="Comic Sans Ms"></Setter>
<Setter Property="Text" Value="Click!"></Setter>
<Setter Property="Foreground" Value="MediumBlue"></Setter>
<Setter Property="FontSize" Value="20"></Setter>
</Style>
Применяется этот стиль к TextBlock посредством свойства Style. Поскольку стиль определен как ресурс, для задания имени стиля используется синтаксис с ключевым словом StaticResource (Статический ресурс):
<TextBlock Style="{StaticResource TextBlockStyle}">
</TextBlock>
И теперь все свойства, применяемые к элементам управления TextBlock кнопки, задаются в одном месте, что значительно упрощает обслуживание и делает XAML удобным для восприятия и понимания.
Любое из свойств, определенных стилем, можно переопределить, просто задавая его в самом объекте. Например, требуется переопределить свойство Foreground, заданное стилем MediumBlue (Светлосиний). Сделать это очень просто, как показано в примере:
<TextBlock Style="{StaticResource TextBlockStyle}"
Foreground="Black">
</TextBlock>
В этом случае, заданное здесь свойство Foreground переопределяет настройку стиля, и теперь для текста TextBlock будет использоваться черный цвет.
Также обратите внимание, что хотя стиль в данном примере определен для TextBlock, располагающегося в кнопке с изображением, он может применяться к любому TextBlock в данном Canvas.
Изменение области действия стиля
В примере из предыдущего раздела, стиль создавался в Canvas, содержащем элементы управления. Это ограничивает область действия этого стиля данным Canvas. Поэтому если в приложении имеется несколько страниц, пришлось бы определять стили на каждой страницы, что весьма неэффективно.
К счастью, Silverlight позволяет описывать стили для всего приложения, задавая их в App.xaml. В стандартном файле App.xaml, создаваемом шаблоном Visual Studio, уже определен раздел Resources!
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication1.App">
<Application.Resources>
</Application.Resources>
</Application>
Итак, размещенные здесь описания стилей будут доступны всему приложению. Рассмотрим пример:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication1.App">
<Application.Resources>
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="FontFamily" Value="Comic Sans Ms"></Setter>
<Setter Property="Text" Value="Click!"></Setter>
<Setter Property="Foreground" Value="MediumBlue"></Setter>
<Setter Property="FontSize" Value="20"></Setter>
</Style>
</Application.Resources>
</Application>
Применяя этот стиль, можно задавать стиль любого TextBlock в приложении, используя один и тот же синтаксис. Точно так же можно переопределить любое из свойств Style, задавая их для конкретного элемента управления.
Шаблоны
В предыдущем разделе была создана кнопка с изображением и использован факт, что кнопка является элементом управления с содержимым. Это позволило создать не просто кнопку с надписью, а включить в нее XAML, описывающий StackPanel с изображением (Image) и текстовым блоком (TextBlock). Затем вы научились с помощью стилей эффективно применять единообразные настройки к свойствам нескольких элементов TextBlock.
Следующий логический шаг - определение стиля сразу всего элемента управления, состоящего из Button и образующих его элементов управления, т.е. StackPanel, Image и TextBlock. Вот где шаблоны становятся основными средствами настройки внешнего вида ваших Silverlight-приложений!
Шаблоны действуют абсолютно аналогично стилям: размещаются в разделе Resources и описываются с помощью Setter. Чтобы создать Template (Шаблон), задается свойство Template и затем с помощью <Setter.Value> определяется ControlTemplate для заданного элемента управления:
Проще в этом разобраться, взглянув на код:
<Canvas.Resources>
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="FontFamily" Value="Comic Sans Ms"></Setter>
<Setter Property="Text" Value="Click!"></Setter>
<Setter Property="Foreground" Value="MediumBlue"></Setter>
<Setter Property="FontSize" Value="20"></Setter>
</Style>
<Style x:Key="ImageButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Button>
<Button.Content>
<StackPanel Orientation="Vertical">
<Image Source="icon.jpg" Height="48" Width="48"></Image>
<TextBlock Style="{StaticResource TextBlockStyle}"
Foreground="Black">
</TextBlock>
</StackPanel>
</Button.Content>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Canvas.Resources>
Здесь создается стиль ImageButton, в котором используется Setter для свойства Template. В нем содержится ControlTemplate, описывающий Button, которую мы видели ранее, включающую StackPanel с Image и TextBlock.
Обратите внимание, что здесь также может использоваться ссылка на стиль, потому что для элемента управления TextBlock, используемого в шаблоне, задан созданный ранее стиль TextBlockStyle.
Теперь XAML для объявления кнопок стал еще проще:
<Button x:Name="btn1" Style="{StaticResource ImageButton}"
Canvas.Top="20" Canvas.Left="20"></Button>
<Button x:Name="btn2" Style="{StaticResource ImageButton}"
Canvas.Top="20" Canvas.Left="120"></Button>
<Button x:Name="btn3" Style="{StaticResource ImageButton}"
Canvas.Top="20" Canvas.Left="220"></Button>
Для каждой кнопки в качестве значения Style задан ресурс ImageButton, который, в свою очередь, определяет шаблон для всего элемента управления. На рис. 12-4 показан результат выполнения этого XAML.
РИС. 12 4 Кнопки, заданные шаблоном.
По-настоящему замечательное свойство шаблонов в том, что в шаблоне не обязательно присутствие типа элемента управления, шаблон которого создается. Вероятно, звучит немного запутанно, поэтому рассмотрим пример, чтобы разобраться во всем. Выше в этом разделе был определен шаблон для кнопки с содержимым, которое делает ее простой кнопкой с изображением. Но, чтобы создать шаблон кнопки, элемент управления Button, по сути, не нужен. Можно без труда создать кнопки с изображением и текстом, не беря за основу стандартный элемент управления Button. Рассмотрим шаблон:
<Style x:Key="ImageButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Vertical">
<Image Source="icon.jpg" Height="48" Width="48"></Image>
<TextBlock Style="{StaticResource TextBlockStyle}"
Foreground="Black">
</TextBlock>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Таким образом, мы получили шаблон (заданный с помощью TargetType) вообще без элемента управления Button, но Silverlight будет интерпретировать его как кнопку, включая все соответствующие свойства и события. Например, если применить этот шаблон (бескнопочный), при выполнении приложения на экране можно будет увидеть примерно следующее (рис. 12-5).
РИС. 12 5 Бескнопочные шаблоны для кнопки.
Убедиться в том, что это настоящие кнопки, можно, попробовав написать код для них. Например, они имеют полную поддержку IntelliSense элемента управления Button в Microsoft Visual Studio. Это можно увидеть на рис. 12-6, где представлено написание кода для события Click.
volte I’ve* о
Inie >et ie»<oeeownc I> т
benl .Cl KkH
1HeMWtvwnlHw*r(btn4 СЬА)в
РИС. 12 6 Написание кода для кнопки, создаваемой по шаблону.
Поскольку шаблоны - это просто особые стили, их тоже можно описывать в App.xaml, чтобы сделать доступными для применения на многих страницах XAML
Заключение
В данной главе мы познакомились со стилями и шаблонами. Это очень важные возможности Silverlight, потому что они позволяют унифицировать и настраивать внешний вид и поведение всех создаваемых вами элементов управления. Вы научились объявлять стиль и использовать его как статический ресурс (StaticResource) элемента управления. Затем было показано, как использовать стиль во всем приложении, задавая его в App.xaml.
Наконец, вы увидели, как эта возможность может быть расширена с помощью шаблонов. Шаблоны аналогичны стилям, но позволяют описать стиль всего элемента управления. Был продемонстрирован ImageButton, созданный без использования Button, но все равно обладающий всеми свойствами, методами и событиями Button, благодаря объявлению ControlTemplate для него.
В следующей главе будет представлен еще один аспект Silverlight 2 и более подробно рассмотрены элементы управления ASP.NET, предлагаемые в Silverlight SDK.
Глава 13
Элементы управления Silverlight в ASP.NET
Software Development Kit (SDK) для Silverlight 2 включает два элемента управления ASP.NET, которые могут использоваться для поставки Silverlight-приложений в ASP.NET. Обратите внимание, что Silver- light можно использовать в ASP.NET и без этих элементов управления, но, несомненно, они намного упрощают задачу по управлению и доставке Silverlight-содержимого.
Начнем с элемента управления Silverlight. Он обеспечивает возможность использовать объявление ASP.NET на сервере, что создаст необходимые теги <OBJECT> и <PARAM> в браузере, позволяя использовать парадигму обработки на стороне сервера, хорошо знакомую разработчикам ASP.NET.
Второй элемент управления - MediaPlayer, который тоже обеспечивает модель объявления ASP.NET, но поставляет не универсальный элемент управления Silverlight, а приложение Silverlight-медиаплеера, со всеми его элементами управления и функциональностью.
В данной главе мы рассмотрим оба этих элемента управления и свойства, методы и события, которые они предлагают разработчикам.
Подсказка Прежде чем использовать элементы управления ASP.NET Silverlight в своей Веб-форме, необходимо зарегистрировать сборку, в которую они входят. Обычно для этого используется следующий код в начале разметки страницы:
<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls" TagPrefix="asp" %>
Серверный элемент управления Silverlight
Элемент управления Silverlight находится в пространстве имен Sys- tem.Web.UI.SilverlightControls.Silverlight. Заметьте, чтобы использовать его на странице, на ней должен присутствовать ScriptManager.
При создании Silverlight-приложения с использованием шаблона Microsoft Visual Studio также создается страница ASPX для размещения элемента управления ASP.NET Silverlight. Тег должен выглядеть примерно так:
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/ASP1.xap" Version="2.0"
Width="100%" Height="100%" />
Как видите, используется обычный синтаксис ASP.NET, т.е. свойства элемента управления задаются посредством атрибутов XML.
Использование счетчика частоты кадров
Атрибут EnableFrameRateCounter позволяет видеть частоту кадров, обеспечиваемую в настоящий момент Silverlight. Так очень удобно контролировать производительность приложения, особенно при выполнении большого количества анимаций.
Например, рассмотрим следующее приложение XAML. В нем выполняется анимация линии: ее разворот на 360 градусов:
<UserControl x:Class="ASP1.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<Storyboard x:Name="Storyboard1" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="path"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[2].(RotateTransform.Angle)"
BeginTime="00:00:00">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="359"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Ellipse HorizontalAlignment="Stretch"
Margin="147,79,151,96"
VerticalAlignment="Stretch"
RenderTransformOrigin="0.5,0.48"
Fill="#FF6A2020" Stroke="#FF000000"/>
<Path Height="115" HorizontalAlignment="Stretch"
Margin="199.564,30.436,194.436,0"
x:Name="path" VerticalAlignment="Top"
RenderTransformOrigin="0.891,0.983"
Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000"
StrokeThickness="6" Data="M196,137.15463 L196,35.15464">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
<Button Height="30" HorizontalAlignment="Left"
Margin="30,19,0,0" VerticalAlignment="Top"
Width="59" Content="Start" x:Name="btnStart"
Click="btnStart Click"/>
</Grid>
</UserControl>
Для Button описано событие Click. Код обработки события Click просто запускает анимацию Storyboard:
private void btnStart Click(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
}
Чтобы увидеть частоту кадров, активируйте счетчик частоты кадров в элементе управления ASP.NET
Silverlight:
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/ASP1.xap" Version="2.0"
Width="100%" Height="100%"
EnableFrameRateCounter="true" />
При выполнении приложения по нажатию кнопки запускается анимация. При этом в строке состояния браузера будет отображаться частота кадров. Это можно увидеть на рис. 13-1.
РИС. 13 1 Использование частоты кадров для элемента управления Silverlight.
Рекомендуется использовать эту возможность только во время отладки; отключите ее для рабочих приложений.
Задание максимальной частоты кадров
По умолчанию частота смены кадров в Silverlight составляет 60 кадров в секунду. Это означает, что все анимации с использованием временной шкалы разделяются на приращения свойств так, что свойство меняется 60 раз в секунду. Например, чтобы развернуть линию на 360 градусов за 1 секунду, анимация была бы разделена на 60 равных операций, каждая из которых осуществляла бы разворот на 6 градусов. Это может создавать большую вычислительную нагрузку, поэтому общую производительность можно повысить, снизив частоту кадров, или наоборот, если производительность не проблема и необходимо повысить плавность анимации приложения, можно увеличить частоту кадров.
Рассмотрим пример, в котором показано, как изменить частоту кадров до 10 кадров в секунду:
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/ASP1.xap" Version="2.0"
Width="100%" Height="100%" EnableFrameRateCounter="true"
MaxFrameRate="10" />
Если выполнить обсуждаемую ранее анимацию с вращением, вы заметите, что движение линии стало не таким плавным, как ранее. Также показания частоты, количество кадров в секунду (frames per second, fps), опустились до отметки 10 кадров в секунду (рис. 13-2).
РИС. 13 2 Сокращение частоты кадров.
Обеспечение доступа к HTML
С помощью свойства EnableHtmlAccess можно получить или задать для элемента управления Silverlight доступ к DOM HTML. По умолчанию это свойство имеет значение true, что активирует доступ к DOM.
Для работы с DOM браузера в приложении используется пространство имен System.Windows.Browser. Это обеспечивает вам доступ к классам, таким как HtmlPage, используемым для запроса метаданных страницы, на которой располагается элемент управления Silverlight, а также возможность поиска определенного элемента в документе. Элементы HTML могут быть представлены в .NET классом HtmlEle- ment (HTML-элемент).
Например, если в HTML имеется элемент <DIV> под именем testDiv, к нему можно обращаться и изменять из кода Silverlight следующим образом:
HtmlElement testDiv = HtmlPage.Document.GetElementById("testDiv"); testDiv.SetAttribute("innerText", "This is the testDiv");
Очень полезный класс - HtmlPage.BrowserInformation, он предоставляет метаданные, такие как Browser Version (Версия браузера), Sub Version (Дополнительная версия), Name (Имя), Platform (Платформа), User Agent (Агент пользователя) и включена поддержка cookie или нет.
Вот пример его содержимого во время выполнения:
? HtmlPage.BrowserInformation
{System.Windows.Browser.BrowserInformation}
BrowserVersion: {4.0}
CookiesEnabled: true
Name: "Microsoft Internet Explorer"
Platform: "Win32"
UserAgent: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0;
SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0;
.NET CLR 3.0.04506; InfoPath.2; .NET CLR 3.5.21022;
MS-RTC LM 8)"
? HtmlPage.BrowserInformation.BrowserVersion
{4.0}
Build: -1
Major: 4
Minor: 0
Revision: -1
Использование перерисовываемых областей
Другой наглядный пример, который поможет понять работу приложения Silverlight, - концепция перерисовываемой области (Redraw Region). Это визуальный индикатор, указывающий на части элемента управления Silverlight, которые перерисовываются. С помощью атрибута EnableRedrawRegions, задавая ему значение true вместо используемого по умолчанию false, можно включить эти маркеры. Итак, если вернуться к примеру с вращающейся линией и изменить разметку элемента управления ASP.NET, как показано в следующем коде, индикация перерисовываемых областей будет включена:
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/ASP1.xap" Version="2.0"
Width="100%" Height="100%" EnableFrameRateCounter="true"
EnableRedrawRegions="true" />
На рис. 13-3 показан создаваемый этим кодом эффект; перерисовываемые области выделены.
РИС. 13 3 Использование перерисовываемых областей.
Как и с частотой кадров, эту возможность рекомендуется использовать только для отладки приложений и выключать при переходе к производственной эксплуатации.
Задание свойства PluginBackground
С помощью свойства PluginBackground (Фон подключаемого модуля) можно задавать цвет фона подключаемого модуля. Вспомним, что элемент управления ASP.NET выполняется на сервере и формирует разметку, что позволяет использовать свойства System.Color, включая некоторые системные цвета (такие как Window или ActiveBorder), и также именованные системные цвета.
Как можно увидеть на рис. 13-4, Visual Studio IntelliSense позволяет выбирать системные и именованные цвета для фона подключаемого модуля.
РИС. 13 4 Задание цвета фона подключаемого модуля.
На рис. 13-5 показано, как будет выглядеть содержимое Silverlight, когда свойству PluginBackground задано значение WindowFrame. Заметьте, что вам придется изменить фон элемента управления Grid в XAML, или он переопределит это значение. Если вы хотите, чтобы цвет фона подключаемого модуля распространялся на все элементы, можно просто удалить это свойство в других элементах.
РИС. 13 5 Использование системного цвета в качестве цвета фона подключаемого модуля.
Если сейчас взглянуть на исходный код страницы, можно увидеть, что значение параметра Background объекта Grid с именем LayoutRoot жестко задано в коде. В примере, представленном на рис. 13-5 для подключаемого модуля задан цвет фона #FF646464.
Управление установкой подключаемого модуля
Если в системе клиента не установлен Silverlight, при переходе на страницу, включающую содержимое Silverlight, пользователь увидит стандартный значок установки Silverlight, как показано на рис. 13-6.
РИС. 13 6 Стандартный значок установки.
Переопределить это поведение можно специальным HTML-шаблоном. Этот HTML будет отображаться вместо значка установки, поэтому он должен содержать ссылку на ресурс загрузки. Microsoft предлагает удобный URL, который определяет используемые браузер и ОС и обеспечивает соответствующий файл для загрузки. Этот URL - http://www.microsoft.com/silverlight/handlers/getsilverlight.ashx?v=2.0.
Итак, изменить схему установки для Silverlight можно с помощью дочернего тега <PluginNotInstalled- Template> (Шаблон 'подключаемый модуль не установлен') элемента управления ASP.NET Silverlight. Рассмотрим пример:
<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/ASP1.xap"
Version="2.0" Width="100%" Height="100%"
PluginBackground="WindowFrame">
<PluginNotInstalledTemplate>
<a href="http://www.microsoft.com/silverlight/handlers/ getsilverlight.ashx?v=2.0">
If you want to install the Silverlight control, you can click here!1
</a>
</PluginNotInstalledTemplate>
</asp:Silverlight>
Здесь используется гиперссылка (тег <a>) на вышеупомянутый URL по которому располагается элемент управления Silverlight, и также задается некоторый доброжелательный текст. Конечно, можно предоставить пользователям что-то намного более вычурное, но здесь мы просто демонстрируем возможности. Попадая на вашу страницу, пользователь, не имеющий Silverlight, будет видеть содержимое, которое покажет, как установить Silverlight. Если Silverlight у пользователя установлен, он будет видеть Silverlight-содержимое.
Использование режима Stretch
Пользователь может менять размер браузера, при этом желательно, чтобы элемент управления Silver- light менялся соответственно. Это можно реализовать в коде, перехватывая события изменения размеров, или автоматически с помощью свойства ScaleMode (Режим масштабирования).
Существует три возможных значения этого свойства:
None Содержимое будет оставаться как есть, поэтому даже при изменении размера браузера, размеры содержимого будут оставаться неизменными.
Stretch Silverlight-содержимое будет менять размеры при изменении размера браузера и менять пропорции соответственно.
Zoom Silverlight-содержимое будет менять размеры при изменении размера браузера, но будет сохранять свои пропорции.
Рис. 13-7 и 13-8 демонстрируют использование Stretch и Zoom, соответственно.
1Если хотите установить элемент управления Silverlight, щелкните здесь! (прим, переводчика)
РИС. 13 7 Stretch меняет пропорции.
РИС. 13 8 Zoom меняет размер содержимого, но не пропорции.
Использование режима Windowless
По умолчанию Silverlight перекрывает все содержимое HTML-страницы, попадающее в область его отображения. Используя режим Windowless, можно обеспечить обратное поведение, т.е. HTML- содержимое будет отображаться поверх содержимого Silverlight. Это полезно, если требуется улучшить существующие приложения с помощью Silverlight. Элементы управления HTML (или другой HTML, создаваемый ASP.NET, JSP или другими серверами) могут просто отображаться поверх содержимого Silverlight. Например, есть элементы управления, доступные в HTML и недоступные (пока) в Silverlight, такие как редактор Rich Text Box (Насыщенное текстовое поле), или, возможно, вы хотите использовать другой Input Method Editor (IME), отличный от предлагаемого Silverlight. В этих случаях, если существуют доступные элементы браузера, обеспечивающие требуемое поведение, можно записать их содержимое поверх содержимого Silverlight.
Рассмотрим пример:
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div style="position: absolute; width: 600px; height: 100px; z-index: 1; left: 0px; top: 0px">
<form action="">
<textarea style="height:100px; width:300px; left:30px; top:30px" title="TextArea">
</textarea>
</form>
</div>
<div style="position: absolute; height:100%;top:0px;">
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/ASP1.xap"
Version="2.0" Width="100%" Height="100%" PluginBackground="WindowFrame"
ScaleMode="Stretch" Windowless="true">
</asp:Silverlight>
</div>
Обратите внимание, что для элементов <DIV> , включающих элемент управления HTML TextArea (Текстовая область), и Silverlight-содержимого задана абсолютная позиция 0 пикселов от верхней границы. Таким образом, они будут находиться в одном и том же месте на экране. Если бы параметру Windowless не было задано значение true, мы видели бы только Silverlight-содержимое. Однако когда Windowless задано значение true, HTML-содержимое отображается сверху (рис. 13-9).
РИС. 13 9 Использование режима Windowless в Silverlight.
Режим Windowless следует использовать аккуратно, потому что он может оказывать негативное влияние на производительность, особенно при большом количестве анимаций.
События серверного элемента управления Silverlight
Серверный элемент управления также предоставляет ряд событий, которые могут перехватываться обработчиками событий JavaScript. К ним относятся:
OnPluginError (Ошибка подключаемого модуля) Определяет функцию JavaScript, которая будет вызываться при возникновении любой ошибки в приложении Silverlight. Это подробно обсуждается в Главе 5, «Трансформация и анимация в XAML».
OnPluginFullScreenChanged (Переход подключаемого модуля к полноэкранному режиму) Определяет функцию JavaScript, которая будет вызываться при переходе к полноэкранному режиму. Не существует способа перехода к полноэкранному режиму автоматически, но элемент управления имеет свойство (isFullScreen), которое может меняться на основании действия пользователя. Если требуется реагировать на это событие, возможно, изменяя компоновку экрана, это можно делать в обработчике событий, определенному OnPluginFullScreeenChanged.
OnPluginLoaded (Подключаемый модуль загружен) Определяет функцию JavaScript, которая будет вызываться по завершении загрузки подключаемого модуля. Более подробно это обсуждается в Главе 5.
OnPluginResized (Изменение размера подключаемого модуля) Определяет функцию JavaScript, которая будет вызываться при каждом изменении размеров подключаемого модуля, что обычно происходит, если в качестве режима растяжения задан Stretch или Zoom (обсуждается ранее в данной главе), и пользователь меняет размеры браузера.
Таким образом, элемент управления ASP.NET позволяет задавать все, необходимое объекту, выполняющемуся на стороне клиента. То есть, можно делать все то же самое, что вы делали с помощью тега <Object> и при помощи ASP.NET!
Элемент управления MediaPlayer в ASP.NET
Элемент управления MediaPlayer обеспечивает доставку полнофункционального Silverlight- медиаплеера (видео и/или аудио) на страницу. Он предоставляет ряд шаблонов оформления, которые не только обеспечивают представление медиаплеера, но также полную функциональность управления воспроизведением, остановкой, приостановкой, маркерами, звуком, переходом в полноэкранный режим и многое другое. Также хочу обратить внимание, что элемент управления ASP.NET MediaPlayer имеет все свойства, методы и события типового элемента управления Silverlight, который обсуждался в первой части данной главы. Таким образом, все, что было сказано о нем здесь, включая настройку Windowless или других свойств, также может применяться к MediaPlayer.
Работать с элементом управления MediaPlayer очень легко: необходимо просто добавить его экземпляр на рабочую поверхность Веб-формы ASP.NET. В верхнем правом углу имеется кнопка, открывающая помощник MediaPlayer Tasks (Задания MediaPlayer), как показано на рис. 13-10.
РИС. 13 10 Использование элемента управления MediaPlayer.
Настройка при помощи MediaPlayer Tasks
Помощник MediaPlayer Tasks поможет задать основные свойства, которые обеспечат использование медиаплеера на вашем сайте:
Настройка Player Skin (Шаблон оформления плеера) позволяет задавать внешний вид и поведение вашего плеера. Инструменты ASP.NET Silverlight поставляются с набором шаблонов, а также можно создавать собственные шаблоны в Expression Blend. Их разработка выходит за рамки рассмотрения данной книги, но на сайте http://www.silverlight.net можно найти соответствующие учебные пособия для этого.
Щелкните ссылку Import Skin (Импортировать шаблон оформления), чтобы импортировать один из предоставляемых шаблонов. По умолчанию они хранятся в каталоге C:\Program Files\Microsoft SDKs\Silverlight \v2.0 \Libraries \Server \MediaPlayerSkins.
Media Source (Источник мультимедиа) - это местоположение медиафайла, который предполагается воспроизводить.
Placeholder Image (Заставка) - изображение, которое будет отображаться перед или после воспроизведения мультимедиа. Это должно быть изображение в формате JPG или PNG.
Volume (Громкость) - значение в диапазоне между 0 и 1, обозначающее громкость по умолчанию, с которой будет выполняться воспроизведение.
Когда флажок Muted (Без звука) установлен, воспроизведение будет выполняться, но звука не будет слышно, независимо от заданной громкости.
Когда флажок Auto-Play (Автовоспроизведение) установлен, воспроизведение мультимедиа начинается, как только оно становится доступным. По умолчанию значение Auto-Play - false (флажок не установлен).
Если внимательней посмотреть на рис. 13-11, можно заметить, что ползунок громкости установлен посередине, потому что значение громкости по умолчанию в помощнике MediaPlayer Tasks (рис. 13-10) - 0,5. Это демонстрирует гибкость данного элемента управления; вы можете настраивать медиаплеер соответственно конкретным нуждам своего приложения.
РИС. 13 11 Медиаплеер, поставляемый MediaControl.
Существует ряд других свойств, которые не представлены в помощнике MediaPlayer Tasks. Например, свойство AutoLoad (Автозагрузка). Когда ему задано значение true, мультимедиа автоматически загружается в базовый элемент управления, несмотря на действия пользователя. Когда AutoLoad задано значение false, мультимедиа не будет загружаться до тех пор, пока пользователь или программа не начнут воспроизведение.
Свойство EnableCaptions (Включить титры) используется для включения/выключения скрытых титров, если они кодированы в потоке.
Взаимодействие с мультимедиа
Прежде чем продолжить наш разговор, не помешало бы найти подходящий медиафайл, содержащий маркеры. Хороший пример того, как это можно сделать, представлен в Главе 11, «Мультимедиа, рукописный ввод и Deep Zoom».
Если в видеопотоке кодированы маркеры, можно написать код, реагирующий на них, и элемент мультимедиа Silverlight будет формировать события, при встрече с этими маркерами. При использовании серверного элемента управления ASP.NET необходим способ ассоциировать эти маркеры с функциями-обработчиками. Рад сообщить, что существуют атрибуты, позволяющие сделать это. Например, OnClientChapterStarted (Начало раздела) определяет функцию JavaScript, которая будет вызываться в начале каждого нового раздела видео. Разделы определяются в Expression Encoder и кодируются в видео или задаются в разметке ASP.NET. Вот пример второго варианта:
<asp:MediaPlayer ID="MediaPlayer1" ScaleMode="Stretch " runat="server" MediaSource="~/ClientBin/balls.wmv" Height="325px"
MediaSkinSource="~/Classic.xaml" Width="461px" OnClientChapterStarted="doChapter" >
<Chapters>
<asp:MediaChapter Position="1.0" Title="Chapter1" />
<asp:MediaChapter Position="2.0" Title="Chapter2" />
</Chapters>
</asp:MediaPlayer>
По достижении очередного раздела будет вызываться JavaScript-функция, определенная в OnClient- ChapterStarted.
С помощью свойства currentstate элемента управления MediaElement можно отслеживать, что происходит с мультимедиа. Это рассматривается в Главе 11. Данное свойство возвращает значения, представляющие текущее состояние воспроизведения мультимедиа, такие как «playing» (воспроизведение), «buffering» (буферизация), «paused» (приостановлено) и т.д. Если необходимо настроить обработчик события, например, события, которое формируется при изменении состояния, используется атрибут OnCurrentStateChanged элемента управления ASP.NET, определяющий необходимую JavaScript- функцию.
Маркеры подобны разделам с той точки зрения, что они тоже являются фрагментами метаданных, кодированными в видеопоток. По умолчанию все маркеры определены как разделы. С помощью атрибута OnMarkerReached (По достижении маркера) элемента управления ASP.NET можно задать JavaScript-функцию, которая будет вызываться при встрече с маркером.
Кроме того, можно задать действия, выполняющиеся при открытии, закрытии и сбое мультимедиа, используя атрибуты OnMediaOpened (При открытии мультимедиа), OnMediaEnded (При закрытии мультимедиа) и OnMediaFailed (При сбое мультимедиа), соответственно.
Заключение
В данной главе рассмотрены два элемента управления ASP.NET, поставляемых с Silverlight SDK. Элемент управления Silverlight используется для управления и развертывания Silverlight-содержимого с использованием парадигмы программирования на стороне сервера. Элемент управления MediaPlayer используется для доставки клиентам медиасодержимого с разным стилевым оформлением. Это чрезвычайно полезные с точки зрения производительности средства в случае использования ASP.NET для доставки Silverlight сайта, и они, безусловно, заслуживают времени, потраченного на их изучение. В следующей главе рассматривает новое захватывающее дополнение Silverlight 2 - поддержка динамических языков.
Глава 14
Использование динамических языков в Silverlight 2
В Silverlight 2 вводится поддержка динамических языков программирования. Динамическими называют языки программирования, которые реализуют многие функции во время выполнения, в то время как в других языках, например C#, это происходит во время компиляции. Динамическое поведение включает расширение объектов и описаний, изменение системы типов и многое другое. Это обеспечивает динамическим языкам простой подход к разработке через цикл «выполнение-вычисление- вывод» с применением метода проб и ошибок.
Silverlight 2 поддерживает три самых распространенных динамических языка: Ruby, Python и Dynamic JavaScript. Данная книга написана для спецификации Silverlight 2, в которую не включен шаблон проекта Microsoft Visual Studio 2008, но SDK предоставляет инструмент, Chiron.exe, для работы с динамическими языками программирования.
Поддержка динамических языков является инициативой Microsoft с открытым исходным кодом и доступна на Веб-сайте CodePlex по адресу http://www.codeplex.com/sdlsdk. В данной главе будет рассмотрено построение базовых приложений для Silverlight 2 с использованием динамических языков. Здесь не ставится задача изучения самих языков программирования и используются очень простые программы, которые будут понятны даже людям, не являющимся экспертами в каком-то конкретном языке.
Эта глава является только лишь введением в динамические языки и их использование в Silverlight. Большая ее часть посвящена рассмотрению Visual Studio и возможностей ее применения для создания приложений на IronPython, IronRuby и управляемом JavaScript в Silverlight, а также интегрированию Chiron.exe в Visual Studio. А напоследок вы совершите тур по знаменитому примеру Silverlight с часами и узнаете, как он реализован на Ruby.
Ваше первое Silverlight-приложение на IronPython
С инструментом Chiron проще всего работать, если настроить специальную структуру каталогов для своего приложения. В данном разделе будет поэтапно рассмотрено, как это сделать.
Прежде всего, необходимо создать пустой Веб-сайт. Для этого запустим Visual Studio и выберем в меню File пункт New Web Site (Новый Веб-сайт). Опция Empty Web Site (Пустой Веб-сайт) предлагается в диалоговом окне New Web Site, как показано на рис. 14-1.
РИС. 14 1 Диалоговое окно New Web Site.
Это обеспечит создание пустого каталога, который для Visual Studio будет являться корневым каталогом Веб-сайта. Для создания сайта будет использоваться Chiron, но вы увидите, что создавать страницы, код и т.д. проще в Visual Studio.
В Solution щелкните правой кнопкой на папке проекта и выберите Add New Item. Откроется диалоговое окно Add New Item, которое может использоваться для создания новой HTML-страницы. Выберите опцию HTML page (HTML-страница) и присвойте ей имя Default.html (рис. 14-2).
РИС. 14 2 Добавление нового элемента на сайт.
Это обеспечит вам базовую HTML-страницу. Ее необходимо отредактировать и превратить в страницу, на которой будет располагаться приложение Silverlight. Рассмотрим код такой страницы:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Dynamic Silverlight Test Page </title>
<style type="text/css">
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost { height: 100%;
}
</style>
</head>
<body>
<div id="silverlightControlHost">
<object data="data:application/x-silverlight,"
type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="app.xap"/>
<param name="background" value="white" />
<param name="windowless" value="true" />
</object>
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>
</body>
Для размещения Silverlight на странице используется тег <object>. Это очень упрощенный пример, и он не включает код для установки Silverlight, если его нет в системе. Более подробно об этом рассказывается в Главе б, «Элемент управления браузера Silverlight».
Обратите внимание на параметр source, которому задано значение app.xap. Chiron создаст его автоматически, как мы увидим через мгновение. Чтобы хар-файлу было присвоено такое имя, ваш файл кода должен называться app. Сначала рассмотрим, как создавать приложение с использованием IronPython и файла app.py, а затем реализуем ту же функциональность на IronRuby и Dynamic JavaScript.
Далее создадим каталог app в вашем Веб-сайте. Для него с помощью Add New Item выберем шаблон XML File (XML-файл) и назовем app.xaml.
Вот пример простого XAML, который можно поместить в этот файл:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="System.Windows.Controls.UserControl" x:Name="Page" >
<TextBlock
x:Name="txtMessage" TextWrapping="Wrap"
Foreground="Black" Text="Hello World," >
</TextBlock>
</UserControl>
Здесь описывается объект UserControl, включающий TextBlock под именем txtMessage. Данный содержит текст «Hello World,». Обратите внимание на запятую в конце фразы, почему она там находится, станет понятно через мгновение.
Теперь добавим файл кода IronPython. Опять же, щелкните правой кнопкой на папке app Веб-сайта и выберите Add New Item. В диалоговом окне выберите Text File (Текстовый файл) и назовите его app.py (py - расширение, используемое для Python).
На рис. 14-3 представлено, как должно выглядеть ваше решение на данный момент.
РИС. 14 3 Структура решения.
Теперь можно приступать к редактированию файла кода Python, чтобы сделать что-то более интересное. Рассмотрим код:
from System.Windows import Application
from System.Windows.Controls import UserControl
def handleClick(sender, eventArgs):
sender.Text = sender.Text + " from Python!"
class App:
def init (self):
self.scene =
Application.Current.LoadRootVisual(UserControl(),"app.xaml")
def start(self):
self.scene.txtMessage.MouseLeftButtonUp += handleClick
App().start()
Если у вас есть опыт разработки приложений Silverlight на C# или VB, синтаксис будет вам знаком. Например, строка
from System.Windows import Application
эквивалентна строке на C#
using System.Windows;
и указывает на пространство имен, в котором находится класс Application.
Затем определяем Python-класс App и задаем объект scene для App, загружая XAML-файл, описанный ранее. Как часть описания класса задается обработчик события запуска:
def start(self):
и код, который будет выполняться в этом обработчике. Этот код определяет обработчик события Mou- seLeftButtonUp элемента управления txtMessage типа TextBlock, который был описан нами ранее. Назовем обработчик handleClick (Обработка щелчка).
Сам код этого обработчика события выглядит следующим образом:
def handleClick(sender, eventArgs):
sender.Text = sender.Text + " from Python!"
Выполнение этого кода обеспечивает добавление фразы «from Python!» (из Python!) в конец значения свойства Text отправителя (которым, в данном случае, является TextBlock).
Чтобы выполнить это приложение, используется Chiron. Настроить Visual Studio на запуск Chiron можно, щелкнув правой кнопкой мыши файл проекта в Solution Explorer (заметьте, вы должны использовать файл проекта, а не файл решения; файла проекта обычно является первым дочерним файлом в решении) и выбрав в контекстном меню опцию Property Pages (Страницы свойств).
На Property Pages выберите страницу Start Options (Опции запуска) и на ней опцию Start External Program (Запустить внешнюю программу). Используйте кнопку с многоточием для перехода к каталогу, в котором находится Chiron.exe. Это должен быть каталог C:\Program Files\Microsoft
SDKs\Silverlight\v2.0\Tools\Chiron\Chiron.exe.
Введите /Ь в поле Command Line Arguments (Аргументы командной строки) и введите местоположение Веб-сайта в поле Working Directory (Рабочий каталог). Все это можно увидеть на рис. 14-4.
РИС. 14 4 Настройка Visual Studio на использование Chiron.
Теперь можно выполнить наше динамическое приложение Silverlight, нажав F5 в Visual Studio. Запустится Chiron, подтверждение этому вы увидите в окне командной строки, которое представлено на рис. 14-5.
РИС. 14 5 Visual Studio выполняет Chiron.
Здесь сообщается, что доступ к приложению осуществляется через http://localhost:2060. Visual Studio также запустит браузер с переходом по этому адресу, что обеспечит вывод на экран списка файлов Веб-каталога, как показано на рис. 14-6.
РИС. 14 6 Список файлов каталога Chiron.
Выберите Default.html, чтобы увидеть свое динамическое приложение Silverlight. В браузере будет выведено сообщение «Hello World,», как показано на рис. 14-7.
РИС. 14 7 Ваше первое Silverlight приложение на Python.
Теперь, если щелкнуть текст «Hello World,», появится дополнительное сообщение «from Python!» (рис. 14-8).
РИС. 14 8 Динамическое приложение в действии.
Это предельно простое приложение, но оно демонстрирует работу Dynamic Language Runtime (Динамическая среда выполнения) в Silverlight и то, как можно настроить Visual Studio для использования динамических языков программирования. В следующем разделе рассматривается, как можно реализовать это же приложение на IronRuby и управляемом JavaScript.
Использование Ruby и JavaScript
В предыдущем разделе мы поэтапно рассмотрели процесс настройки Visual Studio для создания динамических приложений на IronPython. Dynamic Language Runtime также поддерживает языки Ruby и
Dynamic JavaScript, поэтому рассмотрим, как можно создать такое же приложение с их использованием.
Использование Ruby
Начнем процесс с создания структуры проекта, включая HTML-файл и XAML-файл, аналогичной той, что использовалась для IronPython в предыдущем разделе. Но в данном случае, в папке app вместо файла app.py для кода на Ruby создается файл app.rb. Также не забудьте выполнить все настройки для запуска Chiron, так же как это делалось в предыдущем примере. (Вернитесь к рис. 14-4, на котором представлены все необходимые настройки).
Вставьте в app.rb код на IronRuby:
include System::Windows
include System::Windows::Controls
def handleClick(sender, eventArgs) sender.text = "Hello World, from Ruby!" end
class App def initialize @scene = Application.Current.LoadRootVisual(UserControl.new(), "app.xaml") end
def start @scene.find name('txtMessage').mouse left button up { |sender, args| handleClick(sender, args) } end end
App.new.start
Как видите, все очень похоже на пример с IronPython. Включаются пространства имен System.Windows и System.Windows.Controls. Затем описывается обработчик события handleClick для изменения текста по щелчку.
После этого объявляется класс App. Конструктор класса загружает XAML и использует его для инициализации класса. Событие Start связывает обработчик события с TextBlock txtMessage, описанным в XAML.
Теперь при выполнении приложения мы получаем такие же результаты: TextBlock отображает «Hello World,» и затем, когда пользователь щелкает текст, к этому тексту добавляется «from Ruby!».
Использование Dynamic JavaScript
Чтобы использовать JavaScript, выполните ту же процедуру, что в предыдущих двух примерах; т.е. создайте Веб-сайт в Visual Studio и добавьте в него файлы HTML и XAML. Не забудьте также настроить проект на использование Chiron. Как это сделать, показано на рис. 14-4.
На этот раз, вместо файлов app.py или app.rb в каталог app добавляется файл appjsx. Редактируйте содержимое файла app.jsx, добавляя в него следующий JavaScript-код:
Import("System.Windows.Application")
Import("System.Windows.Controls.UserControl")
function handleClick(sender, eventArgs) { sender.Text = sender.Text + " from Dynamic JavaScript";
}
function App() { this.scene =
Application.Current.LoadRootVisual(new UserControl(), "app.xaml")
}
App.prototype.start = function() {
this.scene.txtMessage.MouseLeftButtonUp += handleClick }
app = new App app.start()
Как видите, код по-прежнему предельно понятен. Управляемый JavaScript использует выражение Import для добавления ссылок на классы SystemWindows.Application и System.Windows.Controls.UserControl. В JavaScript само приложение является функцией, в которую добавляются свойства, поэтому scene является членом функции App и описывается путем загрузки XAML. Событие MouseLeftButtonUp обрабатывается функцией handleClick. Это определяется в функции start приложения.
Как и в предыдущих примерах, handleClick добавляет определенный текст, в данном случае, это «from Dynamic JavaScript» (из Dynamic JavaScript), в строку в txtMessage TextBlock, описанного в XAML.
Результат абсолютно аналогичен предыдущим двум примерам. Приложение отображает сообщение «Hello World,» и выводит дополнительный текст, когда пользователь щелкает сообщение.
Более сложный пример
Первым приложением Silverlight, которое увидело свет (еще когда Silverlight назывался WPF/E), было приложение с часами. Как оно выглядит, представлено на рис. 14-9.
Это замечательный пример Silverlight-приложения, потому что он демонстрирует многие принципы программирования в Silverlight. Нет необходимости программировать сами часы, все делает анимация Silverlight. Нам необходимо только установить стрелки часов в исходное положение, соответствующее системному времени.
РИС. 14 9 Часы на Silverlight.
Сначала рассмотрим XAML для часов. Обратите внимание, что это лишь фрагмент XAML, представляющий три стрелки часов и их анимацию:
<Canvas x:Class="System.Windows.Controls.Canvas" xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Opacity="0" x:Name="parentCanvas">
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation x:Name="hour animation"
Storyboard.TargetName="hourHandTransform"
Storyboard.TargetProperty="Angle" From="180" To="540"
Duration="12:0:0"
RepeatBehavior="Forever"/>
<DoubleAnimation x:Name="minute animation"
Storyboard.TargetName="minuteHandTransform"
Storyboard.TargetProperty="Angle" From="180" To="540"
Duration="1:0:0"
RepeatBehavior="Forever"/>
<DoubleAnimation x:Name="second animation"
Storyboard.TargetName="secondHandTransform"
Storyboard.TargetProperty="Angle" From="180" To="540"
Duration="0:1:0"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Canvas.Triggers>
! Часовая стрелка -->
<Path Data="M -4, 16 l 3 40 3 0 2 -40 z" Fill="white">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="hourHandTransform"
Angle="180"/>
<TranslateTransform X="150.5" Y="145"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
! Минутная стрелка -->
<Path Data="M -4, 16 l 3 70 3 0 2 -70 z" Fill="white">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="minuteHandTransform"
Angle="180"/>
<TranslateTransform X="150.5" Y="145"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
! Секундная стрелка -->
<Path Data="M -1, 16 l 0 70 2 0 0 -70 z" Fill="red">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="secondHandTransform"
Angle="180"/>
<TranslateTransform X="150.5" Y="145"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Canvas>
XAML начинается с размещения трех анимаций в соответствующих элементах Storyboard. Стрелки часов можно рассматривать как вращающиеся прямые, поэтому для их анимации используется тип DoubleAnimation, обеспечивающий изменение угла поворота. Подробнее о реализации этого в XAML рассказывает Глава 5, «Трансформация и анимация в XAML».
Следует обратить внимание на имена анимаций: hour animation (анимация часов), minute animation (анимация минут) и second animation (анимация секунд), соответственно. Помните об этом при рассмотрении кода. В качестве цели каждой анимации задана именованная трансформация: hourHandTransform (Трансформация часовой стрелки) реализует отсчет часов, minuteHandTransform
(Трансформация минутной стрелки) реализует отсчет минут и secondHandTransform (Трансформация секундной стрелки) отвечает за перемещение секундной стрелки. Эти трансформации можно будет увидеть ниже в XAML. Каждая стрелка реализована как объект Path, и с каждым из этих контуров ассоциирована одна из упомянутых выше трансформаций.
Итак, анимации запускаются в Canvas.Loaded и повторяются постоянно, обеспечивая перемещение стрелок по циферблату часов на 360 градусов за заданный промежуток времени. Но как инициализировать их, чтобы они представляли текущее время? Вот для этого понадобиться написать код.
Реализация часов выполняется в двух модулях кода на Ruby. Первый - вспомогательный класс, созданный группой Silverlight Dynamic Languages (Динамические языки Silverlight) для использования в Ruby-приложениях. Рассмотрим его код:
include System::Windows
include System::Windows::Controls
include System::Windows::Media
class SilverlightApplication
def application Application.current end
def self.use xaml(options = {})
options = {:type => UserControl, :name => "app"}.merge(options)
Application.current.load root visual(options[:type].new, "#{options[:name]}.xaml") end
def root application.root visual end
def method missing(m) root.send(m)
end end
class FrameworkElement def method missing(m) find name(m.to s.to clr string) end
end
Здесь определяется ряд вспомогательных функций и объектов, включая:
application (приложение) Указывает на текущее приложение (просто обозначается Applica- tion.current)
root (корень) Указывает на корневой визуальный элемент, а именно, элемент верхнего уровня в XAML
method missing (поиск метода по имени) Обрабатывает трансляцию имени метода в строковый формат clr, что помогает при написании кода
use xaml (использовать xaml) Управляет загрузкой XAML в визуальное дерево
В коде приложения, реализующего часы, используется вспомогательные функции root и use xaml. Рассмотрим их:
require 'Silverlight'
class Clock < SilverlightApplication
use xaml :type => Canvas
def start
d = Time.now()
root.hour animation.from = from angle d.hour, 1, d.minute/2
root.hour animation.to = to angle d.hour
root.minute animation.from = from angle d.minute
root.minute animation.to = to angle d.minute
root.second animation.from = from angle d.second root.second animation.to = to angle d.second end
def from angle(time, divisor = 5, offset = 0) ((time / (12.0 * divisor)) * 360) + offset + 180 end
def to angle(time) from angle(time) + 360 end
end
Clock.new.start
Обратите внимание на первую строку кода
require 'Silverlight'
это означает, что должен быть включен файл Silverlight.rb, потому класс нашего приложения будет наследоваться от него.
Затем объявляется класс Clock (Часы), производный от SilverlightApplication (определенный в Silver- light.rb):
class Clock < SilverlightApplication
Вызываем функцию use xaml из SilverlightApplication и задаем, что используем XAML с базовым элементом <Canvas>. Это наследие Silverlight 1, в котором <Canvas> был единственным корневым элементом.
Далее переходим к функции start, которая вызывается по завершении инициализации. Она принимает текущее время с помощью функции Time.now и использует его для определения значений from (от) и to (до) для трех анимаций. Помните анимации hour animation, minute animation и second animation? Теперь можно увидеть, как они используются. В Ruby вызов функции осуществляется путем указания ее имени, за которым следует пробел и список параметров через запятую. Таким образом, угол, представляющий текущее расположение часовой стрелки, получаем, вызывая from angle и передавая в нее соответствующие параметры, которыми в данном случае являются текущее количество часов, 1, и количество минут, деленное на 2. Причина деления количества минут на два в том, что для трансформаций отсчет углов ведется от нижней точки окружности, т.е. здесь необходимо выполнить смещение на 180 градусов, следовательно, текущее показание делится на 2, чтобы «перевернуть» угол, предоставляемый значением minute.
Рассмотрим эту функцию:
def from angle(time, divisor = 5, offset = 0) ((time / (12.0 * divisor)) * 360) + offset + 180 End
Возвращаясь к коду, можно увидеть, что начальное условие просто использует эту функцию для вычисления соответствующего угла трансформации, с которого будет начинаться анимация, и задает его в качестве значения свойства from анимации. Аналогично, значение окончания анимации (to) равно 360 градусам плюс текущее значение from. Таким образом, трансформация обеспечит прохождение стрелкой 360 градусов, начиная от исходного значения, за заданный промежуток времени (12 часов для часовой стрелки, 1 час для минутной и 1 минута для секундной стрелки).
Наконец, приложение начинается с создания нового экземпляра класса Clock и его запуска:
Clock.new.start
Таким образом, с помощью Ruby мы создали функциональное Silverlight-приложение - анимированные часы, которые отображают текущее время.
Заключение
В данной главе представлены динамические языки программирования и создано простое приложение Hello World с использованием IronPython, IronRuby и управляемого JavaScript. Вы увидели, как настраивать Visual Studio для работы с инструментом Chiron, применяемым для построения и управления выполнением динамических приложений.
Это всего лишь простая иллюстрация доступных возможностей, однако, этого достаточно, чтобы вдохновить вас на продолжение экспериментов с динамическими языками.
И на этом наше знакомство с Silverlight подошло к концу. Когда вы выбирали эту книгу, вероятно, вас интересовало, что такое Silverlight и что можно сделать с его помощью. Когда я писал ее, я не хотел создавать исчерпывающий энциклопедический справочник. Я просто хотел представить все замечательные возможности Silverlight 2 в как можно более доступной форме, чтобы вы могли взять книгу, открыть любую главу, проработать ее и понять, что представляет собой эта технология, и захотели пойти дальше.
Надеюсь, вы получили такое же удовольствие от работы с этой книгой, какое испытывал я при ее написании!
Предметный указатель
.NET Frameworkпанель взаимодействий39
3.x17панельинструментов38
CLR18панельпроекта40-41
создание приложений53-70панельсвойств41-42
.NET, взаимодействие иданные196-99рабочаяповерхность39-40
<div>27ExpressionDesign 23
ADO.NET18диалоговое окно Export XAML23-24
AJAXсм.также ASP.NET AJAXи Silverlight23-25
создание серверного приложения времени191-92поддерживаемые форматы графических файлов23
создание элемента отображения времени192-94экспортируемые типы изображений23
App.xaml по умолчанию35Expression Encoder23,28-30
App.xaml, по умолчанию35Expression Media23
AppManifest.xml 59Expression Studio
ASP.NET AJAX191,194-204и Silverlight22-28
Assemblyinfo.cs59инструменты22
ATOM, использование SyndicatedFeed для доступа 199-201Expression Web23
Avalon 20ExpressionEncoder
BeginStoryboard, анимации109сформированный им медиаплеер31
createObjectEx, параметры120-22HTML, доступ с серверного элемента
CSS/DHTML, в модели представления17управления249-50
Deep zoomImageBrush79-81
экспорт метаданных233Java, и Silverlight186-91
Deep Zoom229-40JavaScript
использование мыши и логических координат 235-37Dynamic263-64
коллекции238-40класс scene28
редактор231-34классы рукописного ввода222-24, см. также Классы
создание проекта234-35рукописного ввода для JavaScript
создание функциональности масштабирования сорганизация взаимодействия с сервером191-94
использованием колеса мыши237-38файл с выдеделенным кодом Page.xaml28
Default.aspx62JavaScriptDOM API18-19
Default.html26-27JavaScript Object Notation (JSON)120,194
EventTrigger108-9JSP, отображение Silverlight190-91
Expression Blend23, 25-28LinearGradientBrush21,73-75
App.xaml по умолчанию35LINQ18
выполнение приложения36Media Encoder29
и анимация115-19MP319
интегрированная среда разработки (IDE)....32, см. такжеMySQL Query Browser179
Expression Blend IDEPage.xaml 25
компоновочные инструменты43-48JavaScript-файл с выделенным кодом28
опции диалогового окна New Project33по умолчанию34-35
проектирование анимаций50-52Page.xaml.js25
размещение и настройка визуальных элементов ...48-49PHP, и Silverlight177-86
размещение и настройка элементов управления ...49-50RadialGradientBrush76-79
стандартная Веб-страница26RIAсм. Насыщенные интерактивные приложения
страница по умолчанию34-35RSS, использование SyndicatedFeed для доступа .... 199-201
типы проектов Silverlight25Ruby (динамический язык программирования)263
файлы с выделенным кодом35scene.handleLoad28
элемент управления Border48Silverlight 1 Site33
Expression Blend IDE 32Silverlight 2 Application 25,33
Silverlight Application Wizard56определение108
SilverlightControlHost27параметры109-12, см. также Параметры анимации
SolidColorBrush21,73типы22
Solution, на панели проекта41триггеры и триггеры событий108-15
StoryboardАрхитектура Silverlight18-19
анимация50,109,116Архитектура, Silverlight18-19
SyndicatedFeed199-201Аффинная матрица106
Triggers108-9База данных на стороне сервера, создание178-79
User Experience (UX). см. Взаимодействие с пользователем,База данных, на стороне сервера178-79
см. Взаимодействие с пользователемБиблиотека system.Xml.Linq158-59
UserControlБиблиотеки классов172-76
добавление TextBlock36Буферизация, управление214-15
и страница по умолчанию35Ввод посредством мыши221
VideoBrush81, 220Ввод с помощью пера221
Visual studioВеб, модели программирования и представления18-19
создание приложения Silverlight168-72Веб-проект, Visual Studio62-63
Visual StudioВеб-страница по умолчанию26-28
диалоговое окно New Project55Взаимодействие с пользователем. см.User Experience (UX),
проект элемента управления Silverlightсм. Проектсм. User Experience (UX)
элемента управления SilverlightВзаимодействующие с сервером приложения
проект элемента управления SilverlightASP.NET AJAX и Веб-сервисы194-204
Веб-проект62-63SilverlightиJava186-91
создание игры на Silverlight 264-70SilverlightиPHP177-86
создание приложения Silverlight55-57SilverlightиWCF201-4
установка инструментов53-55и JavaScript191-94
WCF, и Silverlight201-4Видеосм. также Элементы управления MediaElement
Web Services, взаимодействующие с серверомзакрашивание, использование VideoBrush220
приложения194-204запись содержимого поверх210
Windows Presentation Foundation20прогрессивная загрузка214-15
WMA19Визуальные свойства XAML81-85
WMV19поведение курсора82
WPF Application (.exe)33прозрачность82
WPF Control Library33свойства задания размеров и местоположения81-82
xсвойство Stroke82-85
Name20,181Визуальные элементы, размещение и настройка48-49
XAML (Extensible Application Markup Language)16Воспроизведение видео, с помощью элемента управления
вырезание94MediaElement 206-7
генерирование из PHP и MySQL181-85Воспроизведение, автоматическое211
геометрические элементы94Временная шкала
обработка ошибки синтаксического разбора128в раскадровке22
фигуры86-94, см. также записи для всех фигур вредактирование51
отдельностиВырезание
подключение приложенийсм. Подключениев XAML94
приложенийсравнение с обрезкой64
шаблон данных160Геометрические объекты86-94
XAML, компоновочные свойства71-72Геометрические элементы
XAML-шаблон179-81Silverlight20-22
XML20в XAML87-94, 94
Автоматическое воспроизведение211вырезание мультимедиа210
Анимация108-15объект ArcSegment88
BeginStoryboard иStoryboard109объект BezierSegment89
Expression Blend50-52объект LineSegment88
и Expression Blend115-19объект PolyBezierSegment89-90
ключевые кадры112-15объект PolyLineSegment89
объект PolyQuadraticBezierSegment91-92
объект QuadraticBezierSegment90-91
Градиентная заливка21
Градиентная кисть21
Динамические языки программирования Dynamic JavaScript263-64
Ruby 263
определение258
приложение на IronPython258-62
пример реализации часов264-68
Загрузка, управление214-15
Звук, управление211
Игра на Silverlight 2 написание кода игры64,см. также Код игры
создание UI в XAML64
Инструмент Pen48
Инструмент Pencil48
Интернет, сценарии доступа к информации16
Кисти21, см. также Кисти XAML
задание свойства Stroke83
использование для определения трансформации100
Кисти XAML ImageBrush79-81
LinearGradientBrush73-75
RadialGradientBrush76-79
SolidColorBrush73
VideoBrush81
Клавиатура, элементы управления для ее использования 155
Класс Scene28
Класс WebClient196-97
Класс WebRequest197-99
Классы рукописного ввода для JavaScript аргументы событий мыши224-25
программирование225-29
тип Stroke223
тип StrokeCollection222
тип StylusPoint224
Классы рукописного ввода для JavaSkript тип StylusPointCollection223-24
Клиентское приложение для отображения времени, создание192-94
Ключевые кадры112-15
добавление51
дискретной анимации114
задание изменений117
линейные113
сглаженной анимации114-15
Кнопка Assembly Information58-59
Кнопки в StackPanel46
как элементы управления пользовательского интерфейса49
расположенные случайным образом43
элемент управления RepeatButton164-65
элемент управления ToggleButton164-65
Кнопки, расположенные случайным образом43
Код игры инициализация структур данных64-65
обработка пользовательского элемента управления. 68
69
отрисовка игрового поля67-68
перемешивание фрагментов головоломки67
проверка условия выигрыша69-70
создание фрагментов головоломки65-67
Код элемента управления, написание170-72
Колесо мыши, создание функциональности
масштабирования237-38
Компоновочная сетка44
Компоновочные инструменты43-48
ScrollViewer46-48
компоновочный элемент Canvas45-46
компоновочный элемент StackPanel46
сетка43-45
Компоновочные свойства, XAML71-72
Компоновочный элемент Canvas45-46
Компоновочный элемент Grid43-45
Компоновочный элемент StackPanel46
Крень Canvas20
Логические координаты, использование в Deep Zoom. 23537
Маркер временной шкалы217-19
Маркеры временной шкалы мультимедиа217-19
Масштабированиесм.Deep Zoom
Матрица трансформации100
Метаданные29
Метод AddEventListener134-35
Метод CaptureMouse138
метод createFromXaml131-32
Метод createFromXamlDownloader132
Метод createObject132
Метод findName132
Метод GetHost135
Метод getParent135
Метод GetValue135
Метод ReleaseMouseCapture138
Метод RemoveEventListener134-35
Метод SetFontSource136
Метод SetValue136
Методы элемента управления
метод createFromXaml131-32
метод createFromXamlDownloader132
метод createObject132
метод findName132
Многоплатформенные приложения33
Модель представления, CSS/DHTML17
Модель программирования JavaScript/AJAX/.NET Framework 18
Модель разработки, технологии разработки веб
приложений 17
Мультимедиа, взаимодействие256-57
Мышь, использование в Deep Zoom235-37
Насыщенные интерактивные приложениясм. RIA
элементы управления для них157
Непосредственные свойства130
Обработчик ошибок, собственый128-29
Обрезка, сравнение с вырезанием64
Объект ArcSegment88
Объект BezierSegment89
Объект Downloader132-34
Объект GeometryGroup92-93
Объект Line21,48, 86, 87
Объект LineSegment88
Объект Path21,86, 87
Объект PolyBezierSegment89-90
Объект PolyLineSegment89
Объект PolyQuadraticBezierSegment91-92
Объект QuadraticBezierSegment90-91
Объявления пространств имен XML20
Описание проекта41
Опорные кадры22
Опция Assembly Name58
Опция Default Namespace58
Опция Startup Object58
Ошибка синтаксического разбора, обработка128
Пакет средств разработки Silverlight25
Панель Properties, в Expression Blend41-42
Папка Properties41, 59
Папка References41, 59
Параметр userContext125-26
Параметр свойства framerate27
Параметр свойства inplacelnstallPrompt27
Параметр свойства isWindowless27
Параметр свойства version27
Параметры анимации задание момента начала110
задание объекта анимации110
задание продолжительности110
свойство AutoReverse110
свойство DoubleAnimation111
свойство PointAnimation112
свойство RepeatBehavior110-11
свойство SpeedRatio110
Перемещение методом «drag-and-drop» использование событий мыши153-55
реализация138-40
Перерисовываемые области250
Положение курсора воспроизведения, управление .216-17
Приложение на IronPython258-62
Приложения только для Windows33
Пример реализации часов264-68
Программный интерфейс18-19
Проект JavaScript, Silverlight 1 Site25
Проект Silverlight 1 Site25
Проект элемента управления
Visual Studio57-62
папка References59
свойства проекта58-59
файлы App.xaml и App.xaml.cs60-61
файлы свойств59
файы Page.xaml и Page.xaml.cs61-62
Проект, создание нового, в Visual Studio168-72
Профиль кодирования видео29
Разрывы строк99
Раскадровка временные шкалы22
Режим Stretch252-53
Режим Windowless253-54
Свойства задания местоположения81-82
Свойства задания размеров81-82
Свойства настроек130
Свойства проекта58
Свойства содержимого130
Свойства элемента управления
непосредственные свойства130
свойства настроек130
свойства содержимого130
Свойство AutoReverse110
Свойство Canvas.Left71
Свойство Canvas.Top71
Свойство CanvasZIndex71-72
Свойство ColorAnimation22, 50,111-12
Свойство Cursor82
Свойство DoubleAnimation22, 50,111
Свойство Geometry.Transform100
Свойство MatrixTransform22,106
Свойство Opacity82
Свойство Orientation, компоновочный элемент StackPanel 46
Свойство PluginBackground250-51
Свойство PointAnimation22,112
Свойство RepeatBehavior110-11
Свойство RotateTransform22,100-101
Свойство ScaleTransform22,102-3
Свойство SkewTransform22,104
Свойство SkewTransfrom
имитация трехмерного изображения105
Свойство SpeedRatio110
Свойство SpreadMethod77
Свойство Stroke82-85
Свойство TextDecorations98
Свойство TextWrapping98
Свойство TranslateTransform22,103-4
Сегменты контура, составные92
Сенсорный ввод221
Серверное приложение времени, создание191-92
Серверные страницы Java186
Серверные элементы управления см. Серверные элементы управления Silverlight
Серверный элемент управления Silverlight247-55
доступ к HTML249-50
максимальная частота кадров249
перерисовываемые области250
режим Stretch252-53
режим Windowless253-54
свойство PluginBackground250-51
события254-55
счетчик частоты кадров247-49
управление установкой подключаемого модуля.. 251-52
Сервлет187
Сервлет Java187
Сервлет для получения исходного XAML187-89
Событие MouseMove, и Deep Zoom236
Событие onLoad28
Событие OnPluginError254
Событие OnPluginFullScreenChanged254
Событие OnPluginLoaded255
Событие OnPluginResized255
События OnExit35
События OnStartup35
События загрузки страницы, ответ на них124-26 обработка параметров124-25
пользховательский контекст125-26
События мыши
аргументы, используемые с рукописным вводом 224-25 обработчики134-40
элементы управления для обработки153-55
События ошибки страницы, ответ на них127-34
собственный обработчик событий128-29
стандартный обработчик событий128
Соединение линий, определение85
Создание экземпляра27
Составные сегменты контура92
Стандартный обработчик событий128
Стилевое оформление241-44
изменение области действия стиля243-44
создание стиля242-43
Страница по умолчанию34,см. также Page.xaml
Тег <object>37,123
Текстовые элементы управления49
Тестовая страница файла ASPX63
Тип Stroke223
тип StrokeCollection222
Тип StylusPoint224
Тип StylusPointCollection223-24
Трансляция103-4
Трансформации22,100-108
вращение100-101
имитация трехмерного изображения105
масштабироание102-3
наклонение объекта104
определение собственных трансформаций106
перемещение объекта103-4
сочетание107
элемент управления MediaElement209-10
Трехмерное изображение, имитация105
Установка подключаемого модуля, управление251-52
Файл DLL33
Файлы App.xaml60-61
Файлы App.xaml.cs35, 60-61
Файлы ASPX63
Файлы Page.xaml61-62
Файлы Page.xaml.cs61-62
Файлы с выделенным кодом35
Фигура Ellipse21, 48, 86
Фигура Polygon21, 86
Фигура Polyline21, 86
Фигура Rectangle21, 48, 86
Фигуры, в XAML86-94
геометрические элементы87-94
контуры87-88
объект Ellipse86
объект GeometryGroup92-93
объект Line87
язык описания контуров93-94
Фигуры, основные21, 48, см. также Фигуры, в XAML
Фильтр DirectShow29
Форма ввода данных197
Форматы графических файлов, и Expression Design23 Функция createObjectEx27,120-22
Функция createSilverlight27
Функция handleLoad28
Функция handleMouseDown28
Функция IntelliSense171-72
Частота кадров
максимальная249
счетчик247-49
Шаблон Silverlight, Default.html26
Шаблон данных160
Шаблон элемента управления, добавление169-70
Шаблоны244-46, см. также Шаблон Silverlight
XAML179-81
данных160
элемент управления169-70
Шрифты, «Веб-безопасные»97
Элемент Canvas20-21
Элемент Canvas24
Элемент Glyphs96-97
Элемент Image67
Элемент Run98-99
Элемент UI, задание трансформации100
Элемент UI, программирование
методы элемента UI134-36
перемещение методом «drag-and-drop»138-40
события элемента UI137-38
Элемент управления ASP.NET MediaPlayer взаимодействие с мультимедиа256-57
задания MediaPlayer255-56
Элемент управления Border48
Элемент управления Button141-42, 241-42
Элемент управления Calendar162-64
Элемент управления Canvas95-96
Элемент управления CheckBox49,142-43
Элемент управления DataGrid157-62
Элемент управления DatePicker162-64
Элемент управления GridSplitter49
Элемент управления HyperlinkButton143-44
Элемент управления Image96,144-45
Элемент управления InkPresenter220-29
классы рукописного ввода для программистов на
JavaScript222-24
пример в Silverlight220-29
Элемент управления ListBox49
Элемент управления ListBox145-46
Элемент управления MediaElement205-19
автоматическое воспроизведение211
базовые элементы управления воспроизведением . 212
14
вырезание мультимедиа геометрическими формами210
запись содержимого поверх видеоизображения210
звук211
маркеры временной шкалы мультимедиа217-19
определение размера207
положение курсора воспроизведения216-17
программирование212-19
прозрачность видео209
простое воспроизведение видео206-7
растягивание изображения мультимедиа207-9
текущее состояние видео215
трансформации209-10
Элемент управления MultiScaleImage229-40, см. также Deep zoom
Элемент управления RadioButton49
Элемент управления RadioButton147-48
Элемент управления RepeatButton164-65
Элемент управления ScriptManager63
Элемент управления ScrollBar49
Элемент управления ScrollViewer46-48,165-66
Элемент управления Slider49,167
Элемент управления TextBlock148-49
Элемент управления TextBox49
Элемент управления TextBox150-52
Элемент управления ToggleButton164-65
Элемент управления браузера ответ на события загрузки страницы124-26
ответ на события ошибки страницы127-34
размещение Silverlight в браузере120-23
тег<object>123
элементы UI134-40
Элемент управленияMediaElement
буферизация и загрузка214-15
Элементы управлениясм. также Элементы управления
Silverlight
для использования клавиатуры155
размещение и настройка49-50
Элементы управления ASP.NET
MediaPlayer255-57
ScriptManager 63
Silverlight 63
серверный элемент управления Silverlight247-55
Элементы управления Silverlight создание экземпляров
элемент управления MediaElement205-19
элемент управления VideoBrush220
элементы управления ASP.NETсм. Элементы управления
ASP.NET
для обработки событий мыши153-55
для обработки фокуса152
элемент управления Buton141-42
элемент управления Calendar162-64
элемент управления CheckBox142-43
элемент управления DataGrid157-62
элемент управления DatePicker162-64
элемент управления HyperlinkButton143-44
элемент управления Image144-45
элемент управления InkPresenter220-29
элемент управления ListBox145-46
элемент управления MultiScaleImage229-40
элемент управления RadioButton147-48
элемент управления RepeatButton164-65
элемент управления ScrollViewer165-66
элемент управления Slider167
элемент управления TextBlock148-49
элемент управления TextBox150-52
элемент управления ToggleButton164-65
Элементы управления TextBlock22,97-99
добавление в UserControl36
присваивание мен181
разрывы строк99
метод SetFontSource136
TextBlockStyle243
стилевое оформление242
элемент Run98-99
Элементы управления XAML элемент Canvas95-96
элемент Glyphs96-97
элемент Image96
элемент TextBlock97-99
Элементы управления воспроизведением212-14
Элементы управления пользовательского интерфейса....49 для игры67-69
Язык описания контуров93-94
Об автореLaurence Moroney (Лоуренс Морони) является ведущим экспертом по технологиям Microsoft,специализирующимся на Silverlight и User Experience. Имеет более чем десятилетний опыт разработки и реализации программного обеспечения и является автором около десятка книг по разнообразнейшим тематикам, среди которых Windows Presentation Foundation, Веб-разработка, безопасность и способность к взаимодействию.Об автореLaurence Moroney (Лоуренс Морони) является ведущим экспертом по технологиям Microsoft,специализирующимся на Silverlight и User Experience. Имеет более чем десятилетний опыт разработки и реализации программного обеспечения и является автором около десятка книг по разнообразнейшим тематикам, среди которых Windows Presentation Foundation, Веб-разработка, безопасность и способность к взаимодействию.ПОЛЕЗНЫЕ РЕСУРСЫ MICROSOFT®Для дизайнеровВеб-сайт Expressionwww.microsoft.com/rus/expressionБюллетень Expression для дизайнеров www.microsoft.com/rus/expression /news-press/newsletterПОЛЕЗНЫЕ РЕСУРСЫ MICROSOFT®Для дизайнеровВеб-сайт Expressionwww.microsoft.com/rus/expressionБюллетень Expression для дизайнеров www.microsoft.com/rus/expression /news-press/newsletter
Об авторе
Laurence Moroney (Лоуренс Морони) является ведущим экспертом по технологиям Microsoft,специализирующимся на Silverlight и User Experience. Имеет более чем десятилетний опыт разработки и реализации программного обеспечения и является автором около десятка книг по разнообразнейшим тематикам, среди которых Windows Presentation Foundation, Веб-разработка, безопасность и способность к взаимодействию.
Об авторе
Laurence Moroney (Лоуренс Морони) является ведущим экспертом по технологиям Microsoft,специализирующимся на Silverlight и User Experience. Имеет более чем десятилетний опыт разработки и реализации программного обеспечения и является автором около десятка книг по разнообразнейшим тематикам, среди которых Windows Presentation Foundation, Веб-разработка, безопасность и способность к взаимодействию.
ПОЛЕЗНЫЕ РЕСУРСЫ MICROSOFT®
Для дизайнеров
Веб-сайт Expression
www.microsoft.com/rus/expression
Бюллетень Expression для дизайнеров www.microsoft.com/rus/expression /news-press/newsletter
ПОЛЕЗНЫЕ РЕСУРСЫ MICROSOFT®
Для дизайнеров
Веб-сайт Expression
www.microsoft.com/rus/expression
Бюллетень Expression для дизайнеров www.microsoft.com/rus/expression /news-press/newsletter
Введение в Microsoft® Silverlight™ 2 ВТОРОЕ ИЗДАНИЕ
Ваш первый взгляд на инструменты и технологии создания приложений с использованием Silverlight 2.
Начните применять Silverlight 2—кросс-платформенный, кросс-браузерный плагин для представления расширенных мультимедийных интерактивных приложений и пользовательских интерфейсов следующего поколения. Книга основана на знаниях команды разработчиков Microsoft Silverlight, процесс изучения построен с использованием практических упражнений, подробных указаний и примеров кода, чтобы вы сразу могли перейти к собственным разработкам.
Изучите как:
Использовать XAML для отрисовки, масштабирования и анимации
Воспользоваться мощью Microsoft .NET и удобством языков поддерживаемых Visual Studio®
Применять разнообразные компоненты, создавая и расширяя свои собственные
Экспериментировать с возможностями медиа и Deep Zoom
Создавать подключаемые приложения
Применять динамические языки, такие как Ruby и Python
Управлять приложениями Silverlight при помощи ASP.NET
Для веб-разработчиков
Веб-технологии Microsoft' ^v^
www.microsoft.com/rus/web
Загрузите примеры к книге на C# и XAMLwww.microsoft.com/rus/expression/resourcesЗагрузите примеры к книге на C# и XAMLwww.microsoft.com/rus/expression/resources/"*
Загрузите примеры к книге на C# и XAML
www.microsoft.com/rus/expression/resources
Загрузите примеры к книге на C# и XAML
www.microsoft.com/rus/expression/resources
Центр разработки ASP.NET* ji
msdn microsoft.com/ru-ru/asp.net
Для разработчиков
Инструменты на русском языке www.visualstudio2008.ru
Веб-сайт для разработчиков
msdn.microsoft.com/ru-ru
Подробнее см. на msdn.microsoft.com/ru-ru
о
z
гоISBN-13: 978-0-7356-2528-0
CLISBN-10: 0-7356-2528-X
[msdn.microsoft.com/ru-ru] Программирование/Веб
Microsoft