65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (8投票s)

2011 年 10 月 2 日

CPOL

2分钟阅读

viewsIcon

40739

downloadIcon

2036

WPF 内置了对属性进行动画的支持,本文演示了在 Windows Forms 中实现相同功能的方法。

Preview.png

引言

本文的目的在于展示 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,则动画将在完成后以相反方向进行。当 AutoResetAutoReverse 都设置为 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 属性进行动画处理。源代码包含 Intdouble 类型的实现。

历史

  • 第一篇帖子 - 2011 年 10 月 2 日
  • 一些编辑修订 - 2011 年 10 月 3 日
  • 添加了高级用法模式的新示例 - 2011 年 10 月 4 日

希望这能帮助您减少编写动画代码的时间。请务必留下您的评论和建议!

祝您编码愉快!

© . All rights reserved.