如何更新进度条以实现平滑增长?

23

我正在使用 WPF (C#) 的进度条来描述进程的进度。

我的算法如下:

DoSomethingCode1();
ProgressBar.SetPercent(10); // 10%
DoSomethingCode2();
ProgressBar.SetPercent(20); // 20%

...

DoSomethingCode10();
ProgressBar.SetPercent(100); // 100%

可以,但会导致进度条不连贯。

有人能告诉我一些让进度条平滑更新的建议吗?


8
不要在代码中操纵UI元素。学习MVVM。使用后台线程执行操作,然后将百分比属性的更新调度到UI线程。 - Federico Berasategui
1
这个答案可能会对你有所帮助:使用BackgroundWorker和ProgressBar在WPF中 - Abdusalam Ben Haj
1
"not sequent" 的意思是什么?"soft updating" 是什么? - Patrick
1
@HighCore,Abzy:谢谢你们,但这不是我的问题。上面的代码是伪代码。 - TTGroup
3
谢谢,我已经在这个帖子里等了1.5年以上,一直想知道答案。 - Patrick
显示剩余2条评论
4个回答

44
你可以使用一个行为!
public class ProgressBarSmoother
{
    public static double GetSmoothValue(DependencyObject obj)
    {
        return (double)obj.GetValue(SmoothValueProperty);
    }

    public static void SetSmoothValue(DependencyObject obj, double value)
    {
        obj.SetValue(SmoothValueProperty, value);
    }

    public static readonly DependencyProperty SmoothValueProperty =
        DependencyProperty.RegisterAttached("SmoothValue", typeof(double), typeof(ProgressBarSmoother), new PropertyMetadata(0.0, changing));

    private static void changing(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var anim = new DoubleAnimation((double)e.OldValue, (double)e.NewValue, new TimeSpan(0,0,0,0,250));
        (d as ProgressBar).BeginAnimation(ProgressBar.ValueProperty, anim, HandoffBehavior.Compose);
    }
}

您的XAML将如下所示:

<ProgressBar local:ProgressBarSmoother.SmoothValue="{Binding Progress}">

无论你在xaml中绑定的Progress属性何时发生变化,ProgressBarSmoother行为中的代码都会运行,并使用适当的ToFrom值将动画添加到进度条中。请注意保留HTML标签。

8
我加入了这个解决方案,因为它让进度报告和包含进度条视图的部分解耦。 - Owen Johnson
喜欢这个。稍微调整了一下持续时间,效果非常好。然而,自从Vista以来,Windows中的标准进度条就已经实现了这个功能,所以WPF进度条应该早就有了... - OregonGhost
这对我小客户来说是一个完美的解决方案。太棒了,谢谢! - Master Azazel

22

您可以调用BeginAnimation方法来为ProgressBarValue属性添加动画效果。在下面的示例中,我使用了一个DoubleAnimation

我创建了一个扩展方法,它接受所需的百分比:

public static class ProgressBarExtensions
{
    private static TimeSpan duration = TimeSpan.FromSeconds(2);

    public static void SetPercent(this ProgressBar progressBar, double percentage)
    {
        DoubleAnimation animation = new DoubleAnimation(percentage, duration);
        progressBar.BeginAnimation(ProgressBar.ValueProperty, animation);          
    }
}

所以在你的代码中,你可以简单地调用:

myProgressBar.SetPercent(50);

这样做只是为了使过渡更加平滑,看起来更美观。引用另一个答案的话:“这种想法是进度条报告实际进度——而不是经过的时间。它不是旨在成为仅指示发生某些事情的动画。”然而,进度条的默认样式确实具有脉动效果,这可能暗示着正在进行工作。


@Matt 很好。你的参考资料是什么?就是你在 "using" 后面放的东西吗?谢谢! - Cullub
2
抱歉 - 经过一些研究 - 将presentationcore.dll添加到引用中,然后使用“System.Windows.Media”。请参阅此Microsoft网站 - Cullub
这是哪个.NET版本?ProgressBar上没有BeginAnimation事件? - cullimorer

3

请检查是否可以修改进度条的样式,并设置一个缓动函数到其故事板中,以修改进度条的“填充”,从而使其具有平滑的过渡效果。


-1

试一下这个。

private void updateProgressBar(int percent)
    {
        if (ProgressBar.InvokeRequired)
        {
            updateProgressBarCallback cb = new updateProgressBarCallback(updateProgressBar);
            this.Invoke(cb, new object[] { percent });
        }
        else
        {
            ProgressBar.Value = percent;
            ProgressBar.Update();
            ProgressBar.Refresh();
            ProgressBar.Invalidate();
        }

抱歉,对我不起作用。 我复制并粘贴了您的代码片段。 错误显示如下:System.Windows.Control.ProgressBar不包含Update,Refresh,Invalidate的定义。 命名空间updateProgressBarCallback找不到,您是否缺少使用指令或程序集引用? - Arun
如果你想要实现这个功能,你需要在代码中添加类似于“delegate void updateProgressBarCallback(int percent);”的内容。 - SedJ601
如果您的UI线程很忙,这些绘制调用将进入事件队列并一次性发生。进度条不会动画。 - Owen Johnson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接