You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForm语音转文本应用:按钮无法停止识别的解决方法

问题分析与解决方案

你的问题核心有两个:

  1. 按钮点击事件中用RecognitionWithMicrophoneAsync().Wait()阻塞了UI线程,导致后续点击无法响应,UI彻底卡死。
  2. SpeechRecognizer是方法内的局部变量,且被using包裹,无法在第二次点击时调用停止方法终止识别。

修改步骤:

  1. 将SpeechRecognizer和TaskCompletionSource改为类的成员变量,保留识别实例的引用。
  2. 按钮点击事件改为async void,使用await而非Wait(),避免阻塞UI线程。
  3. 增加状态标记_isRecognizing,用于判断当前是启动还是停止识别。
  4. 事件回调中更新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 22:33:25