调度员.从一个新线程调用正在锁定我的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...");

也是,但这也不起作用。什么好主意吗?

调度员.从一个新线程调用正在锁定我的UI

问题是,由于您使用的是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++;
        }
    });
}