你的位置:首页 > ASP.net教程

[ASP.net教程]基于MediaElement的WPF视频播放器(带部分特效)【2】


一、前言

      上回说到需要做放视频的使用向导,这两天公司里的老司机一直帮我答疑解惑,让这个任务变得挺顺的,真心感谢他们!

       这次与【1】中的不同之处在于:

       (1)播放和暂停按钮集成在<MediaElement>的点击事件之中,点一下是播放,再点一下是暂停

       (2)加入了微软官方改写的粒子特效

       (3)加上了自己琢磨的按钮旋转效果,以及按钮淡出popup效果

       (4)进度条改善美观

 

二、代码

      前台:

 1 <Window 2     "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3     "http://schemas.microsoft.com/winfx/2006/xaml" 4     "http://schemas.microsoft.com/expression/blend/2008" 5     "http://schemas.open" 6     "clr-namespace:WPF_Nav" 7     "http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" "http://schemas.devexpress.com/winfx/2008/xaml/windowsui" x:Class="WPF_Nav.MainWindow" 8     mc:Ignorable="d" 9     Title="MainWindow" Height="600" Width="800" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation ="CenterScreen" Loaded="Window_Loaded"> 10  11   <Window.Resources> 12     <LinearGradientBrush x:Key="SliderBackground" StartPoint="0,0" EndPoint="0,1"> 13       <GradientStop Offset="0.5" Color="#00b3fe"/> 14     </LinearGradientBrush> 15     <LinearGradientBrush x:Key="SliderThumb" StartPoint="0,0" EndPoint="0,1"> 16       <GradientStop Offset="0" Color="#FFD9D3E8"/> 17     </LinearGradientBrush> 18  19     <Style x:Key="Slider_RepeatButton" TargetType="RepeatButton"> 20       <Setter Property="Focusable" Value="false" /> 21       <Setter Property="Height" Value="5"/> 22       <Setter Property="BorderBrush" Value="Transparent"/> 23       <Setter Property="Template"> 24         <Setter.Value> 25           <ControlTemplate TargetType="RepeatButton"> 26             <Border Background="{StaticResource SliderBackground}" /> 27           </ControlTemplate> 28         </Setter.Value> 29       </Setter> 30     </Style> 31  32     <Style x:Key="Slider_RepeatButton1" TargetType="RepeatButton"> 33       <Setter Property="Focusable" Value="false" /> 34       <Setter Property="Height" Value="5"/> 35       <Setter Property="BorderBrush" Value="Transparent"/> 36       <Setter Property="Template"> 37         <Setter.Value> 38           <ControlTemplate TargetType="RepeatButton"> 39             <Border Background="Silver" /> 40           </ControlTemplate> 41         </Setter.Value> 42       </Setter> 43     </Style> 44  45     <Style x:Key="Slider_Thumb" TargetType="Thumb"> 46       <Setter Property="Focusable" Value="false" /> 47       <Setter Property="Template"> 48         <Setter.Value> 49           <ControlTemplate TargetType="Thumb"> 50             <Ellipse Name="e" Width="15" Height="15" Fill="White" Stroke="Gray"/> 51           </ControlTemplate> 52         </Setter.Value> 53       </Setter> 54     </Style> 55  56     <Style TargetType="Slider"> 57       <Setter Property="Focusable" Value="false" /> 58       <Setter Property="Template"> 59         <Setter.Value> 60           <ControlTemplate TargetType="Slider"> 61             <Grid> 62               <Border BorderBrush="Red" BorderThickness="0" CornerRadius="0,0,0,0"> 63                 <Track Name="PART_Track"> 64                   <Track.DecreaseRepeatButton> 65                     <RepeatButton Style="{StaticResource Slider_RepeatButton}" Command="Slider.DecreaseLarge"/> 66                   </Track.DecreaseRepeatButton> 67                   <Track.IncreaseRepeatButton> 68                     <RepeatButton Style="{StaticResource Slider_RepeatButton1}" Command="Slider.IncreaseLarge"/> 69                   </Track.IncreaseRepeatButton> 70                   <Track.Thumb> 71                     <Thumb Style="{StaticResource Slider_Thumb}"/> 72                   </Track.Thumb> 73                 </Track> 74               </Border> 75             </Grid> 76           </ControlTemplate> 77         </Setter.Value> 78       </Setter> 79     </Style> 80  81  82     <Style x:Key="Button_Close" TargetType="Button"> 83       <Setter Property="Template"> 84         <Setter.Value> 85           <ControlTemplate> 86             <Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Close.jpg"></Image> 87           </ControlTemplate> 88         </Setter.Value> 89       </Setter> 90     </Style> 91  92     <Style x:Key="Button_Forbidden" TargetType="Button"> 93       <Setter Property="Template"> 94         <Setter.Value> 95           <ControlTemplate> 96             <Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Forbidden.jpg"></Image> 97           </ControlTemplate> 98         </Setter.Value> 99       </Setter>100     </Style>101 102 103     <Style x:Key="Button_Left" TargetType="Button">104       <Setter Property="Template">105         <Setter.Value>106           <ControlTemplate>107             <Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Left.png" Stretch="Fill"></Image>108           </ControlTemplate>109         </Setter.Value>110       </Setter>111     </Style>112 113 114     <Style x:Key="Button_Right" TargetType="Button">115       <Setter Property="Template">116         <Setter.Value>117           <ControlTemplate>118             <Image x:Name="IMG" Source="E:\Test\WPFTest\Sources\Right.png" Stretch="Fill"></Image>119           </ControlTemplate>120         </Setter.Value>121       </Setter>122     </Style>123 124   </Window.Resources>125 126   <Grid Name="Main_Grid">127     <Grid.RowDefinitions>128       <RowDefinition Height="50"></RowDefinition>129       <RowDefinition Height="500"></RowDefinition>130       <RowDefinition Height="50"></RowDefinition>131     </Grid.RowDefinitions>132 133     <Border Name="title_Border" BorderBrush="#FBD3D0CD" BorderThickness="3" Grid.Row="0">134       <Grid Name="Title">135         <Grid.ColumnDefinitions>136           <ColumnDefinition Width="200"></ColumnDefinition>137           <ColumnDefinition Width="400"></ColumnDefinition>138           <ColumnDefinition Width="120"></ColumnDefinition>139           <ColumnDefinition Width="80"></ColumnDefinition>140         </Grid.ColumnDefinitions>141 142         <Grid Grid.Column="1">143           <Canvas x:Name="ParticleHost" Width="400" >144             <TextBlock Name="txtB_Step" Grid.Column="1" Width="200" Height="30" TextAlignment="Center" FontSize="20" FontFamily="Microsoft YaHei" Text="asss" Margin="100,7,0,0"/>145           </Canvas>146         </Grid>147         148         <Grid Name="grid_Cofig" Grid.Column="3">149         <Button Name="btn_Forbidden" Width="30" 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="1" ToolTipService.Placement="Bottom">150           <Button.RenderTransform>151             <RotateTransform x:Name="trans_forbidden" Angle="0"/>152           </Button.RenderTransform>153           <Button.Triggers>154             <EventTrigger RoutedEvent="Button.MouseEnter">155               <BeginStoryboard >156                 <Storyboard>157                   <DoubleAnimation From="0" To="90" Duration="0:0:0.4"158                       Storyboard.TargetName="trans_forbidden"159                       Storyboard.TargetProperty="Angle"/>160                 </Storyboard>161               </BeginStoryboard>162             </EventTrigger>163           </Button.Triggers>164         </Button>165         </Grid>166 167         <Popup x:Name="Pop" PopupAnimation="Slide" Placement="Bottom" Width="93" Height="58" PlacementTarget="{Binding ElementName=grid_Cofig}" AllowsTransparency="True" StaysOpen="False" IsOpen="False" >168           <Border Background="White" BorderBrush="#FFC4C9CD" BorderThickness="2" Width="93">169             <StackPanel Margin="1">170               <StackPanel Name="sp_play" Orientation="Horizontal" Width="83" Height="22" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="2" MouseEnter="sp_play_enter" MouseLeave="sp_play_leave" >171                 <CheckBox x:Name="ch_play" VerticalAlignment="Center" Margin="3,4" />172                 <TextBlock x:Name="txb_play" Text="不再播放" Margin="5,0" VerticalAlignment="Center"/>173               </StackPanel>174               <StackPanel Name="sp_doc" Width="83" Height="22" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="2" MouseEnter="sp_doc_enter" MouseLeave="sp_doc_leave">175                 <TextBlock Name="txb_Doc" Text="官方帮助文档" Margin="4,0,5,0" VerticalAlignment="Center">176                 </TextBlock>177               </StackPanel>178             </StackPanel>179           </Border>180         </Popup>181 182         <Button Name="btn_Close" Grid.Column="3" Width="30" 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="1" ToolTipService.Placement="Bottom">183           <Button.RenderTransform>184             <RotateTransform x:Name="trans" Angle="0"/>185           </Button.RenderTransform>186           <Button.Triggers>187             <EventTrigger RoutedEvent="Button.MouseEnter">188               <BeginStoryboard >189                 <Storyboard>190                   <DoubleAnimation From="0" To="90" Duration="0:0:0.4"191                       Storyboard.TargetName="trans"192                       Storyboard.TargetProperty="Angle"/>193                 </Storyboard>194               </BeginStoryboard>195             </EventTrigger>196           </Button.Triggers>197         </Button>198 199       </Grid>200     </Border>201 202 203     <Grid Name="Movie" Grid.Row="1">204       <MediaElement Stretch="Fill" LoadedBehavior="Manual" Name="QS_Movie" MediaOpened="Element_MediaOpened" Loaded="QS_Movie_Loaded" MouseLeftButtonDown="QS_Movie_MouseLeftButtonDown" />205       <Button Name="btn_pre" Width="30" Height="40" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Left_Click" Focusable="False" Style="{StaticResource Button_Left}"/>206       <Button Name="btn_next" Width="30" Height="40" HorizontalAlignment="Right" VerticalAlignment="Center" Click="Right_Click" Focusable="False" Style="{StaticResource Button_Right}"/>207     </Grid>208 209 210     <Border Name="Progress_Border" BorderBrush="#FBD3D0CD" BorderThickness="3" Grid.Row="2">211       <Grid Name="Control_Progress" >212         <Slider Grid.Column="0" Width="700" Name="timelineSlider" VerticalAlignment="Center" PreviewMouseLeftButtonDown="timelineMDown" PreviewMouseLeftButtonUp="timelineMUp" BorderThickness="0,6,0,0" />213       </Grid>214     </Border>215 216   </Grid>217 </Window>

 

       后台:

 1 using System.Windows.Media; 2 using System.Windows.Media.Effects; 3 using System.Windows.Shapes; 4  5 namespace WPF_Nav 6 { 7   public class Particle 8   { 9     public Point3D Position { get; set; }10     public Point3D Velocity { get; set; }11     public double Size { get; set; }12     public Ellipse Ellipse { get; set; }13     public BlurEffect Blur { get; set; }14     public Brush Brush { get; set; }15   }16 }

 

 1 namespace WPF_Nav 2 { 3   public class Point3D 4   { 5     public double X { get; set; } 6     public double Y { get; set; } 7     public double Z { get; set; } 8  9     public Point3D(double X, double Y, double Z)10     {11       this.X = X;12       this.Y = Y;13       this.Z = Z;14     }15   }16 }

     主体:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Controls.Primitives; 9 using System.Windows.Data; 10 using System.Windows.Documents; 11 using System.Windows.Input; 12 using System.Windows.Media; 13 using System.Windows.Media.Imaging; 14 using System.Windows.Navigation; 15 using System.Windows.Shapes; 16 using System.Windows.Threading; 17 using System.Windows.Media.Effects; 18  19 namespace WPF_Nav 20 { 21   /// <summary> 22   /// MainWindow.xaml 的交互逻辑 23   /// </summary> 24   public partial class MainWindow : Window 25   { 26     DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); // 定义一个DT 27     bool play_flag = true; //判断播放状态 28     int play_now = 0;    //判断当前视频索引 29     int play_target; 30     List<string> Play_Video = new List<string>(); 31     List<string> Title_Video = new List<string>(); 32  33  34  35     public MainWindow() 36     { 37       InitializeComponent(); 38       Play_Video = LoadMovies(); 39       Title_Video = LoadTitles(); 40     } 41  42     private List<string> LoadTitles() 43     { 44       List<string> list_title = new List<string>(); 45       list_title.Add("Step1"); 46       list_title.Add("Step2"); 47       list_title.Add("Step3"); 48       return list_title; 49     } 50     private List<string> LoadMovies() 51     { 52       List<string> Movie_Uri = new List<string>(); 53       Movie_Uri.Add(@"E:\Test\WPFTest\Sources\preview.mp4"); 54       Movie_Uri.Add(@"E:\Test\WPFTest\Sources\preview1.mp4"); 55       Movie_Uri.Add(@"E:\Test\WPFTest\Sources\preview2.mp4"); 56       return Movie_Uri; 57     } 58  59     private void Play_Click(object sender, RoutedEventArgs e) 60     {      61       QS_Movie.Play();      62     } 63  64     private void Pause_Click(object sender, RoutedEventArgs e) 65     { 66       QS_Movie.Pause();      67     } 68  69     private void Element_MediaOpened(object sender, EventArgs e) 70     { 71       timelineSlider.Maximum = QS_Movie.NaturalDuration.TimeSpan.TotalMilliseconds; //设置slider最大值 72       dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); //超过计时间隔时发生 73       dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 200); //DT间隔 74       dispatcherTimer.Start(); //DT启动  75     } 76  77     private void dispatcherTimer_Tick(object sender, EventArgs e) 78     { 79       int time = (int)QS_Movie.Position.TotalSeconds; 80       timelineSlider.ToolTip = SecToTime(time); 81       timelineSlider.Value = QS_Movie.Position.TotalMilliseconds; //slider滑动值随播放内容位置变化 82     } 83  84     private string SecToTime(int sec) 85     { 86       int min = sec / 60; 87       sec = sec - min * 60; 88       int hour = min / 60; 89       min = min - hour * 60; 90       string h = hour.ToString(); 91       string mm = ((min < 10) ? "0" : "") + min.ToString(); 92       string ss = ((sec < 10) ? "0" : "") + sec.ToString(); 93       string time = h + ":" + mm + ":" + ss; 94       return time; 95     } 96     private void timelineMDown(object sender, EventArgs e) 97     { 98       dispatcherTimer.Stop(); 99     }100     private void timelineMUp(object sender, EventArgs e)101     {102       QS_Movie.Position = new TimeSpan(0, 0, 0, 0, (int)timelineSlider.Value);103       dispatcherTimer.Start();104       QS_Movie.Play();105     }106 107     108 109     private void QS_Movie_Loaded(object sender, RoutedEventArgs e)110     {111       PreLoad(400,play_now);112       113     }114 115     private void Left_Click(object sender, RoutedEventArgs e)116     {117         play_target = (play_now + Play_Video.Count-1) % Play_Video.Count;118         PreLoad(200, play_target);119         play_now = play_target;      120     }121 122     private void Right_Click(object sender, RoutedEventArgs e)123     {124        play_target = (play_now + 1) % Play_Video.Count;125        PreLoad(200, play_target);126        play_now = play_target;127     }128 129     private void PreLoad(int interval, int index)130     {131       QS_Movie.Source = new Uri(Play_Video[index]);     132       QS_Movie.Play();133       System.Threading.Thread.Sleep(interval);134       QS_Movie.Pause();135       txtB_Step.Text = Title_Video[index];136     }137 138 139 140     141 142     private void QS_Movie_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)143     {144       145       if(play_flag==true)146       {147         QS_Movie.Play();148         btn_pre.Visibility = System.Windows.Visibility.Hidden;              149         btn_next.Visibility = btn_pre.Visibility = System.Windows.Visibility.Hidden;        150       }151       if(play_flag==false)152       {153         QS_Movie.Pause();154         btn_pre.Visibility = System.Windows.Visibility.Visible;155         btn_next.Visibility = System.Windows.Visibility.Visible;156                157       }158       play_flag = !play_flag;159     }160 161     private void Close_Click(object sender, RoutedEventArgs e)162     {163       this.Close();164     }165 166     private void Config_Click(object sender, RoutedEventArgs e)167     {168       this.Pop.IsOpen = true;169     }170 171     private void sp_play_enter(object sender, MouseEventArgs e)172     {173       Brush br_bg = new SolidColorBrush(Color.FromRgb(0, 162, 232));174       Brush br_white = new SolidColorBrush(Color.FromRgb(255, 255, 255));175       txb_play.Foreground = br_white;176       sp_play.Background = br_bg;177     }178 179     private void sp_play_leave(object sender, MouseEventArgs e)180     {181       Brush br_white = new SolidColorBrush(Color.FromRgb(255, 255, 255));182       Brush br_black = new SolidColorBrush(Color.FromRgb(0, 0, 0));183       txb_play.Foreground = br_black;184       sp_play.Background = br_white;185     }186 187     private void sp_doc_enter(object sender, MouseEventArgs e)188     {189       Brush br_bg = new SolidColorBrush(Color.FromRgb(0, 162, 232));190       Brush br_white = new SolidColorBrush(Color.FromRgb(255, 255, 255));191       txb_Doc.Foreground = br_white;192       sp_doc.Background = br_bg;193     }194 195     private void sp_doc_leave(object sender, MouseEventArgs e)196     {197       Brush br_white = new SolidColorBrush(Color.FromRgb(255, 255, 255));198       Brush br_black = new SolidColorBrush(Color.FromRgb(0, 0, 0));199       txb_Doc.Foreground = br_black;200       sp_doc.Background = br_white;201     }202 203 204 205 206 207 208     /// <summary>209     /// 特效部分210     /// </summary>211   212     List<Particle> particles = new List<Particle>();213     List<Particle> deadList = new List<Particle>();214     Random random = new Random();215 216 217     private void Window_Loaded(object sender, RoutedEventArgs e)218     {219       timer.Interval = TimeSpan.FromMilliseconds(10);220       timer.Tick += new EventHandler(timer_Tick);221       timer.Start();222     }223 224     void timer_Tick(object sender, EventArgs e)225     {226       UpdateParticules();227     }228 229     DispatcherTimer timer = new DispatcherTimer();230 231     double elapsed = 0.1;232     private void UpdateParticules()233     {234       //更新粒子信息235       deadList.Clear();236       foreach (Particle p in this.particles)237       {238         if (p.Position.Y < -p.Size || p.Position.X < -p.Size || p.Position.X > Width + p.Size)239         {240           deadList.Add(p);241         }242         else243         {244           //更新位置245           p.Position.X += p.Velocity.X * elapsed;246           p.Position.Y += p.Velocity.Y * elapsed;247           p.Position.Z += p.Velocity.Z * elapsed;248           TranslateTransform t = (p.Ellipse.RenderTransform as TranslateTransform);249           t.X = p.Position.X;250           t.Y = p.Position.Y;251 252           //更新颜色信息253           p.Ellipse.Fill = p.Brush;254           p.Ellipse.Effect = p.Blur;255         }256       }257 258       //创建新的粒子259       for (int i = 0; i < 10 && this.particles.Count < 40; i++)260       {261         //尝试循环使用已有例子262         if (deadList.Count - 1 >= i)263         {264           SpawnParticle(deadList[i].Ellipse);265           deadList[i].Ellipse = null;266         }267         else268         {269           SpawnParticle(null);270         }271       }272 273       foreach (Particle p in deadList)274       {275         if (p.Ellipse != null) ParticleHost.Children.Remove(p.Ellipse);276         this.particles.Remove(p);277       }278     }279 280     private void SpawnParticle(Ellipse e)281     {282       double x = RandomWithVariance(Width / 2, Width / 2);283       double y = Height;284       double z = 10 * (random.NextDouble() * 100);285       double speed = RandomWithVariance(10, 10);286       double size = RandomWithVariance(10,10);287 288       Particle p = new Particle();289       p.Position = new Point3D(x, y, z);290       p.Size = size;291 292       //模糊293       var blur = new BlurEffect();294       blur.RenderingBias = RenderingBias.Performance;295       blur.Radius = RandomWithVariance(5, 5);296       p.Blur = blur;297       //颜色298       var brush = (Brush)Brushes.Lime.Clone();299       brush.Opacity = RandomWithVariance(0.6, 0.5);300       p.Brush = brush;301 302       TranslateTransform t;303 304       if (e != null)305       {306         e.Fill = null;307         e.Width = e.Height = size;308         p.Ellipse = e;309 310         t = e.RenderTransform as TranslateTransform;311       }312       else313       {314         p.Ellipse = new Ellipse();315         p.Ellipse.Width = p.Ellipse.Height = size;316         this.ParticleHost.Children.Add(p.Ellipse);317 318         t = new TranslateTransform();319         p.Ellipse.RenderTransform = t;320         p.Ellipse.RenderTransformOrigin = new Point(0.5, 0.5);321 322       }323 324       t.X = p.Position.X;325       t.Y = p.Position.Y;326 327       double velocityMultiplier = (random.NextDouble() + 0.25) * speed;328       double vX = (1.0 - (random.NextDouble() * 2.0)) * velocityMultiplier;329       double vY = -Math.Abs((1.0 - (random.NextDouble() * 2.0)) * velocityMultiplier);330 331       p.Velocity = new Point3D(vX, vY, 0);332 333       this.particles.Add(p);334     }335 336     private double RandomWithVariance(double midvalue, double variance)337     {338       double min = Math.Max(midvalue - (variance / 2), 0);339       double max = midvalue + (variance / 2);340       double value = min + ((max - min) * random.NextDouble());341       return value;342     }343 344   }345 346 347 348 }

 三、效果

四、小结

      WPF挺好玩的!前台就能解决一些基本的动画效果,加上后台简直爽。最后,感谢单位的老司机们!