zoukankan      html  css  js  c++  java
  • 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);
            }
        }
    }
  • 相关阅读:
    求一列的和,awk和perl哪个快?
    转:使用memc-nginx和srcache-nginx模块构建高效透明的缓存机制
    使用apt-get autoremove造成的系统无法开机
    因不公对待,技术销毁删除代码数据,谁对谁错?负能量文章,老板慎入。
    我曾经做过的插件
    宝石TD迷宫设计器
    VSX-5 VSXMusic 编码听音乐
    耐得住寂寞,才能守得住繁华
    VSX-4 VSXTra
    VSX-3 VSCT文件
  • 原文地址:https://www.cnblogs.com/T-ARF/p/12727925.html
Copyright © 2011-2022 走看看