C# 使用异步任务和Textbox时出现问题。Text=“Hello”
首先,我很抱歉,因为我是C的新手,我决定提出这个问题,因为我已经被困在这里好几个小时了 我有一个与谷歌云语音服务一起工作的GUI,可以进行语音到文本的操作。我与您分享单击按钮时运行的整个方法: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
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;
}
}
}});