XAML故事板导致无限循环。试图为进度条设置动画

时间:2018-01-31 23:34:56

标签: xaml animation

需要一些帮助才能理解XAML Storyboard动画。我尝试使用ProgressBar控件在XAML Storyboard中创建倒计时动画。动画应该使进度条在给定的持续时间内从它的最大值倒数到它的最小值。这是相关的XAML:

    <ProgressBar  x:Name="PollCountdown" Orientation="Vertical" Width="20" Value="{Binding PollValue}" Maximum="{Binding PollMax}" Minimum="{Binding PollMin}" ValueChanged="ProgressBar_ValueChanged">
        <ProgressBar.Triggers>
            <EventTrigger RoutedEvent="ProgressBar.ValueChanged">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="PollCountdown" Storyboard.TargetProperty="Value"
                            From="{Binding PollMax}" To="{Binding PollMin}" Duration="{Binding Interval, Converter={StaticResource IntToDurationCovnerter}}">
                        </DoubleAnimation>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </ProgressBar.Triggers>
    </ProgressBar>

...这里是ProgressBar_ValueChanged事件的代码。这样做的目的只是为了让我能够看到值的变化,并最终将从XAML代码中删除:

private void ProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    var x = (sender as ProgressBar).Value;
    if (x == 0)
        e.Handled = true;
}

不幸的是,当我触发动画时,会出现无限循环错误。通过捕获value_changed事件,我能够监视Value属性中的更改。我看到的是第一次更改时条形值减少了0.0041,但是在下一次更改时,重置为条形的最大属性。关于什么可能导致这种无限循环的任何线索?

1 个答案:

答案 0 :(得分:0)

这是我最终提出的解决方案。进度条将开始/结束倒计时,Run属性设置为true / false。 Duration属性确定倒计时的持续时间。

<ctrl:CountdownBar x:Name="Countdown" Orientation="Vertical" Run="{Binding RunPoll}" VerticalAlignment="Top" Height="121" Margin="0,1,0,-6" Grid.RowSpan="2" HorizontalAlignment="Left" Width="10" >
    <ctrl:CountdownBar.Triggers>
        <EventTrigger RoutedEvent="ctrl:CountdownBar.Restarting">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="Countdown" Storyboard.TargetProperty="Value" Duration="{Binding PollDuration}" From="100" To="0">
                    </DoubleAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </ctrl:CountdownBar.Triggers>
</ctrl:CountdownBar>

CountdownBar Control:

public class CountdownBar : ProgressBar
{
    public static DependencyProperty IsRunningProperty = DependencyProperty.Register("IsRunning", typeof(bool), typeof(CountdownBar), new PropertyMetadata(false));
    public static DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(Duration), typeof(CountdownBar), new PropertyMetadata(new Duration(TimeSpan.FromSeconds(10))));
    public static DependencyProperty RunProperty = DependencyProperty.Register("Run", typeof(bool), typeof(CountdownBar), new PropertyMetadata(false));
    public static RoutedEvent RestartCountdownEvent = EventManager.RegisterRoutedEvent("Restarting", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CountdownBar));

    public CountdownBar()
    {
        this.Maximum = 100;
        this.Minimum = 0;
        this.Value = 100;
        this.ValueChanged += Bar_ValueChanged;
    }

    ~CountdownBar()
    {
        this.ValueChanged -= Bar_ValueChanged;
    }

    public bool Run
    {
        get { return ((bool)GetValue(RunProperty)); }
        set
        {
            if (value)
                Start();
            else
                Stop();
            SetValue(RunProperty, value);
        }
    }

    public bool IsRunning
    {
        get { return ((bool)GetValue(IsRunningProperty)); }
        set { SetValue(IsRunningProperty, value); }
    }

    public Duration Duration
    {
        get { return ((Duration)GetValue(DurationProperty)); }
        set { SetValue(DurationProperty, value); }
    }

    public void Start()
    {
        IsRunning = true;
        this.Value = this.Minimum;
        if (Value == 0)
            RaiseRestartCountdown();
    }

    public void Stop()
    {
        IsRunning = false;
        this.Value = this.Maximum;
    }

    public event RoutedEventHandler Restarting
    {
        add { AddHandler(RestartCountdownEvent, value); }
        remove { RemoveHandler(RestartCountdownEvent, value); }
    }

    public void RaiseRestartCountdown()
    {
            RoutedEventArgs args = new RoutedEventArgs(RestartCountdownEvent);
            RaiseEvent(args);
    }

    private void Bar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        if (IsRunning)
            if (this.Value == this.Minimum)
                if (this.Maximum > this.Minimum)
                    RaiseRestartCountdown();
    }
}

最初我想让它成为一个完全无法控制的控件,但有时你只需要去做有效的工作。如果有人想要消除c#代码并将所有内容移至XAML,请上传解决方案。