我有一个有点复杂的WPF应用程序,当尝试使用调度程序在UI线程上调用调用时,似乎是"挂起"或卡在Wait调用中.
一般过程是:
处理按钮上的单击事件
创建一个新线程(STA),其中:创建演示者和UI的新实例,然后调用Disconnect方法
断开然后在名为Name的UI上设置属性
然后,Name的setter使用以下代码来设置属性:
if(this.Dispatcher.Thread != Thread.CurrentThread) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate{ this.Name = value; // Call same setter, but on the UI thread }); return; } SetValue(nameProperty, value); // I have also tried a member variable and setting the textbox.text property directly.
我的问题是,当调用 dispatcher invoke方法时,它似乎每次都挂起,并且callstack指示它处于休眠状态,等待或加入Invoke实现.
那么,有什么我做错了,我错过了,显而易见或没有,或者有更好的方法调用UI线程来设置这个属性(和其他)?
编辑:解决方案是在线程委托的末尾调用System.Windows.Threading.Dispatcher.Run()(例如,正在执行工作的地方) - 感谢所有帮助过的人.
调用是同步的 - 您需要Dispatcher.BeginInvoke.另外,我相信你的代码示例应该在"else"语句中移动"SetValue".
我认为这可以通过代码更好地显示出来.考虑这种情况:
线程A执行此操作:
lock (someObject) { // Do one thing. someDispatcher.Invoke(() => { // Do something else. } }
线程B执行此操作:
someDispatcher.Invoke(() => { lock (someObject) { // Do something. } }
乍一看,一切看起来都很精致,但事实并非如此.这将产生僵局.调度程序就像一个线程的队列,当处理像这样的死锁时,以这种方式思考它们很重要:"以前的调度可能会阻塞我的队列?".线程A将进入...并在锁定下发送.但是,如果线程B在标记为"做一件事"的代码中的线程A进入的时候会怎样?好...
线程A锁定someObject并运行一些代码.
线程B现在调度,并且调度程序将尝试获取某个对象的锁定,从而干扰您的调度程序,因为线程A已经具有该锁定.
然后,线程A将排队另一个调度项.永远不会触发此项目,因为您的调度员永远不会完成处理您之前的请求; 它已经卡住了.
你现在有一个漂亮的僵局.
你说你正在创建一个新的STA线程,这个新线程运行的调度程序是什么?
我是从"this.Dispatcher.Thread!= Thread.CurrentThread"得到的,你希望它是一个不同的调度员.确保它运行,否则它不会处理它的队列.