Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GridSplitter not working after applying an animation to a grid column

I'm a beginner in wpf, today I come across an odd issue that the gridsplitter stops working if I add an animation to a grid column, below is the code snippet, it's a meaningless but quite simply test code, it does nothing except when the mouse enters the right column, the width of it will expand from 15 to 100

    <Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Name="c1"/>
        <ColumnDefinition Name="c2" Width="15" MinWidth="15"/>
    </Grid.ColumnDefinitions>
    <Border Grid.Column="0" Background="Gray"></Border>
    <GridSplitter Width="8" Background="Yellow"></GridSplitter>
    <Border Grid.Column="1" Background="Silver" Name="bdRight" MouseEnter="bdRight_MouseEnter"></Border>
</Grid>

and this:

        bool flag = true;
    private void bdRight_MouseEnter(object sender, MouseEventArgs e)
    {
        if (flag)
        {
            flag = false;
            var da = new GridLengthAnimation();
            da.From = new GridLength(c2.MinWidth);
            da.To = new GridLength(100);
            var ef = new BounceEase();
            ef.EasingMode = EasingMode.EaseOut;
            da.EasingFunction = ef;
            this.c2.BeginAnimation(ColumnDefinition.WidthProperty, da);
        }
    }

and here's the GridLengthAnimation, I get it from internet after I find that DoubleAnimation cannot be used against the width of grid column.

public class GridLengthAnimation : AnimationTimeline
{
    public static readonly DependencyProperty FromProperty;
    public static readonly DependencyProperty ToProperty;
    public static readonly DependencyProperty EasingFunctionProperty;

    static GridLengthAnimation()
    {
        FromProperty = DependencyProperty.Register("From", typeof(GridLength), typeof(GridLengthAnimation));
        ToProperty = DependencyProperty.Register("To", typeof(GridLength), typeof(GridLengthAnimation));
        EasingFunctionProperty = DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(GridLengthAnimation));
    }

    protected override Freezable CreateInstanceCore()
    {
        return new GridLengthAnimation();
    }

    public override Type TargetPropertyType
    {
        get { return typeof(GridLength); }
    }

    public IEasingFunction EasingFunction
    {
        get
        {
            return (IEasingFunction)GetValue(GridLengthAnimation.EasingFunctionProperty);
        }
        set
        {
            SetValue(GridLengthAnimation.EasingFunctionProperty, value);
        }

    }

    public GridLength From
    {
        get
        {
            return (GridLength)GetValue(GridLengthAnimation.FromProperty);
        }
        set
        {
            SetValue(GridLengthAnimation.FromProperty, value);
        }
    }

    public GridLength To
    {
        get
        {
            return (GridLength)GetValue(GridLengthAnimation.ToProperty);
        }
        set
        {
            SetValue(GridLengthAnimation.ToProperty, value);
        }
    }

    public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
    {
        double fromValue = ((GridLength)GetValue(GridLengthAnimation.FromProperty)).Value;
        double toValue = ((GridLength)GetValue(GridLengthAnimation.ToProperty)).Value;

        IEasingFunction easingFunction = this.EasingFunction;

        double progress = (easingFunction != null) ? easingFunction.Ease(animationClock.CurrentProgress.Value) : animationClock.CurrentProgress.Value;

        if (fromValue > toValue)
        {
            return new GridLength((1 - progress) * (fromValue - toValue) + toValue, this.To.IsStar ? GridUnitType.Star : GridUnitType.Pixel);
        }
        else
        {
            return new GridLength((progress) * (toValue - fromValue) + fromValue, this.To.IsStar ? GridUnitType.Star : GridUnitType.Pixel);
        }
    }
}

If I comment out codes in the MouseEnter event handler, the splitter works fine, otherwise, it stops working. Any ideas?

like image 740
gfytd Avatar asked Feb 20 '12 08:02

gfytd


2 Answers

You have to set the FillBehavior property of your animation. The default value is HoldEnd, which means that the animation holds the final value after it has ended. If you set FillBehavior to Stop the animated value will revert back to the value it had before beeing animated.

If you add the following lines to your event handler code, it should work as expected:

...
da.FillBehavior = FillBehavior.Stop;
c2.Width = da.To; // set final value before starting the animation
c2.BeginAnimation(ColumnDefinition.WidthProperty, da);

In case setting the final value before starting the animation creates a flickering effect, you may instead set the final value in a Completed handler:

...
da.FillBehavior = FillBehavior.Stop;
da.Completed += (s, e) => c2.Width = da.To;
c2.BeginAnimation(ColumnDefinition.WidthProperty, da);
like image 175
Clemens Avatar answered Oct 18 '22 22:10

Clemens


Just to expand on the earlier answer (would comment but not allowed by the stackoverflow overmaster):

For me, setting the final value before kicking off the animation generates an ugly flicker effect for my grid a split second before the animation kicks in.

What I did was to use the FillBehavior.Stop mentioned above but subscribe to the Animation.Completed event and set the final height of the grid column in there.

Works like a charm without any flickering.

like image 1
Sverrir Sigmundarson Avatar answered Oct 18 '22 23:10

Sverrir Sigmundarson