使用 Silverlight Media Framework 構建自定義播放器

作者: Ben Rush  來源: MSDN  發布時間: 2010-09-01 22:25  閱讀: 2883 次  推薦: 0   原文鏈接   [收藏]  

      流媒體已在網絡上無處不在。似乎所有人(從新聞站點到社交網絡再到隔壁的鄰居)都在享受在線視頻體驗。由于用戶群的不斷攀升,大多數站點需要以一種值得信賴、用戶友好的方式為其客戶提供高品質視頻,通常為高品質帶寬感知 視頻。

      在線媒體傳輸體驗的核心要素是播放器本身。播放器是用戶與之發生交互的介質,它可以驅使用戶獲得在線體驗的每一個要素。播放器如此備受關注,毫無疑問,基于 Web 的現代媒體播放器在實現時勢必要比幾年前的老款播放器復雜得多。因此,開發人員需要一個穩健的框架來構建播放器。

      Silverlight Media Framework (SMF)是一個開源項目,由 Microsoft 在 2009 年 Microsoft 專業開發人員大會上發布。此項目是一個可擴展的、具備高度伸縮性的 Silverlight 視頻框架,它直接解決了開發人員和設計人員的需求,為其提供了穩定的內核來創建自己的播放器。Silverlight Media Framework 的核心代碼已根據從 NBC Olympics 和 Sunday Night Football Web 視頻項目中所學的課程經過優化。

      本文將介紹 SMF 的基本要素,演示如何將 SMF 集成到您自己的播放器項目中,并通過一個簡單項目向您逐步介紹如何使用 SMF 打造自定義播放器體驗。我將向您展示如何使用 SMF 的日志記錄、設置和事件處理功能。最后,我將創建一個播放器應用程序,該應用程序會在當前的視頻播完后顯示建議您日后觀看的視頻。

      SMF 入門

      開始前,您需要先從 Codeplex(smf.codeplex.com)下載框架。您還需要下載平滑流式處理播放器開發工具包(iis.net/expand/smoothplayer)并在使用 SMF 的任何項目中參考它。平滑流式處理播放器開發工具包不屬于 SMF,它是完全獨立的封閉源組件。不過,SMF 可以利用該工具包中的一組核心功能,特別是視頻播放器本身。在撰寫本文檔時,平滑流式處理播放器開發工具包為 beta 2 版本。

      SMF 包含大量 Microsoft .NET 程序集(如圖 1 所示),每個程序集都構成整個框架的不同功能部分。

 

圖 1 Silverlight Media Framework 程序集

      核心程序集是 Microsoft.SilverlightMediaFramework.dll,它由框架其余部分引用的眾多實用程序類和類型組成。使用 SMF 的任意部分時,也必須引用 Microsoft.SilverlightMediaFramework.dll 程序集。

      Microsoft.SilverlightMediaFramework.Data 命名空間提供幫助程序類,以使用播放器外部的數據以及封裝播放器內部的數據。該數據可以是任何格式的通用數據,但也可以是播放器自身的設置信息。Microsoft.SilverlightMediaFramework.Data.Settings 是另一個命名空間,用于顯示類型和處理播放器設置。

除了用于設置的數據以外,您最想要與之發生交互的 Data 命名空間中的類型是流外 DataClient 類,它可以從外部源檢索數據。如果您想要下載和使用播放器外部的數據,請引用此程序集。

      SMF 播放器包含穩健的 Microsoft.SilverlightMediaFramework.Logging 框架,該框架使用回調模式。在這種模式下,寫入日志記錄基礎結構會引發事件。您可以使用日志記錄系統注冊自己的回調方法,這些回調一旦激活,便會執行其他操作,如向 Web 服務發送信息或在文本框中顯示信息。如果您想要使用 SMF 的內置日志記錄工具,請引用此程序集。

      Microsoft.SilverlightMediaFramework.Player 程序集實現播放器本身。它還提供播放器所需的大量控件,如洗帶器、音量控件和時間線標記。默認的 SMF 播放器界面布局簡潔、雅致,對于任何需要 Silverlight 播放器的項目來說,都是一個良好的開端。但是,SMF 中定義的所有控件的核心都是控制模板概念,因此每個控件都可以使用 Expression Blend 或 Visual Studio 等工具作為主題。

      構建和引用 SMF

      SMF 作為單個.zip 文件下載,其中包含一個解決方案文件、每個輸出庫對應的項目,以及用于運行和驗證播放器自身的測試項目。

      SMF 依賴于平滑流式處理播放器開發工具包。要引用該工具包,請將平滑流式處理程序集(Microsoft.Web.Media.SmoothStreaming.dll)移到 SMF 項目的 \Lib 文件夾中。

      然后,在 Visual Studio 中打開 SMF 解決方案并進行構建,創建所有需要利用該框架的程序集。要確認是否一切都如期進行,請按 F5 開始進行調試。系統將構建該解決方案并執行 Microsoft.SilverlightMediaFramework.Test.Web 目標,向您顯示對“Big Buck Bunny”視頻進行流式處理的默認 SMF 播放器(參見圖 2)。注意,默認播放器是否已包含洗帶的位置元素、播放/停止/暫停按鈕、音量控件、全屏控件等。

 

圖 2 SMF 播放器和 Big Buck Bunny視頻

      下一步是創建自己的獨立 Silverlight 項目并利用其所包含的 SMF 功能。在 Visual Studio 中,單擊“文件”|“新建”|“項目”|“Silverlight 應用程序”。調用 SMFPlayerTest 解決方案,然后單擊“確定”。將彈出一個模式對話框,詢問您是否要將 Silverlight 應用程序托管到新的網站中。單擊“確定”,您將看到一個基本的 Silverlight 應用程序解決方案,該解決方案由兩個項目組成,分別是 SMFPlayerTest 和 SMFPlayerTest.Web。

      最后一步是從新建項目中引用平滑流式處理播放器開發工具包和 SMF 程序集。將輸出 SMF 程序集和平滑流式處理播放器開發工具包從 SMF 解決方案的 Debug 文件夾中復制并粘貼到新項目中(如圖 3 所示)。現在,新解決方案將包含利用 SMF 所需的所有程序集引用。

 

圖 3 引用所需的程序集

      顯示播放器

      要開始使用 SMF,請將 SMF 播放器的命名空間添加到 MainPage.xaml 頁中。這樣做可以確保所有引用都可以正確地解析: 

xmlns:p="clr-namespace:Microsoft.SilverlightMediaFramework.Player;assembly=Microsoft.SilverlightMediaFramework.Player"

     現在,將播放器的 XAML 插入此頁面的 LayoutRoot Grid 控件中:   

<Grid x:Name="LayoutRoot">
  <p:Player>
  </p:Player>
</Grid>

      按 F5 將啟用項目并打開 SMF 播放器。但是,因為播放器不知道要播放哪些內容,所以它不會執行任何操作。您所得到的只是一個播放器,不包含任何要播放的內容。

      SMF 使用 SmoothStreamingMediaElement(位于平滑流式處理播放器開發工具包中)播放視頻。從 SmoothStreamingMediaElement 中,SMF 會繼承自有的播放器,名為 CoreSmoothStreamingMediaElement。如果希望播放器對內容進行流式處理,則需要此對象。確保將 SmoothStreamingSource 屬性設置為一個有效的平滑流媒體 URL:  

<Grid x:Name="LayoutRoot">
  <p:Player>
    <p:CoreSmoothStreamingMediaElement
      AutoPlay="True"
      SmoothStreamingSource="replace with address to content here"/>
  </p:Player>
</Grid>

      如前所述,Microsoft 提供“Big Buck Bunny”視頻流示例,開發人員可以用它來測試 Silverlight 項目。要使用這個測試流,請將 CoreSmoothStreamingMediaElement 上的 SmoothStreamingSource 屬性設置為:  

http://video3.smoothhd.com.edgesuite.net/ondemand/Big%20Buck%20Bunny%20Adaptive.ism/Manifest

      請再次按 F5 構建并運行該項目。瀏覽器將和以前一樣使用相同的播放器執行操作,但是這次,“Big Buck Bunny”視頻將在播放器安全加載好后開始進行流式處理。如果您的任務是創建一個基本的 Silverlight 播放器對內容進行流式處理,您已實現此目標。

      但是,SMF 的功能遠不止我們現在所看到的這些。讓我們添加一些基本的日志記錄。

      在播放器中進行日志記錄

      在 SMF 中進行日志記錄很簡單,記錄事件時,會引發一個 LogReceived 事件。您為此事件注冊了一個事件處理程序,因此每次引發一個日志記錄事件都會收到一則相應的通知。要對此通知采取何種措施取決于您;您可以在播放器的一個新窗口中顯示它、在引發特定事件時篩選事件并通知 Web 服務,或者采取任何當前情況下所需的措施。

      LogReceived 事件在 Logger 類中靜態定義(在 Microsoft.SilverlightMediaFramework.Logging.dll 中定義),因此您可以在項目的任意位置注冊日志記錄事件。下面是一個在 SMFPlayerTest 項目的 MainPage.xaml 文件中注冊和定義事件處理程序的示例:

 

public partial class MainPage : UserControl {
  public MainPage() {
    InitializeComponent();

    Logger.LogReceived += 
      new EventHandler<SimpleEventArgs<Log>>(
      Logger_LogReceived);
  }

  void Logger_LogReceived(object sender, 
    Microsoft.SilverlightMediaFramework.SimpleEventArgs<Log> e) {
    throw new NotImplementedException();
  }
}

 

      SMF 會立即引發多個事件。要查看這些事件,請在 Logger_LogReceived 方法中創建一個斷點,然后再次在 Debug 模式下運行播放器。幾乎同時,系統會立即點擊您的斷點,從而讓您可以逐步了解方法的參數并查看傳遞給它的信息。 

      日志事件數據被封裝在一個特定的消息對象中,該對象的類型必須繼承自一個名為 Log 的抽象類。此抽象日志類型包含三個屬性:Sender、Message 和 TimeStamp。Sender 會引用引發事件的對象。Message 是包含日志記錄事件文本的 System.String 類型的對象。TimeStamp 只包含日志記錄對象首次實例化的日期和時間。作為第二個參數傳遞給您的事件處理程序的 SimpleEventArgs<> 對象包含一個通過其 Result 屬性指向 Log 對象的引用。 

      要引發一個日志事件,只需對從 Log 基類繼承的類型進行實例化,然后將此類型傳遞給 Logger 類型上靜態定義的 Log 方法即可。該框架提供一個已從 Log 基類型繼承的 DebugLog 類。但是,DebugLog 類型的特別之處在于,如果 Silverlight 項目要引用的庫使用 Debug 版 SMF 創建,將 DebugLog 類型傳遞給 SMF 日志記錄框架將引發一個相應的日志記錄事件(從而調用您的事件處理程序)。另一方面,Release 版的 SMF 則會忽略任何對 Log 方法的調用,該調用會獲取已傳遞的 DebugLog 類。簡而言之,如果您擁有調試聲明,您只需使用 Dbug 版,將 DebugLog 對象用作日志事件參數;否則,您將需要構造從抽象 Log 類型繼承的屬于自己的類型。

      下面是一個通過 SMF 事件系統引發 Listening 事件的示例,方法是:先對 DebugLog 對象進行實例化,然后將它傳遞給 Logger 的靜態 Log 方法(確保平滑流式處理播放器開發工具包文件在 Debug 設置下構建):

public MainPage() {
  InitializeComponent();

  Logger.LogReceived += 
  new EventHandler<SimpleEventArgs<Log>>(
    Logger_LogReceived);

  Logger.Log(new DebugLog { 
    Message = "Listening!", Sender = this }); 
}

      從 Player 類繼承

      雖然日志記錄是播放器的核心功能,但是從 SMF Player 類型繼承并開始對其進行擴展時,唯一可以訪問的卻是 SMF 播放功能。

      要了解該功能的工作原理,您需要創新一個從 Player 類型繼承的名為 SMFPlayer 的新類。

      新的 SMFPlayer 類如下所示: 

namespace SMFPlayerTest {
  public class SMFPlayer : Player {
    public override void OnApplyTemplate() {
      base.OnApplyTemplate();
    }
  }
}

 

      每個 FrameworkElement 類(如 SMF 中的 Player)都有一個在引發 ApplyTemplate 事件時調用的 OnApplyTemplate 方法。該方法通常可用作初始化 FrameworkElement 類型的有用起點。

      在這種情況下,我可以從新的 SMFPlayer 類中覆蓋默認的 OnApplyTemplate 方法。要證明執行的是新的 SMFPlayer 類型,而不是默認的 Player 類型,您可以在覆蓋中設置一個斷點。在 Visual Studio 中調試播放器時,Silverlight 會在執行 SMFPlayer 時遇到此斷點。現在,請更新 MainPage.xaml 文件以使用新的播放器類。首先,將播放器的命名空間添加到已引用的命名空間列表中(就像您以前對播放器命名空間所做的那樣):

 

xmlns:smf="clr-namespace:SMFPlayerTest"

       然后,只需在 XAML 中更新 Player 標記即可使用 SMFPlayer,而不是 Player:

<Grid x:Name="LayoutRoot">
  <smf:SMFPlayer>
    <p:CoreSmoothStreamingMediaElement
      AutoPlay="true"
      SmoothStreamingSource="http://..."/>
  </smf:SMFPlayer>
</Grid>

      接下來,對 DebugLog 類進行實例化并將它傳遞給 Log 方法,如前所示。這樣做將觸發以前為其注冊事件處理程序的事件   

public override void OnApplyTemplate() {
  Logger.Log(new DebugLog {
    Message = "Hello from OnApplyTemplate!",
    Sender = this
    });

  base.OnApplyTemplate();
}

     要專門從事件處理程序中偵聽此事件,請篩選 DebugLog 對象本身的 Message 屬性。在下例中,查找任何包含“OnApplyTemplate”的消息:

 

void Logger_LogReceived(
  object sender, SimpleEventArgs<Log> e) {
  if (e.Result.Message.Contains("OnApplyTemplate")) {
    return;
  }
}

 

       使用設置數據

 

      用于處理設置的成熟框架對大部分大型軟件項目而言至關重要。SMF 中用于處理設置的代碼構建于 Microsoft.SilverlightMediaFramework.Data.dll 程序集基礎上,您可以借助該代碼下載通用的外部數據。SMF 的設置層使用此基礎結構來訪問和下載駐留在 Web 服務器上的特定格式的 XML 設置文件。成功下載和讀取設置數據后,SMF 設置層會使用 SettingsBase 對象將其封裝起來,然后使用該對象的方法檢索設置值。

      ttingsBase 類,正如其名稱所指,用作一個更具體的類的基礎,該類可以強類型化的方式訪問您的設置值。下面是一個繼承自 SettingsBase 的類的示例。它有兩個屬性,一個用于檢索視頻播放器源 URL,另一個用于檢索指示視頻播放器是需要自動啟動還是等待查看者按播放按鈕的布爾值:

 

 

namespace SMFPlayerTest {
  public class SMFPlayerTestSettings : SettingsBase {
    public Uri VideoPlayerSource {
      get { return new Uri(
        GetParameterValue("videoSource")); }
    }

    public bool? AutoStartVideo {
      get { return GetParameterBoolean(
        "autoStart"); }
    }
  }
}
     屬性方法使用 SettingsBase 類實現的功能來檢查已載入此類型(通過稍后討論的機制)的設置名稱/值對的基礎集合。這提供了一種類型安全、對 IntelliSense 友好的設置信息檢索方法。

 

 

 

      現在,在 SMFPlayerTest.Web 項目中創建一個新 XML 文件,將其命名為 SMFPlayerSettings.xml,然后向其添加以下項:

 

<?xml version="1.0" encoding="utf-8" ?>
<settings>
  <Parameters>
    <Parameter 
      Name="videoSource" 
      Value="http://video3.smoothhd.com.edgesuite.net/ondemand/Big%20Buck%20Bunny%20Adaptive.ism/Manifest"/>
    <Parameter Name="autoStart" Value="True"/>
  </Parameters>
</settings>

 

 

m_settingsGetter = new SettingsClient(
  new Uri("http://localhost:10205/SMFPlayerSettings.xml"));

 

      檢索設置數據是一個異步過程,因此必須在 SettingsClient 上為 RequestCompleted 方法指定一個回調方法:

 

 

m_settingsGetter.RequestCompleted += 
  new EventHandler<SimpleEventArgs<SettingsBase>>
  (m_settingsGetter_RequestCompleted);

 

      最后一步是在 SettingsClient 對象上調用無參數 Fetch 方法。檢索到數據后,將調用 settingsGetter_RequestCompleted 事件處理程序,并將 SettingsBase 對象傳遞給它:

 

 

void m_settingsGetter_RequestCompleted(
  object sender, SimpleEventArgs<SettingsBase> e) {

  SettingsBase settingsBase = e.Result;
  return; 
}

 

      傳遞給 settingsGetter_RequestCompleted 方法的 SettingsBase 對象加載了底層框架從 SMFPlayerSettings.xml 文件解析的名稱/值對。為了將此數據加載到 SMFPlayerTestSettings 對象中,您只需調用 Merge 方法,該方法會將 SettingsBase 派生的對象中的設置信息與另一個對象中的設置信息結合起來:

 

 

SettingsBase settingsBase = e.Result;
m_settings.Merge(settingsBase);

this.mediaElement.SmoothStreamingSource = 
  m_settings.VideoPlayerSource;
this.mediaElement.AutoPlay = 
  (bool)m_settings.AutoStartVideo; 

return;

 

      您不再需要對 XAML 頁中 CoreSmoothStreamingMediaElement 上的 AutoPlay和 SmoothStreamingSource 屬性進行硬編碼,因為播放器設置已從 OnApplyTemplate 方法中下載下來。您只需對播放器 XAML 執行以下操作:

 

 

<Grid x:Name="LayoutRoot">
  <smf:SMFPlayer>
    <p:CoreSmoothStreamingMediaElement/>
  </smf:SMFPlayer>
</Grid>

 

      運行播放器時,將加載所有設置數據,回調會將值加載到播放器的媒體元素中,視頻將開始像以前一樣進行流式處理。

 

 

      擴展 SMF 播放器

      在許多著名的視頻站點上,當視頻播放完成時,您將看到一列類似視頻或建議觀看的視頻。為了說明 SMF 播放器擴展多么容易實現,我們將為您逐步介紹在項目中構建一個類似的建議觀看功能。

      首先將x:Name 屬性添加到 MainPage.xaml 文件中的 Player 元素:

 

 

 

<Grid x:Name="LayoutRoot">
  <smf:SMFPlayer x:Name="myPlayer">
    <p:CoreSmoothStreamingMediaElement/>
  </smf:SMFPlayer>
</Grid>

 

 

      現在,在“解決方案資源管理器”中右鍵單擊 MainPage.xaml,然后選擇“在 Expression Blend 中打開”。將啟動 Expression Blend 3 并顯示 SMF 播放器的設計界面。在“對象和時間線”部分,您將在可視對象樹中找到 myPlayer 節點,該節點對應于以前為 SMFPlayer 對象指定的名稱。目標是創建 SMFPlayer 的模板,然后在該模板中添加三個“建議”按鈕。通過使用 Expression Blend 中的模板,您可以添加、編輯或刪除播放器中內置的控件。

      要創建模板,請在“對象和時間線”窗口中右鍵單擊 myPlayer,然后選擇“編輯模板”|“編輯副本”。將會顯示“創建樣式資源”對話框,單擊“確定”。要在視頻播放器的頂部插入三個按鈕,請在“工具”窗口中對每個要添加的按鈕雙擊按鈕圖標。現在,三個按鈕應會在組成播放器模板的控件樹中顯示(參見圖 4)。

 

 

 

圖 4 添加到控件樹的按鈕控件

 

      在樹中選擇所有三個按鈕,訪問控件的屬性窗口,并將水平和垂直對齊設置為居中對齊(參見圖 5),這樣按鈕便會位于視頻播放器的中間位置。

 

 

 

圖 5 設置按鈕控件對齊

按鈕為默認大小,并相互堆疊。將每個按鈕的寬度設置為 400,高度設置為 75。然后調整邊距,使第一個按鈕偏移底部 175 像素,第二個按鈕偏移頂部 175 像素,第三個按鈕無邊距偏移。最終結果將如圖 6 所示。

 

 

圖 6 Expression Blend 中的居中按鈕

要確定按鈕正好位于播放器上,請保存 Expression Blend 中所有打開的文件,然后返回 Visual Studio。Visual Studio 可能會提示您重新加載由 Expression Blend 更改的文檔。如果出現此提示,請單擊“確定”。在 Visual Studio 中,按 F5 在“調試”模式下重新啟動 SMF 播放器。現在,播放器應會在視頻屏幕的中間顯示三個按鈕,如圖 7 所示。

 

圖 7 SMF 播放器中的居中按鈕

掛接事件處理程序

 

現在,事件處理程序必須與按鈕相關聯。要從代碼引用按鈕,您需要為這些按鈕指定名稱,您可以通過“屬性”選項卡中的“名稱”文本框來實現。為簡便起見,請將這些按鈕命名為 Button1、Button2 和 Button3。完成后,需要更新“對象和時間線”窗口,便會顯示與可視樹中的按鈕圖標相鄰的按鈕名稱。

 

在每個按鈕的“屬性”選項卡中,您將發現一個用于指定可視組件的事件處理程序的“事件”按鈕。選擇其中一個按鈕,單擊“屬性”選項卡中的“事件”按鈕,然后雙擊“單擊文本框以在 MainPage.xaml.cs 中自動生成一個事件處理程序”。現在,每個按鈕的屬性窗口將包含一個為其 Click 事件指定的事件處理程序(參見圖 8),MainPage.xaml.cs 文件將包含為每個按鈕的 Click 事件指定的事件處理程序。

 

圖 8 設置事件處理程序

     現在,您可以調試播放器。單擊屏幕上的任意按鈕將引發一個 Click 事件,該事件現在由 MainPage.xaml.cs 中自動生成的方法處理。

      建議的視頻

      現在,請使用這些按鈕啟用建議的視頻功能。下面的 XML 將顯示這些建議:

 

 

<?xml version="1.0" encoding="utf-8" ?>
<Suggestions>
  <Suggestion DisplayName="A suggestion" Url=""/>
  <Suggestion DisplayName="Another suggestion" Url=""/>
  <Suggestion DisplayName="My final suggestion" Url=""/>
</Suggestions>

 

 

      Ul 屬性的值將指定單擊此按鈕時播放器要加載的視頻,DisplayName 屬性是要寫在該按鈕上的文本。在 SMFPlayerTest.Web 項目中用名稱 Suggestions.xml 保存此文件。

 

      DataClient 類型(在 Microsoft.SilverlightMediaFramework.Data 命名空間中)將用于下載 XML 文檔和以類型安全的方式顯示內容。要以強類型樣式顯示從 XML 文件中讀取的每個“建議”,請在 Silverlight 項目中創建一個名為 SMFPlayerTestSuggestion 的類:

 

 

namespace SMFPlayerTest {
  public class SMFPlayerTestSuggestion {
    public string DisplayName;
    public Uri Url; 
  }
}

 

 

 

      和 SettingsBase 一樣,DataClient 想要派生自某個類,該類可從 XML 內容(此時為一個 SMFPlayerTestSuggestion 對象數組)以強類型樣式顯示數據。

      在 SMFPlayerTest 對象中創建另一個名為 SMFPlayerTestDataClient 的類:

 

 

namespace SMFPlayerTest {
  public class SMFPlayerTestDataClient : 
    DataClient<SMFPlayerTestSuggestion[]> {

    public SMFPlayerTestDataClient(Uri Url) : base(Url) { }

    protected override void OnRequestCompleted(
      object sender, SimpleEventArgs<string> e) {

      throw new NotImplementedException();
    }
  }
}

 

 

 

      SMFPlayerTestDataClient 繼承自 DataClient 并將其模板參數設置為一個 SMFPlayerTestSuggestion 類型數組。DataClient 基類提供登錄網絡并下載外部 XML 文件所需的所有異步聯網邏輯。但是,等內容下載完后,DataClient 基類將調用 OnRequestCompleted 并希望隨后會執行所有 XML 數據處理過程。換言之,DataClient 基類會下載內容,實現程序則負責對內容進行處理。

      下面是 OnRequestCompleted 的更完整的實現過程:

 

 

protected override void OnRequestCompleted(
  object sender, SimpleEventArgs<string> e) {

  XDocument doc = XDocument.Parse(e.Result);
  List<SMFPlayerTestSuggestion> suggestions = 
    new List<SMFPlayerTestSuggestion>();
  foreach (XElement element in doc.Descendants("Suggestion")) {
    suggestions.Add(new SMFPlayerTestSuggestion {
      DisplayName = element.Attribute("DisplayName").GetValue(),
      Url = element.Attribute("Url").GetValueAsUri()
    });
  }

  base.OnFetchCompleted(suggestions.ToArray()); 
}

 

 

 

      為簡便起見,我已在此實現過程中使用 LINQ to XML 來解析 XML 中所需的元素和屬性。當檢索到每個 Suggestion 節點中的 DisplayName 和 Url 屬性值后,將對 SMFPlayerTestSuggestion 對象進行實例化并指定相應的值。

      最后一步是調用 OnFetchCompleted 事件。SMFPlayerTestDataClient 的外部客戶會向 FetchCompleted 事件注冊事件處理程序,以便在建議的視頻數據下載完成后發出通知。因為 OnRequestCompleted 已以類型安全的方式打包 XML 數據,每個事件處理程序將收到一個便利的 SMFPlayerTestSuggestion 對象數組,各自對應 DataClient 基類下載的 XML 文檔中的每個 Suggestion 元素。

      底層 DataClient 提供一種名為 Fetch 的方法。一旦調用該方法,便會開始異步下載內容。要在視頻結束時開始下載建議數據,請將名為 mediaElement_MediaEnded 的事件處理程序附加到 MediaElement 對象上的 MediaEnded 事件:

 

 

void mediaElement_MediaEnded(
  object sender, RoutedEventArgs e) {

  m_client = new SMFPlayerTestDataClient(
    new Uri("http://localhost:10205/Suggestions.xml"));
  m_client.FetchCompleted += 
    new EventHandler<SimpleEventArgs<
    SMFPlayerTestSuggestion[]>>(m_client_FetchCompleted);
  m_client.Fetch(); 
}

 

 

 

      mediaElement_MediaEnded 方法會創建一個 SMFPlayerTestDataClient 類型的實例,為 FetchCompleted 事件指定另一個事件處理程序,然后調用 Fetch 開始下載過程。通過調用以前在 OnRequestCompleted 中實現的 OnFetchCompleted(內容下載完成后由 DataClient 基類調用),將會調用 FetchCompleted 處理程序。

      實現在 mediaElement_MediaEnded 中注冊的 suggestion_FetchCompleted,會獲取強類型的 Suggestion 數據數組,并為每個按鈕指定一個 Suggestion:

 

 

void m_client_FetchCompleted(
  object sender, SimpleEventArgs<
  SMFPlayerTestSuggestion[]> e) {
  for (int c = 1; c <= 3; c++) {
    Button btn = (Button)GetTemplateChild(
      "Button" + c.ToString());
    btn.Tag = e.Result[c - 1].Url;
    btn.Content = 
      e.Result[c - 1].DisplayName; 
  }
}

 

 

 

      底層 FrameworkElement 類型上的方法 GetTemplateChild,可以引用 MainPage XAML 中定義的每個按鈕。對于每個按鈕,將為 Content 屬性指定顯示文本,并為 Tag 屬性指定 URI。然后,每個按鈕的單擊事件處理程序可以從 Tag 屬性中拖出 URI 并將 URL 指定給播放器的 MediaElement 以播放流媒體:

 

 

private void Button1_Click(
  object sender, System.Windows.RoutedEventArgs e) {

  Uri redirectUrl = (Uri)((Button)sender).Tag;
  myPlayer.MediaElement.SmoothStreamingSource = 
    redirectUrl; 
}

 

 

 

      顯示按鈕

      最后一步是隱藏按鈕,直到當前進行流式處理的視頻完成,這時按鈕將變為可見。當用戶單擊某個按鈕時,這些按鈕會再次隱藏起來。

      在 Visual Studio 中,可以通過為 SMFPlayer 類添加兩個 TemplateVisualState 屬性來對其進行編輯:

 

 

[TemplateVisualState(Name = "Hide", GroupName = "SuggestionStates")]
[TemplateVisualState(Name = "Show", GroupName = "SuggestionStates")]
public class SMFPlayer : Player

 

 

 

      TemplateVisualState 是一個特別強大的屬性,可以定義對象處于可視狀態。當可視狀態變得有效時,Silverlight 將更新屬于指定類的可視元素的屬性,如子按鈕控件的可視性。

      要設置當前的可視狀態,請使用 VisualStateManager 類的靜態 GoToState 方法(本機 Silverlight 類型)。TemplateVisualState 的 GroupName 屬性喜歡組合狀態,TemplateVisualState 的 Name 屬性則會指定各個狀態。

      返回 Expression Blend。在 myPlayer 模板中,單擊設計器窗口正上方的 myPlayer,然后單擊“編輯模板”|“編輯當前值”。單擊“狀態”選項卡,并向下滾動 SuggestionStates,如圖 9 所示。

 

圖 9 SuggestionStates 的可視狀態

      屬性創建的兩個 SuggestionStates 分別顯示為“隱藏”和“顯示”。如果單擊“隱藏”,則左側會顯示一個紅色圓圈,表明 Expression Blend 正在記錄設計器中所做的任何屬性更改。Expression Blend 會繼續記錄屬性更改,直到再次單擊“隱藏”,此時紅色記錄圈會消失。

      當 Expression Blend 積極記錄“隱藏”可視狀態時,請將按鈕設置為“折疊”。在“對象和時間線”窗口下選擇所有三個按鈕,并在“屬性”選項卡中選擇“折疊”作為其“可視性”。通過再次單擊“隱藏”按鈕,停止記錄“隱藏”可視狀態。現在,單擊“顯示”,一個紅色圓圈將顯示在“顯示”可視狀態的左側。通過單擊“可視性”下拉菜單右側的“高級屬性選項”按鈕,并選擇“記錄當前值”,這時可以明確將可視性狀態記錄為“可視”。保存所有打開的文檔,再次返回 Visual Studio。

      本機 Silverlight 類 VisualStateManager 可用于明確設置當前有效的可視狀態。在播放器的 OnApplyTemplate 方法中,將“隱藏”設置為當前有效的可視狀態:

 

 

VisualStateManager.GoToState(this, "Hide", true);

 

 

 

在 suggestion_FetchCompleted 中,將“顯示”設置為當前有效的狀態,以在流式處理結束以及“建議”數據下載完成時顯示按鈕:

 

 

VisualStateManager.GoToState(this, "Show", true);

 

 

 

      要在單擊按鈕(或重新播放最初的流媒體)時隱藏按鈕,請為 MediaElement 的 MediaOpened 事件創建一個新事件處理程序,并將可視狀態設置為“隱藏”。

      最后一次啟動并調試播放器。您將看到按鈕不可見,直到視頻播放完畢,這時按鈕將變為可見。單擊某按鈕,可將播放器導航到按鈕對應的“建議”設置中指定的任意 URL。

      利用 Codeplex上的 SMF 項目空間,您可以訪問代碼庫、文檔、討論內容和 Issue Tracker。歡迎您積極投稿。投入更多的項目創意,每個人都能享受到更加優秀的項目成果。

      這可以更加容易地在 Visual Studio 和 Expression Blend 中按名稱引用 SMFPlayer 對象。

       然后,創建一個要向其中加載 XML 設置的 SettingsClient 對象。SettingsClient 會獲取一個指向設置文件的 URI:

 

      利用 Codeplex上的 SMF 項目空間,您可以訪問代碼庫、文檔、討論內容和 Issue Tracker。歡迎您積極投稿。投入更多的項目創意,每個人都能享受到更加優秀的項目成果。

0
0
 
標簽:Silverlight
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()