📄 scriptobjectbuilder.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.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.Script.Serialization;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;
using System.Reflection;
using System.Text;
namespace AjaxControlToolkit
{
/// <summary>
/// Gets the script references for a type
/// </summary>
public static class ScriptObjectBuilder
{
/// <summary>
/// Static constructor to insert standard custom conversions
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Manipulation of CustomConverters can not be moved inline")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.DateTime.ToString(System.String)", Justification="Avoiding possibly breaking change")]
static ScriptObjectBuilder()
{
CustomConverters.Add(typeof(Color), delegate(object value) { return ColorTranslator.ToHtml((Color) value); });
Converter<object, string> dateTimeConverter = delegate(object value)
{
DateTime? date = (DateTime?) value;
return (date != null) ? date.Value.ToUniversalTime().ToString("r") : null;
};
CustomConverters.Add(typeof(DateTime), dateTimeConverter);
CustomConverters.Add(typeof(DateTime?), dateTimeConverter);
}
private static readonly Dictionary<Type, List<ResourceEntry>> _cache = new Dictionary<Type, List<ResourceEntry>>();
private static readonly Dictionary<Type, IList<string>> _cssCache = new Dictionary<Type, IList<string>>();
private static readonly object _sync = new object();
/// <summary>
/// Mapping of types to delegates that convert objects of that type to
/// strings
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification="Type-aware public API")]
public static IDictionary<Type, Converter<object, string>> CustomConverters
{
get { return _customConverters; }
}
private static Dictionary<Type, Converter<object, string>> _customConverters = new Dictionary<Type, Converter<object, string>>();
/// <summary>
/// Describes an object to a ScriptComponentDescriptor based on its reflected properties and methods
/// </summary>
/// <param name="instance">The object to be described</param>
/// <param name="descriptor">The script descriptor to fill</param>
/// <param name="urlResolver">The object used to resolve urls</param>
/// <param name="controlResolver">The object used to resolve control references</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods", Justification = "controlResolver is checked against null before being used")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", Justification = "Assembly is not localized")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Cyclomatic complexity issues not currently being addressed")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification="value is assigned/reassigned numerous times - code below favors clarity")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Coupling issues not currently being addressed")]
public static void DescribeComponent(object instance, ScriptComponentDescriptor descriptor, IUrlResolutionService urlResolver, IControlResolver controlResolver)
{
// validate preconditions
if (instance == null) throw new ArgumentNullException("instance");
if (descriptor == null) throw new ArgumentNullException("descriptor");
if (urlResolver == null) urlResolver = instance as IUrlResolutionService;
if (controlResolver == null) controlResolver = instance as IControlResolver;
// describe properties
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(instance);
foreach (PropertyDescriptor prop in properties)
{
ExtenderControlPropertyAttribute propAttr = null;
ExtenderControlEventAttribute eventAttr = null;
string propertyName = prop.Name;
// Try getting a property attribute
propAttr = (ExtenderControlPropertyAttribute)prop.Attributes[typeof(ExtenderControlPropertyAttribute)];
if (propAttr == null || !propAttr.IsScriptProperty)
{
// Try getting an event attribute
eventAttr = (ExtenderControlEventAttribute)prop.Attributes[typeof(ExtenderControlEventAttribute)];
if (eventAttr == null || !eventAttr.IsScriptEvent)
{
continue;
}
}
// attempt to rename the property/event
ClientPropertyNameAttribute nameAttr = (ClientPropertyNameAttribute)prop.Attributes[typeof(ClientPropertyNameAttribute)];
if (!string.IsNullOrEmpty(nameAttr.PropertyName))
{
propertyName = nameAttr.PropertyName;
}
// determine whether to serialize the value of a property. readOnly properties should always be serialized
bool serialize = prop.ShouldSerializeValue(instance) || prop.IsReadOnly;
if (serialize)
{
// get the value of the property, skip if it is null
Control c = null;
object value = prop.GetValue(instance);
if (value == null)
{
continue;
}
// convert and resolve the value
if (eventAttr != null && prop.PropertyType != typeof(String))
{
throw new InvalidOperationException("ExtenderControlEventAttribute can only be applied to a property with a PropertyType of System.String.");
}
else
{
if (!prop.PropertyType.IsPrimitive && !prop.PropertyType.IsEnum)
{
// Check if we can use any of our custom converters
// (first do a direct lookup on the property type,
// but also check all of its base types if nothing
// was found)
Converter<object, string> customConverter = null;
if (!_customConverters.TryGetValue(prop.PropertyType, out customConverter))
{
foreach (KeyValuePair<Type, Converter<object, string>> pair in _customConverters)
{
if (prop.PropertyType.IsSubclassOf(pair.Key))
{
customConverter = pair.Value;
break;
}
}
}
// Use the custom converter if found, otherwise use
// its current type converter
if (customConverter != null)
{
value = customConverter(value);
}
else
{
// TODO: Determine if we should let ASP.NET AJAX handle this type of conversion, as it supports JSON serialization
TypeConverter conv = prop.Converter;
value = conv.ConvertToString(null, CultureInfo.InvariantCulture, value);
}
}
if (prop.Attributes[typeof(IDReferencePropertyAttribute)] != null && controlResolver != null)
{
c = controlResolver.ResolveControl((string)value);
}
if (prop.Attributes[typeof(UrlPropertyAttribute)] != null && urlResolver != null)
{
value = urlResolver.ResolveClientUrl((string)value);
}
}
// add the value as an appropriate description
if (eventAttr != null)
{
descriptor.AddEvent(propertyName, (string)value);
}
else if (prop.Attributes[typeof(ElementReferenceAttribute)] != null)
{
if (c == null && controlResolver != null) c = controlResolver.ResolveControl((string)value);
if (c != null) value = c.ClientID;
descriptor.AddElementProperty(propertyName, (string)value);
}
else if (prop.Attributes[typeof(ComponentReferenceAttribute)] != null)
{
if (c == null && controlResolver != null) c = controlResolver.ResolveControl((string)value);
if (c != null)
{
ExtenderControlBase ex = c as ExtenderControlBase;
if (ex != null && ex.BehaviorID.Length > 0)
value = ex.BehaviorID;
else
value = c.ClientID;
}
descriptor.AddComponentProperty(propertyName, (string)value);
}
else
{
if (c != null) value = c.ClientID;
descriptor.AddProperty(propertyName, value);
}
}
}
// determine if we should describe methods
foreach (MethodInfo method in instance.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
{
ExtenderControlMethodAttribute methAttr = (ExtenderControlMethodAttribute)Attribute.GetCustomAttribute(method, typeof(ExtenderControlMethodAttribute));
if (methAttr == null || !methAttr.IsScriptMethod)
{
continue;
}
// We only need to support emitting the callback target and registering the WebForms.js script if there is at least one valid method
Control control = instance as Control;
if (control != null)
{
// Force WebForms.js
control.Page.ClientScript.GetCallbackEventReference(control, null, null, null);
// Add the callback target
descriptor.AddProperty("_callbackTarget", control.UniqueID);
}
break;
}
}
/// <summary>
/// Gets the script references for a type
/// </summary>
/// <param name="type"></param>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -