Ich habe eine WinForms-App, und ich habe etwas Code, der auf dem UI-Thread ausgeführt werden muss. Der Code nach dem await
läuft jedoch auf einem anderen Thread.erwarten, ohne ConfigureAwait (falsch) in einem anderen Thread weiter
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// This runs on the UI thread.
mainContainer.Controls.Clear();
var result = await DoSomethingAsync();
// This also needs to run on the UI thread, but it does not.
// Instead it throws an exception:
// "Cross-thread operation not valid: Control 'mainContainer' accessed from a thread other than the thread it was created on"
mainContainer.Controls.Add(new Control());
}
Ich habe auch versucht explizit ConfigureAwait(true)
Zugabe, aber es macht keinen Unterschied. Mein Verständnis war, dass, wenn ich ConfigureAwait(false)
weglasse, sollte die Fortsetzung auf dem ursprünglichen Thread laufen. Ist das in manchen Situationen falsch?
Ich habe auch festgestellt, dass, wenn ich ein Steuerelement vor der Wartezeit auf die Sammlung hinzufügen, dann läuft die Fortsetzung magisch auf dem richtigen Thread.
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// This runs on the UI thread.
mainContainer.Controls.Add(new Control());
mainContainer.Controls.Clear();
var result = await DoSomethingAsync();
// This also runs on the UI thread now. Why?
mainContainer.Controls.Add(new Control());
}
Meine Frage ist:
- Warum ist das passiert?
- Wie kann ich die Fortsetzung davon überzeugen, auf dem UI-Thread zu laufen (idealerweise ohne meinen Hack ein Steuerelement hinzuzufügen und es zu entfernen)?
Als Referenz sind hier die wichtigen Teile von DoSomethingAsync
. Es sendet eine HTTP-Anfrage mit RestSharp.
protected async Task DoSomethingAsync()
{
IRestRequest request = CreateRestRequest();
// Here I await the response from RestSharp.
// Client is an IRestClient instance.
// I have tried removing the ConfigureAwait(false) part, but it makes no difference.
var response = await Client.ExecuteTaskAsync(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
throw new Exception(response.ErrorMessage ?? "The request did not complete successfully.");
if (response.StatusCode >= HttpStatusCode.BadRequest)
throw new Exception("Server responded with an error: " + response.StatusCode);
// I also do some processing of the response here; omitted for brevity.
// There are no more awaits.
}
Warum denkst du läuft das auf einem anderen Thread? Wo läuft dieser Code? Ereignishandler? – i3arnon
Ich weiß, dass es in einem anderen Thread ausgeführt wird, da der Code nach dem Warten eine Ausnahme auslöst: "Cross-Thread-Operation nicht gültig: Control 'mainContainer' zugegriffen von einem anderen Thread als der Thread, auf dem es erstellt wurde". –
Ja, der Code wird in einem Ereignishandler ausgeführt. Ich werde meine Frage aktualisieren. –