📄 animation.cs
字号:
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Xml;
using System.Web.Script.Serialization;
namespace AjaxControlToolkit
{
/// <summary>
/// The Animation class is an object model for the animations used in the Ajax Control Toolkit.
/// It is used primarily as an intermediate representation when converting from XML animation
/// descriptions to JSON objects, but it can also be used to dynamically create and manipulate
/// animations.
/// </summary>
[ParseChildren(true)]
[PersistChildren(false)]
[DefaultProperty("Name")]
public class Animation
{
// JavaScript serializer to read/write JSON animations descriptions
private static JavaScriptSerializer _serializer;
// Name of the animation
private string _name;
// List of child animations
private List<Animation> _children;
// Properties defined for the animation
private Dictionary<string, string> _properties;
/// <summary>
/// Static constructor to setup our serializer
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Call to RegisterConverters can not be moved inline")]
static Animation()
{
_serializer = new JavaScriptSerializer();
_serializer.RegisterConverters(new JavaScriptConverter[] { new AnimationJavaScriptConverter() });
}
/// <summary>
/// Default constructor
/// </summary>
public Animation()
{
_children = new List<Animation>();
_properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Name of the animation (this corresponds to the tag name of the XML
/// description, or the AnimationName property of the JSON description) that
/// matches the name of a registered animation (i.e. this must match one of
/// the names provided on the client in a call to
/// AjaxControlToolkit.Animation.registerAnimation('name', type);).
/// </summary>
[Browsable(false)]
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// List of child animations (this corresponds to any child elements in the XML
/// description, or the AnimationChildren array in the JSON description), which
/// should only be needed for animations inheriting from SequenceAnimation or
/// CompositeAnimation.
/// </summary>
[Browsable(false)]
public IList<Animation> Children
{
get { return _children; }
}
/// <summary>
/// Properties defined for the animation (this corresponds to any of the
/// attributes in the XML description, or any of the members in the JSON
/// description), which specify all the necessary parameters of the animation.
/// </summary>
[Browsable(false)]
public Dictionary<string, string> Properties
{
get { return _properties; }
}
/// <summary>
/// Convert the animation into its JSON description
/// </summary>
/// <returns>JSON description of the animation</returns>
public override string ToString()
{
return Animation.Serialize(this);
}
/// <summary>
/// Convert an animation into its JSON description
/// </summary>
/// <param name="animation">Animation to convert</param>
/// <returns>JSON description of the animation</returns>
public static string Serialize(Animation animation)
{
return _serializer.Serialize(animation);
}
/// <summary>
/// Convert a JSON animation description into an Animation object.
/// </summary>
/// <param name="json">JSON animation description</param>
/// <returns>Animation</returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "json", Justification = "JSON is an acronym")]
public static Animation Deserialize(string json)
{
if (string.IsNullOrEmpty(json))
return null;
return _serializer.Deserialize<Animation>(json);
}
/// <summary>
/// Convert an XML animation description into an Animation object
/// </summary>
/// <param name="node">Node in an XmlDocument to deserialize</param>
/// <returns>Deserialized animation</returns>
[SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "XmlNode is specific to the design")]
public static Animation Deserialize(XmlNode node)
{
if (node == null)
throw new ArgumentNullException("node");
// Create the new animation
Animation animation = new Animation();
animation.Name = node.Name;
// Set the properties of the animation
foreach (XmlAttribute attribute in node.Attributes)
animation.Properties.Add(attribute.Name, attribute.Value);
// Add any children (recursively)
if (node.HasChildNodes)
foreach (XmlNode child in node.ChildNodes)
animation.Children.Add(Animation.Deserialize(child));
return animation;
}
/// <summary>
/// Convert a series of XML animation descriptions into Animations and assign them to their corresponding
/// Animation properties on a provided ExtenderControl instance. This will most likely be called by
/// AnimationExtenderControlBase.Animations, but it is publicly exposed so you can call it in the event
/// your extender cannot inherit from AnimationExtenderControlBase.
/// </summary>
/// <param name="value">
/// Sequence of XML animation descriptions (i.e. there should not be a root node because it's expecting the
/// inner contents of the <Animations> tag)
/// </param>
/// <param name="targetProperties">Target properties that contains the corresponding Animations</param>
public static void Parse(string value, ExtenderControl extenderControl)
{
if (extenderControl == null)
throw new ArgumentNullException("extenderControl");
if (value == null || string.IsNullOrEmpty(value.Trim()))
return;
// Wrap the XML in a root node (because the Animations node
// isn't included in the content
value = "<Animations>" + value + "</Animations>";
// Parse the animation descriptions
XmlDocument xml = new XmlDocument();
using (XmlTextReader reader = new XmlTextReader(new StringReader(value)))
{
try { xml.Load(reader); }
catch (XmlException ex)
{
string message = string.Format(CultureInfo.CurrentCulture,
"Invalid Animation definition for TargetControlID=\"{0}\": {1}",
extenderControl.TargetControlID, ex.Message);
throw new HttpParseException(message, new ArgumentException(message, ex),
HttpContext.Current.Request.Path, value, ex.LineNumber);
}
}
// Create animations for each of the Nodes
foreach (XmlNode node in xml.DocumentElement.ChildNodes)
{
// Get the animation's corresponding property
PropertyDescriptor animationProperty = TypeDescriptor.GetProperties(extenderControl)[node.Name];
if (animationProperty == null || animationProperty.IsReadOnly)
{
string message = string.Format(CultureInfo.CurrentCulture,
"Animation on TargetControlID=\"{0}\" uses property {1}.{2} that does not exist or cannot be set",
extenderControl.TargetControlID, extenderControl.GetType().FullName, node.Name);
throw new HttpParseException(message, new ArgumentException(message),
HttpContext.Current.Request.Path, value, GetLineNumber(value, node.Name));
}
// Create the animation
if (node.ChildNodes.Count != 1)
{
string message = string.Format(CultureInfo.CurrentCulture,
"Animation {0} for TargetControlID=\"{1}\" can only have one child node.",
node.Name, extenderControl.TargetControlID);
throw new HttpParseException(message, new ArgumentException(message),
HttpContext.Current.Request.Path, value, GetLineNumber(value, node.Name));
}
XmlNode child = node.ChildNodes[0];
Animation animation = Animation.Deserialize(child);
// Assign the animation to its property
animationProperty.SetValue(extenderControl, animation);
}
}
/// <summary>
/// GetLineNumber is used when reporting errors in Animation XML
/// descriptions. It will find the line number of the first top level
/// node whose tag matches the provided value.
/// </summary>
/// <param name="source">Animation XML description</param>
/// <param name="tag">Tag of the node to find</param>
/// <returns>Line number of the tag, or the first line if nothing found</returns>
private static int GetLineNumber(string source, string tag)
{
// We'll manually walk through the source using an XmlTextReader
// so we can get the line number
using (XmlTextReader reader = new XmlTextReader(new StringReader(source)))
{
// Move to the document element
if (reader.Read())
{
// Loop though all the top level children
while (reader.Read())
{
// If this node matches, return its line number
if (string.Compare(reader.Name, tag, StringComparison.OrdinalIgnoreCase) == 0)
return reader.LineNumber;
// If this node has children, ignore them all
if (reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement)
reader.Skip();
}
}
}
// If we can't find it, just use the first line
return 1;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -