|
namespace ASPExtenderSample
{
#region [===== Using =====]
using System;
using System.CodeDom;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
#endregion
/// <summary>
/// A <see cref="System.ComponentModel.Design.Serialization.CodeDomSerializer"/> which is able
/// to serialize an <see cref="System.ComponentModel.IExtenderProvider"/> in a ASP.NET application.
/// </summary>
public class ASPExtenderSerializer : CodeDomSerializer
{
#region [===== Public instance methods =====]
/// <summary>
/// Deserializes the specified serialized CodeDOM object into an <see cref="System.ComponentModel.IExtenderProvider"/>.
/// </summary>
/// <param name="manager">A serialization manager interface that is used during the deserialization process.</param>
/// <param name="codeDomObject">A serialized CodeDOM object to deserialize.</param>
/// <returns></returns>
public override object Deserialize(IDesignerSerializationManager manager, object codeDomObject)
{
// just get the serializer of the base class and use that, it is sufficient.
CodeDomSerializer baseSerializer = (CodeDomSerializer)manager.GetSerializer(
typeof(Component), typeof(CodeDomSerializer));
CodeStatementCollection col = codeDomObject as CodeStatementCollection;
return baseSerializer.Deserialize(manager, codeDomObject);
}
/// <summary>
/// Serializes the specified <see cref="System.ComponentModel.IExtenderProvider"/> into a CodeDOM object.
/// </summary>
/// <param name="manager">A serialization manager interface that is used during the deserialization process.</param>
/// <param name="value">The <see cref="System.ComponentModel.IExtenderProvider"/> to serialize.</param>
/// <returns>A CodeDOM object representing the <see cref="System.ComponentModel.IExtenderProvider"/> that has been serialized.</returns>
public override object Serialize(IDesignerSerializationManager manager, object value)
{
// Only serialize IExtenderProviders
if(!(value is IExtenderProvider))
{
throw new ArgumentException("ASPExtenderSerializer not applied to IExtenderProvider.");
}
// First let the base class serializer do its work.
CodeDomSerializer baseSerializer = (CodeDomSerializer)manager.GetSerializer(
value.GetType().BaseType, typeof(CodeDomSerializer));
object codeObject = baseSerializer.Serialize(manager, value);
try
{
// Get the container with statements
CodeStatementCollection statements = (CodeStatementCollection)codeObject;
// And the components on the designer surface
IDesignerHost host = (IDesignerHost)manager.GetService(typeof(IDesignerHost));
ComponentCollection components = host.Container.Components;
// Now serialize the stored extender
SerializeExtender(manager, (IExtenderProvider)value, components, statements);
}
catch(Exception ex)
{
// An error occured, display to the user
string msg = "An error occured in the ASPExtenderSerializer:" + Environment.NewLine +
ex.Message;
ApplicationException appEx = new ApplicationException(msg, ex);
manager.ReportError(appEx);
}
return codeObject;
}
#endregion
#region [===== Private instance methods =====]
/// <summary>
/// Serialize the <see cref="System.ComponentModel.IExtenderProvider"/> which is stored
/// as an instance field.
/// </summary>
/// <param name="components">The components for which the extender might provide
/// properties.</param>
/// <param name="codeObject">The collection of statements to add the
/// created statements to.</param>
/// <param name="provider">The IExtenderProvider which is being serialized.</param>
/// <param name="manager">A serialization manager interface that is used during the deserialization process.</param>
void SerializeExtender(IDesignerSerializationManager manager, IExtenderProvider provider, ComponentCollection components,
CodeStatementCollection codeObject)
{
// TODO A quicker parsing method than 2 foreach statements?
ProvidePropertyAttribute[] properties = GetProvidedProperties(provider);
// Run all components
foreach(IComponent component in components)
{
// Verify if extension is possible for this component.
if(provider.CanExtend(component))
{
// Run all provided properties
foreach(ProvidePropertyAttribute attribute in properties)
{
// Get the current value, if a default value is present
// we need to compare if they are not equal, only then
// can we serialize the property into an expression.
object currentValue = ReflectionHelper.GetCurrentValue(provider, attribute, component);
bool hasDefault = ReflectionHelper.HasDefaultValue(provider, attribute);
object defaultValue = ReflectionHelper.GetDefaultValue(provider, attribute);
// We need to use Object.Equals because == returns a value which indicates
// whether the two are the same object, not if they have the same value.
if( !hasDefault || Object.Equals(defaultValue, currentValue) == false)
{
// Create the expression and add it to the container used by the extender.
CodeExpression exp = CreateExpression(manager, provider, attribute, component, currentValue);
codeObject.Add(exp);
}
}
}
}
}
/// <summary>
/// Returns an array of the properties provided by an IExtenderProvider.
/// </summary>
/// <param name="provider">The provider to return the provided properties for.</param>
/// <returns>An array of the properties provided by <paramref name="provider"/>.</returns>
ProvidePropertyAttribute[] GetProvidedProperties(IExtenderProvider provider)
{
return (ProvidePropertyAttribute[])Attribute.GetCustomAttributes(
provider.GetType(), typeof(ProvidePropertyAttribute), false);
}
/// <summary>
/// Serializes the value of a provided property into a CodeDom statement.
/// </summary>
/// <param name="attribute">The property to serialize into a statement.</param>
/// <param name="component">The component to serialize the value for.</param>
/// <param name="currentValue">The current value of the provided property.</param>
/// <param name="provider">The IExtenderProvider which is being serialized.</param>
/// <param name="manager">A serialization manager interface that is used during the deserialization process.</param>
/// <returns>The serialized expression.</returns>
CodeExpression CreateExpression(IDesignerSerializationManager manager, IExtenderProvider provider,
ProvidePropertyAttribute attribute, IComponent component,
object currentValue)
{
/* The statement has the following structure:
* <provider>.<setMethod>(<control>,<value>)
* For this we need to serialize a method call with 2 parameters,
* which will be called on the provider.
* */
// 1: Serialize a reference to the provider
CodeExpression targetObject = base.SerializeToReferenceExpression(manager,
provider);
// 2. Create the method call.
CodeMethodInvokeExpression methodCall = new CodeMethodInvokeExpression(targetObject, "Set" + attribute.PropertyName);
// 3. Create a reference to the object for which the property
// is provided as the first parameter
methodCall.Parameters.Add(CreateReferencingExpression(manager, component));
// 4. Create a reference to the new value of the
// property as the second parameter
methodCall.Parameters.Add(CreateReferencingExpression(manager, currentValue));
// Return the constructed expression
return methodCall;
}
/// <summary>
/// Creates a CodeExpression referencing a value, taking into account that
/// the value can be of different types which need referencing in a specific way.
/// </summary>
/// <param name="manager">A serialization manager interface that is used during the deserialization process.</param>
/// <param name="value">The value to reference in CodeDom.</param>
/// <returns>A CodeDom expression referencing <paramref name="value"/>.</returns>
CodeExpression CreateReferencingExpression(IDesignerSerializationManager manager, object value)
{
Type currentType = value.GetType();
CodeExpression refExpression = null;
if(currentType.IsValueType || value is String)
{
refExpression = base.SerializeToExpression(manager, value);
}
else
{
refExpression = base.SerializeToReferenceExpression(manager, value);
}
return refExpression;
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Wouter van Vugt is a Microsoft MVP with Office Open XML technologies and an independent consultant focusing on creating Office Business Applications (OBAs) with SharePoint, the Office 2007 system and related .NET technologies. Wouter is a frequent contributor to developer community sites such as OpenXmlDeveloper.org and MSDN and has published several white papers and articles as well a book available on line titled Open XML: the markup explained. Wouter is the founder of Code-Counsel, a Dutch company focusing on delivering cutting-edge technical content through a variety of channels. You can find out more about Wouter by reading his blog and visiting the Code-Counsel Web site.