首页 > 解决方案 > 使用异步任务和 Textbox.Text = "Hello" 时出现问题

问题描述

首先,抱歉,因为我对 C# 还很陌生,所以我决定提出这个问题,因为我已经为此窒息了好几个小时。

我有一个与 Google Cloud Speech 服务配合使用并进行 Speech-to-Text 操作的 GUI。我与您分享单击按钮时运行的整个方法:

private async Task<object> StreamingMicRecognizeAsync(int seconds)
    {
        if (NAudio.Wave.WaveIn.DeviceCount < 1)
        {
            Console.WriteLine("No microphone!");
            return -1;
        }

        GoogleCredential googleCredential;
        using (Stream m = new FileStream(@"..\..\credentials.json", FileMode.Open))
            googleCredential = GoogleCredential.FromStream(m);
        var channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host,
            googleCredential.ToChannelCredentials());
        var speech = SpeechClient.Create(channel);

        var streamingCall = speech.StreamingRecognize();

        // Write the initial request with the config.
        await streamingCall.WriteAsync(
            new StreamingRecognizeRequest()
            {
                StreamingConfig = new StreamingRecognitionConfig()
                {
                    Config = new RecognitionConfig()
                    {
                        Encoding =
                        RecognitionConfig.Types.AudioEncoding.Linear16,
                        SampleRateHertz = 48000,
                        LanguageCode = "es-ES",
                    },
                    InterimResults = true,
                }
            });

        // Read from the microphone and stream to API.
        object writeLock = new object();
        bool writeMore = true;
        var waveIn = new NAudio.Wave.WaveInEvent();
        waveIn.DeviceNumber = 0;
        waveIn.WaveFormat = new NAudio.Wave.WaveFormat(48000, 1);
        waveIn.DataAvailable +=
            (object sender, NAudio.Wave.WaveInEventArgs args) =>
            {
                lock (writeLock)
                {
                    if (!writeMore) return;
                    streamingCall.WriteAsync(
                        new StreamingRecognizeRequest()
                        {
                            AudioContent = Google.Protobuf.ByteString
                                .CopyFrom(args.Buffer, 0, args.BytesRecorded)
                        }).Wait();
                }
            };

        // Print responses as they arrive.
        Task printResponses = Task.Run(async () =>
        {
            while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
            {
                foreach (var result in streamingCall.ResponseStream
                    .Current.Results)
                {
                    foreach (var alternative in result.Alternatives)
                    {
                        Console.WriteLine(alternative.Transcript);
                        //Textbox1.Text = alternative.Transcript;
                    }
                }
            }
        });

        waveIn.StartRecording();
        Console.WriteLine("Speak now.");
        Result_Tone.Text = "Speak now:\n\n";
        await Task.Delay(TimeSpan.FromSeconds(seconds));

        // Stop recording and shut down.
        waveIn.StopRecording();
        lock (writeLock) writeMore = false;
        await streamingCall.WriteCompleteAsync();
        await printResponses;
        return 0;
    }

我的问题是我想更新Textbox1控件的内容,但它不起作用。它将输出完美地写入控制台,Console.WriteLine(alternative.Transcript);但没有写入我的文本框。

如果有人可以提供帮助,我将非常感谢他的帮助。

标签: c#async-awaitgoogle-cloud-speech

解决方案


问题是您正在使用Task.Run,这意味着您的代码将在线程池线程上运行。

而不是调用Task.Run(),只需将该代码移动到一个单独的异步方法中:

async Task DisplayResponses(IAsyncEnumerator<StreamingRecognizeResponse> responses)
{
    while (await responses.MoveNext(default(CancellationToken)))
    {
        foreach (var result in responses.Current.Results)
        {
            foreach (var alternative in result.Alternatives)
            {
                Textbox1.Text = alternative.Transcript;
            }
        }
    }
}

然后从已经在 UI 线程(例如事件处理程序)上的代码直接(不使用)调用该方法。Task.Run

异步机制将确保在await表达式之后,您回到 UI 线程(相同的同步上下文)。因此,对属性的分配Text将发生在 UI 线程上,一切都应该很好。

例如:

// This would be registered as the event handler for a button
void HandleButtonClick(object sender, EventArgs e)
{
     var stream = client.StreamingRecognize();
     // Send the initial config request
     await stream.WriteAsync(...);

     // Presumably you want to send audio data...
     StartSendingAudioData(stream);

     await DisplayResponses(stream.ResponseStream);
}

推荐阅读