2011-12-15 46 views
3

我使用wpf,我的用户界面上有一个按钮。Dispatcher.Invoke从一个新的线程锁定我的UI

当用户点击它,我有一个for循环运行一个新的方法,在一个新的线程使用autoresetevent。

在那个新线程的方法中,我使用了一个标签,我们称它为lblStatus。我想在这个线程上更新那个不在UI上的标签。使用wpf,我必须使用Dispatcher.Invoke。

这里是我的代码示例:

Thread thread= new Thread(StartLooking); 
thread.Start(); 
_waitHandle.WaitOne(); 

private void StartLooking(object value) 
{ 
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread) 
     { 
      lblStatus.Content = "Scanning>..."; 
     } 
     else 
     { 
      lblStatus.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => lblStatus.Content = "Scanning>>>>>")); 
     } 
_waitHandle.Set(); 
} 

程序刚刚在这里结束。它不会更改标签的内容,它会返回到我的UI,但会阻止它。
我试过

lblStatus.Dispatcher.Invoke(DispatcherPriority.Normal, new LblStatusThreadCheck(lblStatusThreadCheck), "Scanning..."); 

为好,但这是不是也工作。有任何想法吗?

+1

你有没有想过使用数据绑定? – GETah 2011-12-15 23:01:17

回答

5

问题在于,由于您正在使用Invoke,因此您无法执行此操作。

Dispatcher.Invoke在UI线程处理之前不会返回。但是,您已通过调用_waitHandle.WaitOne();来阻止UI线程,并且不要在此过程之后设置等待句柄。这两个有效地导致死锁。

如果将此切换为使用BeginInvoke,UI将对队列进行排队,等待句柄将设置,则标签将更新。然而,它会工作而不会阻塞。

0

你可能想用BeginInvoke来代替。 Invoke将阻止调用它的线程,直到UI线程运行该操作为止,并且由于您将优先级设置为Background,所以可能需要一些时间。

2

由于这两个以前的帖子已经盖在你的代码的问题,只是一个建议:不是

if (lblStatus.Dispatcher.Thread == Thread.CurrentThread) 

尝试使用

if (!lblStatus.CheckAccess()) 

这是更清洁,有你想要的确切意图。刚刚阅读它here