要說這Windows Store應用像啥,像網頁,而且還全屏的,所以,這和傳統案頭應用就有著明顯的差異,在同一時刻就只有一個應用在前台運行,對,和手機一樣。
故今天我們的話題,本質上是討論媒體播放的,不過,如果不順便考慮一下後台播放,感覺有點……你想,當你啟動一個播放音樂的應用,正聽著很美的音樂,突然我想看看我微博上有啥更新,回到“開始”螢幕,啟動一下微博應用。我靠!音樂停了,你想這多沒意思啊。
所以啊,當我們希望開發一個播放音樂的應用時,支援後台播放那可是頭等大事。
好了,牛皮就不吹了,開始說正題。
你說在應用程式中如何播放多媒體,這個應該各位都會,當然我這裡指的是XAML中的,HTML5本身就支援多媒體播放。是的,MediaElement,想起來了吧,這位老哥們兒,你不可能不認識D,在玩WPF/Silverlight/Windows Phone等開發的時候,你一定和她親密接觸過的。這控制項用起來也很簡單,給她一個播放源就可以,就好像一位演技很好的MM,你只需為她簡單妝扮,上了舞台就發揮自如。
<MediaElement Source="abcd.mp3" />
可能有時候會設定一下音量什麼的,或者把AutoPlay設定為True,這使得這個控制項在設定源後便馬上播放。
這個,我相信大家都會,這裡就不多重複了,不然又有人說“這和Win8有毛關係,這不是WPF中的XAML嗎?”是的,XAML就是好,跨項目應用;完美的整合性就是好,學會一個知識,可以迅速遷移到其他知識;統一性就是好,專心做程式,不必須要衝突等問題浪費青春。
那麼,如何?後台播放呢,我們來做一做實驗吧。如何建立項目我就省略了,我相信這操作連鴕鳥都會了。
1、開啟資訊清單檔編輯器,切換到“功能”選項卡,選上“音樂庫”,我們待會兒要用。
2、切換到“聲明”選項卡,在下拉式清單中選擇“背景工作”,並點擊“添加”按鈕;添加後,在右側邊窗格中,勾選“音頻”,並填上進入點,預設就是App。
3、開啟首頁的XAML檔案,我們來完成一下UI布局。
<Page x:Class="BackgroundAudioExample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:BackgroundAudioExample" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Margin="28"> <TextBlock Margin="2,1,2,7" TextWrapping="Wrap"> <Span FontSize="24" FontWeight="Bold">實現後台播放,應該要具備以下條件:</Span> <LineBreak/> <Run FontSize="20">在資訊清單檔中,加入背景工作的聲明</Run><LineBreak/> <Run FontSize="20">你的PC或筆記本的鍵盤最好具有多媒體修飾鍵,這樣方便操作</Run> <LineBreak/> <Run FontSize="20" Foreground="Blue">MediaElement的AudioCategory屬性設定為BackgroundCapableMedia或Communications</Run> <LineBreak/> <Run FontSize="20">註冊MediaControl的控制事件</Run> </TextBlock> <StackPanel Orientation="Horizontal" Margin="3,4,3,0"> <Button Content="選擇音頻檔案" Click="onSelectFile"/> <Button x:Name="btnPlayorPause" Content="播放" Click="onPlayOrPause" Margin="12,0,0,0"/> <Button Content="停止" Click="onStop" Margin="8,0,0,0"/> <TextBlock x:Name="tbMessage" Margin="30,0,0,0"/> </StackPanel> </StackPanel> <MediaElement x:Name="myMediaElement" Width="0" Height="0" Opacity="0" AudioCategory="BackgroundCapableMedia" AutoPlay="False" CurrentStateChanged="myMediaElement_CurrentStateChanged_1" MediaFailed="myMediaElement_MediaFailed_1" MediaEnded="myMediaElement_MediaEnded_1" MediaOpened="myMediaElement_MediaOpened_1"/> </Grid></Page>
4、切換程式碼檢視,上面有幾個事件要處理。
using System;using System.Collections.Generic;using System.IO;using System.Linq;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;// 引入以下命名空間using Windows.Media;using Windows.Storage;using Windows.Storage.Pickers;using Windows.Storage.Streams;namespace BackgroundAudioExample{ public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } private string MusicTitle = string.Empty;//音樂標題 private string MusicArtist = string.Empty;//演唱者 private void myMediaElement_CurrentStateChanged_1(object sender, RoutedEventArgs e) { switch (this.myMediaElement.CurrentState) { case MediaElementState.Buffering: tbMessage.Text = "載入中。"; break; case MediaElementState.Closed: tbMessage.Text = "已關閉。"; MediaControl.IsPlaying = false; break; case MediaElementState.Opening: tbMessage.Text = "正在開啟媒體。"; break; case MediaElementState.Paused: MediaControl.IsPlaying = false; tbMessage.Text = "已暫停。"; btnPlayorPause.Content = "播放"; break; case MediaElementState.Playing: MediaControl.IsPlaying = true; tbMessage.Text = "現正播放。"; btnPlayorPause.Content = "暫停"; break; case MediaElementState.Stopped: MediaControl.IsPlaying = false; tbMessage.Text = "已停止"; btnPlayorPause.Content = "播放"; break; default: break; } } private void myMediaElement_MediaFailed_1(object sender, ExceptionRoutedEventArgs e) { tbMessage.Text = "播放音頻失敗,請檢查人品。"; } private void myMediaElement_MediaEnded_1(object sender, RoutedEventArgs e) { // 播放完了,就解除事件綁定吧 MediaControl.PlayPressed -= MediaControl_PlayPressed; MediaControl.PlayPauseTogglePressed -= MediaControl_PlayPauseTogglePressed; MediaControl.PausePressed -= MediaControl_PausePressed; MediaControl.StopPressed -= MediaControl_StopPressed; } private void myMediaElement_MediaOpened_1(object sender, RoutedEventArgs e) { // 註冊播放控制項事件 MediaControl.PlayPressed += MediaControl_PlayPressed; MediaControl.PlayPauseTogglePressed += MediaControl_PlayPauseTogglePressed; MediaControl.PausePressed += MediaControl_PausePressed; MediaControl.StopPressed += MediaControl_StopPressed; // 顯示歌曲標題和歌手名字 MediaControl.TrackName = this.MusicTitle; MediaControl.ArtistName = this.MusicArtist; } async void MediaControl_StopPressed(object sender, object e) { await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { this.myMediaElement.Stop(); }); } async void MediaControl_PausePressed(object sender, object e) { await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { this.myMediaElement.Pause(); }); } async void MediaControl_PlayPauseTogglePressed(object sender, object e) { await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { onPlayOrPause(null, null); }); } async void MediaControl_PlayPressed(object sender, object e) { await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { this.myMediaElement.Play(); }); } private async void onSelectFile(object sender, RoutedEventArgs e) { FileOpenPicker picker = new FileOpenPicker(); picker.FileTypeFilter.Add(".mp3"); picker.FileTypeFilter.Add(".wma"); picker.SuggestedStartLocation = PickerLocationId.MusicLibrary; StorageFile audioFile = await picker.PickSingleFileAsync(); if (audioFile != null) { // 擷取音頻檔案的屬性 var musickProperty = await audioFile.Properties.GetMusicPropertiesAsync(); this.MusicTitle = musickProperty.Title; if (!string.IsNullOrEmpty(musickProperty.AlbumArtist)) { this.MusicArtist = musickProperty.AlbumArtist; } else { this.MusicArtist = musickProperty.Artist; } // 設定播放源 var stream = await audioFile.OpenAsync(FileAccessMode.Read); this.myMediaElement.SetSource(stream, audioFile.FileType); } } private void onPlayOrPause(object sender, RoutedEventArgs e) { if (this.myMediaElement.CurrentState == MediaElementState.Playing) { this.myMediaElement.Pause(); } else { this.myMediaElement.Play(); } } private void onStop(object sender, RoutedEventArgs e) { this.myMediaElement.Stop(); } }}
代碼我們稍候再總結,現在我們迫不及待地想看一下,實驗是否成功。果斷運行吧。
在你的電腦上隨便選一個MP3檔案,然後點擊播放,然後切換到“開始”螢幕,看看音樂是不是繼續播放?如果是,那麼實驗就成功了。
如果你的筆記本鍵盤有多媒體修飾鍵,在任務螢幕,按下“音量”修飾鍵,就會在螢幕上看到如的控制按鈕。
好了,後台播放大體情況就這樣。
大家不妨測試一下,在本例中,如果你只是把MediaElement的AudioCategory屬性設定為BackgroundCapableMedia,而不註冊MediaControl類的事件處理,你會發現,是不能在背景播放的。
MediaControl類位於Windows.Media命名空間,要完成音訊後台播放和控制,少不了這個類。它是一個static類,所以你能想到它的所有成員都是靜態,它有N多個事件,如下面所示,大家不妨開啟“物件瀏覽器”研究一下。
在我們本次實驗中,只註冊了4個事件,也是最基本的4個,大家可以試一下,注釋掉其中一個,都不能後台播放,所以,這4個事件是必須的,其他的是可選。
比較好一個處理方案是在有MediaElement的頁面的Loaded事件中註冊這些事件處理,在UnLoaded中釋放。不過本例有所不同,本例是在媒體開啟時註冊,媒體關閉時釋放,因為本例只播放一個音頻。所以沒有“上一首”,“下一首”。