內容摘要:
這是之前有一個朋友項目中實際遇到的問題:在一個窗口中,希望點擊某個按鈕后(或者同類操作),播放一個警告的聲音,很顯然,這個音頻播放是用異步來實現。但又希望播放一段時間后,自動地停止播放。
這個問題要說難也不是很難,我們無非是要想辦法做一個計時,到達規定時候(例如5秒)后,強制地將線程結束掉。問題出在如何寫較為理想些。
問題分析:
播放音頻本身不難,而且在WPF中,音頻播放默認就是異步的,根本不需要我們單獨去啟動線程。代碼大致如下
var player = new SoundPlayer(); player.SoundLocation = "bell.wav"; player.PlayLooping();
這里的player一般會有兩個方法:Play 和PlayLooping。前者是播放一次,后者是一直播放。但他們都是異步執行的。
如果需要同步執行,則倒是需要調用PlaySync,考慮到播放音頻可能需要的時間較長,一般是不建議用同步的方式的。
而player本身有一個Stop方法,可以終止播放(同時也會將線程關閉或者歸還到線程池)。
所以,問題的關鍵就在於,如何在規定的時間后,調用player.Stop方法。
常規做法:
從最簡單粗暴的角度出發,我們可以用一個定時器,定時一定時間(例如5秒鍾),到了這個時間,就調用player.Stop方法,並且將定時器也停止掉。(所以其實這個定時器只會被觸發一次,我們用它的目的只是希望它能在5秒鍾后被喚醒起來做事情)
var player = new SoundPlayer(); player.SoundLocation = "bell.wav"; var timer = new DispatcherTimer(TimeSpan.FromSeconds(5), DispatcherPriority.Normal, (source, args) => { player.Stop(); ((DispatcherTimer)source).Stop(); }, this.Dispatcher); timer.Start(); player.PlayLooping();
看起來怎么樣呢?問題肯定是解決了。但是有沒有更好的方法呢?
引入Reactive Extensions:
我聯想到之前我正好在研究Reactive Extensions(簡稱Rx),這是微軟提供的一個針對異步和事件處理的增強框架。它的官方地址在:http://msdn.microsoft.com/en-us/data/gg577609.aspx ,目前最新的版本是2.0.
Reactive Extensions提供了一種全新的視角,讓我們來處理事件,和異步任務。它首先是對異步處理和事件進行了一些包裝,然后,它的核心是,通過Obserable和Observer的機制,實現所謂響應式的編程體驗。最后,它結合Linq,提供了語法上面的極大便利。
我對Reactive Extensions的研究也還算不上透徹,逐漸會有一些更多的分享出來吧。這個問題正好遇到了,所以想到可能用Rx來做,代碼會更加易於閱讀,本質上肯定也是有一個等待的過程,但不用Timer去做了。
你可以直接在Visual Studio中導入幾個Rx的Package
解決方案:
我最終的解決方案如下。你覺得怎么樣?是否有更加好的做法呢?
Observable.Start<SoundPlayer>(() => { var player = new SoundPlayer(); player.SoundLocation = "bell.wav"; player.PlayLooping(); return player; }).Delay(TimeSpan.FromSeconds(5)).Subscribe(player => player.Stop());
【備注】本來想要做一個視頻的,但因為近日都在外講課,嗓子要盡量保護。所以就通過文字寫出來吧
完整代碼請通過這里下載 http://files.cnblogs.com/chenxizhang/WpfApplicationSample-rx.zip