调度员.从一个新线程调用正在锁定我的UI
本文关键字:调用 锁定 UI 我的 线程 新线程 一个 调度员 | 更新日期: 2023-09-27 18:17:56
我正在使用wpf,在我的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...");
也是,但这也不起作用。什么好主意吗?
问题是,由于您使用的是Invoke,因此使它无法执行。
调度员。在UI线程处理之前,Invoke不会返回。但是,您通过调用_waitHandle.WaitOne();
阻塞了UI线程,并且在此进程之后才设置等待句柄。这两者会导致死锁
如果你切换到使用BeginInvoke, UI将队列元素,等待句柄将设置,然后标签将更新。
由于前两篇文章已经涵盖了代码中的问题,只是一个建议:而不是
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
尝试使用
if (!lblStatus.CheckAccess())
它更干净,并且具有您想要的确切意图。
您可能想使用BeginInvoke
代替。Invoke
将阻塞调用它的线程,直到UI线程运行动作,并且由于您将优先级设置为Background,这可能需要一些时间。
我为。net 4.5+找到的最佳解决方案是使用SynchronizationContext Post
示例(任务。在并行访问UI中,运行的次数可以是任意的:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var context = SynchronizationContext.Current;
Task.Run(() =>
{
var i = 0;
while (true)
{
context.Post((tmp) =>
{
uiText.Text = $"{i}";
}), this);
Thread.Sleep(1000);
i++;
}
});
}