Методика создания интерактивных приложений Silverlight

Вставка приложений Silverlight в web приложения

Показывать лекцию целиком

Для использования и создания приложений Silverlight не требуется никакого специального программного обеспечения. Создавать сайты на Silverlight можно, используя любое ПО для разработки Веб-сайтов, начиная от Notepad, заканчивая Microsoft Expression Blend.

Чтобы создать и запустить простое приложение Silverlight, не используя никаких других инструментов, кроме Windows Explorer и Notepad, надо сначала создать HTML-файл. Элемент управления Silverlight будет размещаться на этой странице. Для этого используется тег <object>. Вот пример:

<!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>BusinessApplication1</title>
  <style type="text/css">
  html, body {
    height: 100%;
    overflow: auto;
  }
  body {
    padding: 0;
    margin: 0;
  }
  #silverlightControlHost {
    height: 100%;
    text-align:center;
  }
  </style>
  <script type="text/javascript" 
          src="Silverlight.js">
  </script>
  <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;

      if (errorType == "ImageError" || errorType == "MediaError") {
        return;
      }

      var errMsg = "Unhandled Error in Silverlight 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>
  <form id="form1" runat="server" style="height:100%">
    <div id="silverlightControlHost">
      <object data="data:application/x-silverlight-2,"
              type="application/x-  silverlight-2" 
              width="100%" height="100%">
      <param name="source" value="ClientBin/BusinessApplication1.xap"/>
      <param name="onError" value="onSilverlightError" />
      <param name="background" value="white" />
      <param name="minRuntimeVersion" value="3.0.40624.0" />
      <param name="autoUpgrade" value="true" />
      <a href= "http://go.microsoft.com/fwlink/?LinkID=149156v=3.0.40624.0" 
         style="text-decoration:none">
        <img src="http://go.microsoft.com/fwlink/?LinkId=108181" 
             alt="Get Microsoft Silverlight" 
             style="border-style:none"/>
      </a>
      </object>
      <iframe id="_sl_historyFrame" 
              style="visibility:hidden;height:0px;width:0px;border:0px">
      </iframe>
    </div>
  </form>
</body>
</html>

С помощью тега <object> создается экземпляр Silverlight. Это стандартный HTML-тег, следовательно, он поддерживает стандартные параметры. Мы не будем рассматривать здесь полный список параметров, остановимся лишь на используемых в предыдущем примере:

  • Атрибут Type (Тип) определяет тип загружаемого объекта. В данном случае задано значение application/x-silverlight-2, которое указывает браузеру загружать подключаемый модуль Silverlight для доступа к этому содержимому.
  • Атрибут Width (Ширина) определяет ширину элемента управления в процентном соотношении или в пикселах.
  • Атрибут Height (Высота) определяет высоту элемента управления в процентном соотношении или в пикселах.
  • Атрибут ID определяет имя элемента управления, используемое в коде JavaScript.
  • Объекты поддерживают разные наборы настраиваемых параметров, поэтому HTML-тег <object> поддерживает список элементов <Param>, позволяющие задавать нестандартные параметры. Эти элементы используются для определения пар имя/значение.

    Могут быть использованы следующие параметры:

    Параметры HTML, поддерживаемые объектом Silverlight
    Параметр Описание
    Source Определяет либо XAP, содержащий приложение для загрузки и выполнения, либо XAML-документ для формирования визуального представления.
    Width Устанавливает ширину элемента управления в пикселах или в процентном соотношении
    Height Устанавливает высоту элемента управления в пикселах или в процентном соотношении
    Background Определяет цвет фона элемента управления. Можно использовать ARGB-значение, например #FFAA7700, или именованный цвет, например, Black
    Framerate Устанавливает максимально допустимую частоту кадров анимации. Значение по умолчанию равно 24
    isWindowless Этот параметр может принимать значения true или false, значение по умолчанию - false. Если задано true, визуальное представление содержимого Silverlight формируется позади HTML-содержимого, так что HTML-содержимое может отображаться поверх его
    enableHtmlAccess Определяет возможность доступа к содержимому DOM1 браузера из кода, располагающегося в элементе управления Silverlight. Значение по умолчанию - true
    minRuntimeVersion Определяет минимально необходимую поддерживаемую версию Silverlight
    onLoad Определяет функцию, вызов которой будет происходить при загрузке элемента управления
    onError Определяет функцию, вызов которой будет происходить в случае возникновения ошибки
    onFullScreenChange Это событие формируется при изменении свойства FullScreen (Во весь экран) элемента управления Silverlight
    onResize Это событие формируется при изменении свойства ActualWidth или ActualHeight элемента управления Silverlight

    Особенность тега <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" /> 
      <a href="http://go.microsoft.com/fwlink/?LinkID=149156v=3.0.40624.0"     
          style="text-decoration:none">
        <img src="http://go.microsoft.com/fwlink/?LinkId=108181" 
            alt="Get Microsoft Silverlight" 
            style="border-style:none"/>
      </a>
    </object>

    В данном случае в объект встроена гиперссылка, поэтому, если Silverlight не установлен в системе, этот тег обеспечивает ссылку, по которой можно перейти на сайт загрузки Microsoft.

    Рассмотрим, как Silverlight обеспечивает реакцию на события, например, загрузки страницы. Возможны различные варианты обработки событий страницы для загрузки Silverlight.

    Первый вариант - задать функцию JavaScript, которая будет вызываться в ответ на событие Onload (После загрузки) тега <Body> в HTML. Этот метод рекомендуется применять в случае выполнения проверки на возможность загрузки Silverlight, и не обязательно вашего приложения. Приложение Silverlight будет загружаться после выполнения вашей страницы, поэтому положительный ответ на загрузку страницы не означает возможности загрузки приложения Silverlight.

    Второй вариант - задать обработчик событий JavaScript для управления событиями загрузки страницы с помощью параметра onLoad, представленного в табл. 6.1. Событие onLoad формируется после полной загрузки XAML-содержимого или XAP-файла элемента управления Silverlight. Обратите внимание, что если для какого-либо XAML-элемента пользовательского интерфейса будет определено аналогичное событие, оно будет сформировано до события onLoad элемента управления Silverlight. Кроме того, у элемента управления есть доступное только для чтения свойство IsLoaded (Загружен), которое устанавливается непосредственно перед формированием события onLoad.

    При использовании обработчика события onLoad функция JavaScript должна принимать три параметра: первый - ссылка на элемент управления, второй - пользовательский контекст, и третий - ссылка на корневой элемент XAML. Например:

    function handleLoad(control, userContext, rootElement) { ... }

    Третий вариант ответа на загрузку страницы - использование выделенного кода в Silverlight (code-behind), в котором определяются действия, выполняемые в ответ на загрузку либо приложения, либо любого XAML-элемента вашего приложения (например, страницы по умолчанию). Для страницы можно задать обработчик событий в параметре Loaded в XAML и выполняемый после загрузки метод в code-behind, как в данном примере:

    <UserControl 
      …
      Loaded="UserControl_Loaded">
      <Grid>
      …
      </Grid>
    </UserControl>
    void UserControl_Loaded(object sender, RoutedEventArgs e){  }

    В любом случае, совершенно не требуется ASP.NET веб-приложение для того, чтобы разместить (захостить) приложение Silverlight на странице. Для того чтобы в случае отсутствия установленного фреймворка Silverlight браузер предлагал бы зайти на сайт Microsoft и установить пакет Silverlight, необходим файл Silverlight.js следующего содержания:

    //v2.0.30511.0
    if (!window.Silverlight) window.Silverlight = {}; 
    Silverlight._silverlightCount = 0;  
    Silverlight.__onSilverlightInstalledCalled = false; 
    Silverlight.fwlinkRoot = "http://go2.microsoft.com/fwlink/?LinkID="; 
    Silverlight.__installationEventFired = false;  Silverlight.onGetSilverlight = null; 
    Silverlight.onSilverlightInstalled = function() { window.location.reload(false) }; 
    Silverlight.isInstalled = function(b) {
      if (b == undefined) b = null;  var a = false, m = null;  try {
        var i = null, j = false; 
        if (window.ActiveXObject) try {
          i = new ActiveXObject("AgControl.AgControl"); 
          if (b === null) a = true; 
          else if (i.IsVersionSupported(b)) a = true; 
          i = null
        } catch (l) { j = true } 
        else j = true; 
        if (j) {
          var k = navigator.plugins["Silverlight Plug-In"]; 
          if (k) if (b === null) a = true;  else {
            var h = k.description; 
            if (h === "1.0.30226.2") h = "2.0.30226.2"; 
            var c = h.split("."); 
            while (c.length > 3) c.pop(); 
            while (c.length < 4) c.push(0); 
            var e = b.split("."); 
            while (e.length > 4) e.pop(); 
            var d, g, f = 0; 
            do {
                d = parseInt(e[f]); 
                g = parseInt(c[f]);  f++
            } while (f < e.length  d === g);
            if (d <= g  !isNaN(d)) a = true
          } 
        } 
      } catch (l) { a = false } return a
    };
    Silverlight.WaitForInstallCompletion = function() {
      if (!Silverlight.isBrowserRestartRequired  
           Silverlight.onSilverlightInstalled) 
      {
        try { navigator.plugins.refresh() }
        catch (a) { }
        if (Silverlight.isInstalled(null)  !Silverlight.__onSilverlightInstalledCalled) {
            Silverlight.onSilverlightInstalled();
            Silverlight.__onSilverlightInstalledCalled = true
        }
        else setTimeout(Silverlight.WaitForInstallCompletion, 3e3)
      } 
    };
    Silverlight.__startup = function() {
      navigator.plugins.refresh();
      Silverlight.isBrowserRestartRequired = Silverlight.isInstalled(null);
      if (!Silverlight.isBrowserRestartRequired) 
      {
        Silverlight.WaitForInstallCompletion();
        if (!Silverlight.__installationEventFired) 
        {
          Silverlight.onInstallRequired();
          Silverlight.__installationEventFired = true
        } 
      } else if (window.navigator.mimeTypes) {
      var b = navigator.mimeTypes["application/x-silverlight-2"],
     c = navigator.mimeTypes["application/x-silverlight-2-b2"], 
    d = navigator.mimeTypes["application/x-silverlight-2-b1"], a = d;
      if (c) a = c; if (!b  (d || c)) 
      {
        if (!Silverlight.__installationEventFired) 
        {
          Silverlight.onUpgradeRequired();
          Silverlight.__installationEventFired = true
        } 
      } else if (b  a) 
        if (b.enabledPlugin  a.enabledPlugin)
          if (b.enabledPlugin.description != a.enabledPlugin.description) 
            if (!Silverlight.__installationEventFired) 
            { Silverlight.onRestartRequired(); 
              Silverlight.__installationEventFired = true 
            }
      }
      if (!Silverlight.disableAutoStartup)
        if (window.removeEventListener) 
          window.removeEventListener("load", Silverlight.__startup, false); 
        else window.detachEvent("onload", Silverlight.__startup)
      };
      if (!Silverlight.disableAutoStartup) 
      if (window.addEventListener) 
        window.addEventListener("load", Silverlight.__startup, false);
      else window.attachEvent("onload", Silverlight.__startup); 
      Silverlight.createObject = function(m, f, e, k, l, h, j) 
      {
        var d = {}, a = k, c = l; d.version = a.version; a.source = m; d.alt = a.alt;
    if (h) a.initParams = h; if (a.isWindowless  !a.windowless) a.windowless = a.isWindowless;
    if (a.framerate  !a.maxFramerate) a.maxFramerate = a.framerate; if (e  !a.id) a.id = e; 
    delete a.ignoreBrowserVer; delete a.inplaceInstallPrompt; 
    delete a.version; delete a.isWindowless; delete a.framerate; 
    delete a.data; delete a.src; delete a.alt; if (Silverlight.isInstalled(d.version)) {
        for (var b in c) if (c[b]) {
          if (b == "onLoad"  
            typeof c[b] == "function"  
            c[b].length != 1) 
          {
            var i = c[b]; c[b] = function(a) {
              return i(document.getElementById(e), j, a)
            } 
          }
          var g = Silverlight.__getHandlerName(c[b]);
          if (g != null) { a[b] = g; c[b] = null }
          else throw "typeof events." + b + 
                     " must be 'function' or 'string'";
        }
        slPluginHTML = Silverlight.buildHTML(a)
      }
      else slPluginHTML = Silverlight.buildPromptHTML(d); 
      if (f) f.innerHTML = slPluginHTML; else return slPluginHTML 
    };
    Silverlight.buildHTML = function(a) {
      var b = [];
      b.push('<object type="application/x-silverlight" data="data:application/x-silverlight,"');
      if (a.id != null) b.push(' id="' + Silverlight.HtmlAttributeEncode(a.id) + '"');
      if (a.width != null) b.push(' width="' + a.width + '"');
      if (a.height != null) b.push(' height="' + a.height + '"'); b.push(" >");
      delete a.id; delete a.width;
      delete a.height;
      for (var c in a)
        if (a[c]) 
          b.push('<param name="' + 
                Silverlight.HtmlAttributeEncode(c) + 
                '" value="' + 
                Silverlight.HtmlAttributeEncode(a[c]) + 
                '" />'); 
        b.push("</object>");
        return b.join("")
      };
      Silverlight.createObjectEx = function(b) {
        var a = b, 
            c = Silverlight.createObject(a.source, a.parentElement, 
                                         a.id, a.properties, a.events, 
                                         a.initParams, a.context);
        if (a.parentElement == null) return c
    };
    Silverlight.buildPromptHTML = function(b) 
    {
      var a = "", d = Silverlight.fwlinkRoot, c = b.version; 
      if (b.alt) a = b.alt;
      else 
      {
        if (!c) c = ""; 
        a = "<a href='javascript:Silverlight.getSilverlight(\"{1}\");' 
              style='text-decoration: none; '>
            <img src='{2}' alt='Get Microsoft Silverlight' 
              style='border-style: none'/></a>"; 
        a = a.replace("{1}", c); a = a.replace("{2}", d + "108181") 
      } 
      return a 
    }; 
    Silverlight.getSilverlight = function(e) 
    { 
      if (Silverlight.onGetSilverlight) Silverlight.onGetSilverlight(); 
      var b = "", a = String(e).split("."); 
      if (a.length > 1) 
      { var c = parseInt(a[0]); 
        if (isNaN(c) || c < 2) b = "1.0"; 
        else b = a[0] + "." + a[1] 
      } 
      var d = ""; 
      if (b.match(/^\d+\056\d+$/)) 
        d = "v=" + b; Silverlight.followFWLink("149156" + d) 
    }; 
    Silverlight.followFWLink = function(a) 
    { 
      top.location = Silverlight.fwlinkRoot + String(a) 
    }; 
    Silverlight.HtmlAttributeEncode = function(c) 
    { 
      var a, b = ""; 
      if (c == null) return null; 
      for (var d = 0; d < c.length; d++) 
      { a = c.charCodeAt(d); 
        if (a > 96  a < 123 || 
            a > 64  a < 91 || 
            a > 43  a < 58  
            a != 47 || a == 95) 
          b = b + String.fromCharCode(a); 
        else b = b + "#" + a + "; " 
      } 
      return b 
    }; 
    Silverlight.default_error_handler = function(e, b) 
    { 
      var d, c = b.ErrorType; d = b.ErrorCode; 
      var a = "\nSilverlight error message     \n"; 
      a += "ErrorCode: " + d + "\n"; 
      a += "ErrorType: " + c + "       \n"; 
      a += "Message: " + b.ErrorMessage + "     \n"; 
      if (c == "ParserError") { a += "XamlFile: " + b.xamlFile + "     \
      \n"; a += "Line: " + b.lineNumber + "    
       \n"; a += "Position: " + b.charPosition + "     \n" } 
      else if (c == "RuntimeError") { if (b.lineNumber != 0)
      { a += "Line: " + b.lineNumber + "     \n"; a += "Position: " + b.charPosition + "     \n" } 
      a += "MethodName: " + b.methodName + "     \n" } alert(a) 
    }; 
    Silverlight.__cleanup = function() 
    { 
      for (var a = Silverlight._silverlightCount - 1; a >= 0; a--) 
        window["__slEvent" + a] = null; 
      Silverlight._silverlightCount = 0; 
      if (window.removeEventListener) 
        window.removeEventListener("unload", Silverlight.__cleanup, false); 
      else window.detachEvent("onunload", Silverlight.__cleanup) 
    }; 
    Silverlight.__getHandlerName = function(b) 
    { var a = ""; 
      if (typeof b == "string") a = b; 
      else if (typeof b == "function") 
      { if (Silverlight._silverlightCount == 0) 
        if (window.addEventListener) 
          window.addEventListener("onunload", Silverlight.__cleanup, false); 
        else window.attachEvent("onunload", Silverlight.__cleanup); 
        var c = Silverlight._silverlightCount++; 
        a = "__slEvent" + c; 
        window[a] = b 
      } else a = null; 
      return a 
    }; 
    Silverlight.onRequiredVersionAvailable = function() { }; 
    Silverlight.onRestartRequired = function() { }; 
    Silverlight.onUpgradeRequired = function() { }; 
    Silverlight.onInstallRequired = function() { }; 
    Silverlight.IsVersionAvailableOnError = function(d, a) 
    { 
      var b = false; 
      try 
      { 
        if (a.ErrorCode == 8001  !Silverlight.__installationEventFired) 
        { Silverlight.onUpgradeRequired(); 
          Silverlight.__installationEventFired = true 
        } 
        else if (a.ErrorCode == 8002  !Silverlight.__installationEventFired) 
        { Silverlight.onRestartRequired(); 
          Silverlight.__installationEventFired = true 
        } 
        else if (a.ErrorCode == 5014 || a.ErrorCode == 2106) 
        { 
          if (Silverlight.__verifySilverlight2UpgradeSuccess(a.getHost())) 
            b = true 
        } else b = true 
      } 
      catch (c) { } 
      return b 
    }; 
    Silverlight.IsVersionAvailableOnLoad = function(b) 
    { 
      var a = false; 
      try 
      { 
        if (Silverlight.__verifySilverlight2UpgradeSuccess(b.getHost())) 
          a = true 
      } catch (c) { } 
      return a 
    }; 
    Silverlight.__verifySilverlight2UpgradeSuccess = function(d) 
    {
      var c = false, b = "2.0.31005", a = null;
      try {
        if (d.IsVersionSupported(b + ".99")) 
        { a = Silverlight.onRequiredVersionAvailable; c = true }
        else if (d.IsVersionSupported(b + ".0")) 
          a = Silverlight.onRestartRequired; 
        else a = Silverlight.onUpgradeRequired; 
        if (a  !Silverlight.__installationEventFired) 
        { a(); Silverlight.__installationEventFired = true } 
      } catch (e) { }
      return c
    }

    Если разработчик проектирует приложение Silverlight в Visual Studio, то этот файл будет автоматически добавлен в проект из шаблона.

    Silverlight и HTML, AJAX и JavaScript

    В разделе Вставка приложений Silverlight в web-приложения описан процесс вставки приложения Silverlight на веб-страницу. Но приложение Silverlight может взаимодействовать с кодом JavaScript или AJAX, а так же другими элементами HTML на странице где оно размещено.

    Существует несколько направлений или философий для разработки для Веб. Одна нацелена на возможности браузера, где логику обеспечивает JavaScript, динамический HTML, каскадные таблицы стилей и AJAX. Другое направление - логика полностью на сервере, а браузер разработан для отображения документов, а не приложений. В таком подходе философия такова, что создавать приложения, удовлетворяющие все возрастающим требованиям пользователей, полагаясь только на браузер, нецелесообразно.

    Silverlight является золотой серединой между этих двух подходов, является мостом. Silverlight включает "доступ к браузеру", которая предоставляет разработчикам и дизайнерам неограниченные возможности для реализации приложений любой сложности. Использование механизма доступа к объектной модели браузера обеспечивает следующие возможности:

  • Любой код, откомпилированный в сборку Microsoft .NET Framework, доступен браузеру и может быть вызван из JavaScript.
  • Любой JavaScript-код в браузере доступен из .NET-сборки и может вызываться из Silverlight-приложения.
  • Дерево визуального представления XAML доступно браузеру. С помощью JavaScript вы можете создавать XAML-элементы и добавлять их в дерево визуального представления, удалять или редактировать существующие элементы дерева визуального представления.
  • Пример приложения Silverlight, взаимодействующего с JavaScript

    Рассмотрим пример кода, в котором из приложения Silverlight есть доступ к функциям JavaScript. В примере приложение Silverlight отображает бегающую по спидометру стрелку.

    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title>Silverlight</title>
        <script src="scripts/Microsoft.Graphics.Silverlight.js" type="text/ecmascript"></script>
        <script src="scripts/example.Graphics.Silverlight.js" type="text/ecmascript"></script>
        <script type="text/ecmascript">
            example.Instrument = {};
            example.Instrument.Pointer = {};
            example.Instrument.Pointer.Rotation = {};
            example.Instrument.Pointer.Storyboard = {};
            example.Instrument.Pointer.Animation = {};
    
            function onLoadPage() {
              var canvas = new example.Graphics.Silverlight.Canvas();
              canvas.onLoad = onCanvasReady;
              canvas.onError = onCanavsError;
    
              canvas.createCanvas("silverlightPlugin", 384, 384, 
                                  "silverlightContainer");
            }
    
            function onCanavsError(sender, args) {
                alert(args.errorMessage + "\nLine " + args.lineNumber + 
                      " position " + args.charPosition);
            }
    
            function onCanvasReady(control, context, rootElement) { }
    
            function onCanvasLoaded(sender, args) {
                example.Instrument.Pointer.Rotation = 
                    sender.FindName("PointerRotation");
                example.Instrument.Pointer.Storyboard = 
                    sender.FindName("PointerAnimationStoryboard");
                example.Instrument.Pointer.Animation = 
                    sender.FindName("PointerAnimation");
                setTimeout(demo, 2000);
            }
    
            function demo() {
                var a = Math.floor(Math.random() * 240) - 120;
    
                example.Instrument.Pointer.Animation.From = 
                    example.Instrument.Pointer.Rotation.Angle;
                example.Instrument.Pointer.Animation.To = a;
                example.Instrument.Pointer.Storyboard.begin();
    
                setTimeout(demo, 5000);
            }
        </script>
      </head>
      <body onload="onLoadPage()">
        <div id="silverlightContainer"></div>
        <script id="xaml" type="text/xaml">
          // Код Silverlight, встроенный в контейнер object
          <Canvas 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            x:Name="InstrumentCanvas" 
            Loaded="onCanvasLoaded"
          >
            <Ellipse x:Name="BackFace" Width="336" Height="336" 
                Canvas.Left="24" Canvas.Top="24" 
                StrokeThickness="8" StrokeLineJoin="Round" 
                Stroke="#FF880000" Fill="transparent">
            </Ellipse>
    
            <Image x:Name="FaceBackgroundImage" 
                Source="images/gauge.ticks.png" />
    
            <Path x:Name="Path" Width="24" Height="180" 
                Canvas.Left="180" Canvas.Top="48" 
                Stretch="Fill" 
                StrokeThickness="2" StrokeStartLineCap="Round" 
                StrokeEndLineCap="Round" StrokeLineJoin="Round" 
                Stroke="#FFD10000" Data="F1 M 40,0 L 60,0 L 100,100 L 50,102 L 0,100 Z"
            >
              <Path.Fill>
                <LinearGradientBrush StartPoint="0.0,0.5" EndPoint="1.0,0.5">
                  <LinearGradientBrush.GradientStops>
                    <GradientStop Color="#FFD30606" Offset="0.0"/>
                    <GradientStop Color="#FF690303" Offset="0.7"/>
                    <GradientStop Color="#FF000000" Offset="1.0"/>
                  </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
              </Path.Fill>
              <Path.RenderTransform>
                <RotateTransform x:Name="PointerRotation" Angle="0" CenterX="12" CenterY="144" />
              </Path.RenderTransform>
              <Path.Triggers>
                <EventTrigger RoutedEvent="Rectangle.Loaded">
                  <BeginStoryboard>
                    <Storyboard x:Name="PointerAnimationStoryboard">
                      <DoubleAnimation x:Name="PointerAnimation" 
                          Storyboard.TargetName="PointerRotation" 
                          Storyboard.TargetProperty="Angle" 
                          From="-120" To="120" Duration="0:0:1" 
                          RepeatBehavior="1x" AutoReverse="false"/>
                    </Storyboard>
                  </BeginStoryboard>
                </EventTrigger>
              </Path.Triggers>
            </Path>
            <Ellipse x:Name="PointerInnerHub" 
                Width="48" Height="48" 
                Canvas.Left="168" Canvas.Top="168" 
                StrokeThickness="2" StrokeLineJoin="Round" 
                Stroke="#FF000000">
              <Ellipse.Fill>
                <RadialGradientBrush RadiusX="0.5" RadiusY="0.5" Center="0.5,0.2" GradientOrigin="0.5,0.5">
                  <RadialGradientBrush.GradientStops>
                    <GradientStop Color="#FF202020" Offset="0.0"/>
                    <GradientStop Color="#FF000000" Offset="1.0"/>
                  </RadialGradientBrush.GradientStops>
                </RadialGradientBrush>
              </Ellipse.Fill>
            </Ellipse>
          </Canvas>
        </script>
      </body>
    </html>

    Результат работы показан на рис. 6.1

    (рис 6.1) Пример взаимодействия кода JavaScript и Silverlight

    Необходимо разместить в каталоге /scripts файл example.Graphics.Silverlight.js следующего содержания:

    if (typeof example != "object") 
      var example = { _example: this };
    
    example.Graphics = {};
    example.Graphics.Silverlight = {};
    
    example.Graphics.Silverlight.Canvas = function() {
     _canvas = this;
    
     this.createCanvas = function(pluginId, pixelWidth, pixelHeight, containerId) 
     {
       Silverlight.createObjectEx(
       {
         source: "#xaml",
         parentElement: document.getElementById(containerId),
         id: pluginId,
         properties:
         {
           width: pixelWidth,
           height: pixelHeight,
           background: "transparent",
           framerate: "24",
           isWindowless: "true",
           inplaceInstallPrompt: false,
           version: "1.0"
         },
         events:
         {
           onLoad: _canvas.onLoad,
           onError: _canvas.onError
         }
       });
     }
     this.onLoad = null;
     this.onError = null;
    }

    И в том же каталоге /scripts файл Silverlight.js. Это стандартный скрипт Microsoft для размещения объектов Silverlight на веб-страницах. Кроме этого в каталоге /images размещается рисунок с делениями спидометра.

    (рис 6.2) Рисунок примера "спидометр"

    Можно видеть, как код JavaScript вызывает методы PointerRotation, PointerAnimationStoryboard, PointerAnimation, а также, код XAML приложения Silverlight вызывает функцию JavaScript onLoadPage(). Эта функция дает доступ JavaScript к методам Silverlight, регистрируя объект Silverlight на странице как объект, поддерживающий сценарии.

    function onLoadPage() 
    {
       var canvas = new example.Graphics.Silverlight.Canvas();
       canvas.onLoad = onCanvasReady;
       canvas.onError = onCanavsError;
       canvas.createCanvas("silverlightPlugin", 384, 384, 
                           "silverlightContainer");
    }

    К недостаткам во время разработки можно отнести лишь то, что Visual Studio не генерирует прокси-класс для функций JavaScript и поэтому невозможно пользоваться инструментом IntelliSense.

    Пример приложения Silverlight, взаимодействующего с AJAX

    AJAX является расширением языка JavaScript. Поэтому Silverlight и AJAX так же могут взаимодействовать. Далее приведен пример приложения "медиаплеер", который может менять свою оболочку (skin) при выборе из ниспадающего списка стилей. Перегрузки всей страницы не происходит, т.к. используются расширения AJAX.

    (рис 6.3) Пример "медиаплеер"

    Проект содержит:

  • Страницу Default.aspx с кодом code-behind
  • Приложение Silverlight ( SilverlightApplication.Web.dll ) в каталоге Bin
  • Библиотека Ajax ( AjaxControlToolkit.dll ) в каталоге Bin
  • Коллекцию оболочек ( Console.xaml, AudioGray.xaml, Basic.xaml, Classic.xaml, Expression.xaml, Futuristic.xaml, Professional.xaml, Simple.xaml ) в каталоге MediaPlayerSkins
  • Ниже приведено содержимое файлов Default.aspx - веб-страницы, Default.aspx.cs - code-behind. Веб-страница:

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" 
    Inherits="_Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <%@ Register Assembly="System.Web.Silverlight" 
        Namespace="System.Web.UI.SilverlightControls"
        TagPrefix="asp" %>
    
    <%@ Register assembly="AjaxControlToolkit" 
    namespace="AjaxControlToolkit" 
    tagprefix="cc1" %>    
    
    
    
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head runat="server">
          <title>SILVERLIGHT + AJAX</title>
      </head>
      <body>
        <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" 
            runat="server" />
          <asp:UpdatePanel ID="UpdatePanel1" 
              runat="server" updatemode="Conditional" >
            <ContentTemplate> 
              <div>
                <!--STYLE-->
                <div style="float:left">
                  <asp:DropDownList ID="cmbSkins" runat="server" 
                    onselectedindexchanged="cmbSkins_SelectedIndexChanged" />
                </div>               
                <div>
                  <h3> Выберите стиль плеера</h3>
                </div>
              </div>
            
              <!-- MEDIA PLAYER -->
              <asp:MediaPlayer ID="MediaPlayer1" runat="server" 
                  Width="600px" 
                  Height="440px"
                  PlaceholderSource="ImgMain.JPG" >
                <Chapters>
                  <asp:MediaChapter Position="18" 
                      ThumbnailSource="13P1010042.JPG" 
                      Title="Раздел 1" />
                  <asp:MediaChapter Position="37" 
                      ThumbnailSource="18P1010048.JPG" 
                      Title="Раздел 2" />                              
                  <asp:MediaChapter Position="70" 
                      ThumbnailSource="11P1010036.JPG" 
                      Title="Раздел 3" />    
                </Chapters>
              </asp:MediaPlayer>
            </ContentTemplate>
          </asp:UpdatePanel>
        </form>
      </body>
    </html>

    Код приложения:

    using System;
    
    public partial class _Default : System.Web.UI.Page 
    {
      protected enum MediaPlayerSkins
      {
        AudioGray,
        Basic,
        Classic,
        Console,
        Expression,
        Futuristic,
        Professional,
        Simple
      }
    
      private string _Source = "JJ2008_100.wmv";
      
      protected void Page_Load(object sender, EventArgs e)
      {
        if (!IsPostBack)
        {
          MediaPlayer1.AutoPlay = true;
          MediaPlayer1.ScaleMode = System.Web.UI.SilverlightControls.ScaleMode.Zoom;
          cmbSkins.Items.Add(MediaPlayerSkins.Classic.ToString());
          cmbSkins.Items.Add(MediaPlayerSkins.Console.ToString());
          cmbSkins.Items.Add(MediaPlayerSkins.Expression.ToString());
          cmbSkins.Items.Add(MediaPlayerSkins.Futuristic.ToString());
          cmbSkins.Items.Add(MediaPlayerSkins.Professional.ToString());
          cmbSkins.Items.Add(MediaPlayerSkins.AudioGray.ToString());
          cmbSkins.Items.Add(MediaPlayerSkins.Simple.ToString());
          cmbSkins.AutoPostBack = true;
          cmbSkins.SelectedIndex = 4;
          MediaPlayer1.MediaSource = _Source;
          MediaPlayer1.MediaSkinSource = 
              "~/MediaPlayerSkins/" + cmbSkins.SelectedValue + ".xaml";
        }
      }
    
      protected void cmbSkins_SelectedIndexChanged(object sender, EventArgs e)
      {
        MediaPlayer1.MediaSkinSource =
            "~/MediaPlayerSkins/" + cmbSkins.SelectedValue + ".xaml";
      }
    }

    asp:ScriptManager - контейнер для размещения AJAX приложения.

    Заключение

    Механизм доступа к объектной модели браузера - замечательная технология, позволяющая интегрировать приложения Silverlight в существующие веб-приложения. Возможны разнообразные варианты. С его помощью можно вызывать .NET-код и использовать .NET-код из JavaScript, изменять визуальное представление Silverlight из HTML-страницы и вызывать существующие функции JavaScript из .NET-кода. Представленные примеры демонстрируют, как взаимодействуют коды .NET, JavaScript в приложениях Silverlight.

    Вставка приложений Silverlight в Office SharePoint Server

    Для работы Silverlight на портале Office SharePoint Server необходимы следующие компоненты:

  • Windows SharePoint Services 3.0 Service Pack 1.
  • .NET Framework 3.5 для Silverlight
  • Настройки Internet Information Server
  • Visual Studio 2008 Silverlight 3.0 Tools + Silverlight 3.0 SDK
  • Expression Blend 3.0 (если нужен дизайн)
  • Плагин Silverlight 3.0 для браузера
  • Приложение Silverlight в портале SharePoint находится:

  • Внутри веб-части (Web-part), которую можно назвать SilverPart
  • ASP.NET страницы узла
  • Пользовательские типы полей списков
  • Навигационные элементы управления
  • Обмен данными между приложением Silverlight и порталом Office SharePoint Server можно осуществлять с помощью:

  • Веб-сервисов
  • WCF - Windows Communication Foundation
  • Скрытых полей HTML (hidden fields)
  • Свойства initParams
  • Параметры элементов управления Silverlight конфигурируются через свойства веб-части
  • Когда могут использоваться приложения Silverlight в портале SharePoint:

  • Сложные (может быть интерактивные) представления данных в виде графиков, многотабличных отчетов и т.д.
  • Красивое отображение медиа данных из библиотеки SharePoint (см. раздел 0 Smooth Streaming и Expression Encoder)
  • Нестандартная навигация
  • Перенос нагрузки на клиента
  • Асинхронные операции
  • Создание веб-части Silverlight

    Создается проект пор шаблону Visual C# Class Library и добавляется класс BasicSilverLightWebPart.

    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Serialization;
    using System.Text;
    using System.IO;
    using System.Globalization;
    namespace SilverLightWebParts
    {
      [DefaultProperty("Text"),
        ToolboxData("<{0}:BasicSilverLightWebPart 
        runat=server></{0}:BasicSLWebPart>"),
        XmlRoot(Namespace = "http://SilverLightWebParts")
      ]
      public class BasicSilverLightWebPart : WebPart
      {
        //Constructor
        public BasicSilverLightWebPart()
        {
        }
      }
    }

    В класс добавляются переменные:

    #region Private Variables
    
    private string _JSPath = "";
    private const string defaultText = "";
    private string text = defaultText;
    private string _SLCtlHeight = "100%";
    private string _SLCtlWidth = "100%";
    private string _MainCtlJS = "Default_html";
    private string _XAMLPageName = "Page";
    
    #endregion

    В класс добавляются свойства, которые устанавливают путь к файлам *.js и *.xaml. Можно добавить собственные свойства для улучшения функциональности

    #region Properties
    
    [Browsable(true),Personalizable(), WebBrowsable,
      Category("Custom Settings"), DefaultValue(defaultText),
      Description("Text Property")]
    public string Text
    {
      get
      {
        return text;
      }
      set
      {
        text = value;
      }
    }
    
    [Browsable(true),Personalizable(), WebBrowsable,
      Category("Custom Settings"), DefaultValue("100%"),
      Description("Silverlight Control Width")]
    public string SLControlWidth
    {
      get
      {
        return _SLCtlWidth;
      }
    
      set
      {
        _SLCtlWidth = value;
      }
    }
    
    [Browsable(true),Personalizable(), WebBrowsable,
      Category("Custom Settings"), DefaultValue("100%"),
      Description("Silverlight Control Height")]
    public string SLControlHeight
    {
      get
      {
        return _SLCtlHeight;
      }
    
      set
      {
        _SLCtlHeight = value;
      }
    }
    
    [Browsable(true),Personalizable(), WebBrowsable,
      Category("Custom Settings"), DefaultValue(""),
      Description("Javascript file path")]
    public string JSPath
    {
      get
      {
        return _JSPath;
      }
    
      set
      {
        _JSPath = value;
      }
    }
    
    [Browsable(true),Personalizable(), WebBrowsable,
      Category("Custom Settings"), DefaultValue(""),
      Description("Main JS file Name")]
    public string MainCtlJS
    {
      get
      {
        return _MainCtlJS;
      }
    
      set
      {
        _MainCtlJS = value;
      }
    }
    
    [Browsable(true),Personalizable(), WebBrowsable,
      Category("Custom Settings"), DefaultValue("Page"),
      Description("Xaml FileName")]
    public string XAMLPageName
    {
      get
      {
        return _XAMLPageName;
      }
    
      set
      {
        _XAMLPageName = value;
      }
    }
    #endregion

    Регистрируются 3 файла со скриптами Jscript и JavaScript. Это стандартные скрипты любого приложения Silverlight:

  • silverlight.js. Скрипт обнаруживает установлен ли плагин Silverlight в браузер. Если нет, то скрипт покажет иконку-ссылку на странцу, с которой можно его установить.
  • Default_html.js. Скрипт содержит функцию createSilverlight
  • Page.xaml.js. Содержит слушателей событий.
  • protected override void OnPreRender(EventArgs e)
    {
    
      String JSString;
    
      // Register the webpart specfic script (Each different type of webpart needs its own main, 
      multiple instances of the same webpart on a page 
       reference the same script
      JSString = "<script type=\"text/javascript\" src=\"" 
                + _JSPath + _MainCtlJS + ".js\"></script>\n";
      if (!Page.ClientScript.IsClientScriptBlockRegistered("SilverlightWebPartScript"))
      Page.ClientScript.RegisterClientScriptBlock(this.GetType(), 
            "SilverlightDefaultScript", JSString);
    
      // Register the general scripts (Two web parts can use this same script blocks as they are generic)
      JSString = "<script type=\"text/javascript\" src=\"" 
                + _JSPath + "Silverlight.js\"></script>\n";
    
      JSString += "<script type=\"text/javascript\" src=\"" 
                + _JSPath + "Page.xaml.js\"></script>\n";
      if (!Page.ClientScript.IsClientScriptBlockRegistered("GeneralSilverlightScripts"))
      Page.ClientScript.RegisterClientScriptBlock(this.GetType(), 
            "GeneralSilverlightScripts", JSString);
    }

    Добавляется код, который генерирует таг <div>, где объект Silverlight будет вставлен в веб-часть

    protected override void RenderContents(HtmlTextWriter writer)
    {
      EnsureChildControls();
      HtmlTextWriter textWriter = new HtmlTextWriter(new StringWriter(CultureInfo.InvariantCulture));
    
      try
      {
        string width, height;
    
        width = "400px"; height = "300px";
        if (this.SLControlWidth.Length > 0)
        width = _SLCtlWidth;
    
        if (this.SLControlHeight.Length > 0)
        height = _SLCtlHeight;
    
    
        textWriter.WriteLine("<TABLE class='ms-summarycustombody' cellpadding='0' cellspacing='0' border='0'>");
        textWriter.WriteLine("<tr><td width='95%'>");
        textWriter.WriteLine("<div id='SilverlightControlHost" + 
              this.ClientID + "' Class=''>");
        textWriter.WriteLine("<script type=\"text/javascript\"> ");
        textWriter.WriteLine("var localScene=new SilverlightTest1.Page();");
        textWriter.WriteLine("createSilverlight('SilverlightControlHost" + this.ClientID + 
              "', '" + _XAMLPageName + 
              "', 'SilverlightControl" + this.ClientID + 
              "','" + width + "','" + height + 
              "', localScene);  ");
        textWriter.WriteLine("</script></div>");
        textWriter.WriteLine("</td></tr></TABLE>");
      }
      catch
      {
        textWriter = new HtmlTextWriter(new StringWriter(CultureInfo.InvariantCulture));
        textWriter.WriteLine("<TABLE class='ms-summarycustombody' 
            cellpadding='0' cellspacing='0' border='0'>");
        textWriter.WriteLine("<TR><TD>There was an error creating this web part</TD></TR>");
        textWriter.WriteLine("</TABLE>");
      }
      
      writer.Write(textWriter.InnerWriter.ToString());
    }

    Создается файл Default_html.js file и в него копируется код модифицированной функции createSilverlight.

    function createSilverlight(controlHost, xamlSource, controlName, controlWidth, controlHeight)
    {
      var SLObj = new SilverlightTest1.Page();
      Silverlight.createObjectEx(
      {
        source: xamlSource,
        parentElement: document.getElementById(controlHost),
        id: controlName,
        properties: 
        {
          width: controlWidth,
          height: controlHeight,
          version: "1.0"
        },
        events: 
        {
          onLoad: Silverlight.createDelegate(SLObj,  SLObj.handleLoad)
        }
      });
    }
    
    if (!window.Silverlight) 
      window.Silverlight = {};
    
    Silverlight.createDelegate = function(instance, method) 
    {
      return function() 
      {
        return method.apply(instance, arguments);
      }

    Создание XAML

    Создается Page.xaml файл:

    <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 Width="247" Height="72" Canvas.Left="197" Canvas.Top="121" Text="This is great" TextWrapping="Wrap"/>
    </Canvas>

    Развертывание веб-части Silverlight на Office SharePoint Server

    Развертывание веб-части Silverlight на Office SharePoint Server 2007 выполняется в следующей последовательности:

  • Устанавливается последняя версия плагина Silverlight. Если плагина нет, отображается ссылка на страницу установки
  • Копируется сборка *.dll в каталог _app_bin приложения SharePoint ( C:\Inetpub\wwwroot\wss\VirtualDirectories\80\_app_bin ). Файл можно установить в global assembly cache (GAC)
  • Копируются файлы default_html.js, Page.xaml, Page.xaml.js и SilverLight.js в корневую директорию. Укажите этот же путь в свойствах JSPath веб-части
  • Добавить строку в web.config файл
    <SafeControl Assembly="SilverLightWebPart2005"
    Namespace="SilverLightWebParts" 
    TypeName="*" Safe="True" />
  • Зайти на галерею веб-частей и добавить веб-часть BasicSilverLightWebPart в список.
  • Зайти на сайт SharePoint и добавить на страницу созданную веб-часть
  • Убедиться, что в строке custom properties указан полный либо относительный путь к файлу Page.xaml, например /Page.xaml.
  • Файлы Page.xaml.js и Default_html.js

    Файлы Page.xaml.js и Default_html.js должны содержать следующий код.

    Page.xaml.js
    if (!window.SilverlightTest1)
      window.SilverlightTest1 = {};
    
    SilverlightTest1.Page = function() 
    {
    }
    
    SilverlightTest1.Page.prototype =
    {
      handleLoad: function(control, userContext, rootElement) 
      {
        this.control = control;
        
        // Sample event hookup:  
        rootElement.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
      },
      
      // Sample event handler
      handleMouseDown: function(sender, eventArgs) 
      {
        // The following line of code shows how to find an element by name and call a method on it.
        // this.control.content.findName("Timeline1").Begin();
      }
    }
    Default_html_js
    function createSilverlight()
    {
      var scene = new SilverlightTest1.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)
        }
      });
    }
    
    
    
    function createSilverlight(controlHost, xamlSource, controlName, controlWidth, controlHeight)
    {
      var SLObj = new SilverlightTest1.Page();
      Silverlight.createObjectEx({
        source: xamlSource,
        parentElement: document.getElementById(controlHost),
        id: controlName,
        properties: {
          width: controlWidth,
          height: controlHeight,
          version: "1.0"
        },
        events: {
          onLoad: Silverlight.createDelegate(SLObj, SLObj.handleLoad)
        }
      });
    }
    
    
    if (!window.Silverlight) 
      window.Silverlight = {};
    
    Silverlight.createDelegate = function(instance, method) {
      return function() {
        return method.apply(instance, arguments);
      }
    }

    Заключение

    С помощью веб-частей Silverlight можно создавать очень сложные веб-части и публиковать их на портале Office SharePoint Server.

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