如何在wpf中以顺序方式从子窗口更新父UI窗口的标签控件?

时间:2017-09-27 15:23:50

标签: c# wpf dispatcher

我试图找出答案,但没有找到真正的答案。谁能回答以下问题?我试图通过调用Dispatcher方法更新父窗口中的状态,但我发现它不会以顺序方式更新状态。我在主窗口中看到状态更新如下:

第一道工序开始...... 第一个过程完成! 完成第三个过程!

可以有一些其他方法或任务,而不是UpdateStatus之间的延迟。那么,为什么它不更新其他状态?有什么真正的答案吗?

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        UpdateStatus("First Process started...");
        Thread.Sleep(5000); //or any method
        UpdateStatus("First Process done!");

        Thread.Sleep(5000); //or any method

        UpdateStatus("Second Process started...");
        Thread.Sleep(5000); //or any method
        UpdateStatus("Second Process done!");

        Thread.Sleep(5000); //or any method

        UpdateStatus("Third Process started...");
        Thread.Sleep(5000); //or any method
        UpdateStatus("Third Process done!");
    }

    private void UpdateStatus(string message)
    {
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
        {
            MainWindow.main.lblTest.Content = message;
        }
        ));
    }

3 个答案:

答案 0 :(得分:0)

单个线程无法同时更新UI和睡眠。

您可以在状态更新之间异步等待:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    UpdateStatus("First Process started...");
    await Task.Delay(5000);
    UpdateStatus("First Process done!");

    await Task.Delay(5000);

    UpdateStatus("Second Process started...");
    await Task.Delay(5000);
    UpdateStatus("Second Process done!");

    await Task.Delay(5000);

    UpdateStatus("Third Process started...");
    await Task.Delay(5000);
    UpdateStatus("Third Process done!");
}

private void UpdateStatus(string message)
{
    MainWindow.main.lblTest.Content = message;
}

答案 1 :(得分:0)

我希望这会更清楚。

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        // I run on the main thread and return immediately
        await SearchForAliensAsync();
    }

    private async Task SearchForAliensAsync()
    {
        // I run on (capture) the caller thread (main thread)
        UpdateStatus("Searching for aliens...");

        /* Dispatch the dirty work on a background thread and return immediately,
         * so that the caller thread (main thread) remains responsive.
         * If you don't do that, the main thread will get blocked.
         * From the user perspective the UI is frozen.
         * The main thread will search infinitely for aliens,
         * instead of doing its main job - poping and dispatching messages from
         * its message queue (Win32 is event driven).
         * The operating system will keep notifying the main thread,
         * that the user has clicked on the window or smashed multiple keys on the keyboard,
         * but the main thread won't listen, it's searching for aliens!
         * The operating system monitors all main threads, by measuring what
         * time has elapsed from the last call to GetMessage(...) and
         * if the latter exceeds a certain amount, it will play a trick on you.
         * The OS will create a transparent window and place it on top of the 
         * unresponsive one, so that it can detect the next angry mouse click
         * and display the famous "Application is not responding" dialog...
         */
        await Task.Run(() =>
        {
            // I run synchronously on the thread pool and I won't finish any time soon..
            SearchForAliens();
        });

        // When my time comes, I'll be dispatched on the captured thread (main thread)
        UpdateStatus("Aliens exist!");
    }

答案 2 :(得分:-1)

您正在UI线程中同步运行所有内容,阻止任何调用,直到您完成(因此没有更新,然后一次更新所有更新)。只需在任务中移动代码:

void Button_Click(object sender, RoutedEventArgs e) => Task.Run(() =>
{
     ... // rest of your code
});

你应该没问题(除非你按两次按钮,否则这很好,但我想这很容易解决)。

顺便说一句,您还可以使用另一个调用重载:

Dispatcher.Invoke(() => lblTest.Content = message);