?如何實現 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