C# 使用异步任务和Textbox时出现问题。Text=“Hello”

C# 使用异步任务和Textbox时出现问题。Text=“Hello”,c#,async-await,google-cloud-speech,C#,Async Await,Google Cloud Speech,首先,我很抱歉,因为我是C的新手,我决定提出这个问题,因为我已经被困在这里好几个小时了 我有一个与谷歌云语音服务一起工作的GUI,可以进行语音到文本的操作。我与您分享单击按钮时运行的整个方法: private async Task<object> StreamingMicRecognizeAsync(int seconds) { if (NAudio.Wave.WaveIn.DeviceCount < 1) { C

首先,我很抱歉,因为我是C的新手,我决定提出这个问题,因为我已经被困在这里好几个小时了

我有一个与谷歌云语音服务一起工作的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;
    }
我的问题是我想更新Textbox1control的内容,但它不起作用。它使用console.WriteLinealternative.Transcript行将输出完美地写入控制台;但不是在我的文本框里


如果有人能帮助我,我将非常感谢他的帮助。

问题是您使用的是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;
            }
        }
    }
}

任务在不同的线程上运行,因此必须调用将在控件线程上执行的操作

Textbox1.Invoke(new Action(() =>
{
    Textbox1.Text= "";
}));
编辑:对于WPF,我认为等效的是

Textbox1.Dispatcher.Invoke(new Action(() =>
{
    Textbox1.Text= "";
}));

您是否尝试过使用Dispatcher.InvokeASync

await Dispatcher.InvokeAsync(() => {while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
        {
            foreach (var result in streamingCall.ResponseStream
                .Current.Results)
            {
                foreach (var alternative in result.Alternatives)
                {                       
                    Textbox1.Text = alternative.Transcript;
                }
            }
        }});    

Textbox1是在调用main方法的线程上创建的。此异步方法是一个单独的线程。您遇到的异常是,您试图从未创建GUI对象的线程更新该对象。简单的解决方案是,创建一个用于更新的委托,然后使用Textbox1.Invoke或BeginInvoke@mjwills不,它只是破坏了我的代码,甚至把我的演讲变成了文字worker@PrateekShrivastava您能给我一点指导吗?一般经验法则-一旦您开始编写基于异步/等待的代码,任何使用Task.Run或道德等价物的行为都应受到怀疑。如果您需要运行其他cpu繁重的工作,这没关系,但我通常会建议您寻找更高级别的构造,即使这样,也可以让您在手动时专注于工作,而异步/等待的部分要点是允许我们避免所有这些。异步方法是更好的方法,我想。这不起作用,因为我不能在我的文本框中调用Invoke方法:@FernandodelCastillo Olivares这是WinForms文本框还是其他什么?@p3tch这是WPFTextbox@FernandodelCastillo-Olivares更新了WPF虽然Daisy的答案是最好的谢谢你的回答,这对我来说相当困难,但似乎很管用。@FernandodelCastillo Olivares:如果你是C新手,我真的建议你稳扎稳打地学习async/await——这是一个相当高级的主题,但你需要对它有相当好的理解才能有效地使用它,依我看,如果首先从UI线程启动显示结果任务,则不需要执行此操作。
await Dispatcher.InvokeAsync(() => {while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
        {
            foreach (var result in streamingCall.ResponseStream
                .Current.Results)
            {
                foreach (var alternative in result.Alternatives)
                {                       
                    Textbox1.Text = alternative.Transcript;
                }
            }
        }});