问题
private void LogInButton_Click(object sender, RoutedEventArgs e)
{
var api = new RestAPI("http://localhost:2624/", UsernameTextBox.Text, PasswordTextBox.Password);
api.AutenticarUsuarioFinalizado += (o, args) =>
{
ProgressBar.IsIndeterminate = false;
ProgressBar.Visibility = Visibility.Collapsed;
LogInButton.IsEnabled = true;
if (args.Error) return;
if (args.Resultado.Autenticado)
{
}
};
api.AutenticarUsuario();
ProgressBar.Visibility = Visibility.Visible;
ProgressBar.IsIndeterminate = true;
LogInButton.IsEnabled = false;
}
api.AutenticarUsuario(); calls a rest API asynchronously, when it's done it calls the event handler api.AutenticarUsuarioFinalizado and got this error in line ProgressBar.IsIndeterminate = false; because the call open a new thread, how can I fix it? the error is:
The application called an interface that was marshalled for a different thread.
回答1:
The problem is that your event handler doesn't execute on the UI thread. I think the best way to fix that is to convert your EAP (Event-based Asynchronous Pattern) method to TAP (Task-based Asynchronous Pattern) using TaskCompletionSource
:
public static Task<Resultado> AutenticarUsuarioAsync(this RestAPI api)
{
var tcs = new TaskCompletionSource<Resultado>();
api.AutenticarUsuarioFinalizado += (sender, args) =>
{
if (args.Error)
tcs.TrySetException(new SomeAppropriateException());
else
tcs.TrySetResult(args.Resultado);
};
api.AutenticarUsuario();
return tcs.Task;
}
…
private async void LogInButton_Click(object sender, RoutedEventArgs e)
{
var api = new RestAPI(
"http://localhost:2624/", UsernameTextBox.Text,
PasswordTextBox.Password);
ProgressBar.Visibility = Visibility.Visible;
ProgressBar.IsIndeterminate = true;
LogInButton.IsEnabled = false;
try
{
var resultado = await api.AutenticarUsuarioAsync();
if (resultado.Autenticado)
{
// whatever
}
}
catch (SomeAppropriateException ex)
{
// handle the exception here
}
finally
{
ProgressBar.IsIndeterminate = false;
ProgressBar.Visibility = Visibility.Collapsed;
LogInButton.IsEnabled = true;
}
}
Because await
ing a Task
will always resume on the original context, you're not going to get an exception this way. As an additional advantage, you don't have to write your code “inside-out”, like you do with EAP.
You should also consider using bindings, instead of setting the properties of your UI controls manually.
回答2:
Your AutenticarUsuarioFinalizado event handler is probably being executed in a thread different from the UI thread. You should only modify/create UI objects from the UI thread. Use a dispatcher in your event handler, check here: Run code on UI thread in WinRT
var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
api.AutenticarUsuarioFinalizado += (o, args) =>
{
dispatcher.RunAsync(DispatcherPriority.Normal, () =>
ProgressBar.IsIndeterminate = false;
ProgressBar.Visibility = Visibility.Collapsed;
[...]
来源:https://stackoverflow.com/questions/17245512/exception-the-application-called-an-interface-that-was-marshalled-for-a-differe