C# WPF实现的语音播放自定义控件
作者:ARM830 发布时间:2022-11-23 19:45:49
标签:c#,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);
}
}
}
来源:https://www.cnblogs.com/T-ARF/p/12727925.html
0
投稿
猜你喜欢
- 前言工作中是否有这样的场景,多个线程任务,如果所有线程完成到某个阶段,你希望知道所有线程均完成该阶段。当然你使用线程计数可以实现,只是不够优
- 开发环境: springboot + mybatis plus场景:在DAO的bean中有byte[]类时,写入可以成功,但是读取不行。从错
- JAVA基础八股文Switch能支持哪些类型?jdk5之前,switch能够作用在byte,short,char,int(实际上都是提升为i
- @PropertySource注解是Spring用于加载配置文件,默认支持.properties与.xml两种配置文件。@PropertyS
- 如果需要处理的数字有许多位,就可以使用BitArray类和BitVector32结构。BitArray类位于System.Collectio
- ps:我用的版本是7.0.5场景:左侧第一列宽度不够,导致数据换行。Table table = new Table(new float[2]
- 开发环境 android studio 3.0.1 已支持 kotlin1、定义接口interface CallBack{ fun call
- C#WinForm程序设计之图片浏览器,这次我们一起做一个图片查看器,这个图片查看器的原始图如下:我们首先来介绍一下这个原始图的构成:左边上
- 本文实例为大家分享了C++实现大整数乘法的具体代码,供大家参考,具体内容如下#include<iostream>#include
- 1.Java内存模型JAVA定义了一套在多线程读写共享数据时时,对数据的可见性、有序性和原子性的规则和保障。屏蔽掉不同操作系统间的微小差异。
- 1、首先导入solrj需要的的架包2、需要注意的是低版本是solr是使用SolrServer进行URL实例的,5.0之后已经使用SolrCl
- java事件机制中包含下述三要素:1、事件,发生了什么事,比如用户在界面上的一个操作(手势滑动屏幕),当一个事件发生的时候,该事件用一个事件
- 目录前言1、什么是Filter2、过滤器实现拦截过程3、过滤器与 * 的不同之处1.过滤器:2. * :3.两者的区别:4、使用Filter
- 目录前言开始总结前言小伙伴们都知道,现在市面上最流行的web开发框架就是springboot了,在springboot开始流行之前,我们都用
- 一、日志1、配置日志级别日志记录器(Logger)的行为是分等级的。如下表所示:分为:OFF、FATAL、ERROR、WARN、INFO、D
- 它所表示的是“这部分是无法修改的”。不想被改变的原因有两个:效率、设计。使用到final的有三种情况:数据、方法、类。一、 final数据有
- 1、什么是序列化与反序列化?序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传
- 1、点击【File】->【Project Structure】菜单(或使用Shift+Ctrl+Alt+S快捷键),打开【Projec
- 本文实例讲述了C#修改及重置电脑密码DirectoryEntry实现方法。分享给大家供大家参考。具体如下:C#修改电脑密码方法如下:///
- Spring session 获取当前账户登录数一、登录校验成功时,向session加入关键信息,代码如下:session.setAttri