using System.Web.Util;
using System.ComponentModel.Design.Serialization;
#if NET_2_0
+using System.Configuration;
using System.Collections.Specialized;
+using System.Collections.Generic;
using System.Text.RegularExpressions;
+using System.Web.Configuration;
#endif
namespace System.Web.Compilation
internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
#if NET_2_0
- static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled);
+ static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ static Regex bindRegexInValue = new Regex (@"Bind\s*\(""(.*?)""\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
#endif
public TemplateControlCompiler (TemplateControlParser parser)
}
void CreateField (ControlBuilder builder, bool check)
- {
+ {
+ if (builder == null || builder.ID == null || builder.ControlType == null)
+ return;
#if NET_2_0
if (partialNameOverride [builder.ID] != null)
return;
#endif
+
+ MemberAttributes ma = MemberAttributes.Family;
currentLocation = builder.location;
- if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType))
+ if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType, ref ma))
return; // The field or property already exists in a base class and is accesible.
CodeMemberField field;
field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
- field.Attributes = MemberAttributes.Family;
- mainClass.Members.Add (field);
+ field.Attributes = ma;
+#if NET_2_0
+ field.Type.Options |= CodeTypeReferenceOptions.GlobalReference;
+
+ if (partialClass != null)
+ partialClass.Members.Add (field);
+ else
+#endif
+ mainClass.Members.Add (field);
}
- bool CheckBaseFieldOrProperty (string id, Type type)
+ bool CheckBaseFieldOrProperty (string id, Type type, ref MemberAttributes ma)
{
FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
return false;
if (!other.IsAssignableFrom (type)) {
+#if NET_2_0
+ ma |= MemberAttributes.New;
+ return false;
+#else
string msg = String.Format ("The base class includes the field '{0}', but its " +
"type '{1}' is not compatible with {2}",
id, other, type);
throw new ParseException (currentLocation, msg);
+#endif
}
return true;
/* in the case this is the __BuildControlTree
* method, allow subclasses to insert control
* specific code. */
- if (builder is RootBuilder)
+ if (builder is RootBuilder) {
+#if NET_2_0
+ SetCustomAttributes (method);
+#endif
AddStatementsToInitMethod (method);
-
+ }
+
if (builder.HasAspCode) {
CodeMemberMethod renderMethod = new CodeMemberMethod ();
builder.renderMethod = renderMethod;
if (childrenAsProperties || builder.ControlType == null) {
string typeString;
- if (builder is RootBuilder) {
-#if NET_2_0
- if (parser.IsPartial)
- typeString = parser.PartialClassName;
- else
-#endif
- typeString = parser.ClassName;
- }
+ if (builder is RootBuilder)
+ typeString = parser.ClassName;
else {
if (builder.ControlType != null && builder.isProperty &&
!typeof (ITemplate).IsAssignableFrom (builder.ControlType))
}
#if NET_2_0
+ if (builder.ParentTemplateBuilder is System.Web.UI.WebControls.ContentBuilderInternal) {
+ PropertyInfo pi;
+
+ try {
+ pi = type.GetProperty ("TemplateControl");
+ } catch (Exception) {
+ pi = null;
+ }
+
+ if (pi != null && pi.CanWrite) {
+ // __ctrl.TemplateControl = this;
+ assign = new CodeAssignStatement ();
+ assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
+ assign.Right = thisRef;
+ method.Statements.Add (assign);
+ }
+ }
+
// _ctrl.SkinID = $value
// _ctrl.ApplyStyleSheetSkin (this);
//
}
#endif
+ // process ID here. It should be set before any other attributes are
+ // assigned, since the control code may rely on ID being set. We
+ // skip ID in CreateAssignStatementsFromAttributes
+ if (builder.attribs != null) {
+ string ctl_id = builder.attribs ["id"] as string;
+ if (ctl_id != null && ctl_id != String.Empty)
+ CreateAssignStatementFromAttribute (builder, "id");
+ }
#if NET_2_0
if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
// this is the bit that causes the following stuff to end up in the else { }
builder.methodStatements = condStatement.FalseStatements;
-
- // __ctrl.TemplateControl = this;
- assign = new CodeAssignStatement ();
- assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
- assign.Right = thisRef;
-
- method.Statements.Add (assign);
}
#endif
}
-
+
mainClass.Members.Add (method);
}
+#if NET_2_0
+ void SetCustomAttribute (CodeMemberMethod method, UnknownAttributeDescriptor uad)
+ {
+ CodeAssignStatement assign = new CodeAssignStatement ();
+ assign.Left = new CodePropertyReferenceExpression (
+ new CodeArgumentReferenceExpression("__ctrl"),
+ uad.Info.Name);
+ assign.Right = GetExpressionFromString (uad.Value.GetType (), uad.Value.ToString (), uad.Info);
+
+ method.Statements.Add (assign);
+ }
+
+ void SetCustomAttributes (CodeMemberMethod method)
+ {
+ Type baseType = parser.BaseType;
+ if (baseType == null)
+ return;
+
+ List <UnknownAttributeDescriptor> attrs = parser.UnknownMainAttributes;
+ if (attrs == null || attrs.Count == 0)
+ return;
+
+ foreach (UnknownAttributeDescriptor uad in attrs)
+ SetCustomAttribute (method, uad);
+ }
+#endif
+
protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
{
}
#if NET_2_0
bool need_if = false;
value = value.Trim ();
- if (StrUtils.StartsWith (value, "Bind")) {
- value = "Eval" + value.Substring (4);
- need_if = true;
+ if (StrUtils.StartsWith (value, "Bind", true)) {
+ Match match = bindRegexInValue.Match (value);
+ if (match.Success) {
+ value = "Eval" + value.Substring (4);
+ need_if = true;
+ }
}
#endif
-
method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
-
+
CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
// This should be a CodePropertyReferenceExpression for properties... but it works anyway
CodeAssignStatement assign = new CodeAssignStatement (field, expr);
#if NET_2_0
if (need_if) {
- CodeExpression page = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Page");
+ CodeExpression page = new CodePropertyReferenceExpression (thisRef, "Page");
CodeExpression left = new CodeMethodInvokeExpression (page, "GetDataItem");
CodeBinaryOperatorExpression ce = new CodeBinaryOperatorExpression (left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
CodeConditionStatement ccs = new CodeConditionStatement (ce, assign);
return method.Name;
}
- void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound)
- {
+ void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound, bool isExpression)
+ {
CodeMemberMethod method = builder.method;
- if (isDataBound && IsWritablePropertyOrField (member)) {
+ bool isWritable = IsWritablePropertyOrField (member);
+ if (isDataBound && isWritable) {
string dbMethodName = DataBoundProperty (builder, type, var_name, att);
AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
return;
}
-
+#if NET_2_0
+ else if (isExpression && isWritable) {
+ AddExpressionAssign (method, member, type, var_name, att);
+ return;
+ }
+#endif
+
CodeAssignStatement assign = new CodeAssignStatement ();
assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
currentLocation = builder.location;
}
#if NET_2_0
+ bool IsExpression (string value)
+ {
+ if (value == null || value == "")
+ return false;
+ string str = value.Trim ();
+ return (StrUtils.StartsWith (str, "<%$") && StrUtils.EndsWith (str, "%>"));
+ }
+
void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
{
string str = value.Trim ();
str = str.Substring (3).Trim (); // eats "<%#"
- if (StrUtils.StartsWith (str, "Bind")) {
+ if (StrUtils.StartsWith (str, "Bind", true)) {
Match match = bindRegex.Match (str);
if (match.Success) {
string bindingName = match.Groups [1].Value;
}
bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
- string attValue, string prefix)
+ string attValue, string prefix)
{
int hyphen = id.IndexOf ('-');
bool isPropertyInfo = (member is PropertyInfo);
bool isDataBound = IsDataBound (attValue);
-
+#if NET_2_0
+ bool isExpression = !isDataBound && IsExpression (attValue);
+#else
+ bool isExpression = false;
+#endif
Type type;
if (isPropertyInfo) {
type = ((PropertyInfo) member).PropertyType;
if (InvariantCompareNoCase (member.Name, id)) {
#if NET_2_0
- if (isDataBound) RegisterBindingInfo (builder, member.Name, ref attValue);
+ if (isDataBound)
+ RegisterBindingInfo (builder, member.Name, ref attValue);
+
#endif
if (!IsWritablePropertyOrField (member))
return false;
- AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound);
+ AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound, isExpression);
return true;
}
string prop_field = id.Replace ("-", ".");
string [] parts = prop_field.Split (new char [] {'.'});
int length = parts.Length;
+
if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
return false;
if (sub_member == null)
return false;
- string new_prefix = prefix + parts [0] + ".";
+ string new_prefix = prefix + member.Name + ".";
string new_id = id.Substring (hyphen + 1);
return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
}
if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
#endif
AddCodeForPropertyOrField (builder, subprop.PropertyType,
- prefix + member.Name + "." + subprop.Name,
- val, subprop, isDataBound);
+ prefix + member.Name + "." + subprop.Name,
+ val, subprop, isDataBound, isExpression);
return true;
}
+#if NET_2_0
+ void AddExpressionAssign (CodeMemberMethod method, MemberInfo member, Type type, string name, string value)
+ {
+ CodeAssignStatement assign = new CodeAssignStatement ();
+ assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
+
+ // First let's find the correct expression builder
+ string expr = value.Substring (3, value.Length - 5).Trim ();
+ int colon = expr.IndexOf (':');
+ if (colon == -1)
+ return;
+ string prefix = expr.Substring (0, colon).Trim ();
+
+ System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration ("");
+ if (config == null)
+ return;
+ CompilationSection cs = (CompilationSection)config.GetSection ("system.web/compilation");
+ if (cs == null)
+ return;
+ if (cs.ExpressionBuilders == null || cs.ExpressionBuilders.Count == 0)
+ return;
+
+ System.Web.Configuration.ExpressionBuilder ceb = cs.ExpressionBuilders[prefix];
+ if (ceb == null)
+ return;
+ string builderType = ceb.Type;
+
+ Type t;
+ try {
+ t = HttpApplication.LoadType (builderType, true);
+ } catch (Exception e) {
+ throw new HttpException (
+ String.Format ("Failed to load expression builder type `{0}'", builderType), e);
+ }
+
+ if (!typeof (System.Web.Compilation.ExpressionBuilder).IsAssignableFrom (t))
+ throw new HttpException (
+ String.Format (
+ "Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder",
+ builderType));
+
+ System.Web.Compilation.ExpressionBuilder eb = null;
+ object parsedData;
+ ExpressionBuilderContext ctx;
+
+ try {
+ eb = Activator.CreateInstance (t) as System.Web.Compilation.ExpressionBuilder;
+ ctx = new ExpressionBuilderContext (HttpContext.Current.Request.FilePath);
+ parsedData = eb.ParseExpression (expr.Substring (colon + 1).Trim (), type, ctx);
+ } catch (Exception e) {
+ throw new HttpException (
+ String.Format ("Failed to create an instance of type `{0}'", builderType), e);
+ }
+
+ BoundPropertyEntry bpe = CreateBoundPropertyEntry (member as PropertyInfo, prefix, expr);
+ assign.Right = eb.GetCodeExpression (bpe, parsedData, ctx);
+
+ method.Statements.Add (assign);
+ }
+
+ BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr)
+ {
+ if (pi == null)
+ return null;
+
+ BoundPropertyEntry ret = new BoundPropertyEntry ();
+ ret.Expression = expr;
+ ret.ExpressionPrefix = prefix;
+ ret.Generated = false;
+ ret.Name = pi.Name;
+ ret.PropertyInfo = pi;
+ ret.Type = pi.PropertyType;
+
+ return ret;
+ }
+
+ void AssignPropertyFromResources (CodeMemberMethod method, MemberInfo mi, string attvalue)
+ {
+ bool isProperty = mi.MemberType == MemberTypes.Property;
+ bool isField = !isProperty && (mi.MemberType == MemberTypes.Field);
+
+ if (!isProperty && !isField || !IsWritablePropertyOrField (mi))
+ return;
+
+ string memberName = mi.Name;
+ string resname = String.Format ("{0}.{1}", attvalue, memberName);
+
+ // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
+ string inputFile = parser.InputFile;
+ string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
+
+ if (StrUtils.StartsWith (inputFile, physPath))
+ inputFile = parser.InputFile.Substring (physPath.Length - 1);
+ else
+ return;
+
+ char dsc = System.IO.Path.DirectorySeparatorChar;
+ if (dsc != '/')
+ inputFile = inputFile.Replace (dsc, '/');
+
+ object obj = HttpContext.GetLocalResourceObject (inputFile, resname);
+ if (obj == null)
+ return;
+
+ if (!isProperty && !isField)
+ return; // an "impossible" case
+
+ Type declaringType = mi.DeclaringType;
+ CodeAssignStatement assign = new CodeAssignStatement ();
+
+ assign.Left = new CodePropertyReferenceExpression (ctrlVar, memberName);
+ assign.Right = ResourceExpressionBuilder.CreateGetLocalResourceObject (mi, resname);
+
+ method.Statements.Add (assign);
+ }
+
+ void AssignPropertiesFromResources (CodeMemberMethod method, Type controlType, string attvalue)
+ {
+ // Process all public fields and properties of the control. We don't use GetMembers to make the code
+ // faster
+ FieldInfo [] fields = controlType.GetFields (
+ BindingFlags.Instance | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.FlattenHierarchy);
+ PropertyInfo [] properties = controlType.GetProperties (
+ BindingFlags.Instance | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.FlattenHierarchy);
+
+ foreach (FieldInfo fi in fields)
+ AssignPropertyFromResources (method, fi, attvalue);
+ foreach (PropertyInfo pi in properties)
+ AssignPropertyFromResources (method, pi, attvalue);
+ }
+
+ void AssignPropertiesFromResources (ControlBuilder builder, string attvalue)
+ {
+ if (attvalue == null || attvalue.Length == 0)
+ return;
+
+ Type controlType = builder.ControlType;
+ if (controlType == null)
+ return;
+
+ AssignPropertiesFromResources (builder.method, controlType, attvalue);
+ }
+#endif
+
void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
{
//"__ctrl.{0} += new {1} (this.{2});"
{
EventInfo [] ev_info = null;
Type type = builder.ControlType;
-
+
string attvalue = builder.attribs [id] as string;
if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
if (ev_info == null)
}
+#if NET_2_0
+ if (id.ToLower () == "meta:resourcekey") {
+ AssignPropertiesFromResources (builder, attvalue);
+ return;
+ }
+#endif
+
int hyphen = id.IndexOf ('-');
string alt_id = id;
if (hyphen != -1)
string val;
CodeMemberMethod method = builder.method;
bool databound = IsDataBound (attvalue);
+
if (databound) {
val = attvalue.Substring (3);
val = val.Substring (0, val.Length - 2);
protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
{
+#if NET_2_0
+ bool haveMetaKey = false;
+#endif
this.dataBoundAtts = 0;
IDictionary atts = builder.attribs;
if (atts == null || atts.Count == 0)
return;
-
+
foreach (string id in atts.Keys) {
if (InvariantCompareNoCase (id, "runat"))
continue;
-
+ // ID is assigned in BuildControltree
+ if (InvariantCompareNoCase (id, "id"))
+ continue;
+
#if NET_2_0
/* we skip SkinID here as it's assigned in BuildControlTree */
if (InvariantCompareNoCase (id, "skinid"))
continue;
+ if (InvariantCompareNoCase (id, "meta:resourcekey")) {
+ haveMetaKey = true;
+ continue;
+ }
#endif
CreateAssignStatementFromAttribute (builder, id);
}
+
+#if NET_2_0
+ if (haveMetaKey)
+ CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
+#endif
}
void CreateDBAttributeMethod (ControlBuilder builder, string attr, string code)
protected void AddChildCall (ControlBuilder parent, ControlBuilder child)
{
+ if (parent == null || child == null)
+ return;
CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
- object [] atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
+ object [] atts = null;
+
+ if (child.ControlType != null)
+ child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
if (atts != null && atts.Length > 0) {
PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
{
CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
- CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
- newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+ CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
+ new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
newCompiled.Parameters.Add (newBuild);
{
CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
- CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
- newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+ CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
+ new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
- CodeObjectCreateExpression newExtract = new CodeObjectCreateExpression (typeof (ExtractTemplateValuesMethod));
- newExtract.Parameters.Add (new CodeMethodReferenceExpression (thisRef, extractMethodName));
+ CodeDelegateCreateExpression newExtract = new CodeDelegateCreateExpression (
+ new CodeTypeReference (typeof (ExtractTemplateValuesMethod)), thisRef, extractMethodName);
CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
newCompiled.Parameters.Add (newBuild);
CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
if (builder.Bindings != null) {
+ Hashtable hash = new Hashtable ();
foreach (TemplateBinding binding in builder.Bindings) {
- CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
- method.Statements.Add (dec);
- CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
- CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
- invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
-
- CodeAssignStatement assign = new CodeAssignStatement ();
- CodeVariableReferenceExpression control = new CodeVariableReferenceExpression (binding.ControlId);
- assign.Left = control;
- assign.Right = new CodeCastExpression (binding.ControlType, invoke);
- method.Statements.Add (assign);
-
- CodeConditionStatement sif = new CodeConditionStatement ();
- sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
-
+ CodeConditionStatement sif;
+ CodeVariableReferenceExpression control;
+ CodeAssignStatement assign;
+
+ if (hash [binding.ControlId] == null) {
+
+ CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
+ method.Statements.Add (dec);
+ CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
+ CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
+ invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
+
+ assign = new CodeAssignStatement ();
+ control = new CodeVariableReferenceExpression (binding.ControlId);
+ assign.Left = control;
+ assign.Right = new CodeCastExpression (binding.ControlType, invoke);
+ method.Statements.Add (assign);
+
+ sif = new CodeConditionStatement ();
+ sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
+
+ method.Statements.Add (sif);
+
+ hash [binding.ControlId] = sif;
+ }
+
+ sif = (CodeConditionStatement) hash [binding.ControlId];
+ control = new CodeVariableReferenceExpression (binding.ControlId);
assign = new CodeAssignStatement ();
assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
sif.TrueStatements.Add (assign);
- method.Statements.Add (sif);
}
}
void AddContentTemplateInvocation (ContentBuilderInternal cbuilder, CodeMemberMethod method, string methodName)
{
- CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
- newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+ CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
+ new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
newCompiled.Parameters.Add (newBuild);
TemplateBuilder tb = builder as TemplateBuilder;
if (tb != null && tb.ContainerType != null)
return tb.ContainerType;
-
+#if NET_2_0
+ return builder.BindingContainerType;
+#else
Type type = builder.BindingContainerType;
PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
return type;
return prop.PropertyType;
+#endif
}
CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
{
EnsureID (builder);
bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
+
if (!isTemplate && !inTemplate) {
CreateField (builder, true);
} else if (!isTemplate) {
- builder.ID = builder.GetNextID (null);
- CreateField (builder, false);
+ bool doCheck = false;
+
+#if NET_2_0
+ bool singleInstance = false;
+ ControlBuilder pb = builder.parentBuilder;
+ TemplateBuilder tpb;
+ while (pb != null) {
+ tpb = pb as TemplateBuilder;
+ if (tpb == null) {
+ pb = pb.parentBuilder;
+ continue;
+ }
+
+ if (tpb.TemplateInstance == TemplateInstance.Single)
+ singleInstance = true;
+ break;
+ }
+
+ if (!singleInstance)
+#endif
+ builder.ID = builder.GetNextID (null);
+#if NET_2_0
+ else
+ doCheck = true;
+#endif
+ CreateField (builder, doCheck);
}
InitMethod (builder, isTemplate, childrenAsProperties);
StringBuilder sb = new StringBuilder ();
foreach (object b in builder.Children) {
-
if (b is string) {
sb.Append ((string) b);
continue;
if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
- }
+#if NET_2_0
+ if (builder is RootBuilder)
+ if (!String.IsNullOrEmpty (parser.MetaResourceKey))
+ AssignPropertiesFromResources (builder.method, parser.BaseType, parser.MetaResourceKey);
+#endif
+ }
+
protected internal override void CreateMethods ()
{
base.CreateMethods ();
}
CreateApplicationInstance ();
- CreateTemplateSourceDirectory ();
- }
-
- void CreateTemplateSourceDirectory ()
- {
- CodeMemberProperty prop = new CodeMemberProperty ();
- prop.Type = new CodeTypeReference (typeof (string));
- prop.Name = "TemplateSourceDirectory";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Override;
-
- CodePrimitiveExpression expr = new CodePrimitiveExpression (parser.BaseVirtualDir);
- prop.GetStatements.Add (new CodeMethodReturnStatement (expr));
- mainClass.Members.Add (prop);
}
-
+
void CreateApplicationInstance ()
{
CodeMemberProperty prop = new CodeMemberProperty ();
CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
+#if NET_2_0
+ if (partialClass != null)
+ partialClass.Members.Add (prop);
+ else
+#endif
mainClass.Members.Add (prop);
}
fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
ret.Expression = fldRef;
prop.GetStatements.Add (ret);
-
prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
+#if NET_2_0
+ CodeAttributeDeclaration attr = new CodeAttributeDeclaration ("System.Obsolete");
+ prop.CustomAttributes.Add (attr);
+#endif
+
mainClass.Members.Add (prop);
// Add the __autoHandlers field
return str;
}
#endif
-
- CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
- {
+
+ TypeConverter GetConverterForMember (MemberInfo member)
+ {
+ TypeConverterAttribute tca = null;
+ object[] attrs;
+
#if NET_2_0
- Type origType = type;
- bool wasNullable = false;
+ attrs = member.GetCustomAttributes (typeof (TypeConverterAttribute), true);
+ if (attrs.Length > 0)
+ tca = attrs [0] as TypeConverterAttribute;
+#else
+ attrs = member.GetCustomAttributes (true);
+ foreach (object attr in attrs) {
+ tca = attr as TypeConverterAttribute;
+
+ if (tca != null)
+ break;
+ }
+#endif
+
+ if (tca == null)
+ return null;
+
+ string typeName = tca.ConverterTypeName;
+ if (typeName == null || typeName.Length == 0)
+ return null;
+
+ Type t = null;
+ try {
+ t = HttpApplication.LoadType (typeName);
+ } catch (Exception) {
+ // ignore
+ }
+
+ if (t == null)
+ return null;
+
+ return (TypeConverter) Activator.CreateInstance (t);
+ }
+
+ CodeExpression CreateNullableExpression (Type type, CodeExpression inst, bool nullable)
+ {
+#if NET_2_0
+ if (!nullable)
+ return inst;
+
+ return new CodeObjectCreateExpression (
+ type,
+ new CodeExpression[] {inst}
+ );
+#else
+ return inst;
+#endif
+ }
+
+ bool SafeCanConvertFrom (Type type, TypeConverter cvt)
+ {
+ try {
+ return cvt.CanConvertFrom (type);
+ } catch (NotImplementedException) {
+ return false;
+ }
+ }
+
+ bool SafeCanConvertTo (Type type, TypeConverter cvt)
+ {
+ try {
+ return cvt.CanConvertTo (type);
+ } catch (NotImplementedException) {
+ return false;
+ }
+ }
+
+ CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
+ {
+ TypeConverter cvt = GetConverterForMember (member);
+ if (cvt != null && !SafeCanConvertFrom (typeof (string), cvt))
+ cvt = null;
+
+ object convertedFromAttr = null;
+ bool preConverted = false;
+ if (cvt != null && str != null) {
+ convertedFromAttr = cvt.ConvertFromInvariantString (str);
+ if (convertedFromAttr != null) {
+ type = convertedFromAttr.GetType ();
+ preConverted = true;
+ }
+ }
+
+ bool wasNullable = false;
+ Type originalType = type;
+#if NET_2_0
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
Type[] types = type.GetGenericArguments();
+ originalType = type;
type = types[0]; // we're interested only in the first type here
wasNullable = true;
}
#endif
-
+
if (type == typeof (string)) {
+ if (preConverted)
+ return CreateNullableExpression (originalType,
+ new CodePrimitiveExpression ((string) convertedFromAttr),
+ wasNullable);
+
#if NET_2_0
object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
if (urlAttr.Length != 0)
str = HandleUrlProperty (str, member);
#endif
- return new CodePrimitiveExpression (str);
+ return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
}
if (type == typeof (bool)) {
+ if (preConverted)
+ return CreateNullableExpression (originalType,
+ new CodePrimitiveExpression ((bool) convertedFromAttr),
+ wasNullable);
+
if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
- return new CodePrimitiveExpression (true);
+ return CreateNullableExpression (originalType, new CodePrimitiveExpression (true), wasNullable);
else if (InvariantCompareNoCase (str, "false"))
- return new CodePrimitiveExpression (false);
+ return CreateNullableExpression (originalType, new CodePrimitiveExpression (false), wasNullable);
#if NET_2_0
else if (wasNullable && InvariantCompareNoCase(str, "null"))
return new CodePrimitiveExpression (null);
throw new ParseException (currentLocation,
"Value '" + str + "' is not a valid boolean.");
}
-
+
if (str == null)
return new CodePrimitiveExpression (null);
if (type.IsPrimitive)
- return new CodePrimitiveExpression (Convert.ChangeType (str, type, CultureInfo.InvariantCulture));
+ return CreateNullableExpression (originalType,
+ new CodePrimitiveExpression (
+ Convert.ChangeType (preConverted ? convertedFromAttr : str,
+ type, CultureInfo.InvariantCulture)),
+ wasNullable);
if (type == typeof (string [])) {
- string [] subs = str.Split (',');
+ string [] subs;
+
+ if (preConverted)
+ subs = (string[])convertedFromAttr;
+ else
+ subs = str.Split (',');
CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
expr.CreateType = new CodeTypeReference (typeof (string));
- foreach (string v in subs) {
+ foreach (string v in subs)
expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
- }
- return expr;
+ return CreateNullableExpression (originalType, expr, wasNullable);
}
-
- if (type == typeof (Color)){
- if (colorConverter == null)
- colorConverter = TypeDescriptor.GetConverter (typeof (Color));
-
- if (str.Trim().Length == 0) {
- CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
- return new CodeFieldReferenceExpression (ft, "Empty");
- }
-
+
+ if (type == typeof (Color)) {
Color c;
- try {
- if (str.IndexOf (',') == -1) {
- c = (Color) colorConverter.ConvertFromString (str);
- } else {
- int [] argb = new int [4];
- argb [0] = 255;
-
- string [] parts = str.Split (',');
- int length = parts.Length;
- if (length < 3)
- throw new Exception ();
-
- int basei = (length == 4) ? 0 : 1;
- for (int i = length - 1; i >= 0; i--) {
- argb [basei + i] = (int) Byte.Parse (parts [i]);
- }
- c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
- }
- } catch (Exception e){
- // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
- // TypeConverter for Color fails to ConvertFromString.
- // Hence this hack...
- if (InvariantCompareNoCase ("LightGrey", str)) {
- c = Color.LightGray;
- } else {
- throw new ParseException (currentLocation,
- "Color " + str + " is not a valid color.", e);
+
+ if (!preConverted) {
+ if (colorConverter == null)
+ colorConverter = TypeDescriptor.GetConverter (typeof (Color));
+
+ if (str.Trim().Length == 0) {
+ CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
+ return CreateNullableExpression (originalType,
+ new CodeFieldReferenceExpression (ft, "Empty"),
+ wasNullable);
}
- }
- if (c.IsKnownColor){
+ try {
+ if (str.IndexOf (',') == -1) {
+ c = (Color) colorConverter.ConvertFromString (str);
+ } else {
+ int [] argb = new int [4];
+ argb [0] = 255;
+
+ string [] parts = str.Split (',');
+ int length = parts.Length;
+ if (length < 3)
+ throw new Exception ();
+
+ int basei = (length == 4) ? 0 : 1;
+ for (int i = length - 1; i >= 0; i--) {
+ argb [basei + i] = (int) Byte.Parse (parts [i]);
+ }
+ c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
+ }
+ } catch (Exception e) {
+ // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
+ // TypeConverter for Color fails to ConvertFromString.
+ // Hence this hack...
+ if (InvariantCompareNoCase ("LightGrey", str)) {
+ c = Color.LightGray;
+ } else {
+ throw new ParseException (currentLocation,
+ "Color " + str + " is not a valid color.", e);
+ }
+ }
+ } else
+ c = (Color)convertedFromAttr;
+
+ if (c.IsKnownColor) {
CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
if (c.IsSystemColor)
type = typeof (SystemColors);
expr.TargetObject = new CodeTypeReferenceExpression (type);
expr.FieldName = c.Name;
- return expr;
+ return CreateNullableExpression (originalType, expr, wasNullable);
} else {
CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
m.TargetObject = new CodeTypeReferenceExpression (type);
invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
- return invoke;
+ return CreateNullableExpression (originalType, invoke, wasNullable);
}
}
- TypeConverter converter = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
-
- if (converter != null && converter.CanConvertFrom (typeof (string))) {
- object value = converter.ConvertFrom (str);
+ TypeConverter converter = preConverted ? cvt :
+ wasNullable ? TypeDescriptor.GetConverter (type) :
+ TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
+
+ if (preConverted || (converter != null && SafeCanConvertFrom (typeof (string), converter))) {
+ object value = preConverted ? convertedFromAttr : converter.ConvertFromInvariantString (str);
- if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
+ if (SafeCanConvertTo (typeof (InstanceDescriptor), converter)) {
InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
- return GenerateInstance (idesc, true);
+ if (wasNullable)
+ return CreateNullableExpression (originalType, GenerateInstance (idesc, true),
+ wasNullable);
+
+ return new CodeCastExpression (type, GenerateInstance (idesc, true));
}
CodeExpression exp = GenerateObjectInstance (value, false);
- if (exp != null) return exp;
+ if (exp != null)
+ return CreateNullableExpression (originalType, exp, wasNullable);
CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
invoke.Parameters.Add (new CodePrimitiveExpression (str));
- return new CodeCastExpression (tref, invoke);
+ if (wasNullable)
+ return CreateNullableExpression (originalType, invoke, wasNullable);
+
+ return new CodeCastExpression (type, invoke);
}
-
- Console.WriteLine ("Unknown type: " + type + " value: " + str);
- return new CodePrimitiveExpression (str);
+ Console.WriteLine ("Unknown type: " + type + " value: " + str);
+
+ return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
}
CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
{
if (value == null)
return new CodePrimitiveExpression (null);
+
+ if (value is System.Type) {
+ CodeTypeReference tref = new CodeTypeReference (value.ToString ());
+ return new CodeTypeOfExpression (tref);
+ }
- Type t = value.GetType();
+ Type t = value.GetType ();
+
if (t.IsPrimitive || value is string)
return new CodePrimitiveExpression (value);
-
+
if (t.IsArray) {
Array ar = (Array) value;
CodeExpression[] items = new CodeExpression [ar.Length];
{
if (value is System.Web.UI.WebControls.Unit) {
System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
- MethodInfo met = typeof(System.Web.UI.WebControls.Unit).GetMethod ("Parse", new Type[] {typeof(string)});
- return new InstanceDescriptor (met, new object[] {s.ToString ()});
+ ConstructorInfo c = typeof(System.Web.UI.WebControls.Unit).GetConstructor (
+ BindingFlags.Instance | BindingFlags.Public,
+ null,
+ new Type[] {typeof(double), typeof(System.Web.UI.WebControls.UnitType)},
+ null);
+
+ return new InstanceDescriptor (c, new object[] {s.Value, s.Type});
}
if (value is System.Web.UI.WebControls.FontUnit) {
System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
- MethodInfo met = typeof(System.Web.UI.WebControls.FontUnit).GetMethod ("Parse", new Type[] {typeof(string)});
- return new InstanceDescriptor (met, new object[] {s.ToString ()});
+
+ Type cParamType = null;
+ object cParam = null;
+
+ switch (s.Type) {
+ case FontSize.AsUnit:
+ case FontSize.NotSet:
+ cParamType = typeof (System.Web.UI.WebControls.Unit);
+ cParam = s.Unit;
+ break;
+
+ default:
+ cParamType = typeof (string);
+ cParam = s.Type.ToString ();
+ break;
+ }
+
+ ConstructorInfo c = typeof(System.Web.UI.WebControls.FontUnit).GetConstructor (
+ BindingFlags.Instance | BindingFlags.Public,
+ null,
+ new Type[] {cParamType},
+ null);
+ if (c != null)
+ return new InstanceDescriptor (c, new object[] {cParam});
}
return null;
}
}
+