如何实现 WPF 视频封面查看器

控件名:NineGridView

作   者:WPFDevelopersOrg - 驚鏵

原文链接[1]:https://github.com/WPFDevelopersOrg/WPFDevelopers

  • 框架使用.NET40

  • Visual Studio 2019;

  • 实现视频封面查看器NineGridView基于Grid实现列,使用列做主封面展示视频播放(也可以做rtsp视频流播放),还剩下个做候选封面区展示,当点击封面区某个封面时进行替换主封面区视频(流)播放。

  • 当鼠标移动到候选封面区时,动画从上一次鼠标的位置到当前鼠标位置做移动动画。

1)新建 NineGridView.cs 代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;namespace WPFDevelopers.Controls
{public class NineGridView : Grid{private int _rows = 3;private int _columns = 3;private Dictionary<Rect, int> _dicRect = new Dictionary<Rect, int>();private Border _border;private Storyboard _storyboard;private Rect _lastRect;private int _last;public static readonly DependencyProperty SelectBrushProperty =DependencyProperty.Register("SelectBrush", typeof(Brush), typeof(NineGridView),new PropertyMetadata(Brushes.Red));public static readonly DependencyProperty BorderThicknessProperty =DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(NineGridView),new PropertyMetadata(new Thickness(1)));public NineGridView(){Loaded += NineGridView_Loaded;SizeChanged += NineGridView_SizeChanged;}public Brush SelectBrush{get => (Brush)GetValue(SelectBrushProperty);set => SetValue(SelectBrushProperty, value);}public Thickness BorderThickness{get => (Thickness)GetValue(BorderThicknessProperty);set => SetValue(BorderThicknessProperty, value);}private void NineGridView_SizeChanged(object sender, SizeChangedEventArgs e){if (_border == null || _last == 0) return;var frameworkElement = InternalChildren[_last] as FrameworkElement;if (frameworkElement == null) return;_border.Width = frameworkElement.ActualWidth;_border.Height = frameworkElement.ActualHeight;var point = frameworkElement.TranslatePoint(new Point(0, 0), this);CreateStoryboard(point);}private void NineGridView_Loaded(object sender, RoutedEventArgs e){RowDefinitions.Clear();for (int i = 0; i < _rows; i++){var row1 = new RowDefinition();RowDefinitions.Add(row1);}ColumnDefinitions.Clear();for (int i = 0; i < _columns; i++){var col1 = new ColumnDefinition();ColumnDefinitions.Add(col1);}UIElementCollection children = InternalChildren;int numCol = 0, numRow = 0;for (int i = 0, count = children.Count; i < count; ++i){if (i > 6) return;UIElement child = children[i];if (child != null){if (i == 0){SetRowSpan(child, 2);SetColumnSpan(child, 2);}else{var num = i - 1;var col = GetColumnSpan(children[num]);col = col == 1 ? GetColumn(children[num]) : col;if (i + 1 <= _columns){SetColumn(child, col);SetRow(child, numRow);numRow++;}else{var row = GetRowSpan(children[0]);SetColumn(child, numCol);SetRow(child, row);numCol++;}}}}if(_border != null)Children.Remove(_border);_border = new Border{BorderThickness = BorderThickness,BorderBrush = SelectBrush,VerticalAlignment = VerticalAlignment.Top,HorizontalAlignment = HorizontalAlignment.Left};_border.Name = "PART_Adorner";_border.RenderTransform = new TranslateTransform();SetRowSpan(_border, _rows);SetColumnSpan(_border, _columns);_border.Width = ActualWidth / _columns - 2;_border.Height = ActualHeight / _rows - 2;var _translateTransform = (TranslateTransform)_border.RenderTransform;_translateTransform.X = _border.Width * 2 + 4;Children.Add(_border);_last = 1;}protected override void OnPreviewMouseMove(MouseEventArgs e){base.OnPreviewMouseMove(e);var currentPoint = e.GetPosition(this);if (_lastRect.Contains(currentPoint))return;_dicRect.Clear();UIElementCollection children = InternalChildren;for (int i = 0, count = children.Count; i < count; ++i){if (i >= 6 || i == 0) continue;var child = children[i] as FrameworkElement;if (child != null){var point = child.TranslatePoint(new Point(0, 0), this);var rect = new Rect(point.X, point.Y, child.ActualWidth, child.ActualHeight);_dicRect.Add(rect, i);}}var model = _dicRect.Keys.FirstOrDefault(x => x.Contains(currentPoint));if (model == default) return;_dicRect.TryGetValue(model, out _last);if (_border == null) return;CreateStoryboard(new Point(model.X, model.Y));_border.Width = model.Width;_border.Height = model.Height;_lastRect = model;}void CreateStoryboard(Point point){var sineEase = new SineEase() { EasingMode = EasingMode.EaseOut };if (_storyboard == null)_storyboard = new Storyboard();else_storyboard.Children.Clear();var animationX = new DoubleAnimation{Duration = TimeSpan.FromMilliseconds(500),To = point.X,EasingFunction = sineEase};Storyboard.SetTargetProperty(animationX, new PropertyPath("(Border.RenderTransform).(TranslateTransform.X)"));_storyboard.Children.Add(animationX);var animationY = new DoubleAnimation{Duration = TimeSpan.FromMilliseconds(500),To = point.Y,EasingFunction = sineEase};Storyboard.SetTargetProperty(animationY, new PropertyPath("(Border.RenderTransform).(TranslateTransform.Y)"));_storyboard.Children.Add(animationY);_storyboard.Begin(_border);}}
}

2)新建 NineGridViewExample.xaml 代码如下:

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.NineGridViewExample"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls"xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"><controls:CodeViewer><wpfdev:NineGridView BorderThickness="1" SelectBrush="Red"><wpfdev:NineGridView.Resources><Style TargetType="TextBlock"><Setter Property="Foreground" Value="White"/><Setter Property="VerticalAlignment" Value="Center"/><Setter Property="HorizontalAlignment" Value="Center"/></Style><Style TargetType="Border"><Setter Property="Margin" Value="1"/></Style></wpfdev:NineGridView.Resources><MediaElement x:Name="MyMediaElement" Loaded="MyMediaElement_Loaded"MediaEnded="MyMediaElement_MediaEnded"/><Border Background="#282C34"><wpfdev:SmallPanel><TextBlock Text="信号源1"/><Border Background="{DynamicResource PrimaryNormalSolidColorBrush}"VerticalAlignment="Top"HorizontalAlignment="Right"Padding="10,4"CornerRadius="3"><TextBlock Text="HD"/></Border></wpfdev:SmallPanel></Border><Border Background="#282C34"><TextBlock Text="无信号"/></Border><Border Background="#282C34"><TextBlock Text="无信号"/></Border><Border Background="#282C34"><TextBlock Text="无信号"/></Border><Border Background="#282C34"><TextBlock Text="无信号"/></Border></wpfdev:NineGridView><controls:CodeViewer.SourceCodes><controls:SourceCodeModel CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/NineGridViewExample.xaml" CodeType="Xaml"/><controls:SourceCodeModel CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/NineGridViewExample.xaml.cs" CodeType="CSharp"/></controls:CodeViewer.SourceCodes></controls:CodeViewer>
</UserControl>

3)新建 NineGridViewExample.xaml.cs 代码如下:

using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;namespace WPFDevelopers.Samples.ExampleViews
{/// <summary>/// NineGridViewExample.xaml 的交互逻辑/// </summary>public partial class NineGridViewExample : UserControl{public NineGridViewExample(){InitializeComponent();}private void MyMediaElement_Loaded(object sender, RoutedEventArgs e){var path = "E:\\DCLI6K5UIAEmH9R.mp4";if (File.Exists(path))MyMediaElement.Source = new Uri("path");}private void MyMediaElement_MediaEnded(object sender, RoutedEventArgs e){MyMediaElement.Position = new TimeSpan(0);}}
}

参考资料

[1]

原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers

如何实现 WPF 视频封面查看器相关推荐

  1. chrome扩展——bilibili视频封面获取器

    (2018.7)由于bilibili更改了封面链接的位置,所以下面的代码已经无法使用,新版请见:https://github.com/akimusume/GetBilibiliVideoCover 昨 ...

  2. 抖音如何快速上热门 视频md5 查看器

              抖音如何快速上热门 视频md5 查看器          01案例"黑脸V",人尽皆知,如今的抖音真的是火的一塌糊涂,日活跃两亿人次的战绩,可以说已然成了同等A ...

  3. 视频消重方法 视频md5查看器

             视频消重方法 视频md5查看器          去年3月,张一鸣曾在一次学术对话中谈到,今日头条遵循的出海策略不是"一个国家一款产品",而是"全球化产 ...

  4. iOS好使的各种文件文档、音乐、视频下载查看器有进度条

    一.使用说明 采用第三方下载插件MCDownloadManager, csdn地址   http://download.csdn.net/download/wangxiaoertedaye/10166 ...

  5. 《浮图秀》如何优雅查看B站视频封面大图?

    浮图秀(PhotoShow)是一款看大图工具, 只需将鼠标放到图片上方,即可查看到图片的最大尺寸 ​以Bilibili主页视频封面为例 浮图秀(PhotoShow)特别适合看bilibili的视频大图 ...

  6. B站视频下载器,超清4k视频下载,一键解析视频合集,支持批量下载提取视频封面

    文末提供软件下载链接~ 一.软件简介 该视频下载器完全免费,没有广告,不需要安装,支持下载绝大多数站内视频,并且可以对视频合集自动解析,支持多种清晰度下载,如480P,720P,1080P,1080P ...

  7. iOS主题更换、音乐播放器、栏目管理、上传视频封面等源码

    iOS精选源码 主题更换库ThemeStyleTools ios 上传视频选择视频封面(videoCoverController) 网络音乐播放器SCMusic(适配iOS11) OpenGL DEM ...

  8. 日志查看器:显示日志记录信息的快速WPF控件

    对于长时间运行的后台任务,用户了解当前执行的步骤很有帮助.LogViewer可以安全地多线程收集此信息,并将其显示为可滚动文本.LogViewer允许后台线程在不使用任何WPF代码的情况下写入格式化文 ...

  9. WPF 模仿 UltraEdit 文件查看器系列 开篇和导读

    WPF 模仿 UltraEdit 文件查看器系列 开篇和导读 运行环境:Win10 x64, NetFrameWork 4.8, 作者:乌龙哈里,日期:2019-05-10 学 .Net FrameW ...

最新文章

  1. 一年两次新产品发布,APICloud上线App定制服务平台
  2. MavenMybatis可能会遇到的问题
  3. 深度学习(三十六)——R-FCN, FPN, RetinaNet, CornerNet
  4. 解决WDCP3环境gbk网站编码程序乱码问题
  5. ubuntu服务器ssh登录密码修改,Ubuntu-18.04 下修改root用户密码,安装SSH服务,允许root用户远程登录,安装vsftp服务器...
  6. 曾经拒绝马云的实习生 他说要开启云工作时代
  7. 总结2-深度学习网络搭建学习
  8. 将一副遥感影像裁剪为多幅图像
  9. 数字安全一个都不能少:360为企业数字化转型护航
  10. 文件夹压缩为war包
  11. 四级网络工程师笔记-计算机网络(下)
  12. 应用于arcgis的代码,长期更新…
  13. “大数据应用场景”之隔壁老王(连载一)
  14. ESP-12F 烧录方法
  15. 深入浅出即时通讯(1)_即时通讯协议对比
  16. 计算机考博面试题,交大系统博士笔试和面试题目
  17. html级联选择器,jquery实现 级联选择器
  18. 微信小游戏上线字节平台超全攻略
  19. Android——在线计算器完整代码
  20. Ubuntu20.04设置开机自启脚本、开机自启命令(ubuntu自启,ubuntu开机自启)rc(run command)(systemd)(/etc/rc.local)(开机启动原理)开机自启动

热门文章

  1. 简单两步彻底根除系统多余输入法
  2. C++虚函数、纯虚函数、虚析构、纯虚析构、动态绑定和抽象类详解。
  3. php 查询域名被注册,查询域名是否被注册 API 接口调用请求
  4. 阿里云架构和openstack架构简析
  5. MemoryError: Unable to allocate 1.43 TiB for an array with shape (3700, 5300) and data type float64
  6. 李航《统计学习方法》AdaBoost算法(课后习题)
  7. Spring @Order注解详解
  8. 【C语言从零到入门】第二节 C语言开发工具的安装
  9. 企业如何摆脱低效的客户服务,从建立客服中心知识库开始,让企业客服更科学、更智能!
  10. FPGA NVME IP 核 纯逻辑实现NVME协议,读写SSD