繁体   English   中英

来自新线程的Dispatcher.Invoke正在锁定我的UI

[英]Dispatcher.Invoke from a new thread is locking my UI

我正在使用wpf,我的ui上有一个按钮。

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

在那个新线程的方法中,我正在使用一个标签,我们称之为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线程处理之前,Dispatcher.Invoke不会返回。 但是,您已通过调用_waitHandle.WaitOne();阻止了UI线程_waitHandle.WaitOne(); ,并且在此过程之后才设置等待句柄。 这两个有效地导致死锁。

如果您将其切换为使用BeginInvoke,则UI将对元素进行排队,等待句柄将设置,然后标签将更新。 然而,它会起作用而不是阻挡。

由于之前的两个帖子已经涵盖了您的代码中的问题,只是一个建议:而不是

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

尝试使用

if (!lblStatus.CheckAccess())

它更干净,具有您想要的确切意图。 请在这里阅读它。

我发现.net 4.5+的最佳解决方案是使用SynchronizationContext Post

示例(Task.Run可以和您并行访问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++;

        }
    });

}

您可能希望使用BeginInvoke Invoke将阻止调用它的线程,直到UI线程运行Action,并且由于您将优先级设置为Background,这可能需要一些时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM