异常:应用程序调用了为不同线程封送的接口

本文关键字:线程 接口 应用程序 调用 异常 | 更新日期: 2023-09-27 18:19:39

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;
}

应用程序接口。AutenticarUsuario((;异步调用 rest API,完成后调用事件处理程序 API。AutenticarUsuarioFinalizado 并在 ProgressBar.IsIndesure = false 行中得到此错误; 因为调用打开了一个新线程,我该如何修复它?错误是:

应用程序调用了为不同线程封送的接口。

异常:应用程序调用了为不同线程封送的接口

问题是事件处理程序不会在 UI 线程上执行。我认为解决此问题的最佳方法是使用以下TaskCompletionSource将EAP(基于事件的异步模式(方法转换为TAP(基于任务的异步模式(:

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;
    }
}

由于await Task将始终在原始上下文中恢复,因此您不会以这种方式获得异常。作为另一个优势,您不必像使用 EAP 那样"由内而外"编写代码。

还应考虑使用绑定,而不是手动设置 UI 控件的属性。

您的 AutenticarUsuarioFinalizado 事件处理程序可能在与 UI 线程不同的线程中执行。应仅从 UI 线程修改/创建 UI 对象。在事件处理程序中使用调度程序,请查看此处:在 WinRT 中的 UI 线程上运行代码

var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
api.AutenticarUsuarioFinalizado += (o, args) =>
{
   dispatcher.RunAsync(DispatcherPriority.Normal, () => 
       ProgressBar.IsIndeterminate = false;
       ProgressBar.Visibility = Visibility.Collapsed;
   [...]