WPF调度器线程冻结主窗口



而不是在后台工作 - 此代码仍然冻结我的程序:

private void button_Click(object sender, RoutedEventArgs e)
{
    this.Dispatcher.BeginInvoke(new Action(() =>
    {
        Thread.Sleep(5000);
        label.Content = "Done";
    }), DispatcherPriority.Normal);
}

我尝试了线程/任务,线程示例:

private void button_Click(object sender, RoutedEventArgs e)
{
    var t = new Thread(new ThreadStart(runtask));
    t.Start();
}
private void runtask()
{
    this.Dispatcher.BeginInvoke(new Action(() =>
    {
        Thread.Sleep(5000);
        label.Content = "Done";
    }), DispatcherPriority.Normal);
}

任务示例:

private void button_Click(object sender, RoutedEventArgs e)
{
    Task.Run(() =>
    {
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
        {
            Thread.Sleep(5000);
            label.Content = "Done";
        }));
    });
}

,我的程序仍然在冻结。有任何建议吗?

Dispatcher类的文档:

提供用于管理线程队列的服务。

来自Dispatcher.BeginInvoke的文档:

用在线程上的指定参数上执行指定的委托,以创建调度程序。

在这里"异步"&quot'是指次要线程,而不是主要线程。因为主要调度员拥有主要的。这意味着该调度程序上的InvokeBeginInvoke的每个呼叫,从任何线程中,都会将被调用的操作放在主线程必须执行的操作队列中,但是从主线程的角度来看,它们将同步执行,一个接一个。

例如,如果您在调度器上10毫秒内将3个 Thread.Sleep(1000);这样的操作,无论是使用Invoke还是BeginInvoke,以及是否是否从线程中,该调度程序将使UI线程同时执行3个操作,以便他们进行总计3000 ms。

也许关于BeginInvoke的文档可能已经写得更好,例如:

用在创建调度程序的线程上的指定参数执行指定的委托。指定的委托从调用线程的角度异步执行。

现在... InvokeBeginInvoke

使用Invoke,辅助线程对调度程序说:让我们在主线程上执行此操作,并且直到线程的作业完成之前,请不要敢返回。然后,我才会继续

例如,如果您写这篇文章:

this.Dispatcher.Invoke(new Action(() =>
    {
        Thread.Sleep(5000);
        Debug.WriteLine("After Sleep");
    }));
Debug.WriteLine("Continuation on secondary Thread");

控制台将在〜5000 ms之后打印:

"睡眠后"

'在辅助线程上延续'

使用BeginInvoke,该线程说:'嘿,调度员,在主线程上排队此操作,但尽快返回,以便我可以立即继续工作&quot&quot&quot; <<<<<</em> <</p>

在这种情况下,控制台将立即打印:

'在辅助线程上延续'

和〜5000 ms之后:

"睡眠后"


现在,如果您的目的是在后台执行一些重型操作,则应了解异步/等待模式,可从.NET 4.5和C#5.0获得。

在您的示例中,我会写:

private async void button_Click(object sender, RoutedEventArgs e)
{
    await Task.Delay(5000); // await a heavy operation executed in background
    label.Content = "Done"; // control back to the UI Thread that executes this
}

如果您的UI访问是您的最后一个方法,则可以使用此小扩展名。

https://mitsufu.wordpress.com/2015/08/03/dispatcher-switchto/

private void Button_Click(object sender, RoutedEventArgs e)
{
    Task.Run(async () =>
    {
        //heavy background operation
        await Dispatcher.SwitchTo();
        Title = "ok";
    });
}

最新更新