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?
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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With