--- tags: 110-2視窗程式設計 --- # 實作幾種操作功能 我們已經初步完成基本影音播放程式的介面,並且實現最基本的開啟檔案,播放媒體。 接下來我們讓程式完整一些,增加幾種的操作功能。 ## 播放、暫停、停止按鍵 這部分不難,當然請先把這些按鍵的功能作功能綁定。 ![](https://i.imgur.com/QzP3gXB.png) 再將以下程式碼放進去 ```csharp= private void btnPlay_Click(object sender, RoutedEventArgs e) { // 設定影音播放狀態為「Play」,將狀態設定到目前的讀取行為 MedShow.LoadedBehavior = MediaState.Play; } private void btnPause_Click(object sender, RoutedEventArgs e) { // 設定影音播放狀態為「Pause」,將狀態設定到目前的讀取行為 MedShow.LoadedBehavior = MediaState.Pause; } private void btnStop_Click(object sender, RoutedEventArgs e) { // 設定影音播放狀態為「Stop」,將狀態設定到目前的讀取行為 MedShow.LoadedBehavior = MediaState.Stop; } ``` 你可以發現,其實很簡單,就只是設定影音播放狀態,然後將影音元件的讀取行為設定進去就可以了。 這時你測試程式,你可以將影片設定暫停播放,或者全部停止,然後繼續播放等動作。 ## 離開按鍵 這裡的離開按鍵等同於關閉整個程式,語法如下。你也可以發現不難,而且要做類似的功能都可以用相同的語法) ```csharp= private void btnExit_Click(object sender, RoutedEventArgs e) { Environment.Exit(0); // 關閉整個程式的指令 } ``` ## 聲音大小調整,使用控制項:滑桿元件 請同學再到「工具箱」拖一個「Slider(滑桿元件)」控制項進來,「滑桿元件」是一個可以調整高低程度的元件,可以用來讓使用者調整數量上的大小。你可以調整大小,調整成你想要的大小,就像下圖的樣子。 也別忘了給他一個名稱「sliVolume」。 ![](https://i.imgur.com/7bEdqIT.png) ![](https://i.imgur.com/hv44ju3.png) 設定好之後,我們來初步瞭解他的內容,先跟同學說明,Maximum與Minimum是指滑桿移到最左邊的最小值與最右邊的最大值各為多少,Value則是設定滑桿現在的值是多少? ![](https://i.imgur.com/FxgR8oF.png) 為什麼要先跟同學說明這個,因為如果我們想調整聲音大小,可以直接設定最大值最小值是什麼就可以了,由於影音元件的聲音大小最小是0,最大則是1,所以我們可以把滑桿元件的設定改為以下: ![](https://i.imgur.com/dMZdKeB.png) 接下來要綁定這個滑桿元件的事件綁定,請選擇的事件為「ValueChanged」,白話文就是「當數值改變時」,這樣我們可以在使用者拉動滑桿改變數值時,同時也改變影音播放的聲音大小。 ![](https://i.imgur.com/6xig4Ln.png) 再請同學將以下程式加入,現在你應該可以發現可以自由調整聲音大小。 ```csharp= private void sliVolume_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { MedShow.Volume = sliVolume.Value; // 設定聲音大小 //txtFilePath.Text = MedShow.Volume.ToString(); } ``` ## 稍微難一點的:影音播放進度調整 接下來我們帶同學實作一個稍微難一點的功能,影音播放軟體通常都有一個必備功能,就是可以調整播放進度,讓我們可以快轉與倒轉影音。 我們也是使用「滑桿元件」,就像下面的設計,請將這個滑桿改名叫「sliProgress」,你可以改一改它的底色,不過其他設定就不用調整。 ![](https://i.imgur.com/YPP0Kwu.png) 再來就要設定事件綁定,不過你**需要設定影音元件的「MediaOpened」事件**,白話文就是「**當影音媒體被開啟的時候**」。 ![](https://i.imgur.com/nyjcq76.png) 為什麼要選這個事件呢?原因很簡單,每一個影音媒體長度都不一定,如果是音樂或許只有五、六分鐘,但是影片可能長達一兩個小時。 滑桿因為長度都是固定的,所以你就需要設定滑桿的最大與最小值,才能符合既有的滑桿長度設定。所以==我們需要在「影音檔案開啟的時間點」,找出這個影音檔案的總播放時間長度==,設定為滑桿的最大值,這裡我們取得影片的總毫秒數來設定。 除此之外,我們也需要設定一個「**計時器(Timer)**」,這個計時器要用來計算目前影片播放的進度,然後我們要同時顯示在滑桿上面,才能實現那種影片播放的同時,滑桿也跟著往右邊移動的效果。 要使用「計時器」則需要使用「**using System.Windows.Threading**」函式庫,請將以下程式碼放到程式上方引用函式庫的片段。 ```csharp using System.Windows.Threading; ``` ### 程式說明 以下便是範例程式碼。 ```csharp= TimeSpan TimePosition; // 宣告一個時間間格 DispatcherTimer timer = null; // 宣告一個「空的」計時器 private void MedShow_MediaOpened(object sender, RoutedEventArgs e) { // 取得所開啟的影片時間長度 TimePosition = MedShow.NaturalDuration.TimeSpan; // 重新設定影片播放滑桿 sliProgress.Minimum = 0; sliProgress.Maximum = TimePosition.TotalMilliseconds; //最大值設定為影片的總毫秒數 // 設定計時器 timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(1); // 這個計時器設定每一個刻度為1秒 timer.Tick += new EventHandler(timer_tick); //每一個時間刻度設定一個小程序timer_tick timer.Start(); // 啟動這個計時器 } private void timer_tick(object sender, EventArgs e) { // 小程序,更新目前影片播放進度 sliProgress.Value = MedShow.Position.TotalMilliseconds; } ``` 一開始我們宣告了兩個變數,一個用來記錄影片長度的 **時間間格(TimeSpan)** 變數「TimePosition」,一個「空的」計時器(DispatcherTimer)變數「timer」。 然後在影音元件的「MediaOpened」事件設定程式,「**當影音媒體被開啟的時候**」,會抓取影片的長度存在「TimePosition」變數裡,將這個變數設定為影片播放滑桿的最大值,這樣才能在滑動滑桿的時候取得適當的長度來設定影片播放位置。 其中要說明的是,什麼是「**時間間格(TimeSpan)**」,它其實是一種標準的時間規格變數,你可以依照「**天、小時、分、秒、毫秒**」的數值,來設定一個時間長度。假設你要設定一個時間長度,你只要這樣宣告就好了: ```csharp TimeSpan ts1 = new TimeSpan(4, 20, 33); //將時間間隔ts1初始化爲4小時20分33秒 TimeSpan ts2 = new TimeSpan(2, 10, 36, 45); //將時間間隔ts2初始化爲2天10小時36分45秒 TimeSpan ts3 = new TimeSpan(6, 12, 56, 45, 23); //將時間間隔ts3初始化爲6天12小時56分45秒23毫秒 ``` 所以我們可以直接取得一個影片長度,並且存到這個時間間格變數裡面。 接下來我們會設定一個計時器(DispatcherTimer)變數「timer」,我們設定為刻度為1秒的計時器,並且設定每1秒要執行一個小程序叫「time_tick」,我們讓這個小程序做的事情就放在以下的程式碼片段,做的事情就是將目前影片拍攝的進度,更新到影片進度滑桿之中。 ```csharp private void timer_tick(object sender, EventArgs e) { // 小程序,更新目前影片播放進度 sliProgress.Value = MedShow.Position.TotalMilliseconds; } ``` 現在如果你試著再開啟一個影片,應該就可以看到滑桿自己往右移動的效果。 ![](https://i.imgur.com/SntrWeU.png) ### 設定滑桿的「PreviewMouseLeftButtonUp」的事件綁定 最後我們設定滑桿的「PreviewMouseLeftButtonUp」的事件綁定,這個是指「當用滑鼠左鍵點選滑桿後的時間點」。 ![](https://i.imgur.com/4AORH9z.png) 範例程式如下: ```csharp= private void sliProgress_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { int SliderValue = (int)sliProgress.Value; // 還記得轉型嗎? TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue); //將滑桿的數值改變成時間間格的資料形式 MedShow.Position = ts; // 調整影片播放進度到新的時間 } ``` 程式的原理很簡單,首先擷取你移動滑桿後的新數值,然後轉成影片的時間,再將時間設定到目前播放的影片中。如果你往右邊拉,時間就會增加,影片播放的時間會往後,往左邊拉,時間減少,影片就會倒轉。 其中「TimeSpan」是一種用來表示時間的資料型態,你可以依照「日、時、分、秒、毫秒」的格式來定義時間,因為我們之前取得影片的總毫秒數來設定滑桿的最大值,所以抓取滑桿的數值要轉成毫秒,然後調整現在播放的影音時間。 ## 完整程式碼 :::spoiler ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace MediaPlayer { /// <summary> /// MainWindow.xaml 的互動邏輯 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void btnOpenFile_Click(object sender, RoutedEventArgs e) { // 檔案開啟物件 var fd = new Microsoft.Win32.OpenFileDialog(); // 設定檔案過濾,格式:說明文字|*.副檔名 fd.Filter = "音訊檔案(*.mp3,*.3gp,*.wma)|*.mp3; *.3gp; *.wma|影片檔案(*.mp4, *.avi, *.mpeg, *.wmv)|*.mp4; *.avi; *.mpeg; *.wmv|所有檔案(*.*)|*.*"; //fd.Filter = "MP3(*.mp3)|*.mp3|MP4(*.mp4)|*.mp4|3GP(*.3gp)|*.3gp|WMA(*.wma)|*.wma|MOV(*.mov)|*.mov|AVI(*.avi)|*.avi|WMV(*.wmv)|*.wmv|MPEG(*.mpeg)|*.mpeg|所有檔案(*.*)|*.*"; // 設定預設開啟檔案位置,設定為桌面 fd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); // 開啟對話框 fd.ShowDialog(); // 如果使用者有選取檔案,就把檔案與檔案位置儲存到filename中 string filename = fd.FileName; if (filename != "") { // 將檔案與檔案位置顯示在輸入文字框裡面 txtFilePath.Text = filename; // 將檔案與檔案位置轉化成URI,一種用來設定檔案資源定位的位置資料 Uri u = new Uri(filename); // 將URI放進影音元件中 MedShow.Source = u; // 設定這個影音的聲音大小(可有可無) MedShow.Volume = 0.5f; // 將影音進行播放 MedShow.LoadedBehavior = MediaState.Play; } } private void btnPlay_Click(object sender, RoutedEventArgs e) { // 設定影音播放狀態為「Play」,將狀態設定到目前的讀取行為 MedShow.LoadedBehavior = MediaState.Play; } private void btnPause_Click(object sender, RoutedEventArgs e) { // 設定影音播放狀態為「Pause」,將狀態設定到目前的讀取行為 MedShow.LoadedBehavior = MediaState.Pause; } private void btnStop_Click(object sender, RoutedEventArgs e) { // 設定影音播放狀態為「Stop」,將狀態設定到目前的讀取行為 MedShow.LoadedBehavior = MediaState.Stop; } private void btnExit_Click(object sender, RoutedEventArgs e) { Environment.Exit(0); // 關閉整個程式的指令 } private void sliVolume_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { MedShow.Volume = sliVolume.Value; //txtFilePath.Text = MedShow.Volume.ToString(); } TimeSpan TimePosition; // 宣告一個時間間格 DispatcherTimer timer = null; // 宣告一個「空的」計時器 private void MedShow_MediaOpened(object sender, RoutedEventArgs e) { // 取得所開啟的影片時間長度 TimePosition = MedShow.NaturalDuration.TimeSpan; // 重新設定影片播放滑桿 sliProgress.Minimum = 0; sliProgress.Maximum = TimePosition.TotalMilliseconds; //最大值設定為影片的總毫秒數 // 設定計時器 timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(1); // 這個計時器設定每一個刻度為1秒 timer.Tick += new EventHandler(timer_tick); //每一個時間刻度設定一個小程序timer_tick timer.Start(); // 啟動這個計時器 } private void timer_tick(object sender, EventArgs e) { // 小程序,更新目前影片播放進度 sliProgress.Value = MedShow.Position.TotalMilliseconds; } private void sliProgress_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { int SliderValue = (int)sliProgress.Value; // 還記得轉型嗎? TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue); //將滑桿的數值改變成時間間格的資料形式 MedShow.Position = ts; // 調整影片播放進度到新的時間 } } } ``` :::