在我的TPL应用程序中,我希望通过PlayTTS(string text)
方法播放文本到语音。
public static CancellationTokenSource cTokenSource = new CancellationTokenSource();
public static CancellationToken cToken = cTokenSource.Token;
然后在消费者方法中。
async Task Consumer()
{
try
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 50,
CancellationToken = cToken
};
var consumerBlock = new ActionBlock<AppointmentReminder>(
remainder =>
{
if (cToken.IsCancellationRequested)
return;
Dictionary<string, string> dict = new OutboundDial(ts).RunScript(remainder, cToken);
// update UI by the returned dictionary
},
executionDataflowBlockOptions);
m_bufferBlock.LinkTo(
consumerBlock, new DataflowLinkOptions { PropagateCompletion = true });
await consumerBlock.Completion;
}
我有一个取消流程的按钮事件(WPF)。
private void Cancel_Click(object sender, RoutedEventArgs e)
{
cTokenSource.Cancel();
}
您看到cToken.IsCancellationRequested
中有ActionBlock
,但是虽然我已经传入了取消令牌,但它无法在方法OutboundDial(ts).RunScript(remainder, cToken);
中停止该过程。
现在让我们看看方法RunScript
。
public Dictionary<string, string> RunScript(AppointmentReminder callData, CancellationToken cToken)
{
try
{
m_ChannelResource = m_TelephonyServer.GetChannel() as SipChannel;
m_VoiceResource = m_ChannelResource.VoiceResource;
// Many logging
// Dial out
MakeTest(callData, cToken);
}
catch
{throw;}
finally
{
// destroy m_ChannelResource and m_VoiceResource
}
return dict;
}
关键点是方法MakeTest
,我们在其中PlayTTS
;
public void MakeTest(AppointmentReminder callData, CancellationToken cToken)
{
try
{
if (!cToken.IsCancellationRequested)
{
m_VoiceResource.PlayTTS(callData.Text);
}
else
{
cToken.ThrowIfCancellationRequested();
m_VoiceResource.Stop(); // Stops any current activity on m_VoiceResource.
dict["ConnectedTime"] = " no connection";
dict["DialingResult"] = " cancellation";
}
单击取消按钮时,我当前的代码未到达m_VoiceResource.Stop()
部分。
所以我的问题是cTokenSource.Cancel();
时,如何让代码运行在:
m_VoiceResource.Stop(); // Stops any current activity on m_VoiceResource.
dict["ConnectedTime"] = " no connection";
dict["DialingResult"] = " cancellation";
编辑:2014年10月31日下午1:10
根据Servy的评论,我使用了cToken.Register(() => m_VoiceResource.Stop());
我在OneDrive创建了一个类似的演示。
答案 0 :(得分:5)
在您检查了令牌是否被取消并开始播放后,您取消了令牌。你永远不会再回去再次执行这个条件来停止。
您需要做的只是注册一个回调令牌的取消,以阻止玩家:
cToken.Register(() => m_VoiceResource.Stop());
只需在开始游戏后立即添加注册即可。
答案 1 :(得分:0)
最后,我在Microsoft MVP的帮助下找到了解决方案。 Servy的解决方案很漂亮,但有缺陷。
cToken.Register(() => m_VoiceResource.Stop());
注册应该在开始播放之前而不是之后进行。
编辑: 2014年11月10日上午8:09
更好的一个:
cToken.Register(() => m_VoiceResource.Stop());
return;