WPF音频播放动画控件
驚鏵 人气:01.实现代码
一、创建AnimationAudio.xaml代码如下
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:WPFDevelopers.Controls" xmlns:helpers="clr-namespace:WPFDevelopers.Helpers"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Basic/ControlBasic.xaml"/> <ResourceDictionary Source="Basic/Animations.xaml"/> </ResourceDictionary.MergedDictionaries> <Style TargetType="{x:Type controls:AnimationAudio}" BasedOn="{StaticResource ControlBasicStyle}"> <Setter Property="Width" Value="80"/> <Setter Property="Height" Value="35"/> <Setter Property="Cursor" Value="Hand"/> <Setter Property="Foreground" Value="{DynamicResource WhiteSolidColorBrush}"/> <Setter Property="Background" Value="{DynamicResource PrimaryNormalSolidColorBrush}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type controls:AnimationAudio}"> <ControlTemplate.Resources> <Storyboard x:Key="PlayStoryboard" RepeatBehavior="Forever"> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PathAudioTwo" Storyboard.TargetProperty="(Path.Visibility)"> <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Hidden}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PathAudioThree" Storyboard.TargetProperty="(Path.Visibility)"> <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Hidden}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames BeginTime="0:0:.3" Duration="0:0:.4" Storyboard.TargetName="PathAudioTwo" Storyboard.TargetProperty="(Path.Visibility)"> <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames BeginTime="0:0:.7" Duration="0:0:.4" Storyboard.TargetName="PathAudioThree" Storyboard.TargetProperty="(Path.Visibility)"> <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </ControlTemplate.Resources> <Border x:Name="PART_Border" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding helpers:ControlsHelper.CornerRadius}" SnapsToDevicePixels="True" UseLayoutRounding="True"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel Width="20" Height="30" HorizontalAlignment="Left" Orientation="Horizontal" Margin="10,0" RenderTransformOrigin=".5,.5" x:Name="PART_StackPanel"> <Path Data="{StaticResource PathAudioOne}" Width="4" Height="6" Stretch="Fill" Fill="{TemplateBinding Foreground}"/> <Path x:Name="PathAudioTwo" Data="{StaticResource PathAudioTwo}" Width="6" StrokeThickness="1.5" Stroke="Transparent" Margin="0,7" Stretch="Fill" Fill="{TemplateBinding Foreground}"/> <Path x:Name="PathAudioThree" Data="{StaticResource PathAudioThree}" Width="8" Margin="-3,4" Stretch="Fill" Fill="{TemplateBinding Foreground}" StrokeThickness="2" Stroke="Transparent"/> </StackPanel> <TextBlock VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}" FontSize="{DynamicResource TitleFontSize}" Grid.Column="1" x:Name="PART_TextBlock"> <Run x:Name="PART_RunTimeLength"></Run> </TextBlock> </Grid> </Border> <ControlTemplate.Triggers> <Trigger Property="IsPlay" Value="True"> <Trigger.EnterActions> <BeginStoryboard x:Name="PlayBeginStoryboard" Storyboard="{StaticResource PlayStoryboard}"/> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="PlayBeginStoryboard"/> </Trigger.ExitActions> </Trigger> <Trigger Property="IsRight" Value="True"> <Setter Property="Grid.Column" TargetName="PART_TextBlock" Value="0"/> <Setter Property="HorizontalAlignment" TargetName="PART_TextBlock" Value="Right"/> <Setter Property="Grid.Column" TargetName="PART_StackPanel" Value="1"/> <Setter Property="HorizontalAlignment" TargetName="PART_StackPanel" Value="Right"/> <Setter Property="RenderTransform" TargetName="PART_StackPanel"> <Setter.Value> <TransformGroup> <RotateTransform Angle="180"/> </TransformGroup> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
二、创建AnimationAudioe.cs代码如下
using System; using System.IO; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Interop; using WPFDevelopers.Helpers; namespace WPFDevelopers.Controls { [TemplatePart(Name = RunTemplateName, Type = typeof(Run))] public partial class AnimationAudio : Control { const string RunTemplateName = "PART_RunTimeLength"; private Run _run; private TimeSpan _timeSpan; private IntPtr _handle; private AudioWindow _win = null; static string[] mediaExtensions = { ".MP3", ".WAV" }; /// <summary> /// 音频路径 /// </summary> public string AudioPath { get { return (string)GetValue(AudioPathProperty); } set { SetValue(AudioPathProperty, value); } } public static readonly DependencyProperty AudioPathProperty = DependencyProperty.Register("AudioPath", typeof(string), typeof(AnimationAudio), new PropertyMetadata(string.Empty)); /// <summary> /// 是否右侧 /// </summary> public bool IsRight { get { return (bool)GetValue(IsRightProperty); } set { SetValue(IsRightProperty, value); } } public static readonly DependencyProperty IsRightProperty = DependencyProperty.Register("IsRight", typeof(bool), typeof(AnimationAudio), new PropertyMetadata(false)); public bool IsPlay { get { return (bool)GetValue(IsPlayProperty); } set { SetValue(IsPlayProperty, value); } } public static readonly DependencyProperty IsPlayProperty = DependencyProperty.Register("IsPlay", typeof(bool), typeof(AnimationAudio), new PropertyMetadata(false, new PropertyChangedCallback(OnIsPlayChanged))); private static void OnIsPlayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { bool newValue = (bool)e.NewValue; var animationAudio = d as AnimationAudio; if(newValue != (bool)e.OldValue) { if (newValue) { animationAudio.Play(); } else { AudioPlayer.Stop(); } } } static AnimationAudio() { DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimationAudio), new FrameworkPropertyMetadata(typeof(AnimationAudio))); } public override void OnApplyTemplate() { base.OnApplyTemplate(); _run = GetTemplateChild(RunTemplateName) as Run; if (string.IsNullOrWhiteSpace(AudioPath)) return; if (!File.Exists(AudioPath)) return; if (!mediaExtensions.Contains(Path.GetExtension(AudioPath), StringComparer.OrdinalIgnoreCase)) return; _timeSpan = AudioPlayer.GetSoundLength(AudioPath); if (_timeSpan == TimeSpan.Zero) return; _run.Text = $"{_timeSpan.Seconds.ToString()}\""; Width = 80; if (_timeSpan.Seconds > 5) { Width += _timeSpan.Seconds; } } private void Play() { if(_win != null) { _win.Close(); _win = null; } _win = new AudioWindow { Width = 0, Height = 0, Left = Int32.MinValue, Top = Int32.MinValue, WindowStyle = WindowStyle.None, ShowInTaskbar = false, ShowActivated = false, }; _win.Show(); _win.StopDelegateEvent += _win_StopDelegateEvent; _handle = new WindowInteropHelper(_win).Handle; AudioPlayer.PlaySong(AudioPath, _handle); } private void _win_StopDelegateEvent() { IsPlay = false; _win.Close(); _win = null; } } }
三、新建AudioWindow.cs代码如下
using System; using System.Windows; using System.Windows.Interop; namespace WPFDevelopers.Controls { public class AudioWindow:Window { const int MM_MCINOTIFY = 0x3B9; public delegate void StopDelegate(); public event StopDelegate StopDelegateEvent; protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; if (hwndSource != null) { hwndSource.AddHook(new HwndSourceHook(this.WndProc)); } } IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case MM_MCINOTIFY: StopDelegateEvent?.Invoke(); break; } return IntPtr.Zero; } } }
四、新建AnimationAudioExample.xaml代码如下。
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.AnimationAudioExample" 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:local="clr-namespace:WPFDevelopers.Samples.ExampleViews" xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UniformGrid Columns="2" x:Name="MyUniformGrid"> <StackPanel Orientation="Horizontal"> <wpfdev:BreathLamp Width="60" Height="60" LampEffect="Ripple" IsLampStart="true" Margin="10,0"> <Ellipse Width="50" Height="50"> <Ellipse.Fill> <ImageBrush ImageSource="pack://application:,,,/WPFDevelopers.Samples;component/Images/Breathe/0.jpg"/> </Ellipse.Fill> </Ellipse> </wpfdev:BreathLamp> <wpfdev:AnimationAudio x:Name="AnimationAudioLeft" MouseDown="AnimationAudioLeft_MouseDown"/> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <wpfdev:AnimationAudio x:Name="AnimationAudioRight" IsRight ="true" Background="{DynamicResource SuccessSolidColorBrush}" Foreground="Black" MouseDown="AnimationAudioLeft_MouseDown"/> <wpfdev:BreathLamp Width="50" Height="50" LampEffect="Streamer" Background="LightGray" IsLampStart="True" Margin="10,0"> <Ellipse Width="43" Height="43"> <Ellipse.Fill> <ImageBrush ImageSource="pack://application:,,,/WPFDevelopers.Samples;component/Images/Chat/UserImages/yanjinhua.png"/> </Ellipse.Fill> </Ellipse> </wpfdev:BreathLamp> </StackPanel> </UniformGrid> </UserControl>
六、新建AnimationAudioExample.xaml.cs下
using System; using System.IO; using System.Windows.Controls; using WPFDevelopers.Controls; using WPFDevelopers.Samples.Helpers; namespace WPFDevelopers.Samples.ExampleViews { /// <summary> /// 微信公众号:WPF开发者 /// </summary> public partial class AnimationAudioExample : UserControl { public AnimationAudioExample() { InitializeComponent(); AnimationAudioLeft.AudioPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Audio", "HelloWPFDevelopes_en.mp3"); AnimationAudioRight.AudioPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Audio", "HelloWPFDevelopes_zh.mp3"); } private void AnimationAudioLeft_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { var animationAudio = sender as AnimationAudio; var animationAudioList = ElementVisualTreeHelper.FindVisualChild<AnimationAudio>(MyUniformGrid); if (animationAudioList == null) return; if (!animationAudio.IsPlay) { animationAudioList.ForEach(h => { if (h.IsPlay && h != animationAudio) { h.IsPlay = false; } }); animationAudio.IsPlay = true; } else animationAudio.IsPlay = false; } } }
2.效果预览
加载全部内容