一、前言
上回说到需要做放视频的使用向导,这两天公司里的老司机一直帮我答疑解惑,让这个任务变得挺顺的,真心感谢他们!
这次与【1】中的不同之处在于:
(1)播放和暂停按钮集成在<MediaElement>的点击事件之中,点一下是播放,再点一下是暂停
(2)加入了微软官方改写的粒子特效
(3)加上了自己琢磨的按钮旋转效果,以及按钮弹出popup效果
(4)进度条改善美观
二、代码
前台:
<Window
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:local="clr-namespace:WPF_Nav"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" xmlns:dxwui="http://schemas.devexpress.com/winfx/2008/xaml/windowsui" x:Class="WPF_Nav.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="" Width="" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation ="CenterScreen" Loaded="Window_Loaded"> <Window.Resources>
<LinearGradientBrush x:Key="SliderBackground" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.5" Color="#00b3fe"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SliderThumb" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="" Color="#FFD9D3E8"/>
</LinearGradientBrush> <Style x:Key="Slider_RepeatButton" TargetType="RepeatButton">
<Setter Property="Focusable" Value="false" />
<Setter Property="Height" Value=""/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border Background="{StaticResource SliderBackground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="Slider_RepeatButton1" TargetType="RepeatButton">
<Setter Property="Focusable" Value="false" />
<Setter Property="Height" Value=""/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border Background="Silver" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="Slider_Thumb" TargetType="Thumb">
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Ellipse Name="e" Width="" Height="" Fill="White" Stroke="Gray"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style TargetType="Slider">
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid>
<Border BorderBrush="Red" BorderThickness="" CornerRadius="0,0,0,0">
<Track Name="PART_Track">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource Slider_RepeatButton}" Command="Slider.DecreaseLarge"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource Slider_RepeatButton1}" Command="Slider.IncreaseLarge"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource Slider_Thumb}"/>
</Track.Thumb>
</Track>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="Button_Close" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Close.jpg"></Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="Button_Forbidden" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Forbidden.jpg"></Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="Button_Left" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Left.png" Stretch="Fill"></Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="Button_Right" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Right.png" Stretch="Fill"></Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> </Window.Resources> <Grid Name="Main_Grid">
<Grid.RowDefinitions>
<RowDefinition Height=""></RowDefinition>
<RowDefinition Height=""></RowDefinition>
<RowDefinition Height=""></RowDefinition>
</Grid.RowDefinitions> <Border Name="title_Border" BorderBrush="#FBD3D0CD" BorderThickness="" Grid.Row="">
<Grid Name="Title">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=""></ColumnDefinition>
<ColumnDefinition Width=""></ColumnDefinition>
<ColumnDefinition Width=""></ColumnDefinition>
<ColumnDefinition Width=""></ColumnDefinition>
</Grid.ColumnDefinitions> <Grid Grid.Column="">
<Canvas x:Name="ParticleHost" Width="" >
<TextBlock Name="txtB_Step" Grid.Column="" Width="" Height="" TextAlignment="Center" FontSize="" FontFamily="Microsoft YaHei" Text="asss" Margin="100,7,0,0"/>
</Canvas>
</Grid> <Grid Name="grid_Cofig" Grid.Column="">
<Button Name="btn_Forbidden" Width="" Click="Config_Click" Margin="2,10,48,12" HorizontalAlignment="Center" Focusable="False" Style="{StaticResource Button_Forbidden}" RenderTransformOrigin="0.5,0.5" ToolTipService.ToolTip="播放设置" ToolTipService.InitialShowDelay="" ToolTipService.Placement="Bottom">
<Button.RenderTransform>
<RotateTransform x:Name="trans_forbidden" Angle=""/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard >
<Storyboard>
<DoubleAnimation From="" To="" Duration="0:0:0.4"
Storyboard.TargetName="trans_forbidden"
Storyboard.TargetProperty="Angle"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid> <Popup x:Name="Pop" PopupAnimation="Slide" Placement="Bottom" Width="" Height="" PlacementTarget="{Binding ElementName=grid_Cofig}" AllowsTransparency="True" StaysOpen="False" IsOpen="False" >
<Border Background="White" BorderBrush="#FFC4C9CD" BorderThickness="" Width="">
<StackPanel Margin="">
<StackPanel Name="sp_play" Orientation="Horizontal" Width="" Height="" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="" MouseEnter="sp_play_enter" MouseLeave="sp_play_leave" >
<CheckBox x:Name="ch_play" VerticalAlignment="Center" Margin="3,4" />
<TextBlock x:Name="txb_play" Text="不再播放" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Name="sp_doc" Width="" Height="" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="" MouseEnter="sp_doc_enter" MouseLeave="sp_doc_leave">
<TextBlock Name="txb_Doc" Text="官方帮助文档" Margin="4,0,5,0" VerticalAlignment="Center">
</TextBlock>
</StackPanel>
</StackPanel>
</Border>
</Popup> <Button Name="btn_Close" Grid.Column="" Width="" Click="Close_Click" Margin="37,10,13,12" HorizontalAlignment="Center" Focusable="False" Style="{StaticResource Button_Close}" RenderTransformOrigin="0.5,0.5" ToolTipService.ToolTip="关闭视频" ToolTipService.InitialShowDelay="" ToolTipService.Placement="Bottom">
<Button.RenderTransform>
<RotateTransform x:Name="trans" Angle=""/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard >
<Storyboard>
<DoubleAnimation From="" To="" Duration="0:0:0.4"
Storyboard.TargetName="trans"
Storyboard.TargetProperty="Angle"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button> </Grid>
</Border> <Grid Name="Movie" Grid.Row="">
<MediaElement Stretch="Fill" LoadedBehavior="Manual" Name="QS_Movie" MediaOpened="Element_MediaOpened" Loaded="QS_Movie_Loaded" MouseLeftButtonDown="QS_Movie_MouseLeftButtonDown" />
<Button Name="btn_pre" Width="" Height="" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Left_Click" Focusable="False" Style="{StaticResource Button_Left}"/>
<Button Name="btn_next" Width="" Height="" HorizontalAlignment="Right" VerticalAlignment="Center" Click="Right_Click" Focusable="False" Style="{StaticResource Button_Right}"/>
</Grid> <Border Name="Progress_Border" BorderBrush="#FBD3D0CD" BorderThickness="" Grid.Row="">
<Grid Name="Control_Progress" >
<Slider Grid.Column="" Width="" Name="timelineSlider" VerticalAlignment="Center" PreviewMouseLeftButtonDown="timelineMDown" PreviewMouseLeftButtonUp="timelineMUp" BorderThickness="0,6,0,0" />
</Grid>
</Border> </Grid>
</Window>
后台:
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Shapes; namespace WPF_Nav
{
public class Particle
{
public Point3D Position { get; set; }
public Point3D Velocity { get; set; }
public double Size { get; set; }
public Ellipse Ellipse { get; set; }
public BlurEffect Blur { get; set; }
public Brush Brush { get; set; }
}
}
namespace WPF_Nav
{
public class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; } public Point3D(double X, double Y, double Z)
{
this.X = X;
this.Y = Y;
this.Z = Z;
}
}
}
主体:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Media.Effects; namespace WPF_Nav
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); // 定义一个DT
bool play_flag = true; //判断播放状态
int play_now = ; //判断当前视频索引
int play_target;
List<string> Play_Video = new List<string>();
List<string> Title_Video = new List<string>(); public MainWindow()
{
InitializeComponent();
Play_Video = LoadMovies();
Title_Video = LoadTitles();
} private List<string> LoadTitles()
{
List<string> list_title = new List<string>();
list_title.Add("Step1");
list_title.Add("Step2");
list_title.Add("Step3");
return list_title;
}
private List<string> LoadMovies()
{
List<string> Movie_Uri = new List<string>();
Movie_Uri.Add(@"E:\Test\WPFTest\Sources\preview.mp4");
Movie_Uri.Add(@"E:\Test\WPFTest\Sources\preview1.mp4");
Movie_Uri.Add(@"E:\Test\WPFTest\Sources\preview2.mp4");
return Movie_Uri;
} private void Play_Click(object sender, RoutedEventArgs e)
{
QS_Movie.Play();
} private void Pause_Click(object sender, RoutedEventArgs e)
{
QS_Movie.Pause();
} private void Element_MediaOpened(object sender, EventArgs e)
{
timelineSlider.Maximum = QS_Movie.NaturalDuration.TimeSpan.TotalMilliseconds; //设置slider最大值
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); //超过计时间隔时发生
dispatcherTimer.Interval = new TimeSpan(, , , , ); //DT间隔
dispatcherTimer.Start(); //DT启动
} private void dispatcherTimer_Tick(object sender, EventArgs e)
{
int time = (int)QS_Movie.Position.TotalSeconds;
timelineSlider.ToolTip = SecToTime(time);
timelineSlider.Value = QS_Movie.Position.TotalMilliseconds; //slider滑动值随播放内容位置变化
} private string SecToTime(int sec)
{
int min = sec / ;
sec = sec - min * ;
int hour = min / ;
min = min - hour * ;
string h = hour.ToString();
string mm = ((min < ) ? "" : "") + min.ToString();
string ss = ((sec < ) ? "" : "") + sec.ToString();
string time = h + ":" + mm + ":" + ss;
return time;
}
private void timelineMDown(object sender, EventArgs e)
{
dispatcherTimer.Stop();
}
private void timelineMUp(object sender, EventArgs e)
{
QS_Movie.Position = new TimeSpan(, , , , (int)timelineSlider.Value);
dispatcherTimer.Start();
QS_Movie.Play();
} private void QS_Movie_Loaded(object sender, RoutedEventArgs e)
{
PreLoad(,play_now); } private void Left_Click(object sender, RoutedEventArgs e)
{
play_target = (play_now + Play_Video.Count-) % Play_Video.Count;
PreLoad(, play_target);
play_now = play_target;
} private void Right_Click(object sender, RoutedEventArgs e)
{
play_target = (play_now + ) % Play_Video.Count;
PreLoad(, play_target);
play_now = play_target;
} private void PreLoad(int interval, int index)
{
QS_Movie.Source = new Uri(Play_Video[index]);
QS_Movie.Play();
System.Threading.Thread.Sleep(interval);
QS_Movie.Pause();
txtB_Step.Text = Title_Video[index];
} private void QS_Movie_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ if(play_flag==true)
{
QS_Movie.Play();
btn_pre.Visibility = System.Windows.Visibility.Hidden;
btn_next.Visibility = btn_pre.Visibility = System.Windows.Visibility.Hidden;
}
if(play_flag==false)
{
QS_Movie.Pause();
btn_pre.Visibility = System.Windows.Visibility.Visible;
btn_next.Visibility = System.Windows.Visibility.Visible; }
play_flag = !play_flag;
} private void Close_Click(object sender, RoutedEventArgs e)
{
this.Close();
} private void Config_Click(object sender, RoutedEventArgs e)
{
this.Pop.IsOpen = true;
} private void sp_play_enter(object sender, MouseEventArgs e)
{
Brush br_bg = new SolidColorBrush(Color.FromRgb(, , ));
Brush br_white = new SolidColorBrush(Color.FromRgb(, , ));
txb_play.Foreground = br_white;
sp_play.Background = br_bg;
} private void sp_play_leave(object sender, MouseEventArgs e)
{
Brush br_white = new SolidColorBrush(Color.FromRgb(, , ));
Brush br_black = new SolidColorBrush(Color.FromRgb(, , ));
txb_play.Foreground = br_black;
sp_play.Background = br_white;
} private void sp_doc_enter(object sender, MouseEventArgs e)
{
Brush br_bg = new SolidColorBrush(Color.FromRgb(, , ));
Brush br_white = new SolidColorBrush(Color.FromRgb(, , ));
txb_Doc.Foreground = br_white;
sp_doc.Background = br_bg;
} private void sp_doc_leave(object sender, MouseEventArgs e)
{
Brush br_white = new SolidColorBrush(Color.FromRgb(, , ));
Brush br_black = new SolidColorBrush(Color.FromRgb(, , ));
txb_Doc.Foreground = br_black;
sp_doc.Background = br_white;
} /// <summary>
/// 特效部分
/// </summary> List<Particle> particles = new List<Particle>();
List<Particle> deadList = new List<Particle>();
Random random = new Random(); private void Window_Loaded(object sender, RoutedEventArgs e)
{
timer.Interval = TimeSpan.FromMilliseconds();
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
} void timer_Tick(object sender, EventArgs e)
{
UpdateParticules();
} DispatcherTimer timer = new DispatcherTimer(); double elapsed = 0.1;
private void UpdateParticules()
{
//更新粒子信息
deadList.Clear();
foreach (Particle p in this.particles)
{
if (p.Position.Y < -p.Size || p.Position.X < -p.Size || p.Position.X > Width + p.Size)
{
deadList.Add(p);
}
else
{
//更新位置
p.Position.X += p.Velocity.X * elapsed;
p.Position.Y += p.Velocity.Y * elapsed;
p.Position.Z += p.Velocity.Z * elapsed;
TranslateTransform t = (p.Ellipse.RenderTransform as TranslateTransform);
t.X = p.Position.X;
t.Y = p.Position.Y; //更新颜色信息
p.Ellipse.Fill = p.Brush;
p.Ellipse.Effect = p.Blur;
}
} //创建新的粒子
for (int i = ; i < && this.particles.Count < ; i++)
{
//尝试循环使用已有例子
if (deadList.Count - >= i)
{
SpawnParticle(deadList[i].Ellipse);
deadList[i].Ellipse = null;
}
else
{
SpawnParticle(null);
}
} foreach (Particle p in deadList)
{
if (p.Ellipse != null) ParticleHost.Children.Remove(p.Ellipse);
this.particles.Remove(p);
}
} private void SpawnParticle(Ellipse e)
{
double x = RandomWithVariance(Width / , Width / );
double y = Height;
double z = * (random.NextDouble() * );
double speed = RandomWithVariance(, );
double size = RandomWithVariance(,); Particle p = new Particle();
p.Position = new Point3D(x, y, z);
p.Size = size; //模糊
var blur = new BlurEffect();
blur.RenderingBias = RenderingBias.Performance;
blur.Radius = RandomWithVariance(, );
p.Blur = blur;
//颜色
var brush = (Brush)Brushes.Lime.Clone();
brush.Opacity = RandomWithVariance(0.6, 0.5);
p.Brush = brush; TranslateTransform t; if (e != null)
{
e.Fill = null;
e.Width = e.Height = size;
p.Ellipse = e; t = e.RenderTransform as TranslateTransform;
}
else
{
p.Ellipse = new Ellipse();
p.Ellipse.Width = p.Ellipse.Height = size;
this.ParticleHost.Children.Add(p.Ellipse); t = new TranslateTransform();
p.Ellipse.RenderTransform = t;
p.Ellipse.RenderTransformOrigin = new Point(0.5, 0.5); } t.X = p.Position.X;
t.Y = p.Position.Y; double velocityMultiplier = (random.NextDouble() + 0.25) * speed;
double vX = (1.0 - (random.NextDouble() * 2.0)) * velocityMultiplier;
double vY = -Math.Abs((1.0 - (random.NextDouble() * 2.0)) * velocityMultiplier); p.Velocity = new Point3D(vX, vY, ); this.particles.Add(p);
} private double RandomWithVariance(double midvalue, double variance)
{
double min = Math.Max(midvalue - (variance / ), );
double max = midvalue + (variance / );
double value = min + ((max - min) * random.NextDouble());
return value;
} } }
三、效果
四、小结
WPF挺好玩的!前台就能解决一些基本的动画效果,加上后台简直爽。最后,感谢单位的老司机们!