MediaElement,一个可以播放音频或视频的控件,继承于FrameworkElement基类。MediaElement包含了常见的音频或视频格式,如果您需要更强大的功能,可以考虑使用VLC库。
官方说明
MediaElement 可以在两种不同的模式下使用,具体取决于驱动控件的内容:独立模式或时钟模式。 在独立模式下使用 时, MediaElement 类似于图像, Source 可以直接指定 URI。 在时钟模式下, MediaElement 可以将 视为动画的目标,因此它将在计时树中具有相应的 Timeline 和 Clock 条目。
一、MediaElement的定义
public class MediaElement : FrameworkElement, IUriContext
{
    public static readonly DependencyProperty SourceProperty;
    public static readonly RoutedEvent ScriptCommandEvent;
    public static readonly RoutedEvent BufferingEndedEvent;
    public static readonly RoutedEvent BufferingStartedEvent;
    public static readonly RoutedEvent MediaOpenedEvent;
    public static readonly RoutedEvent MediaFailedEvent;
    public static readonly DependencyProperty StretchDirectionProperty;
    public static readonly RoutedEvent MediaEndedEvent;
    public static readonly DependencyProperty LoadedBehaviorProperty;
    public static readonly DependencyProperty UnloadedBehaviorProperty;
    public static readonly DependencyProperty ScrubbingEnabledProperty;
    public static readonly DependencyProperty IsMutedProperty;
    public static readonly DependencyProperty BalanceProperty;
    public static readonly DependencyProperty VolumeProperty;
    public static readonly DependencyProperty StretchProperty;
    public MediaElement();
    public MediaState LoadedBehavior { get; set; }
    public bool CanPause { get; }
    public bool IsBuffering { get; }
    public double DownloadProgress { get; }
    public double BufferingProgress { get; }
    public int NaturalVideoHeight { get; }
    public Duration NaturalDuration { get; }
    public bool HasAudio { get; }
    public bool HasVideo { get; }
    public TimeSpan Position { get; set; }
    public double SpeedRatio { get; set; }
    public MediaState UnloadedBehavior { get; set; }
    public int NaturalVideoWidth { get; }
    public bool ScrubbingEnabled { get; set; }
    public MediaClock Clock { get; set; }
    public double Balance { get; set; }
    public double Volume { get; set; }
    public StretchDirection StretchDirection { get; set; }
    public Stretch Stretch { get; set; }
    public Uri Source { get; set; }
    public bool IsMuted { get; set; }
    public event RoutedEventHandler BufferingEnded;
    public event RoutedEventHandler BufferingStarted;
    public event RoutedEventHandler MediaOpened;
    public event EventHandler<ExceptionRoutedEventArgs> MediaFailed;
    public event RoutedEventHandler MediaEnded;
    public event EventHandler<MediaScriptCommandRoutedEventArgs> ScriptCommand;
    public void Close();
    public void Pause();
    public void Play();
    public void Stop();
    protected override Size ArrangeOverride(Size finalSize);
    protected override Size MeasureOverride(Size availableSize);
    protected override AutomationPeer OnCreateAutomationPeer();
    protected override void OnRender(DrawingContext drawingContext);
}
二、属性成员
| 属性名称 | 说明 | 
| LoadedBehavior | 获取或设置加载媒体的行为,如果加载希望手动控制播放,请设置为Manual。 | 
| CanPause | 获取一个值,该值指示是否可以暂停媒体。 | 
| IsBuffering | 获取一个值,该值指示是否缓冲媒体。 | 
| DownloadProgress | 获取一个百分比值,该值为位于远程服务器上的内容完成的下载量。 | 
| BufferingProgress | 获取一个值,该值指示缓冲进度的百分比。0-1之间 | 
| NaturalVideoHeight | 获取与媒体关联的视频的高度。 | 
| NaturalDuration | 获取介质的自然持续时间。也就是视频播放总时长。 | 
| HasAudio | 获取一个值,该值指示媒体是否具有音频。 | 
| HasVideo | 获取一个值,该值指示媒体是否具有视频。 | 
| Position | 通过媒体的播放时间获取或设置进度的当前位置。 | 
| SpeedRatio | 获取或设置媒体的速率。也就是按几倍播放视频。 | 
| UnloadedBehavior | 获取或设置卸载媒体的行为。 | 
| NaturalVideoWidth | 获取与媒体关联的视频的宽度。 | 
| ScrubbingEnabled | 获取或设置一个值,该值指示MediaElement 是否将更新帧的查找操作在暂停状态。 | 
| Clock | 获取或设置MediaElement 媒体播放相关联的时钟。 | 
| Balance | 获取或设置扬声器的音量比。 | 
| Volume | 获取或设置媒体的音量。0-1之间,默认0.5 | 
| StretchDirection | 获取或设置一个值,确定扩展的限制应用于映像。 | 
| Stretch | 获取或设置MediaElement媒体的拉伸方式。 | 
| Source | 获取或设置MediaElement媒体源[重点] | 
| IsMuted | 是否静音 | 
三、事件成员
| 事件名称 | 说明 | 
| BufferingEnded | 媒体缓冲结束时发生。 | 
| BufferingStarted | 媒体缓冲开始时发生。 | 
| MediaOpened | 媒体加载已完成时发生。 | 
| MediaFailed | 遇到错误时发生。 | 
| MediaEnded | 媒体结束时发生。 | 
| ScriptCommand | 在媒体中遇到的脚本命令时发生。 | 
四、MediaElement示例
我们以MediaElement的独立模式为例,开发一个基础版本的视频播放器,该项目将会用到MediaElement、Gird、Border、TextBlock、Button、Slider、ProgressBar等控件,也算是对之前学过的控件章节一次总结和回顾。
前端代码
<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:HelloWorld"
        mc:Ignorable="d" FontSize="14"
        Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="400" Width="550">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Grid>
            <MediaElement x:Name="_MediaElement" LoadedBehavior="Manual" />
            <Border x:Name="_Border" Background="Black">
                <TextBlock x:Name="_TextBlock" Text="MediaElement | 媒体播放器" Foreground="LightCoral" FontSize="20"
                           HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Border>
        </Grid>
        
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <Button Content="打开" Width="60" Height="25" Margin="5" Click="OpenMedia"/>
            <Button Content="播放" Width="60" Height="25" Margin="5" Click="PlayMedia"/>
            <Button Content="停止" Width="60" Height="25" Margin="5" Click="StopMedia"/>
            <Button Content="后退" Width="60" Height="25" Margin="5" Click="BackMedia"/>
            <Button Content="前进" Width="60" Height="25" Margin="5" Click="ForwardMedia"/>
            <TextBlock Text="音量" VerticalAlignment="Center" Margin="5"/>
            <Slider x:Name="_Slider" Width="120" VerticalAlignment="Center" Maximum="100" Value="50" ValueChanged="_Slider_ValueChanged"/>
        </StackPanel>
        <Grid Grid.Row="2">
            <ProgressBar x:Name="_ProgressBar" Height="10" Margin="5"/>
        </Grid>
    </Grid>
</Window>
后端代码
using System;
using System.Windows;
using System.Windows.Threading;
namespace HelloWorld
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private string file = string.Empty;
        public MainWindow()
        {
            InitializeComponent();
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(1000);
            timer.Tick += (s, e) =>
            {
                var ts = _MediaElement.Position;
                _ProgressBar.Value = ts.TotalMilliseconds;//更新当前播放进度
            };
            timer.Start();
        }
        private void OpenMedia(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new Microsoft.Win32.OpenFileDialog()
            {
                Filter = "视频文件 (.mp4)|*.mp4",
                Multiselect = true
            };
            var result = openFileDialog.ShowDialog();
            if (result == true)
            {
                file = openFileDialog.FileName;
                _MediaElement.MediaOpened += _MediaElement_MediaOpened;
                _MediaElement.Source = new System.Uri(file);
                this.Title = file;
                _TextBlock.Text = file;
            }
        }
        private void _MediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            if (_MediaElement.NaturalDuration.HasTimeSpan)
            {
                var ts = _MediaElement.NaturalDuration.TimeSpan;
                _ProgressBar.Maximum = ts.TotalMilliseconds;//设置播放进度条总长
            }
        }
        private void PlayMedia(object sender, RoutedEventArgs e)
        {
            _MediaElement.Play();//播放
            _Border.Visibility = Visibility.Collapsed;            
           
        }
        private void StopMedia(object sender, RoutedEventArgs e)
        {
            _MediaElement.Pause();//暂停
        }
        private void BackMedia(object sender, RoutedEventArgs e)
        {
            _MediaElement.Position = _MediaElement.Position - TimeSpan.FromSeconds(10);//快退10秒
        }
        private void ForwardMedia(object sender, RoutedEventArgs e)
        {
            _MediaElement.Position = _MediaElement.Position + TimeSpan.FromSeconds(10);//快进10秒
        }
        private void _Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            _MediaElement.Volume = _Slider.Value;//设置音量
        }
    }
}

如图所示,我们将前面所学的控件知识综合利用起来,设计出一款播放界面。MediaElement控件没有Background属性,所以我们放了一个Border控件(黑色背景)在MediaElement控件的上方,待加载视频并播放时,将Border隐藏起来。
在后端C#语言中,我们在构造函数里通过DispatcherTimer 开启了一个子线程,用以更新当前播放进度。DispatcherTimer是运行在UI线程上的定时器,可以直接更新UI元素,不会引发跨线程调用的异常。
在打开视频业务中,我们采用Microsoft.Win32.OpenFileDialog去获取视频文件地址,然后创建一个Uri实例,最后把这个实例赋值给MediaElement的Source属性。

最后,我们只需要调用MediaElement提供的一系列方法成员,比如Play()、Pause()、或设置播放位置的Position属性。好,关于MediaElement控件就先介绍到这里啦。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:037-《MediaElement媒体播放器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年8月31日
			
									WPF中文网