能否在 .NET 的 PictureBox 控件中使用 MediaPlayer 播放视频?
结论
不能直接把 PictureBox 指定为 WPF System.Windows.Media.MediaPlayer 的视频输出控件。要在 WinForms 窗体的指定区域播放视频,需要使用相应的视频显示组件。
如果希望视频显示在原来 PictureBox 的位置,可以将它替换为 Panel,再通过 ElementHost 承载 WPF 视频画面。
MediaPlayer 可能来自 WPF、Windows Runtime 或第三方库。由于问题没有给出完整类型名,以下说明和示例针对 System.Windows.Media.MediaPlayer。
为什么不能直接使用 PictureBox
PictureBox 通过 Image 属性接收 System.Drawing.Image 来显示图片,没有绑定 MediaPlayer 视频输出的接口,因此不能通过给 PictureBox.Image 赋值来连接播放器。PictureBox API 文档
WPF 的 MediaPlayer 负责媒体播放,本身不是界面控件,需要通过 VideoDrawing 或 DrawingContext 显示视频画面。它也没有可设置为 pictureBox1.Handle 的输出窗口属性,无法通过传入控件句柄来连接 PictureBox。WPF 多媒体概述
解决步骤
如果需要保留 WPF MediaPlayer,可以采用以下结构:
WinForms Panel
└─ ElementHost
└─ WPF Image
└─ DrawingImage
└─ VideoDrawing
└─ MediaPlayer
VideoDrawing 关联播放器,DrawingImage 将绘图内容提供给 WPF Image,再由 ElementHost 把 WPF 元素嵌入 WinForms。VideoDrawing 播放示例、DrawingImage 用法、ElementHost API 文档
- 在 WinForms 设计器中,用
Panel替换原来的PictureBox,命名为videoPanel,按需要设置位置和大小。 - 为项目启用 WPF 支持。
- 创建播放器和视频绘图对象,将显示元素放入
ElementHost。 - 打开视频文件,处理加载成功和播放失败事件,并在窗口关闭时释放媒体资源。
如果使用 SDK 风格的 Windows 桌面项目,请确认现有 .csproj 的 PropertyGroup 中包含以下设置,并且 TargetFramework 使用 Windows 目标框架:
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
这两个属性分别启用 WinForms 和 WPF。桌面项目配置说明
传统 .NET Framework 项目需要添加 WindowsFormsIntegration、PresentationCore、PresentationFramework 和 WindowsBase 等相关程序集引用。
代码示例
将以下代码放入现有 WinForms 项目的 Form1 类,保留项目原有的命名空间。使用前,需要在设计器中创建 videoPanel,并保留 WinForms 模板中带有 [STAThread] 的程序入口。
using System;
using System.IO;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Windows.Media;
using WpfImage = System.Windows.Controls.Image;
public partial class Form1 : Form
{
private readonly MediaPlayer _player = new MediaPlayer();
private readonly VideoDrawing _videoDrawing;
public Form1()
{
InitializeComponent();
_videoDrawing = new VideoDrawing
{
Player = _player,
Rect = new System.Windows.Rect(0, 0, 1, 1)
};
var videoImage = new WpfImage
{
Source = new DrawingImage(_videoDrawing),
Stretch = Stretch.Uniform
};
var host = new ElementHost
{
Dock = DockStyle.Fill,
Child = videoImage
};
videoPanel.Controls.Add(host);
_player.MediaOpened += (sender, e) =>
{
int width = _player.NaturalVideoWidth;
int height = _player.NaturalVideoHeight;
if (width > 0 && height > 0)
{
_videoDrawing.Rect =
new System.Windows.Rect(0, 0, width, height);
}
_player.Play();
};
_player.MediaFailed += (sender, e) =>
{
MessageBox.Show(
this,
e.ErrorException.Message,
"视频播放失败");
};
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
// 替换为实际存在的视频文件路径。
string filePath = @"C:\Videos\sample.wmv";
if (!File.Exists(filePath))
{
MessageBox.Show(this, "找不到视频文件:" + filePath);
return;
}
_player.Open(new Uri(filePath, UriKind.Absolute));
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
_player.Close();
base.OnFormClosed(e);
}
}
这里的 WpfImage 是 System.Windows.Controls.Image,与 WinForms 的 PictureBox 不同。代码在媒体打开后读取视频尺寸,并配合 Stretch.Uniform 保持画面比例。
如果只需要视频播放界面,无须保留 MediaPlayer 对象,也可以使用 WPF MediaElement,通过 ElementHost 嵌入 WinForms,减少绘图对象的配置。
注意事项
- 视频能否播放取决于实际编码格式和运行环境,不能仅凭
.mp4、.wmv等扩展名判断。出现黑屏或加载失败时,应查看MediaFailed提供的异常信息。 - 创建和操作这些界面及播放对象时,应使用 UI 线程。示例依赖 WinForms 的消息循环。
- 如果必须把每帧画面写入
PictureBox.Image,需要另外实现解码、帧提取和图片更新,并处理音视频同步及旧图片释放。这些工作已超出直接连接MediaPlayer与PictureBox的范围。 - 如果使用第三方库中的
MediaPlayer,应检查该库是否提供输出窗口句柄或专用视频控件,不能直接套用 WPF 的结论。
备注:内容仅供参考。
