4

我正在尝试在 UI 调度程序上调用一个对话框:

class DialogService : IDialogService
{
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher;

    public bool? Show(IDialogViewModel viewModel)
    {
        if (_dispatcher.CheckAccess())
        {
            var dialogWindow = new DialogWindow();
            return dialogWindow.Show(viewModel);
        }
        else
        {
            Func<IDialogViewModel, bool?> func = Show;
            return (bool?)_dispatcher.Invoke(func, viewModel);
        }
    }
}

但是,调用Invoke永远阻塞,并且Show永远不会在 UI 线程上调用......

使用BeginInvoke不是一个选项:我需要立即得到结果,因为我正在处理来自远程对象的事件(使用 .NET 远程处理)

任何的想法 ?


更新

以下是对该问题的更完整描述:

我有一个使用 .NET Remoting 与 Windows 服务通信的客户端应用程序。在某些时候,客户端调用服务以执行操作(此调用由用户操作触发,在这种情况下单击按钮)。服务可能需要凭据来执行操作:在这种情况下,它会引发一个CredentialsNeeded由客户端处理的事件。然后客户端显示一个对话框以提示用户输入凭据,并在事件的参数中设置适当的属性。当事件处理程序返回时,服务使用凭据完成操作,并将控制权返回给客户端。

因此,当我收到事件时,UI 线程正在等待服务端的操作完成......我认为这Invoke是未处理调用的原因,但我该如何解决呢?我可以创建另一个UI 线程来显示对话框吗?在 WinForms 中,我知道我可以使用 启动另一个消息泵Application.Run,但我不知道如何在 WPF 中做同样的事情......

4

3 回答 3

4

在此方法调用期间,您是否拥有 UI 线程上的另一个方法试图获取的锁?那肯定会解释的。

每次都会出现这种情况吗?这显然会使诊断变得更容易。

对我来说不同寻常的是,我建议去调试器:只需点击 break 看看线程在做什么。

最后,我知道您需要结果...但是如果您改为调用BeginInvoke(并返回一个虚拟值)会发生什么?这会调用调度程序中的方法吗?显然这不会是一个长期的修复,但它会提供更多的诊断信息。

于 2010-06-22T16:57:38.200 回答
2

我最终找到了解决问题的方法:我只需要在新线程上显示对话框,并使用它自己的调度程序。这是修改后的代码:

class DialogService : IDialogService
{
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher;

    public bool? Show(IDialogViewModel viewModel)
    {
        if (_dispatcher.CheckAccess())
        {
            DoShow(viewModel);
        }
        else
        {
            bool? r = null;
            Thread thread = new Thread(() => r = DoShow(viewModel));
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
            return r;
        }
    }

    private static bool? DoShow(IDialogViewModel viewModel)
    {
        var dialogWindow = new DialogWindow();
        return dialogWindow.Show(viewModel);
    }
}
于 2010-06-23T09:39:32.113 回答
1

在您尝试使用 Invoke 时,UI 线程是否对其他东西(可能是您的后台线程)进行了阻塞调用?如果是这样,那么您手上有一个经典的僵局。两个线程各自等待另一个返回。

在 Windows 窗体中,它们经常在您最不期望的情况下执行很多幕后“消息泵送”,以避免死锁,但很多时候它会产生更多问题,并且由于意外重新进入而难以发现错误。

如果您不认为您的 UI 线程正在进行阻塞调用,您应该在调试器中运行应用程序,并在发生死锁时进入调试器。然后在线程窗口中查找主线程。双击主线程,然后查看调用堆栈窗口以查看主线程所在的位置。

您也可以尝试明确指定发送的 DispatcherPriority,尽管我认为如果存在真正的死锁,这并不重要。

于 2010-06-22T16:58:50.037 回答