mediaelement 播放本地视频需设 loadedbehavior、用绝对/正确 pack:// 路径、绑定 viewmodel 属性并监听 mediafailed;全屏需无边框窗口手动管理;进度/音量控制应防抖、暂停后 seek、延时更新。

用 MediaElement 播放本地视频是最直接的方式
WPF 自带的 MediaElement 控件能直接加载本地文件、网络地址甚至内存流,不需要额外引用第三方库。它底层调用 Windows Media Foundation,对 MP4(H.264+AAC)、WMV、AVI 等常见格式支持稳定,但不支持 WebM 或纯 VP9 视频。
关键点:必须设置 LoadedBehavior="Manual" 或 "Play",否则控件初始化后不会自动加载媒体;路径要用绝对路径或相对路径(需确保运行时工作目录正确)。
-
Source属性只接受 URI 字符串,不能传FileInfo或 byte[];若视频在项目资源中,得先复制到输出目录并设Copy to Output Directory = Copy always - 播放前建议检查
MediaElement.LoadedBehavior == MediaState.Manual,否则调用Play()会静默失败 - 如果视频黑屏但有声音,大概率是解码器缺失(比如没装 HEVC 扩展)或硬件加速冲突,可尝试加
RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.NearestNeighbor)临时绕过
绑定视频路径时别直接写死字符串,用 Binding + INotifyPropertyChanged
硬编码 Source="pack://application:,,,/Assets/demo.mp4" 看似简单,但换环境、改资源结构就容易崩。真实项目里推荐把路径抽成 ViewModel 属性,靠数据绑定驱动。
注意 pack:// 协议的写法细节:application 表示当前程序集,siteoforigin 表示启动目录;若视频放在子文件夹,路径要写成 pack://application:,,,/Assets/Video/demo.mp4,漏掉斜杠或大小写错误都会导致 MediaFailed 事件触发。
- 绑定后记得监听
MediaElement.MediaFailed事件,错误信息通常在e.ErrorException.Message里,常见如 “The specified media is not supported” 或 “Access is denied” - 若用 MVVM,ViewModel 中路径属性变更后,必须触发
PropertyChanged,否则 UI 不更新 —— 这个坑很多人栽在调试半天发现只是忘了OnPropertyChanged() - 不要在
MediaOpened里立刻调用Position获取时长,得等MediaElement.HasVideo为true后再读NaturalDuration,否则返回Automatic
全屏播放时 MediaElement 会脱离 WPF 渲染树,需手动处理尺寸和焦点
WPF 的 MediaElement 在全屏模式下实际由系统渲染器接管,不再走 WPF 的布局逻辑。这意味着你不能靠 Stretch="Uniform" 或 Grid.RowSpan 控制它的显示区域,也不能响应鼠标事件(比如点击暂停)。
解决方案是:全屏时不真“全屏”,而是用一个无边框窗口覆盖整个屏幕,把 MediaElement 放进去,并手动同步窗口尺寸与视频宽高比。Windows 10+ 上还可启用 IsManipulationEnabled="True" 配合手势缩放,但要注意触摸事件和键盘焦点的冲突。
- 调用
WindowStyle="None"+WindowState="Maximized"后,必须设Topmost="True",否则任务栏可能遮挡视频 - 按 Esc 退出全屏时,别只改
WindowState,还得重置MediaElement.Width和Height,否则恢复窗口后画面拉伸变形 - 某些显卡驱动下,全屏时右键菜单或系统快捷键(Win+D)会导致
MediaElement卡住,建议监听Deactivated事件并主动Pause()
想控制进度条或音量?别直接拖 Slider,要双向绑定 + 事件防抖
把 Slider.Value 绑定到 MediaElement.Position.TotalSeconds 看起来合理,但实际会因精度丢失、异步加载、Seek 不精确等问题频繁跳变。更稳的做法是:Slider 拖动时暂停播放,松手后再 Seek 并恢复。
音量控制同理,MediaElement.Volume 是 double 类型(0.0–1.0),但系统音量调节有滞后,连续快速拖动 Slider 容易触发多次 ValueChanged,造成卡顿。
- 给 Slider 加
IsMoveToPointEnabled="True",避免用户必须拖到刻度点才能生效 - 在
Slider.PreviewMouseLeftButtonUp里调用MediaElement.Seek(),而不是ValueChanged,减少无效 Seek - 音量 Slider 最好加个
Delay="100"(通过附加属性模拟),防止每像素移动都写一次Volume - 进度条最大值应绑定
MediaElement.NaturalDuration.TimeSpan.TotalSeconds,但首次获取可能为 0,需等MediaOpened后再更新绑定










