Введение в Microsoft Silverlight 2

Использование динамических языков в Silverlight 2

Разбить на страницы
Показывать лекцию целиком

В Silverlight 2 вводится поддержка динамических языков программирования. Динамическими называют языки программирования, которые реализуют многие функции во время выполнения,в то время как в других языках, например C#, это происходит во время компиляции.Динамическое поведение включает расширение объектов и описаний, изменение системы типов и многое другое. Это обеспечивает динамическим языкам простой подход к разработке через цикл "выполнение-вычисление-вывод" с применением метода проб и ошибок.

Silverlight 2 поддерживает три самых распространенных динамических языка: Ruby, Python и Dynamic JavaScript. Данный курс написан для спецификации Silverlight 2, в которую не включен шаблон проекта Microsoft Visual Studio 2008, но SDK предоставляет инструмент, Chiron.exe, для работы с динамическими языками программирования.

Поддержка динамических языков является инициативой Microsoft с открытым исходным кодом и доступна на Веб-сайте CodePlex по адресу . В данной лекции будет рассмотрено построение базовых приложений для 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, если его нет в системе. Более подробно об этом рассказывается в лекц. 6, "Элемент управления браузера 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.Load RootVisua l (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):

и код, который будет выполняться в этом обработчике. Этот код определяет обработчик события MouseLeftButtonUp элемента управления 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.

Введите /b в поле 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 He забудьте также настроить проект на использование Chiron. Как это сделать, показано на рис. 14.4.

На этот раз, вместо файлов app.py или app.rb в каталог app добавляется файл app.jsx. Редактируйте содержимое файла 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.Load 
 RootVisual(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" 
                             Story="" board.TargetProperty="Angle" From="180" To="540" 
                             Duration="12:0:0" RepeatBehavior="Forever"/>
            <DoubleAnimation x:Name="minute animation" Storyboard.TargetName="minuteHandTransform" 
                             Story="" board.TargetProperty="Angle" From="180" To="540" 
                             Duration="1:0:0" RepeatBehavior="Forever"/>
            <DoubleAnimation x:Name="second  animation" Storyboard.TargetName="secondHandTransform" 
                             Story="" board.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" Fi="" ll= "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 ( приложение ) Указывает на текущее приложение (просто обозначается Application.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 (определенный в Silverlight.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 в как можно более доступной форме, чтобы вы могли взять курс, открыть любую лекцию, проработать ее и понять, что представляет собой эта технология, и захотели пойти дальше.

    Надеюсь, вы получили такое же удовольствие от работы с этим курсом, какое испытывал я при ее написании!

    Страницы:

    В Silverlight 2 вводится поддержка динамических языков программирования. Динамическими называют языки программирования, которые реализуют многие функции во время выполнения,в то время как в других языках, например C#, это происходит во время компиляции.Динамическое поведение включает расширение объектов и описаний, изменение системы типов и многое другое. Это обеспечивает динамическим языкам простой подход к разработке через цикл "выполнение-вычисление-вывод" с применением метода проб и ошибок.

    Silverlight 2 поддерживает три самых распространенных динамических языка: Ruby, Python и Dynamic JavaScript. Данный курс написан для спецификации Silverlight 2, в которую не включен шаблон проекта Microsoft Visual Studio 2008, но SDK предоставляет инструмент, Chiron.exe, для работы с динамическими языками программирования.

    Поддержка динамических языков является инициативой Microsoft с открытым исходным кодом и доступна на Веб-сайте CodePlex по адресу . В данной лекции будет рассмотрено построение базовых приложений для 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, если его нет в системе. Более подробно об этом рассказывается в лекц. 6, "Элемент управления браузера 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.Load RootVisua l (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):

    и код, который будет выполняться в этом обработчике. Этот код определяет обработчик события MouseLeftButtonUp элемента управления 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.

    Введите /b в поле 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 He забудьте также настроить проект на использование Chiron. Как это сделать, показано на рис. 14.4.

    На этот раз, вместо файлов app.py или app.rb в каталог app добавляется файл app.jsx. Редактируйте содержимое файла 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.Load 
     RootVisual(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" 
                                 Story="" board.TargetProperty="Angle" From="180" To="540" 
                                 Duration="12:0:0" RepeatBehavior="Forever"/>
                <DoubleAnimation x:Name="minute animation" Storyboard.TargetName="minuteHandTransform" 
                                 Story="" board.TargetProperty="Angle" From="180" To="540" 
                                 Duration="1:0:0" RepeatBehavior="Forever"/>
                <DoubleAnimation x:Name="second  animation" Storyboard.TargetName="secondHandTransform" 
                                 Story="" board.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" Fi="" ll= "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 ( приложение ) Указывает на текущее приложение (просто обозначается Application.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 (определенный в Silverlight.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 в как можно более доступной форме, чтобы вы могли взять курс, открыть любую лекцию, проработать ее и понять, что представляет собой эта технология, и захотели пойти дальше.

    Надеюсь, вы получили такое же удовольствие от работы с этим курсом, какое испытывал я при ее написании!

    Вернуться к учебному плану