强制 WPF UI 线程更新任务

Posted

技术标签:

【中文标题】强制 WPF UI 线程更新任务【英文标题】:Force WPF UI thread to update on a task 【发布时间】:2019-06-08 03:59:59 【问题描述】:

目前这段代码有效,我想它没有按预期工作,因为我还没有弄清楚如何为按钮中的每个不透明度更改强制更新 UI 线程。

    private void BtnStart_Click(object sender, RoutedEventArgs e) 
        // Create a timer and add its corresponding event

        System.Timers.Timer timer = new System.Timers.Timer();
        timer.Elapsed += TimerFade_Elapsed;

        timer.Interval = 750;

        // Want a new thread to run this task on so
        // the main thread doesn't wait.

        Task task = new Task(() => timer.Start());
        task.Start();          
        //r.SingleThread();

    

    private void TimerFade_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
        // Access UI thread to decrease Opacity on a button from a different thread.

        Dispatcher.Invoke(() => 
            if (btnStart.Opacity != 0.0) 
                btnStart.Opacity -= 1.0;
                // code here to force update the GUI.
             else 
                System.Timers.Timer t;
                t = (System.Timers.Timer)sender;
                t.Stop();
            
        );          

    

代码在视觉上可以正常工作,但事实并非如此。我怀疑这与我在进行更改时没有更新 GUI 有关。

【问题讨论】:

你为什么不直接使用动画,也就是故事板? @zackraiyan 这是个好主意,我会调查的!但是,我仍然很好奇如何修复我的原始代码以查看我的不足之处。 不透明度的范围为 0.0 到 1.0 (0%..100%),您只需一步即可完成此范围。没有真正褪色;o) 用 btnStart.Opacity -= 1.0 / 20.0 尝试 20 步 顺便说一句,您在这里不需要任务。 Timer.Start 方法不会真正阻塞任何东西 您提供的代码运行良好。只需更改 btnStart.Opacity -= 1.0;到 btnStart.Opacity -= 0.1;并且您将能够看到该按钮更新缓慢。 【参考方案1】:

您可以简单地使用故事板。在对象的资源中创建一个(例如Window/Page 或任何您拥有的),然后从后面的代码中调用情节提要。

这是一个示例:

 <Window.Resources>
 <Storyboard x:Key="FadeAnim">
        <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.4"/>
    </Storyboard>
 </Window.Resources>

然后像这样从后面的代码中调用它:

 Storyboard sb = this.FindResource("FadeAnim") as Storyboard;
 Storyboard.SetTarget(sb, this.YourButton);
 sb.Begin();

【讨论】:

我刚试过这个,我可能需要这个,因为之前写所有的代码很烦人。很好的建议。【参考方案2】:

提供的代码运行良好。 opacity 的值范围从 0 到 1。您在第一次将其设置为 1,这将使按钮在第一次刷新时消失。如果您可以更改以下行

btnStart.Opacity -= 1.0;

btnStart.Opacity -= 0.1;

您将能够看到按钮慢慢消失。

PS:最好的方法是使用 @zack 提到的 StoryBoard(DoubleAnimation)

【讨论】:

这太棒了。我完全忘记了它是通过 0-1.0,干得好!

以上是关于强制 WPF UI 线程更新任务的主要内容,如果未能解决你的问题,请参考以下文章

富客户端 wpf, Winform 多线程更新UI控件

WPF Dispatcher.BeginInvoke子线程更新UI

WPF 根据 UI 线程控制状态更新 NON UI 线程数据

一种WPF在后台线程更新UI界面的简便方法

从 UI 线程强制 GUI 更新

“调用线程无法访问此对象,因为不同的线程拥有它”从 WPF 中的不同线程更新 UI 控件时出现错误