C# WinForm语音转文本应用:按钮无法停止识别的解决方法
问题分析与解决方案
你的问题核心有两个:
- 按钮点击事件中用
RecognitionWithMicrophoneAsync().Wait()阻塞了UI线程,导致后续点击无法响应,UI彻底卡死。 SpeechRecognizer是方法内的局部变量,且被using包裹,无法在第二次点击时调用停止方法终止识别。
修改步骤:
- 将
SpeechRecognizer和TaskCompletionSource改为类的成员变量,保留识别实例的引用。 - 按钮点击事件改为
async void,使用await而非Wait(),避免阻塞UI线程。 - 增加状态标记
_isRecognizing,用于判断当前是启动还是停止识别。 - 事件回调中更新UI控件时,使用
Invoke确保在UI线程执行,避免跨线程操作异常。
修改后的完整代码:
using Microsoft.CognitiveServices.Speech; using Microsoft.CognitiveServices.Speech.Audio; using System; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp5 { public partial class Form1 : Form { // 类成员变量,保存识别器和停止信号 private SpeechRecognizer _recognizer; private TaskCompletionSource<int> _stopRecognition; private bool _isRecognizing = false; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // 初始化按钮和图片状态 picture_btn.Image = Properties.Resources.green; } private async Task StartRecognitionAsync() { var config = SpeechConfig.FromSubscription("key", "region"); _recognizer = new SpeechRecognizer(config); _stopRecognition = new TaskCompletionSource<int>(); _recognizer.Recognizing += (s, e) => { // 识别中事件,可按需处理 }; _recognizer.Recognized += (s, e) => { if (e.Result.Reason == ResultReason.RecognizedSpeech) { // 跨线程更新UI,需要Invoke Invoke(new Action(() => { SendKeys.SendWait(e.Result.Text); })); } else if (e.Result.Reason == ResultReason.NoMatch) { Console.WriteLine("NOMATCH: 无法识别语音"); } }; _recognizer.Canceled += (s, e) => { Console.WriteLine($"CANCELED: 原因={e.Reason}"); if (e.Reason == CancellationReason.Error) { Console.WriteLine($"CANCELED: 错误码={e.ErrorCode}"); Console.WriteLine($"CANCELED: 错误详情={e.ErrorDetails}"); Console.WriteLine("CANCELED: 请检查订阅信息是否正确?"); } // 重置状态并更新UI Invoke(new Action(() => { _isRecognizing = false; button1.Enabled = true; picture_btn.Image = Properties.Resources.green; })); _stopRecognition.TrySetResult(0); }; _recognizer.SessionStopped += (s, e) => { // 重置状态并更新UI Invoke(new Action(() => { _isRecognizing = false; button1.Enabled = true; picture_btn.Image = Properties.Resources.green; })); _stopRecognition.TrySetResult(0); }; // 启动连续识别 await _recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false); // 等待停止信号 await _stopRecognition.Task.ConfigureAwait(false); // 停止识别 await _recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false); // 释放资源 _recognizer.Dispose(); } private async void button1_Click(object sender, EventArgs e) { if (!_isRecognizing) { // 启动识别 _isRecognizing = true; button1.Enabled = false; picture_btn.Image = Properties.Resources.red; await StartRecognitionAsync(); } else { // 停止识别 _isRecognizing = false; button1.Enabled = true; picture_btn.Image = Properties.Resources.green; _recognizer.StopContinuousRecognitionAsync(); _stopRecognition.TrySetResult(0); } } } }
关键说明:
- 用
_isRecognizing标记当前识别状态,点击按钮时切换启动/停止逻辑。 - 按钮事件用
async void,内部用await避免阻塞UI线程,保证后续点击能响应。 - 所有UI控件的更新操作都通过
Invoke包装,确保在UI线程执行,防止跨线程操作异常。 - 停止识别时,主动调用
StopContinuousRecognitionAsync()并触发_stopRecognition的完成信号,让等待的任务结束。
内容的提问来源于stack exchange,提问作者Babar Ali
相关产品推荐
相关产品推荐

