文章目录
- 自定义控件
- 控件调用
- 自定义事件
- 更改音量和语速
txt阅读器系列:
- 需求分析和文件读写
- 目录提取类💎列表控件与目录
- 字体控件绑定💎前景/背景颜色
- 书籍管理系统💎用树形图管理书籍
- 语音播放💎播放进度显示💎快进快退💎语速音量
自定义控件
音量和语速都可以用数值来表示,这一点与之前的字体大小就十分相似,故其xml代码也设置为Slider
和+-
号相结合。
换言之,阅读设置中的文字大小,朗读设置中的阅读速度和阅读音量,从控件的角度来说是完全雷同的。为了提高代码的复用率,最好能够把这些TextBox, Slider, Button
等控件打包在一起,形成一个新的控件。
方法也很简单,右键TxtReader
,添加用户控件
,命名为AdvanceSlider
,其xaml
代码为
<DockPanel LastChildFill="True">
<TextBlock Text="{Binding Title}" Width="30" VerticalAlignment="Center"/>
<TextBox Width="50" Height="20" Text="{Binding Value, ElementName=slider}"/>
<Button Content="-" Width="20" Click="btnChange_Click"/>
<Button Content="+" Width="20" DockPanel.Dock="Right" Click="btnChange_Click"/>
<Slider x:Name="slider" VerticalAlignment="Center" Width="150"
Minimum="{Binding Min}" Maximum="{Binding Max}"
Value="{Binding Value}" IsSnapToTickEnabled="True"/>
</DockPanel>
其C#
代码为
public partial class AdvanceSlider : UserControl
{
public AdvanceSlider()
{
InitializeComponent();
this.DataContext = this;
}
public double Min { set; get; }
public double Max { set; get; }
public double Value { set; get; }
public string Title { set; get; }
private void btnChange_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
slider.Value += btn.Content.ToString() == "+" ? 1 : -1;
}
}
其中,this.DataContext=this
,可方便xaml
中绑定控件属性,使得后面定义的Min, Max, Value, Title
在引用时可以设置。
btnChange_Click
表示当加减号按钮被点击时,slider
随之加1或减1,这种写法其实并不陌生,只不过这次是在控件中使用罢了。
在这一切都做好之后,先别急着使用,要首先生成一下代码。
控件调用
接下来要做的,就是在主窗口中调用我们自定义的控件,其xaml
代码为
<local:AdvanceSlider Title="测试" Max="100" Min="0" Value="50"/>
非常简洁地就实现了下面的效果
自定义事件
有了这个基本控件的雏形还不够,这个控件需要可以注册事件,从而在数值发生变化的时候,可以让音量和语速发生变化。
自定义事件方法如下
public static readonly RoutedEvent ValueChangedEvent =
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(AdvanceSlider));
public event RoutedEventHandler ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
RoutedEventArgs arg = new RoutedEventArgs();
arg.RoutedEvent = ValueChangedEvent;
RaiseEvent(arg);
}
首先,通过EventManager
注册一个以ValueChanged
为标志的事件ValueChangedEvent
,然后设置ValueChanged
,其原理与set,get
如出一辙。接下来将这个新事件与现有的Slider
事件联系起来,从而当Slider
的值发生变化时,就可以触发这个新控件的ValueChanged
事件。
更改音量和语速
有了这个AndvanceSlider
,就可以非常便捷地创建音量语速更改控件了,其xaml
代码为
<local:AdvanceSlider x:Name="sSoundVolume"
Title="音量" Max="100" Min="0" Value="25" ValueChanged="sSoundVolume_ValueChanged"/>
<local:AdvanceSlider x:Name="sSpeechRate"
Title="语速" Max="10" Min="-10" Value="0" ValueChanged="sSpeechRate_ValueChanged"/>
然后修改主窗口以及MySpeech
类的代码
private void sSoundVolume_ValueChanged(object sender, RoutedEventArgs e)
{
speech.setProp(volume: (int)sSoundVolume.Value);
txt.Focus();
}
private void sSpeechRate_ValueChanged(object sender, RoutedEventArgs e)
{
speech.setProp(rate : (int)sSpeechRate.Value);
txt.Focus();
}
下面是MySpeech
中创建的setProp
函数,之所以设计得这么复杂,是因为我们使用的Speak
相当于新开了一个线程,当其运行之后,任何设置都不会生效,所以在设置之前,要将其取消,并重新开启一段线程,这与快进快退的逻辑是相同的。
public void setProp(string voice = null, int rate=-100, int volume = -100)
{
if(voice!=null)
this.voice = voice;
if (rate != -100)
this.rate = rate;
if (volume != -100)
this.volume = volume;
bool speaking = speech.State.ToString() == "Speaking";
if (speaking)
{
st += charPosition;
speech.SpeakAsyncCancelAll();
}
setSpeech(this.voice, this.rate, this.volume);
if(speaking)
Speak();
}
最终其效果为,可以明显感受到语速的变化