WP7有約(八):在ListPicker控件的選擇頁面上播放鈴聲
WP7有約(八):在ListPicker控件的選擇頁面上播放鈴聲
Written by Allen Lee
上節課我們在ListPicker控件的選擇頁面上實現了播放圖標的效果,隨后sjcxyf同學又發現了新的問題:
我在項目里面添加了一個MP3文件,然后我在頁面加了一個MediaElement控件,我在Image_Tap事件里面添加了播放音樂的代碼,但是表現出來的結果是當選擇頁面彈出來之后點擊播放圖標不能播放音樂,我試圖嘗試在選擇模板里面加入MediaElement控件來實現,但是最后結果還是一樣。
在Silverlight for Windows Phone里,MediaElement有一個很特別的限制,你必須把它添加到可視化樹,否則它不會播放。假設我們在鈴聲設置頁面上添加一個播放按鈕,如圖1所示,接著在這個按鈕的Click事件處理程序里創建MediaElement對象,然后通過它播放預先添加的鈴聲(這個鈴聲文件的Build Action屬性的值是Content),如代碼1所示。

圖 1 鈴聲設置頁面
代碼 1 通過MediaElement對象播放鈴聲
private void Button_Click(object sender, RoutedEventArgs e)
{
var media = new MediaElement();
media.Volume = 1;
media.Source = new Uri(“Windows Logon Sound.wav”, UriKind.Relative);
}
運行這個應用程序,然后單擊播放按鈕,你會發現什么聲音也沒有。但如果我們在創建MediaElement對象之后把它添加到LayoutRoot里,如代碼2所示,那么單擊播放按鈕就能聽到聲音了,因為此時MediaElement對象已在可視化樹上了。
代碼 2 把MediaElement對象添加到LayoutRoot
private void Button_Click(object sender, RoutedEventArgs e)
{
var media = new MediaElement();
LayoutRoot.Children.Add(media);
media.Volume = 1;
media.Source = new Uri("Windows Logon Sound.wav", UriKind.Relative);
}
這正是為什么我們經常看到別人在XAML里創建MediaElement對象,然后在代碼隱藏里調用它的Play方法播放音頻。不過,如果你試圖把代碼2照搬到Image控件的Tap事件處理程序里,你會發現還是聽不到聲音,為什么呢?
當我們單擊ListPicker控件時,它會打開一個新的選擇頁面,此時,由于鈴聲設置頁面不再可見,不用渲染,Silverlight for Windows Phone會把它從可視化樹上摘除,因此,我們在Image控件的Tap事件處理程序里把MediaElement對象添加到鈴聲設置頁面的LayoutRoot里就失去意義了。
那么,如果我們在選擇頁面的項目模板里創建MediaElement對象又會怎樣呢?毫無疑問,這會導致同一個頁面存在多個MediaElement對象,而Silverlight for Windows Phone并不支持這種用法,因此這條路是行不通的。
從上面的分析不難看出,MediaElement的最大問題在于它對可視化樹的依賴,那么,有沒有不依賴于可視化樹的解決方案?有的,我們可以借用XNA的SoundEffect:
1) 添加Microsoft.Xna.Framework庫的引用,如圖2所示。

圖 2添加Microsoft.Xna.Framework庫的引用
2) 添加XNA命名空間的引用,如代碼3所示。
代碼 3 XNA命名空間
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
3) 把Image控件的Tap事件處理程序改為代碼4所示的那樣。
代碼 4 通過XNA的SoundEffect播放鈴聲
private void Image_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
using (var stream = TitleContainer.OpenStream("Windows Logon Sound.wav"))
{
var audio = SoundEffect.FromStream(stream);
FrameworkDispatcher.Update();
audio.Play();
}
e.Handled = true;
}
代碼4所做的事情很簡單,它以流的形式打開鈴聲文件,然后用這個流對象創建SoundEffect對象,并更新XNA的組件狀態,最后播放鈴聲。
一般情況下,當我們提到Windows Phone應用程序的存儲區域時,很多人會第一時間想到獨立存儲區,不過,Windows Phone應用程序還有另外一個存儲區域,這個區域就是應用程序的安裝文件夾,和獨立存儲區不同的是,安裝文件夾里面的內容是只讀的。當我們在Visual Studio的屬性窗口里把內容文件的Build Action屬性的值設為Content時,比如前面那個鈴聲文件,安裝程序會把它們部署到安裝文件夾里。事實上,Windows Phone SDK 7.1的LINQ to SQL就通過"appdata"和"isostore"在連接字符串里區分這兩種區域。
XNA提供的TitleContainer.OpenStream方法可以用來讀取安裝文件夾里的內容,如果你的應用是從網上下載鈴聲的,那么這些鈴聲將會保存在獨立存儲區里,這意味著代碼4里打開文件流的代碼應該換成對應的獨立存儲訪問代碼。


浙公網安備 33010602011771號