基于WPF开发视频播放器

news/2025/1/7 19:40:06/文章来源:https://www.cnblogs.com/hsiang/p/18550163

在实际应用中,视频播放功能在很多软件中都会用到,将音频和视频集成到应用程序中不仅可以增强用户体验,还能起到事半功倍的效果。今天本文以一个简单的小例子,简述如何通过WPF中的MediaElement开发视频播放器,仅供学习分享使用,如有不足之处,还请指正!

涉及知识点

在本实例中,开发视频播放器,主要用到MediaElement控件,而MediaElement 是受 Layout 支持的 UIElement,并可用作许多控件的内容。涉及知识点如下:

  • LoadedBehavior,UnloadedBehavior 主要用于控制IsLoaded属性为true和false时的视频播放行为,即视频加载成功和没有加载时的播放行为。此两个属性为MediaState类型,共有五种值供选择,Manual,Play,Stop,Pause,Close。 例如,默认 LoadedBehavior 为 Play,默认 UnloadedBehavior 为 Close。 这意味着,一旦加载 MediaElement 并且预滚完成,媒体开始播放。 一旦播放完毕,媒体就会关闭并且发布所有媒体资源。
  • Source,主要用于指定视频播放源路径,Uri类型。
  • Play、Pause 和 Stop 方法分别用于播放、暂停和停止媒体。 更改 MediaElement 的 Position 属性可让你在媒体中跳转。 最后,Volume 和 SpeedRatio 属性用于调整媒体的音量和播放速度。

注意:MediaElement 的 LoadedBehavior 属性必须设置为 Manual 才能以交互方式停止、暂停和播放媒体。

依赖库

所谓麻雀虽小,五脏俱全,本实例虽然是一个视频播放器的小例子,但是也遵循MVVM的设计思想。主要采用CommunityToolkit.Mvvm,可通过Nuget包管理器进行安装,如下所示:

关于CommunityToolkit.Mvvm的使用方法,可参考相关文档,在此不在赘述。

UI布局

虽然MediaElement控件可以实现视频的播放,但是要实现完整的功能,还需要其他的页面布局控件。在本实例中,主要分为三个组成部分:

  • 播放区,主要用于显示视频的播放内容,时长,播放进度等内容
  • 视频列表,主要用于显示播放的视频的列表,以及手动添加视频到列表中,双击列表项进行播放等。
  • 视频控制,主要用于控制视频的播放,暂停,停止,速度,音量等内容。

视频播放器UI源码如下所示:

<Window x:Class="DemoMedia.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:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:local="clr-namespace:DemoMedia"mc:Ignorable="d"Title="Windows Media Player" Height="450" Width="800" Background="AliceBlue"><Window.Resources><ResourceDictionary Source="\Resources\Icons.xaml"></ResourceDictionary></Window.Resources><i:Interaction.Triggers><i:EventTrigger EventName="Loaded"><i:InvokeCommandAction Command="{Binding LoadedCommand}" PassEventArgsToCommand="True"/></i:EventTrigger></i:Interaction.Triggers><Grid><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition Width="Auto" MinWidth="150" MaxWidth="200"></ColumnDefinition></Grid.ColumnDefinitions><Grid><Grid.RowDefinitions><RowDefinition></RowDefinition><RowDefinition Height="Auto"></RowDefinition><RowDefinition Height="Auto"></RowDefinition></Grid.RowDefinitions><Border Grid.Row="0" Background="AliceBlue"></Border><MediaElement Grid.Row="0" Name="mediaElement" MinHeight="300" MinWidth="300"Source="{Binding Model.CurSource}"LoadedBehavior="Manual" UnloadedBehavior="Manual" Stretch="Uniform"><i:Interaction.Triggers><i:EventTrigger EventName="MediaOpened"><i:InvokeCommandAction Command="{Binding MediaOpenedCommand}"/></i:EventTrigger><i:EventTrigger EventName="MediaEnded"><i:InvokeCommandAction Command="{Binding MediaEndedCommand}"/></i:EventTrigger></i:Interaction.Triggers></MediaElement><Button Command="{Binding PlayCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0.6" Visibility="{Binding Model.PlayButtonVisibility}" Cursor="Hand"><Button.Template><ControlTemplate><Border Background="AliceBlue"><Path Data="{StaticResource play}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill" ></Path></Border></ControlTemplate></Button.Template></Button><Grid Grid.Row="1" VerticalAlignment="Bottom" Margin="2 0 2 4"><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"></ColumnDefinition><ColumnDefinition></ColumnDefinition><ColumnDefinition Width="Auto"></ColumnDefinition></Grid.ColumnDefinitions><TextBlock Grid.Column="0" Text="00:00" VerticalAlignment="Bottom"></TextBlock><ProgressBar Grid.Column="1"  Height="5" Background="Black"  Foreground="White" Value="{Binding Model.Position}" Minimum="0" Maximum="{Binding Model.MediaMaximum}"></ProgressBar><StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Bottom"><!--<TextBlock  Text="时长:"></TextBlock>--><TextBlock  Text="{Binding Model.TimeLen}"></TextBlock></StackPanel></Grid><StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center"><Button x:Name="btnPlay" Margin="5" Command="{Binding PlayCommand}"><Button.Template><ControlTemplate><Border Background="AliceBlue"><Path Data="{StaticResource play}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill"></Path></Border></ControlTemplate></Button.Template></Button><Button x:Name="btnPause" Margin="5"  Command="{Binding PauseCommand}"><Button.Template><ControlTemplate><Border Background="AliceBlue"><Path Data="{StaticResource pause}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill"></Path></Border></ControlTemplate></Button.Template></Button><Button x:Name="btnStop" Margin="5"  Command="{Binding StopCommand}"><Button.Template><ControlTemplate><Border Background="AliceBlue"><Path Data="{StaticResource stop}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill"></Path></Border></ControlTemplate></Button.Template></Button><TextBlock Foreground="#3259CE" VerticalAlignment="Center" Margin="5" Text="音量"></TextBlock><Slider Name="volumeSlider" VerticalAlignment="Center" Value="{Binding ElementName=mediaElement, Path=Volume, Mode=TwoWay}" Minimum="0" Maximum="1" Width="70"/><TextBlock Foreground="#3259CE" Margin="5"  VerticalAlignment="Center" Text="速度"></TextBlock><Slider Name="speedRatioSlider" VerticalAlignment="Center"  Value="{Binding ElementName=mediaElement, Path=SpeedRatio, Mode=TwoWay}"  Width="70" /></StackPanel></Grid><GridSplitter Grid.Column="0" HorizontalAlignment="Right" Width="2"></GridSplitter><Grid Grid.Column="1" Background="AliceBlue"><Grid.RowDefinitions><RowDefinition Height="Auto" MinHeight="30"></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><Border Background="Transparent" BorderBrush="White" BorderThickness="1" Grid.Row="0"></Border><Grid Grid.Row="0" Margin="2"><TextBlock Text="播放列表" VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock><Button x:Name="btnOpen" Width="18" Height="18" Command="{Binding BrowserCommand}" Margin="5" HorizontalAlignment="Right"><Button.Template><ControlTemplate><Border Background="AliceBlue"><Path Data="{StaticResource browser}" Stroke="#27A2DF" Fill="White" Width="18" Height="18" Stretch="Fill"></Path></Border></ControlTemplate></Button.Template></Button></Grid><ListView Grid.Row="1" Margin="2" ItemsSource="{Binding Model.Movies}" BorderThickness="0" SelectionMode="Single" Background="AliceBlue"><ListView.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Id, StringFormat='[00]'}" Margin="2 3"></TextBlock><TextBlock Text="{Binding Name}" Margin="3 3" ToolTip="{Binding Url}"></TextBlock></StackPanel></DataTemplate></ListView.ItemTemplate><i:Interaction.Triggers><i:EventTrigger EventName="MouseDoubleClick"><i:InvokeCommandAction Command="{Binding MouseDoubleCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Path=SelectedItem}"/></i:EventTrigger></i:Interaction.Triggers></ListView></Grid></Grid>
</Window>

在本实例中,为了UI美观,所有按钮都采用图标显示,而图标的实现方式采用几何图形,具体实现方式可参考相关文章。

核心源码

在本实例中,业务逻辑和UI分离,主要实现手动添加视频,及视频的播放,暂停,停止,音量,进度等功能。

浏览视频并加入到播放列表,如下所示:

private void Browser()
{OpenFileDialog dialog = new OpenFileDialog();dialog.Title = "请选择要播放的影片";dialog.Filter = "MP4|*.mp4";dialog.Multiselect = true;if (dialog.ShowDialog()==true){var files=dialog.FileNames;foreach (var file in files){var maxId = this.Model.Movies.Count>0 ? this.Model.Movies.Max(x => x.Id):0;if (this.Model.Movies.FirstOrDefault(item => item.Url == file) == null){this.Model.Movies.Add(new Movie(){Id = maxId + 1,Name = Path.GetFileNameWithoutExtension(file),Url = file});}}}
}

视频播放功能,开始播放后,单独打开一个线程,用来刷新播放的进度,如下所示:

private void Play()
{//影片播放,如果没有,则打开选择文件夹if (this.Model.CurMovie == null){this.Browser();if (this.Model.Movies.Count < 1){return;}this.Model.CurMovie = this.Model.Movies.Last();}this.Model.CurSource = new Uri(this.Model.CurMovie.Url, UriKind.RelativeOrAbsolute);if (this.media.NaturalDuration != Duration.Automatic && this.media.Position.TotalSeconds == this.media.NaturalDuration.TimeSpan.TotalSeconds){this.media.Position=new TimeSpan(0,0,0);}this.media.Play();this.IsRunning = true;this.Model.PlayButtonVisibility = Visibility.Collapsed;//this.mediaTask = Task.Run(() =>{while (this.IsRunning){Application.Current.Dispatcher.Invoke(() =>{this.Model.Position = this.media.Position.TotalSeconds;});Thread.Sleep(100);}});
}

注意,MediaElement的Position并非依赖属性,无法进行绑定,所以采用后台线程刷新的方式进行实现。

视频暂停功能,通过MediaElement的Pause方法即可控制视频的暂停,如下所示:

private void Pause()
{if (this.Model.CurMovie == null){return;}this.media.Pause();this.IsRunning = false;
}

视频停止功能,通过MediaElement的Stop方法即可控制视频的停止,如下所示:

private void Stop()
{if (this.Model.CurMovie == null){return;}this.media.Stop();this.IsRunning= false;
}

注意,暂停功能是将播放位置保持在当前位置;停止功能是将视频的播放位置重置到初始位置。

视频打开事件,即当视频开始时触发的路由事件,如下所示:

private void MediaOpened()
{if (this.media.NaturalDuration.TimeSpan.TotalMinutes < 60){this.Model.TimeLen = this.media.NaturalDuration.TimeSpan.ToString(@"mm\:ss");}else{this.Model.TimeLen = this.media.NaturalDuration.TimeSpan.ToString(@"hh\:mm\:ss");}this.Model.MediaMaximum = this.media.NaturalDuration.TimeSpan.TotalSeconds;
}

注意:在这里,视频开始时,初始化播放时长等内容。

视频结束事件,当视频播放结束时触发的路由事件,如下所示:

private void MediaEnded()
{this.Model.PlayButtonVisibility = Visibility.Visible;this.IsRunning = false;
}

注意,视频播放结束时,将播放状态置为flase,不在监控播放位置。

视频播放器效果

视频播放器初始化页面,如下图所示:

添加视频到播放列表,如下所示:

视频播放效果截图,如下所示:

源码下载

WPF版本的视频播放器,可通过两种方式获取源码:

1. 关注“老码识途”公众号,并回复关键字“WMEDIA”进行获取,如下所示:

2. 通过Gitee仓库【下载网址:https://gitee.com/ahsiang/wpf-media】进行下载,如下所示:

以上就是《基于WPF开发视频播放器》的全部内容,旨在抛砖引玉,一起学习,共同进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/836088.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wincc 7.5SP2下VBA编程学习练习15:批量删除变量

在前面练习的基础上学习批量删除变量。 新建下面的脚本: Sub DeleteTags()批量删除变量Dim hmigo As hmigoDim strTagName As StringDim i As IntegerSet hmigo = New hmigoFor i = 1 To 5 strTagName = "Real" & CStr(i) hmigo.DeleteTag strTagNameNext…

vue2-基础核心

vue简介 vue中文官网动态构建用户界面的渐进式 JavaScript 框架 vue的特点:遵循MVVM模式 采用组件化模式,提高代码复用率,让代码更好维护 声明式编码,无需直接操作DOM,提高开发效率,编码简洁、体积小,运行效率高 本身只关注UI,也可以引入其他三方库开发项目 使用虚拟DOM…

数据采集与融合技术实践作业四

数据采集与融合技术实践作业四 gitee链接:https://gitee.com/wei-yuxuan6/myproject/tree/master/作业4 作业① selenium爬取股票实验要求: 熟练掌握 Selenium 查找 HTML 元素、爬取 Ajax 网页数据、等待 HTML 元素等内容。 使用 Selenium 框架+ MySQL 数据库存储技术路线爬取…

creo装配体零件合并

一张图看懂creo5.0中装配体转零件creo中自带装配体转成零件的功能,无需另存为stp再以零件方式打开(可能出现烂面情况)1.先在装配体中创建一个空的零件;2.在装配体下按图中步骤进行操作,最终创建的空零件将变成装配体转成的零件

jenjins设置中文界面

参考 https://blog.csdn.net/weixin_45131680/article/details/142759961点击Manage Jenkins下滑到System Configuration 点击Manage Plugins点击“可选插件”,输入“Locale”点击Install without restart等待下载完成 显示“sucess”即为安装完成,然后点击管理jenkins下滑到…

又稳又快!基于ByteHouse ELT构建高性能离/在线一体化数仓

近期,ByteHouse与某数字娱乐公司达成合作,双方聚焦高性能离/在线一体化数仓展开合作。近期,ByteHouse与某数字娱乐公司达成合作,双方聚焦高性能离/在线一体化数仓展开合作。随着自身领域迅速发展的同时,该数字娱乐公司需要更稳定、易用的数据基础服务,但该方面遇到多种挑…

js设置浏览器cookie

https://blog.csdn.net/x550392236/article/details/77651579

猫映射(Arnold变换),猫脸变换介绍与基于例题脚本的爆破

前置信息 http://www.jiamisoft.com/blog/index.php/7249-erzhituxiangjiamisuanfaarnold.html https://mp.weixin.qq.com/s/IbkAlyAPvbgMeNgqfwisTg Arnold变换 Arnold变换是V.J.Arnold在遍历理论的研究中提出的一种变换,原意为catmapping,俗称猫脸变换。Arnold变换直观、简…

伯索云学堂视频课件课程下载工具,如何在电脑端下载伯索云学堂视频课程课件资料PDF,PPT到本地?

一. 安装伯索云课程下载器 1.获取学无止下载器 https://www.xuewuzhi.cn/plaso_downloader 2.下载安装后,然后点击桌面快捷方式运行即可。 注意:杀毒软件可能会阻止外部exe文件运行,并将其当做成病毒,直接添加信任即可,本软件绝对没有木马病毒。 二. 使用说明 1.学无止下载…

一个自托管免费开源的人脸识别系统

大家好,今天给大家分享一个自托管免费开源的人脸识别系统CompreFace。CompreFace 是一个开源的人脸识别系统,由 Exadel 公司开发并维护。它提供了一个基于深度学习的解决方案,用于人脸检测、识别和验证。 CompreFace 的设计旨在简化人脸识别技术的使用,使得开发者无需深入理…

洛谷题单指南-二叉堆与树状数组-P3374 【模板】树状数组 1

原题链接:https://www.luogu.com.cn/problem/P3374 题意解读:树状数组模版:单点修改,区间求值。 解题思路: 树状数组-Binary Index Tree可以动态维护一组数,可以O(logn)的修改一个数,也可以O(logn)的计算一段区间的和。 思考一下朴素做法:如何修改一个数,计算区间和?…

11月16日,工信部人才交流中心 CUUG - PGCP / PGCM认证考试完成!

2024年11月16日,由工业和信息化部人才交流中心 与 北京神脑资讯技术有限公司共同举办的PostgreSQL管理员岗位能力认证考试(PGCP中级/PGCM高级)完成。 中级PG认证专家-PGCP(PostgreSQL Certified Professional):是对PostgreSQL数据库技术能力的一种认可,达到了专家级别,…