简单而可扩展的 Windows Forms 动画框架






4.72/5 (8投票s)
WPF 内置了对属性进行动画的支持,本文演示了在 Windows Forms 中实现相同功能的方法。

引言
本文的目的在于展示 WPF 内置功能所带来的惊喜。WPF 拥有尽可能多的功能,而这些功能在 Windows Forms 中需要花费更多时间去编码。WPF 的众多关键功能之一是它支持对依赖属性进行动画。
本文演示了 Windows Forms 的概念以及一个简单而可扩展的动画框架。
查看基于此动画框架构建的这篇文章:Windows Forms 的 Carousel 控件。 :)
背景
该项目实现了一个定义 Animation
类型的通用接口,并使用反射在目标属性上调用动画。
它让您的工作变得简单,像在 WPF 中一样,对按钮的宽度进行动画处理一样简单!通过对一些简单的小东西进行动画处理,您可以创造奇迹!!
IntAnimation widthAnimation =
new IntAnimation
{
AutoReset = true,
AutoReverse = true,
From = 100,
To = 250,
By = 1,
Interval = 10,
Duration = 3000
};
this.button1.Animate<int>("Width", widthAnimation);
这难道不够简单吗?继续阅读以了解如何实现!!
Using the Code
IAnimation<T> 接口
IAnimation<T>
接口实现了以下字段,这些字段表示动画处理属性所需的信息。类型T
标记动画处理的目标属性的类型。例如,要对控件的宽度进行动画处理,类型将为整数。AutoReset
:如果设置为true
,则动画完成后将再次开始。AutoReverse
:如果设置为true
,则动画将在完成后以相反方向进行。当AutoReset
和AutoReverse
都设置为true
时,动画将无休止地来回进行。Interval
:连续值变化之间的时间间隔。Duration
:运行动画的时间。(注意:当值的范围和持续时间已知时,可以在 Animation 实现中计算连续更新之间的时间间隔作为替代方案。)By
:更新目标属性的值。From
:动画将开始的值。To
:动画完成的值。GetNewValue(int delta)
:提供用于更新的下一个连续值。
/// <summary>
/// Defines IAnimation interface.
/// </summary>
/// <typeparam name="T">the type Animation is applied to</typeparam>
public interface IAnimation<T>
{
bool AutoReset { get; set; }
bool AutoReverse { get; set; }
int Interval { get; set; }
int Duration { get; set; }
T By { get; set; }
T From { get; set; }
T To { get; set; }
T GetNewValue(int delta);
event AnimationEventHandler<T> Completed;
event AnimationEventHandler<T> Started;
event AnimationEventHandler<T> Freezed;
}
Animator
Animator
定义了 static
扩展方法,用于在目标属性上调用动画,它就是这样工作的。
#1. 通过名称获取目标对象的 PropertyInfo
。
/// <summary>
/// Gets the PropertyInfo of specified type on the target object.
/// </summary>
/// <param name="target" />the target object.
/// <param name="property" />the name of the property.
/// <param name="t" />the return type of the property.
/// <returns>the property info if found, null otherwise.</returns>
private static PropertyInfo GetPInfo(object target, string property, Type t)
{
if (t == null || target == null || String.IsNullOrEmpty(property))
return null;
return target.GetType().GetProperty(property, t);
}
#2. 在目标属性上设置更新后的值。
pinfo.SetValue(target, newValue, null);
实际工作发生在 static
扩展方法 Animator.Animate()
中,它消耗目标对象、属性的名称以及动画类型的实例,该实例包含有关类型和值的信息。
Animator
中运行着两个计时器,一个用于以特定的间隔更新目标属性上的值,另一个用于更新动画器的状态。
/**** truncated for clarity ****/
animSteps.Tick += (_, __) =>
{
T newValue = animation.GetNewValue(++delta);
pinfo.SetValue(target, newValue, null);
}
};
animDuration.Elapsed += (_, __) =>
{
if (!state.IsFreezed)
{
delta = -1;
state.IsReversed = animation.AutoReverse ? !state.IsReversed : false;
}
if (!animSteps.Enabled && !animDuration.Enabled)
state.RaiseCompleted(target);
};
关注点
这是一个通用的实现,可以用于对任何目标类型的任何 public
属性进行动画处理。源代码包含 Int
和 double
类型的实现。
历史
- 第一篇帖子 - 2011 年 10 月 2 日
- 一些编辑修订 - 2011 年 10 月 3 日
- 添加了高级用法模式的新示例 - 2011 年 10 月 4 日
希望这能帮助您减少编写动画代码的时间。请务必留下您的评论和建议!
祝您编码愉快!