我正在尝试在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
的调用将永久阻止,并且永远不会在UI线程上调用Show
...
使用BeginInvoke
不是一个选项:我需要立即得到结果,因为我正在处理来自远程对象的事件(使用.NET远程处理)
有什么想法吗?
更新
以下是对此问题的更完整描述:
我有一个客户端应用程序,它使用.NET Remoting与Windows服务进行通信。在某些时候,客户端调用服务来执行操作(此调用由用户操作触发,在这种情况下单击按钮)。该服务可能需要凭据来执行操作:在这种情况下,它会引发由客户端处理的CredentialsNeeded
事件。然后,客户端会显示一个对话框,提示用户输入凭据,并在事件的参数中设置相应的属性。当事件处理程序返回时,服务使用凭据完成操作,并将控制权返回给客户端。
因此,当我收到事件时,UI线程正在等待服务端的操作完成...我认为这就是为什么没有处理Invoke
调用的原因,但是我怎么工作周围 ?我可以创建另一个 UI线程来显示对话框吗?在WinForms中,我知道我可以使用Application.Run
启动另一个消息泵,但我不知道如何在WPF中执行相同操作...
答案 0 :(得分:4)
你是否在这个方法调用期间拥有一个锁,这是UI线程上的另一个方法试图获取的?这当然可以解释它。
这是每时间发生的吗?这显然会使诊断变得更容易。
对我来说不同寻常,我建议去调试器:只需点击中断,看看线程在做什么。
最后,我知道你需要结果...但是如果你做而不是调用BeginInvoke
并返回一个虚拟值会发生什么?这会调用调度程序中的方法吗?显然这不是一个长期修复,但它会提供更多的诊断信息。
答案 1 :(得分:1)
当您尝试使用Invoke时,UI线程是否阻止调用其他东西(可能是您的后台线程)?如果是这样,那么你手上就会出现经典的僵局。两个线程各等待另一个返回。
在Windows窗体中,他们经常在幕后“消息抽取”中做很多事情,当你最不希望它是为了避免死锁时,但很多时候它会产生更多的问题,并且由于意外的重入而很难找到错误。
如果您认为您的UI线程不在进行阻塞调用,那么您应该在调试器中运行该应用程序,并在发生死锁时进入调试器。然后在Threads窗口中查找主线程。双击主线程,然后查看“调用堆栈”窗口以查看主线程所在的位置。
您也可以尝试显式指定DispatcherPriority of Send虽然我认为如果存在真正的死锁则无关紧要。
答案 2 :(得分:1)
我最终找到了解决问题的方法:我只需要在一个新线程上显示对话框,并使用自己的调度程序。这是修改后的代码:
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);
}
}