我有一个基于 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/