• WPF 仿语音播放 自定义控件


    原理很简单,利用Path画一个图,然后用动画进行播放,播放时间由依赖属性输入赋值与控件内部维护的一个计时器进行控制。

    控件基本是玩具,无法作为真实项目使用。

    因为没有设置播放源,所以编写异步播放源或者实际播放时候要将事件引发,是否播放等属性,事件移到真实播放事件

    非专业UI,即使知道怎么画图也是画的不如意,到底是眼睛会了,手不行啊。

    主界面xaml

       <local:VoiceAnimeButton    Height="40" Width="200" IconMargin="5,0,-8,0"  HorizontalContentAlignment="Center"  CornerRadius="15" VerticalContentAlignment="Center" BorderBrush="Black"  IconFill="Black"    BorderThickness="1" Background="Transparent"   VoicePlayTime="0:0:1" >
                <local:VoiceAnimeButton.ContentTemplate>
                    <DataTemplate>
                        <TextBlock FontSize="10" >
                         <Run Text="播放时间"/>
                         <Run Text="{Binding  RelativeSource={RelativeSource AncestorLevel=1,AncestorType=local:VoiceAnimeButton,Mode=FindAncestor}, Path=VoicePlayTime}"/>
                         <Run Text="  "/>
                         <Run Text="状态: "/>
                         <Run Text="{Binding  RelativeSource={RelativeSource AncestorLevel=1,AncestorType=local:VoiceAnimeButton,Mode=FindAncestor}, Path=IsVoicePlay}"/>
                        </TextBlock>
                    </DataTemplate>
                </local:VoiceAnimeButton.ContentTemplate>
            </local:VoiceAnimeButton>

    控件设计XAML

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:声音播放动画">
    
    
        <Style TargetType="{x:Type local:VoiceAnimeButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:VoiceAnimeButton}">
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"  CornerRadius="{TemplateBinding CornerRadius}" Padding="1">
                            <Grid  >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Border Margin="{TemplateBinding IconMargin}" >
                                    <Viewbox>
                                        <Path x:Name="VoicePath"  Height="{TemplateBinding IconHieght}" Width="{TemplateBinding IconWidth}"   Fill="{TemplateBinding IconFill}" >
                                            <Path.Data>
                                                <PathGeometry>
                                                    <PathFigureCollection>
                                                        M20 20 Q12 45 20 85 l7 -4 Q18 48 27 23 l-7 -3Z
                                        M32 29 Q22 45 32 75 l7 -4 Q29 50 38 33 l-6.5 -4
                                        M45 35 Q38 48 45 68 l7 -4 Q45 50 52 39 l-7.5 -4
                                        M58 41 Q55 49 58 61 l17 -11Z
                                                    </PathFigureCollection>
                                                </PathGeometry>
                                            </Path.Data>
                                        </Path>
                                    </Viewbox>
                                </Border>
                                <ContentPresenter Grid.Column="1"   HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <EventTrigger  RoutedEvent="VoicePlayStart">
                                <BeginStoryboard x:Name="bs1">
                                    <Storyboard Storyboard.TargetProperty="Data" Storyboard.TargetName="VoicePath" RepeatBehavior="Forever" Duration="0:0:0.4" BeginTime="0">
                                        <ObjectAnimationUsingKeyFrames>
                                            <DiscreteObjectKeyFrame KeyTime="0:0:0.1">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <PathGeometry>
                                                        <PathFigureCollection>
                                                            M45 35 Q38 48 45 68 l7 -4 Q45 50 52 39 l-7.5 -4
                                                            M58 41 Q55 49 58 61 l17 -11Z
                                                        </PathFigureCollection>
                                                    </PathGeometry>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                            <DiscreteObjectKeyFrame KeyTime="0:0:0.2">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <PathGeometry>
                                                        <PathFigureCollection>
                                                            M32 29 Q22 45 32 75 l7 -4 Q29 50 38 33 l-6.5 -4
                                                            M45 35 Q38 48 45 68 l7 -4 Q45 50 52 39 l-7.5 -4
                                                            M58 41 Q55 49 58 61 l17 -11Z
                                                        </PathFigureCollection>
                                                    </PathGeometry>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                            <DiscreteObjectKeyFrame KeyTime="0:0:0.3">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <PathGeometry>
                                                        <PathFigureCollection>
                                                            M20 20 Q12 45 20 85 l7 -4 Q18 48 27 23 l-7 -3Z
                                                            M32 29 Q22 45 32 75 l7 -4 Q29 50 38 33 l-6.5 -4
                                                            M45 35 Q38 48 45 68 l7 -4 Q45 50 52 39 l-7.5 -4
                                                            M58 41 Q55 49 58 61 l17 -11Z
                                                        </PathFigureCollection>
                                                    </PathGeometry>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
    
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="VoicePlayEnd">
                                <RemoveStoryboard BeginStoryboardName="bs1"/>
                            </EventTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    控件CS代码

    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.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;
    
    namespace 声音播放动画
    {
       
        public class VoiceAnimeButton : ContentControl
        {
            static VoiceAnimeButton()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(VoiceAnimeButton), new FrameworkPropertyMetadata(typeof(VoiceAnimeButton)));
            }
    
            private DispatcherTimer Timer;
    
            public VoiceAnimeButton()
            {
                Timer = new DispatcherTimer();
                Timer.Tick += Timer_Tick;
                Timer.Interval = TimeSpan.FromSeconds(1);
            }
    
            private void Timer_Tick(object sender, EventArgs e)
            {
                Timer.Stop();
                IsVoicePlay = false;
                this.RaiseEvent(new RoutedEventArgs(VoicePlayEndEvent, this));
    
            }
    
            public static readonly RoutedEvent VoicePlayStartEvent = EventManager.RegisterRoutedEvent("VoicePlayStart", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VoiceAnimeButton));
    
            /// <summary>
            /// 声音播放开始事件
            /// </summary>
            public event RoutedEventHandler VoicePlayStart
            {
                add
                {
                    this.AddHandler(VoicePlayStartEvent, value);
                }
                remove
                {
                    RemoveHandler(VoicePlayStartEvent, value);
                }
            }
    
    
            public static readonly RoutedEvent VoicePlayEndEvent= EventManager.RegisterRoutedEvent("VoicePlayEnd", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VoiceAnimeButton));
    
            /// <summary>
            /// 声音播放结束事件
            /// </summary>
            public event RoutedEventHandler VoicePlayEnd
            {
                add
                {
                   AddHandler(VoicePlayEndEvent, value);
                }
                remove
                {
                    RemoveHandler(VoicePlayEndEvent, value);
                }
            }
    
            protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
            {
                base.OnMouseLeftButtonDown(e);
                IsMouseLeftClick = true;
                Timer.Interval = VoicePlayTime;
                Timer.Start();
                IsVoicePlay = true;
                this.RaiseEvent(new RoutedEventArgs(VoicePlayStartEvent,this));
               
            }
            protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
            {
                base.OnMouseLeftButtonUp(e);
                IsMouseLeftClick = false;
            }
    
            public static readonly DependencyProperty VoicePlayTimeProperty = DependencyProperty.Register("VoicePlayTime", typeof(TimeSpan), typeof(VoiceAnimeButton), new PropertyMetadata(TimeSpan.FromMilliseconds(1000)));
          
            public TimeSpan VoicePlayTime
            {
                get => (TimeSpan)GetValue(VoicePlayTimeProperty);
                set => SetValue(VoicePlayTimeProperty, value);
            }
            public static readonly DependencyProperty IsMouseLeftClickProperty = DependencyProperty.Register("IsMouseLeftClick", typeof(bool), typeof(VoiceAnimeButton),new PropertyMetadata(false));
    
            public bool IsMouseLeftClick
            {
                get => (bool)GetValue(IsMouseLeftClickProperty);
                set => SetValue(IsMouseLeftClickProperty, value);
            }
            public static readonly DependencyProperty IconWidthProperty = DependencyProperty.Register("IconWidth", typeof(double), typeof(VoiceAnimeButton), new PropertyMetadata(100.0));
    
            public double IconWidth
            {
                get => Convert.ToDouble(IconWidthProperty);
                set => SetValue(IconWidthProperty, value);
            }
            public static readonly DependencyProperty IconHieghtProperty = DependencyProperty.Register("IconHieght", typeof(double), typeof(VoiceAnimeButton), new PropertyMetadata(100.0));
    
            public double IconHieght
            {
                get => Convert.ToDouble(IconHieghtProperty);
                set => SetValue(IconHieghtProperty, value);
            }
    
            public static readonly DependencyProperty IconFillProperty= DependencyProperty.Register("IconFill", typeof(SolidColorBrush), typeof(VoiceAnimeButton), new PropertyMetadata(new SolidColorBrush(Colors.Black)));
    
            public SolidColorBrush IconFill
            {
                get => GetValue(IconFillProperty) as SolidColorBrush;
                set => SetValue(IconFillProperty, value);
            }
    
            public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(VoiceAnimeButton), new PropertyMetadata(new CornerRadius(0)));
    
            public CornerRadius CornerRadius
            {
                get => (CornerRadius)GetValue(CornerRadiusProperty);
                set => SetValue(CornerRadiusProperty, value);
            }
            public static readonly DependencyProperty IconMarginProperty = DependencyProperty.Register("IconMargin", typeof(Thickness), typeof(VoiceAnimeButton), new PropertyMetadata(new Thickness(0.0)));
    
            public Thickness IconMargin
            {
                get => (Thickness)GetValue(IconMarginProperty);
                set => SetValue(IconMarginProperty, value);
            }
    
            public static readonly DependencyProperty IsVoicePlayProperty = DependencyProperty.Register("IsVoicePlay", typeof(bool), typeof(VoiceAnimeButton));
    
            public bool IsVoicePlay
            {
                get => (bool)GetValue(IsVoicePlayProperty);
                set => SetValue(IsVoicePlayProperty, value);
            }
        }
    }
  • 相关阅读:
    JavaScript中判断函数是new还是()调用
    IE6/7 and IE8/9(Q)中td的上下padding失效
    JQuery中html()方法使用不当带来的陷阱
    有name为action的表单元素时取form的属性action杯具了
    为非IE浏览器添加mouseenter,mouseleave事件
    各浏览器中querySelector和querySelectorAll的实现差异
    仅IE6/7/8中innerHTML返回值忽略英文空格
    各浏览器关键字/保留字作为对象属性的差异
    各浏览器中鼠标按键值的差异
    给body标签和document.body都添加点击事件后仅Firefox弹出了两次
  • 原文地址:https://www.cnblogs.com/T-ARF/p/12727925.html
Copyright © 2020-2023  润新知