---
# System prepended metadata

title: 實作幾種操作功能
tags: [110-2視窗程式設計]

---

---
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; // 調整影片播放進度到新的時間
        }
    }
}

```
:::