wpf - 当 WPF ProgressBar 达到 100% 时,如何停止它的脉冲/动画?

标签 wpf mvvm progress-bar

我有一个基于 MVVM 的 WPF 4 应用程序,它使用 ProgressBar显示长时间运行的操作的完成百分比。

<ProgressBar Name="ProgressBar"
    IsIndeterminate="False"
    Minimum="0"
    Maximum="100"
    Value="{Binding Path=ProgressPercentageComplete, Mode=OneWay}"
    Visibility="Visible"/>

我很高兴在进度条移动时出现“脉冲”动画,但是一旦达到 100%,我希望它停止动画并保持 100% 的静态。

我试过设置IsIndeterminate="False"但这无济于事,我可以在阅读 MSDN 文档后了解原因:

When this property is true, the ProgressBar animates a few bars moving across the ProgressBar in a continuous manner and ignores the Value property.



是否可以停止此动画?要么完全,要么只是100%。

最佳答案

我使用附加属性为此编写了一个通用解决方案,允许我在任何 ProgressBar 上切换行为。只需通过直接的属性或样式 setter ,如下所示:

<ProgressBar helpers:ProgressBarHelper.StopAnimationOnCompletion="True" />

编码:

public static class ProgressBarHelper {
    public static readonly DependencyProperty StopAnimationOnCompletionProperty =
        DependencyProperty.RegisterAttached("StopAnimationOnCompletion", typeof(bool), typeof(ProgressBarHelper),
                                            new PropertyMetadata(OnStopAnimationOnCompletionChanged));

    public static bool GetStopAnimationOnCompletion(ProgressBar progressBar) {
        return (bool)progressBar.GetValue(StopAnimationOnCompletionProperty);
    }

    public static void SetStopAnimationOnCompletion(ProgressBar progressBar, bool value) {
        progressBar.SetValue(StopAnimationOnCompletionProperty, value);
    }

    private static void OnStopAnimationOnCompletionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
        var progressBar = obj as ProgressBar;
        if (progressBar == null) return;

        var stopAnimationOnCompletion = (bool)e.NewValue;

        if (stopAnimationOnCompletion) {
            progressBar.Loaded += StopAnimationOnCompletion_Loaded;
            progressBar.ValueChanged += StopAnimationOnCompletion_ValueChanged;
        } else {
            progressBar.Loaded -= StopAnimationOnCompletion_Loaded;
            progressBar.ValueChanged -= StopAnimationOnCompletion_ValueChanged;
        }

        if (progressBar.IsLoaded) {
            ReevaluateAnimationVisibility(progressBar);
        }
    }

    private static void StopAnimationOnCompletion_Loaded(object sender, RoutedEventArgs e) {
        ReevaluateAnimationVisibility((ProgressBar)sender);
    }

    private static void StopAnimationOnCompletion_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
        var progressBar = (ProgressBar)sender;

        if (e.NewValue == progressBar.Maximum || e.OldValue == progressBar.Maximum) {
            ReevaluateAnimationVisibility(progressBar);
        }
    }

    private static void ReevaluateAnimationVisibility(ProgressBar progressBar) {
        if (GetStopAnimationOnCompletion(progressBar)) {
            var animationElement = GetAnimationElement(progressBar);
            if (animationElement != null) {
                if (progressBar.Value == progressBar.Maximum) {
                    animationElement.SetCurrentValue(UIElement.VisibilityProperty, Visibility.Collapsed);
                } else {
                    animationElement.InvalidateProperty(UIElement.VisibilityProperty);
                }
            }
        }
    }

    private static DependencyObject GetAnimationElement(ProgressBar progressBar) {
        var template = progressBar.Template;
        if (template == null) return null;

        return template.FindName("PART_GlowRect", progressBar) as DependencyObject;
    }
}

基本上,它添加了 ValueChanged调整动画元素可见性的处理程序。

几点注意事项:
  • 我正在使用 "PART_GlowRect"找到动画元素,尽管有人称之为 hack。我不同意:这个元素名称是通过 TemplatePartAttribute 正式记录的。 ,您可以在 ProgressBar's declaration 中看到.虽然这并不一定保证命名元素存在,但缺少它的唯一原因是动画功能根本不受支持。如果它受支持但使用的元素名称与记录的元素名称不同,我会认为这是一个错误,而不是实现细节。
  • 由于我要从模板中拉出一个元素,因此还需要处理 Loaded事件(在应用模板时引发)等待模板变得可用,然后再尝试设置初始可见性,如果有必要,当模板被主题更改动态替换时再次设置它。
  • 而不是显式切换 Visibility Collapsed之间和 Visible , 我正在使用 SetCurrentValue设置为 Collapsed , 和 InvalidateProperty重置它。 SetCurrentValue应用不优先于其他值源的值,并且 InvalidateProperty重新评估属性(property)而不采取SetCurrentValue考虑到。这确保了如果存在会影响正常条件下(即,当它不是 100% 时)可见性的现有样式或触发器,如果​​重复使用进度条(从 100% 回到 0%),它将重置为该行为) 而不是硬编码为 Visible .
  • 关于wpf - 当 WPF ProgressBar 达到 100% 时,如何停止它的脉冲/动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4570865/

    相关文章:

    c# - 按钮的依赖属性

    unit-testing - 使代码可单元测试的最佳方法

    c# - 如何将对象作为可绑定(bind)属性传递给 Xamarin.Forms 自定义控件

    progress-bar - 运行部分的 Inno Setup 简单进度页面

    wpf - 将标签与停靠面板的中间对齐

    c# - WPF:以编程方式更改具有自定义样式的控件的颜色

    c# - 双向绑定(bind)忽略源更改

    带有进度条的 Android 自定义适配器

    iphone - 建立一个漂亮的进度条

    c# - WPF 数据网格 : DataGridCheckBoxColumn events