媒體呈現是 App 體驗核心。WinRT 提供 Image(靜態圖片)與 MediaElement(影音播放)兩大控件。本文深入解析 Image 的四種拉伸模式、九宮格 防止邊框變形、多種圖片來源載入方式;以及 MediaElement 的豐富播放控制、狀態監聽、串流來源指定、倍速播放、多音軌切換等進階功能。
| 模式 | 行為 | 保留比例 |
|---|---|---|
Fill | 填滿容器,可能變形 | 否 |
None | 原始尺寸,超出容器被裁剪 | 是 |
Uniform | 等比縮放至容器內(預設) | 是 |
UniformToFill | 等比縮放填滿容器,超出部分裁剪 | 是 |
<StackPanel Orientation="Horizontal" Margin="120 0 0 0">
<Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100">
<Image Source="/Assets/Logo.png" Stretch="Fill" Width="200" Height="100"/>
</Border>
<Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">
<Image Source="/Assets/Logo.png" Stretch="None" Width="200" Height="100"/>
</Border>
<Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">
<Image Source="/Assets/Logo.png" Stretch="Uniform" Width="200" Height="100"/>
</Border>
<Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">
<Image x:Name="myImage" Stretch="UniformToFill" Width="200" Height="100"/>
</Border>
</StackPanel>
private void ImageDemo_Loaded(object sender, RoutedEventArgs e)
{
// 方式 1:BitmapImage + ms-appx URI
myImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/Logo.png", UriKind.Absolute));
// 方式 2:RandomAccessStreamReference + IRandomAccessStream
// var streamRef = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Logo.png", UriKind.Absolute));
// var stream = await streamRef.OpenReadAsync();
// var bitmap = new BitmapImage();
// bitmap.SetSource(stream);
// myImage.Source = bitmap;
}
NineGrid 以 Thickness 格式指定四條切割線(左、上、右、下),四角不縮放、邊緣單向縮放、中心雙向縮放。適用於按鈕背景、對話框邊框、進度條軌道等。
<StackPanel Orientation="Horizontal" Margin="0 50 0 0">
<!-- 無九宮格:邊框被拉伸變粗 -->
<Image Source="/Assets/NineGrid/Demo.png" Width="200" Height="200"/>
<!-- 九宮格 1,1,1,1:四邊各保留 1 像素不縮放 -->
<Image Source="/Assets/NineGrid/Demo.png" Width="200" Height="200"
NineGrid="1 1 1 1" Margin="20 0 0 0"/>
</StackPanel>
Source / SetSource(stream, mimeType):本地檔案或網路串流AutoPlay:載入後自動播放(預設 true)Play()、Pause()、Stop()Position:目前播放位置(TimeSpan,可設定 Seek)CanSeek、CanPause:媒體能力查詢| 場景 | DefaultPlaybackRate | PlaybackRate |
|---|---|---|
| 正常播放 | 1 | 1 |
| 2 倍速快轉 | 0 | 2 |
| 1 倍速倒轉 | 0 | -1 |
💡 規則:PlaybackRate != 1 時,必須先將 DefaultPlaybackRate = 0。
Volume (0~1)、Balance (-1~1)、IsMutedAudioCategory:ForegroundOnlyMedia(前台)、BackgroundCapableMedia(支援背景播放)AudioStreamCount、AudioStreamIndex、GetAudioStreamLanguage(index):多音軌切換AudioDeviceType:輸出裝置類型NaturalVideoWidth/Height、AspectRatioWidth/Height:原始解析度與比例PosterSource:影片載入前顯示的佔位圖(同 HTML5 video poster)IsAudioOnly:純音訊為 trueDownloadProgress (0~1):下載進度DownloadProgressOffset:Seek 後重新連線的偏移比例BufferingProgress (0~1):緩衝進度,達 1 可播放MediaOpened、MediaEnded、MediaFailedCurrentStateChanged:Closed/Opening/Buffering/Playing/Paused/StoppedDownloadProgressChanged、BufferingProgressChangedRateChanged、VolumeChanged、MarkerReached(時間標記)<StackPanel Orientation="Horizontal" Margin="120 0 0 0">
<StackPanel>
<Button x:Name="btnPickFile" Content="播放本地影音" Click="btnPickFile_Click"/>
<Button x:Name="btnPlayUrl" Content="播放網路影片" Click="btnPlayUrl_Click" Margin="0 10 0 0"/>
<StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<Button x:Name="btnPlay" Content="播放" Margin="0 0 10 0" Click="btnPlay_Click"/>
<Button x:Name="btnPause" Content="暫停" Margin="0 0 10 0" Click="btnPause_Click"/>
<Button x:Name="btnStop" Content="停止" Margin="0 0 10 0" Click="btnStop_Click"/>
</StackPanel>
<MediaElement x:Name="mediaElement" AutoPlay="True"
PosterSource="/Assets/Logo.png"
Width="480" Height="320"
HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="0 10 0 0"/>
</StackPanel>
<TextBlock x:Name="lblMsg" FontSize="14.667" Margin="10 0 0 0"/>
</StackPanel>
public sealed partial class MediaElementDemo : Page
{
public MediaElementDemo()
{
this.InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
timer.Tick += dTimer_Tick;
timer.Start();
}
void dTimer_Tick(object sender, object e)
{
lblMsg.Text = "Source: " + mediaElement.Source + "\n";
lblMsg.Text += "PosterSource: " + mediaElement.PosterSource + "\n";
lblMsg.Text += "CurrentState: " + mediaElement.CurrentState + "\n";
lblMsg.Text += "Position: " + mediaElement.Position + "\n";
lblMsg.Text += "DownloadProgress: " + mediaElement.DownloadProgress + "\n";
lblMsg.Text += "DownloadProgressOffset: " + mediaElement.DownloadProgressOffset + "\n";
lblMsg.Text += "BufferingProgress: " + mediaElement.BufferingProgress + "\n";
lblMsg.Text += "DefaultPlaybackRate: " + mediaElement.DefaultPlaybackRate + "\n";
lblMsg.Text += "PlaybackRate: " + mediaElement.PlaybackRate + "\n";
lblMsg.Text += "CanSeek: " + mediaElement.CanSeek + "\n";
lblMsg.Text += "CanPause: " + mediaElement.CanPause + "\n";
lblMsg.Text += "NaturalDuration: " + mediaElement.NaturalDuration + "\n";
lblMsg.Text += "NaturalVideoWidth: " + mediaElement.NaturalVideoWidth + "\n";
lblMsg.Text += "NaturalVideoHeight: " + mediaElement.NaturalVideoHeight + "\n";
lblMsg.Text += "AspectRatioWidth: " + mediaElement.AspectRatioWidth + "\n";
lblMsg.Text += "AspectRatioHeight: " + mediaElement.AspectRatioHeight + "\n";
lblMsg.Text += "AutoPlay: " + mediaElement.AutoPlay + "\n";
lblMsg.Text += "IsLooping: " + mediaElement.IsLooping + "\n";
lblMsg.Text += "Volume: " + mediaElement.Volume + "\n";
lblMsg.Text += "Balance: " + mediaElement.Balance + "\n";
lblMsg.Text += "IsMuted: " + mediaElement.IsMuted + "\n";
lblMsg.Text += "IsAudioOnly: " + mediaElement.IsAudioOnly + "\n";
lblMsg.Text += "AudioCategory: " + mediaElement.AudioCategory + "\n";
lblMsg.Text += "AudioStreamCount: " + mediaElement.AudioStreamCount + "\n";
lblMsg.Text += "AudioStreamIndex: " + mediaElement.AudioStreamIndex + "\n";
lblMsg.Text += "AudioDeviceType: " + mediaElement.AudioDeviceType + "\n";
}
private async void btnPickFile_Click(object sender, RoutedEventArgs e)
{
var picker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.VideosLibrary
};
picker.FileTypeFilter.Add(".wmv");
picker.FileTypeFilter.Add(".mp4");
picker.FileTypeFilter.Add(".mp3");
picker.FileTypeFilter.Add(".wma");
var file = await picker.PickSingleFileAsync();
if (file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
mediaElement.SetSource(stream, file.ContentType);
}
}
private void btnPlayUrl_Click(object sender, RoutedEventArgs e)
{
mediaElement.Source = new Uri("https://media.w3.org/2010/05/sintel/trailer.mp4", UriKind.Absolute);
}
private void btnPlay_Click(object sender, RoutedEventArgs e) => mediaElement.Play();
private void btnPause_Click(object sender, RoutedEventArgs e) => mediaElement.Pause();
private void btnStop_Click(object sender, RoutedEventArgs e) => mediaElement.Stop();
}
// 回傳 "Probably" / "Maybe" / ""
var likelihood = mediaElement.CanPlayType("video/mp4");
Stretch 模式按需選擇,NineGrid 完美解決邊框縮放變形,支援 ms-appx/ms-appdata/http/串流多種來源Stop() 並設 Source=null掌握這兩大控件,即可構建圖文並茂、影音豐富的現代化 App 體驗。