Silverlight 3: глубокий взгляд изнутри

четверг, 16 апреля 2009, Александр Краковецкий

По материалам блога  Байдачного Сергея (Microsoft Украина). Публикуется с разрешения автора.

Аннотация

В данной статье поговорим о новых возможностях технологии Silverlight 3.

Содержание

Что нового
        3D проекции
        Offline работа
        Обновление приложения в разъединенном окружении
        Реакция на изменение сетевого интерфейса
        SaveFileDialog
        Поддержка ToolTip
        CaretBrush
        Множественный выбор в ListBox
        Проверка данных при связывании

Новые элементы управления
        Элемент ChildWindow
        Элемент Expander, HeaderedContentControl, HeaderedItemsControl
        Элемент TreeView
        Элемент AutoCompleteBox
        Элемент Label

GPU Acceleration

RenderForAnimation

Smooth Streaming

Работа с эффектами

Простая анимация

Улучшенная работа с изображениями, системные цвета
        Поддержка системных цветов
        Улучшенная работа с кешем
        ImageOpened, MediaOpened

Pixel API

Улучшения при связывании элементов с данными

Local Connection

Что нового в Silverlight 3

3D проекции

Естественно, что реализовать механизм полноценного 3D движка в плагине размером 4-6 Мб достаточно тяжело. Между тем псевдо 3D позволяет реализовать множество различных сценариев, но требует от разработчика значительное количество усилий. Благодаря элементу PlaneProjection в SilverLight 3 разработчик может стоить простые проекции, указав всего несколько параметров. Рассмотрим простой код, отображающий MediaElement:

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   
       
           
               
           

       

   

В результате мы получим MediaElement "повернутый" на 60 градусов по оси Y.

image

Тут мы использовали элемент PlaneProjection с атрибутом RotationY. Логично, что если Вы хотите развернуть изображение по другим осям, то нужно воспользоваться атрибутами (свойствами) RotationX, RotationZ. Элемент PlaneProjection можно использовать по отношению к любому из элементов-наследников от UIElement.

Добавим к нашему коду 4 слайдера, чтобы изменять угол вращения по запросу пользователя:

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   
       
           
               
           

       

       
       
       
       
   

В этом примере мы воспользовались еще одним свойством LocalOffsetZ. Свойства LocalOffsetX, LocalOffsetY, LocalOffsetZ позволяют разместить объект в трехмерном пространстве. Как пример использования этих свойств можно рассмотреть "карусель", где все объекты кроме одного расположны на некотором удалении. Кроме этих свойств существуют еще свойства GlobalOffsetX, GlobalOffsetY, GlobalOffsetZ. Разница между ними только в том, что первые устанавливают смещение относительно текущего контейнера, а вторые - относительно всего окна.

Последние свойства, которые могут быть интересны разработчику, это CenterOfRotationX, CenterOfRotationY, CenterOfRotationZ. Позволяют задать точку, вокруг которой проводить вращение.

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

Offline работа

Следующая интересная возможность - установка SilverLight приложения в локальный кэш пользователя с возможностью запуска в режиме, отключенном от сети.

Для того, чтобы установить приложение в кэш на машине пользователя, необходимо выполнить два шага:

1). Вызвать метод Detach у объекта Application. При этом данный метод должен быть вызван только из обработчика события, инициируемого пользователем. Например, событие может быть связано с нажатием на кнопку.

Добавим кнопку в предыдущий XAML файл.

Разместите кнопку сразу после последнего элемента Slider.

Обработчик нажатия на кнопку будет выглядеть так:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Application.Current.Detach();
}

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

http://schemas.microsoft.com/client/2007/deployment"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   
   

   
                    ShortName="Offline App"
            Title="My Title">
           
              This is my offline App
           

       

   

Если Вы хотите также описать и иконки, то добавьте следующий элемент:


   icons/16x16.png
   icons/32x32.png
   icons/48x48.png
   icons/128x128.png

Если иконки явно не указаны, то подставляется иконка по умолчанию.

Теперь можно запустить приложение и нажать на кнопку. На экране появится следующее сообщение:

image 

Итак, пользователь выбирает, где он хочет видеть иконку своего приложения и должен нажать ОК для установки приложения в кэш. Нужн отметить, что для установки приложения в кэш пользователь НЕ должен обладать административными правами.

Для удаления приложения пользователь должен инициировать вызов контекстного меню (раньше можно было вызвать только SilverLight Configuration) и выбрать Remove This Application. При этом команда доступна вне зависимости от того запустил пользователь локальную версию или воспользовался браузером.

Работая с приложение в отключенном режиме программист имеет возможность определять метод запуска приложения, а также реагировать на изменение метода запуска. Во-первых в объекте Application всегда доступно свойство ExecutionState, через которое можно получить значение перечислимого типа ExecutionStates. Последнее может содержать следующие значения: Detached, DetachedUpdatesAvailable, DetachedFailed, Detaching, RunningOnline. Во-вторых, есть возможность реагировать на событие приложения Application_ExecutionStateChanged.

Работая в отключенном режиме, разработчик может определить состояние подключения. Это может быть очень полезно при реализации механизма синхронизации данных. Проверить соединение можно с помощью вот этого статического метода: NetworkInterface.GetIsNetworkAvailable(). Обращаю Ваше внимание на то, что класс NetworkInterface находится в пространстве имен System.Net.NetworkInformation.

Обновление приложения в разъединенном окружении

Что же происходит, если приложение было обновлено в сети? Оказывается приложение автоматически проверяет, доступны ли обновления. Это происходит сразу после того, как приложение обнаружило доступ в сеть. Если обновления обнаружены, то они тут же начинают загружаться в кэш пользователя, после чего происходит событие ExecutionStateChanged. Обработав это событие, можно нотифицировать пользователя о том, что обновление уже доступно и ему нужно перезапустить приложение. Какой-либо возможности управлять загрузкой обновлений или отключить эту функциональность (ключи в реестре не считаются) - нет.

Реакция на изменение сетевого интерфейса

Оказывается, что оперативно определять разрыв связи с сетью можно с помощью реакции на статическое событие NetworkAddressChanged, которое описано в классе NetworkChange. Это событие происходит всякий раз, когда с сетевым интерфейсом что-то происходит. Далее задача программиста воспользоваться методом GetIsNetworkAvailable, чтобы понять, есть ли соединение.

SaveFileDialog

В предыдущих версиях SilverLight Вы могли общаться с файловой системой только через OpenFileDialog. Это вызывало много нареканий от разработчиков, так как при отображении текстовой информации пользователь не имел возможности сохранить ее на локальный диск. Это же касалось различных графических редакторов и т. д. Теперь разработчик имеет возможность записать на диск любую информацию и в любое место, используя возможности SaveFileDialog. Смотрим пример:

SaveFileDialog file= new SaveFileDialog();
file.Filter = "Text File | *.txt";
file.DefaultExt = ".txt";
file.ShowDialog();

if (file.File.Name != "")
{
     System.IO.StreamWriter s =
         new System.IO.StreamWriter(file.OpenFile());
     s.Write("Hello");
     s.Close();
}

Этот код можно разместить в любом методе интерфейсного потока. В результате работы кода, пользователю будет предложено выбрать папку для записи и имя файла (по умолчанию .txt). В файл будет записано Hello. Ничего сложного.

Поддержка ToolTip

Следующий интересный элемент управления, это ToolTip. Он может быть привязан к любому UIElement и содержать практически любой контент для отображения. Привязку к элементу можно выполнять, как указав свойство PlacementTarget, так и использовав этот элемент в качестве части контента. Ниже показан код, который позволяет отобразить ToolTip для кнопки. В качестве контента тут используется видео-файл:

ToolTip может быть привязан к одной из границ элемента или к координатам курсора мыши. Привязка задается с помощью свойства Placement.

CaretBrush

Еще одной небольшой особенностью SilverLight 3 является возможность установки каретки для текстового поля и поля для задания пароля (TextBox PasswordBox). Дело в том, что элементы в SilverLight реализуются таким образом, что представление отделено от логики. Поэтому разработчик может всегда заменить внешний вид уже существующего элемента. Например, можно создать треугольную кнопку или овальное поле для ввода данных. Но в элементах TextBox и PasswordBox одна часть не поддавалась изменениям - каретка. Она была исключительно черной. Даже, если разработчик просто меня цвет поля ввода, каретку не всегда было видно. Теперь ситуация изменилась. Теперь каретка может использовать любую из доступных кистей для заливки. Разработчик может просто поменять цвет, а может и установить видеоролик в качестве каретки. Вот пример использования свойства:



   
       
           
           
           
           
       

   

   
       
   

Множественный выбор в ListBox

Поскольку как-то так получилось, что мы начали вести речь об элементах управления, рассмотрим еще один, уже знакомый элемент - ListBox. Тут появилось свойство SelectionMode. Это свойство может содержать одно из трех значений: Single, Multiple, Extended. При установке свойства Multiple пользователь может выбирать несколько значений, простым кликом, а при выборе Extended также доступны функциональные клавиши и поведение больше похоже на полюбившийся ListBox из Forms или WPF.


   
       
       
       
       
   


private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    textBox1.Text = String.Format("{0} items selected",listBox1.SelectedItems.Count);
}

Проверка данных при связывании

Рассмотрим небольшой пример. Для этого опишем простой класс Employee с двумя полями:

    public class Employee
    {
        private string firstName;

        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (!value.Equals("Sergey"))
                {
                    throw new Exception("First Name must be Sergey!");
                }
                firstName = value;
            }
        }
        private string lastName;

        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }

        public Employee(string fName, string lName)
        {
            this.FirstName = fName;
            this.LastName = lName;
        }
    }

А также опишем форму, которая связана с объектом типа Employee


   
   

И код:

Employee emp;

private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    emp = new Employee("Sergey","B");
    LayoutRoot.DataContext = emp;
}

Как видно из реализации класса Employee, в качестве имени может быть установленно только Sergey. В SilverLight 3 есть два хороших механизма по обработке ошибок при связывании с данными.

Первый механизм, это специальный элемент управления, который будет нотифицировать пользователя об ошибке связывания. Для этого внесем небольшие изменения в описание TextBox.

Мы добавили простое свойство ValidatesOnException. Чтобы посмотреть на его работу, запустите приложение и введите неверные данные. Поле ввода будет выделено красной рамкой, а при наведении фокуса Вы увидете сообщение, которое заключено в исключении.

image

Второй механизм позволяет написать код в ответ на исключение при связывании. Для этого изменим TextBox следующим образом:

Тут мы описали обработчик специального события BindingValidationError, а также указали свойство NotifyOnValidationError, которое говорит о необходимости генерации этого события.

А вот и код обработчика:

private void TextBox_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
    textBox1.Focus();
}

Тут мы просто устанавливаем фокус на наше поле, чтобы дополнительно пивлечь внимание пользователя и заставить его исправить ошибку.

Новые элементы управления

Рассматривая существующие элементы управления можно выделить несколько отдельных групп:

  • элементы управления, которые входят в стандартную поставку плагина – тут практически ничего не изменилось. О небольших изменениях для ListBox, тултипах, SaveFileDialog и валидаторе я писал ранее. С одной стороны в плагине есть все необходимое, а с другой – увеличение количества элементов привело бы к росту размера плагина;
  • элементы, которые входят в SDK – тут присутствует около двух десятков элементов управления, расширяющих существующую иерархию такими элементами, как DataGrid, Calendar и др. Если Вы используете эти элементы, то вместе со своим приложением необходимо поставлять сборку, в которой они расположены. Основные сборки, содержащие элементы управления, это System.Windows.Controls.dll, System.Windows.Controls.Data.DataForm.dll, System.Windows.Controls.Navigation.dll, System.Windows.Controls.Data.dll, System.Windows.Controls.Input.dll;
  • элементы, которые входят в Toolkit, развиваемый как OpenSource проект на codeplex.com (http://www.codeplex.com/silverlight). Нужно отметить, что многие из этих элементов мигрируют в официальный SDK сразу после стабилизации, но Toolkit развивается довольно динамично, поэтому разработчики могут найти что-то интересное для себя;
  • платные элементы управления – сегодня существует множество компаний, которые предлагают свои библиотеки.
ChildWindow

Элемент ChildWindows позволяет Вам достаточно оперативно создать всплывающее окно, блокирующее весь остальной интерфейс. Если Вы используете Visual Studio, то для создания простейшего окна достаточно добавить в проект новый элемент на основе шаблона SilverLight Child Window. Данный шаблон создает XAML файл, описывающий Child окно и ассоциированный с ним код:

.XAML файл

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
      Width="400" Height="300"
      Title="ChildWindow1">
  
    
      
      
    


    

       
       
       

   

Чтобы пример был более эффектным, будем делать снимок не просто формы, а всего интерфейса, включая и панель со снимком. Чтобы реализовать такой код, нам понадобится класс WritableBitmap. Вот он то и представляет собой реализацию Pixel API в SilverLight 3. Этот класс содержится в пространстве имен System.Windows.Media.Imaging и позволяет создать Bitmap контекст заданного размера (длина, ширина изображения). Доступ к изображению может быть осуществлен попиксельно, используя простой индексатор.

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

private void Button_Click(object sender, RoutedEventArgs e)
{
    WriteableBitmap bit = new WriteableBitmap(this.Width, this.Height, PixelFormats.Pbgra32);
    bit.Render(LayoutRoot, new MatrixTransform());
    Image img = new Image();
    img.Source = bit;
    stk1.Children.Clear();
    stk1.Children.Add(img);
}

Вот так будет выглядить наше приложение после многократного нажатия кнопки Update.


Улучшения при связывании элементов с данными

SilverLight 3 позволяет с легкостью связывать свойства различных элементов управления, используя только XAML код.

Фактически мы использовали эту возможность в разделе, посвященном 3D проекциям. Вот как выглядил наш код:       

 
    
      
  
 
 

Тут мы связали свойство RotationX элемента projection с текущим значением Slider. Как видите, тут используется довольно простая конструкция.

Local Connection

Рассмотрим пространство имен System.Windows.Messaging, которое позволяет наладить взаимодействие между несколькими приложениями SilverLight.

Создадим простое приложение, которое отображает эллипс двигающийся снизу вверх:

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300" Loaded=”UserControl_Loaded”>
   
       
                                         Storyboard.TargetProperty="(Canvas.Top)"
                             From="300" To="-30" Duration="0:0:5">
           

       

   

   
       
   

Запуск анимации будет происходить при загрузке главного контейнера:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    sb1.Begin();
}

Создайте второе приложение, которое будет содержать точно такой же код, за исключением метода UserControl_Loaded. Разместите приложения на HTML странице следующим образом:

image

Давайте попробуем реализовать код прриложений таким образом, чтобы после окончания анимации в приложении 1, запускалась анимация во втором приложении. Таким образом, мы должны достигнуть эффета, когда наш шарик будет “перелетать” из одного приложения в другое.

Реализуем следующий код в первом приложении:

LocalMessageSender msgSender = new LocalMessageSender("DownSide");

public MainPage()
{
    InitializeComponent();

    LocalMessageReceiver receiver = new LocalMessageReceiver("UpSide");
    receiver.MessageReceived += new EventHandler(receiver_MessageReceived);
    receiver.Listen();
}

void receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
{
    sb1.Begin();
}

private void sb1_Completed(object sender, EventArgs e)
{
    msgSender.SendAsync("start");
}

Тут мы создали объект типа LocalMessageSender, в задачи которого входит отправка сообщения “слушателю” с указанным именем (DownSide, наверное стоило назвать по другому). Этот метод отправляет сообщение сразу после окончания анимации с помощью метода SendAsync (фактически передает управление другому приложению).

Объект LocalMessageReceiver, напротив, ожидает сообщение от других приложений. Как только сообщение приходит (второе приложение закончило анимацию), то тут же анимация запускается повторно (полетел еще один шарик).

Код во втором приложении выглядит аналогично:

LocalMessageSender msgSender = new LocalMessageSender("UpSide");

public MainPage()
{
    InitializeComponent();

    LocalMessageReceiver receiver = new LocalMessageReceiver("DownSide");
    receiver.MessageReceived += new EventHandler(receiver_MessageReceived);
    receiver.Listen();
}

void receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
{
    sb1.Begin();
}

private void sb1_Completed(object sender, EventArgs e)
{
    msgSender.SendAsync("start");
}

Откомпилировав и запустив данный пример, мы получим желаемый эффект:

image

Следует отметить, что если Ваши приложения загружаются из различных доменов, то наладить взаимодействие между ними также возможно. Для этого просто следует указать имя домена в конструкторе классов LocalMessage…

Ссылки и литература

  1. Блог Andy Beauliue
  2. Brad Adams - http://blogs.msdn.com/brada/default.aspx
  3. Chris Hay http://www.screencast.com/users/chrishayuk
  4. DotNet Curry http://www.dotnetcurry.com/
  5. Jesse Liberty http://silverlight.net/blogs/jesseliberty/
  6. Joe Stegman http://blogs.msdn.com/jstegman/default.aspx
  7. Nikola Mihaylov http://blogs.msdn.com/nikola/default.aspx
  8. Page Brooks http://pagebrooks.com/
  9. Pete Brown http://community.irritatedvowel.com/blogs/pete_browns_blog/default.aspx
  10. Silverlight Learning Resources http://silverlight.net/learn/
  11. SilverlightShow http://www.silverlightshow.net/
  12. Terence Tsang http://www.shinedraw.com/
  13. Tim Heuer http://timheuer.com/blog/
  14. Timmy Kokke http://geekswithblogs.net/tkokke/Default.aspx
  15. Rick Boarman http://www.netvibes.com/rboarman#Silverlight
  16. Официальный сайт - http://silverlight.net/
  17. Все о Microsoft Silverlight - http://silverlightru.net/
  18. Блог для дизайнеров (Siverlight / WPF / Blend) - http://dev.net.ua/blogs/helen/

Компании из статьи


Microsoft Украина


Сайт:
http://www.microsoft.com/ukr/ua/

Microsoft Украина Украинское подразделение компании Microsoft.

Ищите нас в интернетах!

Комментарии

Свежие вакансии