2 // System.Web.Compilation.TemplateControlCompiler
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.ComponentModel;
35 using System.Globalization;
36 using System.Reflection;
40 using System.Web.UI.WebControls;
41 using System.Web.Util;
42 using System.ComponentModel.Design.Serialization;
44 using System.Configuration;
45 using System.Collections.Specialized;
46 using System.Collections.Generic;
47 using System.Text.RegularExpressions;
48 using System.Web.Configuration;
51 namespace System.Web.Compilation
53 class TemplateControlCompiler : BaseCompiler
55 static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
56 BindingFlags.Instance | BindingFlags.IgnoreCase;
58 TemplateControlParser parser;
60 ILocation currentLocation;
62 static TypeConverter colorConverter;
64 internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
67 static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
68 static Regex bindRegexInValue = new Regex (@"Bind\s*\(""(.*?)""\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
71 public TemplateControlCompiler (TemplateControlParser parser)
77 protected void EnsureID (ControlBuilder builder)
79 if (builder.ID == null || builder.ID.Trim () == "")
80 builder.ID = builder.GetNextID (null);
83 void CreateField (ControlBuilder builder, bool check)
85 if (builder == null || builder.ID == null || builder.ControlType == null)
88 if (partialNameOverride [builder.ID] != null)
91 MemberAttributes ma = MemberAttributes.Family;
92 currentLocation = builder.location;
93 if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType, ref ma))
94 return; // The field or property already exists in a base class and is accesible.
96 CodeMemberField field;
97 field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
98 field.Attributes = ma;
100 if (partialClass != null)
101 partialClass.Members.Add (field);
104 mainClass.Members.Add (field);
107 bool CheckBaseFieldOrProperty (string id, Type type, ref MemberAttributes ma)
109 FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
112 if (fld == null || fld.IsPrivate) {
113 PropertyInfo prop = parser.BaseType.GetProperty (id, noCaseFlags);
115 MethodInfo setm = prop.GetSetMethod (true);
117 other = prop.PropertyType;
120 other = fld.FieldType;
126 if (!other.IsAssignableFrom (type)) {
128 ma |= MemberAttributes.New;
131 string msg = String.Format ("The base class includes the field '{0}', but its " +
132 "type '{1}' is not compatible with {2}",
134 throw new ParseException (currentLocation, msg);
141 void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr)
143 if (!builder.haveParserVariable) {
144 CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
146 p.Type = new CodeTypeReference (typeof (IParserAccessor));
147 p.InitExpression = new CodeCastExpression (typeof (IParserAccessor), ctrlVar);
148 builder.methodStatements.Add (p);
149 builder.haveParserVariable = true;
152 CodeVariableReferenceExpression var = new CodeVariableReferenceExpression ("__parser");
153 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (var, "AddParsedSubObject");
154 invoke.Parameters.Add (expr);
155 builder.methodStatements.Add (invoke);
158 void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
160 string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID));
161 CodeMemberMethod method = new CodeMemberMethod ();
162 builder.method = method;
163 builder.methodStatements = method.Statements;
165 method.Name = "__BuildControl" + tailname;
166 method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
167 Type type = builder.ControlType;
169 /* in the case this is the __BuildControlTree
170 * method, allow subclasses to insert control
172 if (builder is RootBuilder) {
174 SetCustomAttributes (method);
176 AddStatementsToInitMethod (method);
179 if (builder.HasAspCode) {
180 CodeMemberMethod renderMethod = new CodeMemberMethod ();
181 builder.renderMethod = renderMethod;
182 renderMethod.Name = "__Render" + tailname;
183 renderMethod.Attributes = MemberAttributes.Private | MemberAttributes.Final;
184 CodeParameterDeclarationExpression arg1 = new CodeParameterDeclarationExpression ();
185 arg1.Type = new CodeTypeReference (typeof (HtmlTextWriter));
186 arg1.Name = "__output";
187 CodeParameterDeclarationExpression arg2 = new CodeParameterDeclarationExpression ();
188 arg2.Type = new CodeTypeReference (typeof (Control));
189 arg2.Name = "parameterContainer";
190 renderMethod.Parameters.Add (arg1);
191 renderMethod.Parameters.Add (arg2);
192 mainClass.Members.Add (renderMethod);
195 if (childrenAsProperties || builder.ControlType == null) {
197 if (builder is RootBuilder)
198 typeString = parser.ClassName;
200 if (builder.ControlType != null && builder.isProperty &&
201 !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
202 typeString = builder.ControlType.FullName;
204 typeString = "System.Web.UI.Control";
207 method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
210 if (typeof (Control).IsAssignableFrom (type))
211 method.ReturnType = new CodeTypeReference (typeof (Control));
213 // _ctrl = new $controlType ($parameters);
215 CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (type);
217 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
218 if (atts != null && atts.Length > 0) {
219 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
221 newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
222 } else if (builder is DataBindingBuilder) {
223 newExpr.Parameters.Add (new CodePrimitiveExpression (0));
224 newExpr.Parameters.Add (new CodePrimitiveExpression (1));
227 method.Statements.Add (new CodeVariableDeclarationStatement (builder.ControlType, "__ctrl"));
228 CodeAssignStatement assign = new CodeAssignStatement ();
229 assign.Left = ctrlVar;
230 assign.Right = newExpr;
231 method.Statements.Add (assign);
233 // this.$builderID = _ctrl;
235 CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
236 builderID.TargetObject = thisRef;
237 builderID.FieldName = builder.ID;
238 assign = new CodeAssignStatement ();
239 assign.Left = builderID;
240 assign.Right = ctrlVar;
241 method.Statements.Add (assign);
242 if (typeof (UserControl).IsAssignableFrom (type)) {
243 CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ();
244 mref.TargetObject = builderID;
245 mref.MethodName = "InitializeAsUserControl";
246 CodeMethodInvokeExpression initAsControl = new CodeMethodInvokeExpression (mref);
247 initAsControl.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
248 method.Statements.Add (initAsControl);
252 if (builder.ParentTemplateBuilder is System.Web.UI.WebControls.ContentBuilderInternal) {
256 pi = type.GetProperty ("TemplateControl");
257 } catch (Exception) {
261 if (pi != null && pi.CanWrite) {
262 // __ctrl.TemplateControl = this;
263 assign = new CodeAssignStatement ();
264 assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
265 assign.Right = thisRef;
266 method.Statements.Add (assign);
270 // _ctrl.SkinID = $value
271 // _ctrl.ApplyStyleSheetSkin (this);
273 // the SkinID assignment needs to come
274 // before the call to
275 // ApplyStyleSheetSkin, for obvious
276 // reasons. We skip SkinID in
277 // CreateAssignStatementsFromAttributes
280 if (builder.attribs != null) {
281 string skinid = builder.attribs ["skinid"] as string;
283 CreateAssignStatementFromAttribute (builder, "skinid");
285 if (typeof (WebControl).IsAssignableFrom (type)) {
286 CodeMethodInvokeExpression applyStyleSheetSkin = new CodeMethodInvokeExpression (ctrlVar, "ApplyStyleSheetSkin");
287 if (typeof (Page).IsAssignableFrom (parser.BaseType))
288 applyStyleSheetSkin.Parameters.Add (thisRef);
290 applyStyleSheetSkin.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
291 method.Statements.Add (applyStyleSheetSkin);
296 if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
297 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
298 CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add");
299 addPlaceholder.Parameters.Add (ctrlVar);
300 method.Statements.Add (addPlaceholder);
303 CodeConditionStatement condStatement;
305 // Add the __Template_* field
306 CodeMemberField fld = new CodeMemberField (typeof (ITemplate), "__Template_" + builder.ID);
307 fld.Attributes = MemberAttributes.Private;
308 mainClass.Members.Add (fld);
310 CodeFieldReferenceExpression templateID = new CodeFieldReferenceExpression ();
311 templateID.TargetObject = thisRef;
312 templateID.FieldName = "__Template_" + builder.ID;
314 // if ((this.ContentTemplates != null)) {
315 // this.__Template_$builder.ID = ((System.Web.UI.ITemplate)(this.ContentTemplates["$builder.ID"]));
318 CodeFieldReferenceExpression contentTemplates = new CodeFieldReferenceExpression ();
319 contentTemplates.TargetObject = thisRef;
320 contentTemplates.FieldName = "ContentTemplates";
322 CodeIndexerExpression indexer = new CodeIndexerExpression ();
323 indexer.TargetObject = new CodePropertyReferenceExpression (thisRef, "ContentTemplates");
324 indexer.Indices.Add (new CodePrimitiveExpression (builder.ID));
326 assign = new CodeAssignStatement ();
327 assign.Left = templateID;
328 assign.Right = new CodeCastExpression (new CodeTypeReference (typeof (ITemplate)), indexer);
330 condStatement = new CodeConditionStatement (new CodeBinaryOperatorExpression (contentTemplates,
331 CodeBinaryOperatorType.IdentityInequality,
332 new CodePrimitiveExpression (null)),
335 method.Statements.Add (condStatement);
337 // if ((this.__Template_mainContent != null)) {
338 // this.__Template_mainContent.InstantiateIn(__ctrl);
340 // and also set things up such that any additional code ends up in:
345 CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
346 methodRef.TargetObject = templateID;
347 methodRef.MethodName = "InstantiateIn";
349 CodeMethodInvokeExpression instantiateInInvoke;
350 instantiateInInvoke = new CodeMethodInvokeExpression (methodRef, ctrlVar);
352 condStatement = new CodeConditionStatement (new CodeBinaryOperatorExpression (templateID,
353 CodeBinaryOperatorType.IdentityInequality,
354 new CodePrimitiveExpression (null)),
355 new CodeExpressionStatement (instantiateInInvoke));
356 method.Statements.Add (condStatement);
358 // this is the bit that causes the following stuff to end up in the else { }
359 builder.methodStatements = condStatement.FalseStatements;
364 mainClass.Members.Add (method);
368 void SetCustomAttribute (CodeMemberMethod method, UnknownAttributeDescriptor uad)
370 CodeAssignStatement assign = new CodeAssignStatement ();
371 assign.Left = new CodePropertyReferenceExpression (
372 new CodeArgumentReferenceExpression("__ctrl"),
374 assign.Right = GetExpressionFromString (uad.Value.GetType (), uad.Value.ToString (), uad.Info);
376 method.Statements.Add (assign);
379 void SetCustomAttributes (CodeMemberMethod method)
381 Type baseType = parser.BaseType;
382 if (baseType == null)
385 List <UnknownAttributeDescriptor> attrs = parser.UnknownMainAttributes;
386 if (attrs == null || attrs.Count == 0)
389 foreach (UnknownAttributeDescriptor uad in attrs)
390 SetCustomAttribute (method, uad);
394 protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
398 void AddLiteralSubObject (ControlBuilder builder, string str)
400 if (!builder.HasAspCode) {
401 CodeObjectCreateExpression expr;
402 expr = new CodeObjectCreateExpression (typeof (LiteralControl), new CodePrimitiveExpression (str));
403 AddParsedSubObjectStmt (builder, expr);
405 CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
406 methodRef.TargetObject = new CodeArgumentReferenceExpression ("__output");
407 methodRef.MethodName = "Write";
409 CodeMethodInvokeExpression expr;
410 expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
411 builder.renderMethod.Statements.Add (expr);
415 string TrimDB (string value)
417 string str = value.Trim ();
418 str = str.Substring (3);
419 return str.Substring (0, str.Length - 2);
422 string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
424 value = TrimDB (value);
425 CodeMemberMethod method;
426 string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
428 bool need_if = false;
429 value = value.Trim ();
430 if (StrUtils.StartsWith (value, "Bind", true)) {
431 Match match = bindRegexInValue.Match (value);
433 value = "Eval" + value.Substring (4);
438 method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
440 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
442 // This should be a CodePropertyReferenceExpression for properties... but it works anyway
443 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (targetExpr, varName);
446 if (type == typeof (string)) {
447 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
448 CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
449 tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
450 tostring.Parameters.Add (new CodeSnippetExpression (value));
453 CodeSnippetExpression snippet = new CodeSnippetExpression (value);
454 expr = new CodeCastExpression (type, snippet);
457 CodeAssignStatement assign = new CodeAssignStatement (field, expr);
460 CodeExpression page = new CodePropertyReferenceExpression (thisRef, "Page");
461 CodeExpression left = new CodeMethodInvokeExpression (page, "GetDataItem");
462 CodeBinaryOperatorExpression ce = new CodeBinaryOperatorExpression (left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
463 CodeConditionStatement ccs = new CodeConditionStatement (ce, assign);
464 method.Statements.Add (ccs);
468 method.Statements.Add (assign);
470 mainClass.Members.Add (method);
474 void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound, bool isExpression)
476 CodeMemberMethod method = builder.method;
477 bool isWritable = IsWritablePropertyOrField (member);
478 if (isDataBound && isWritable) {
479 string dbMethodName = DataBoundProperty (builder, type, var_name, att);
480 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
484 else if (isExpression && isWritable) {
485 AddExpressionAssign (method, member, type, var_name, att);
490 CodeAssignStatement assign = new CodeAssignStatement ();
491 assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
492 currentLocation = builder.location;
493 assign.Right = GetExpressionFromString (type, att, member);
495 method.Statements.Add (assign);
498 bool IsDataBound (string value)
500 if (value == null || value == "")
503 string str = value.Trim ();
504 return (StrUtils.StartsWith (str, "<%#") && StrUtils.EndsWith (str, "%>"));
508 bool IsExpression (string value)
510 if (value == null || value == "")
512 string str = value.Trim ();
513 return (StrUtils.StartsWith (str, "<%$") && StrUtils.EndsWith (str, "%>"));
516 void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
518 string str = value.Trim ();
519 str = str.Substring (3).Trim (); // eats "<%#"
520 if (StrUtils.StartsWith (str, "Bind", true)) {
521 Match match = bindRegex.Match (str);
523 string bindingName = match.Groups [1].Value;
525 TemplateBuilder templateBuilder = builder.ParentTemplateBuilder;
526 if (templateBuilder == null || templateBuilder.BindingDirection == BindingDirection.OneWay)
527 throw new HttpException ("Bind expression not allowed in this context.");
529 string id = builder.attribs ["ID"] as string;
531 throw new HttpException ("Control of type '" + builder.ControlType + "' using two-way binding on property '" + propName + "' must have an ID.");
533 templateBuilder.RegisterBoundProperty (builder.ControlType, propName, id, bindingName);
540 static bool InvariantCompare (string a, string b)
542 return (0 == String.Compare (a, b, false, CultureInfo.InvariantCulture));
546 static bool InvariantCompareNoCase (string a, string b)
548 return (0 == String.Compare (a, b, true, CultureInfo.InvariantCulture));
551 static MemberInfo GetFieldOrProperty (Type type, string name)
553 MemberInfo member = null;
555 member = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
562 member = type.GetField (name, noCaseFlags & ~BindingFlags.NonPublic);
568 static bool IsWritablePropertyOrField (MemberInfo member)
570 PropertyInfo pi = member as PropertyInfo;
573 FieldInfo fi = member as FieldInfo;
575 return !fi.IsInitOnly;
576 throw new ArgumentException ("Argument must be of PropertyInfo or FieldInfo type", "member");
579 bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
580 string attValue, string prefix)
582 int hyphen = id.IndexOf ('-');
583 bool isPropertyInfo = (member is PropertyInfo);
584 bool isDataBound = IsDataBound (attValue);
586 bool isExpression = !isDataBound && IsExpression (attValue);
588 bool isExpression = false;
591 if (isPropertyInfo) {
592 type = ((PropertyInfo) member).PropertyType;
594 type = ((FieldInfo) member).FieldType;
597 if (InvariantCompareNoCase (member.Name, id)) {
600 RegisterBindingInfo (builder, member.Name, ref attValue);
603 if (!IsWritablePropertyOrField (member))
606 AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound, isExpression);
613 string prop_field = id.Replace ("-", ".");
614 string [] parts = prop_field.Split (new char [] {'.'});
615 int length = parts.Length;
616 if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
620 MemberInfo sub_member = GetFieldOrProperty (type, parts [1]);
621 if (sub_member == null)
624 string new_prefix = prefix + parts [0] + ".";
625 string new_id = id.Substring (hyphen + 1);
626 return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
629 MemberInfo subpf = GetFieldOrProperty (type, parts [1]);
630 if (!(subpf is PropertyInfo))
633 PropertyInfo subprop = (PropertyInfo) subpf;
634 if (subprop.CanWrite == false)
637 bool is_bool = (subprop.PropertyType == typeof (bool));
638 if (!is_bool && attValue == null)
639 return false; // Font-Size -> Font-Size="" as html
641 string val = attValue;
642 if (attValue == null && is_bool)
643 val = "true"; // Font-Bold <=> Font-Bold="true"
645 if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
647 AddCodeForPropertyOrField (builder, subprop.PropertyType,
648 prefix + member.Name + "." + subprop.Name,
649 val, subprop, isDataBound, isExpression);
655 void AddExpressionAssign (CodeMemberMethod method, MemberInfo member, Type type, string name, string value)
657 CodeAssignStatement assign = new CodeAssignStatement ();
658 assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
660 // First let's find the correct expression builder
661 string expr = value.Substring (3, value.Length - 5).Trim ();
662 int colon = expr.IndexOf (':');
665 string prefix = expr.Substring (0, colon).Trim ();
667 System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration ("");
670 CompilationSection cs = (CompilationSection)config.GetSection ("system.web/compilation");
673 if (cs.ExpressionBuilders == null || cs.ExpressionBuilders.Count == 0)
676 System.Web.Configuration.ExpressionBuilder ceb = cs.ExpressionBuilders[prefix];
679 string builderType = ceb.Type;
683 t = System.Type.GetType (builderType, true);
684 } catch (Exception e) {
685 throw new HttpException (
686 String.Format ("Failed to load expression builder type `{0}'", builderType), e);
689 if (!typeof (System.Web.Compilation.ExpressionBuilder).IsAssignableFrom (t))
690 throw new HttpException (
692 "Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder",
695 System.Web.Compilation.ExpressionBuilder eb = null;
697 ExpressionBuilderContext ctx;
700 eb = Activator.CreateInstance (t) as System.Web.Compilation.ExpressionBuilder;
701 ctx = new ExpressionBuilderContext (HttpContext.Current.Request.FilePath);
702 parsedData = eb.ParseExpression (expr.Substring (colon + 1).Trim (), type, ctx);
703 } catch (Exception e) {
704 throw new HttpException (
705 String.Format ("Failed to create an instance of type `{0}'", builderType), e);
708 BoundPropertyEntry bpe = CreateBoundPropertyEntry (member as PropertyInfo, prefix, expr);
709 assign.Right = eb.GetCodeExpression (bpe, parsedData, ctx);
711 method.Statements.Add (assign);
714 BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr)
719 BoundPropertyEntry ret = new BoundPropertyEntry ();
720 ret.Expression = expr;
721 ret.ExpressionPrefix = prefix;
722 ret.Generated = false;
724 ret.PropertyInfo = pi;
725 ret.Type = pi.PropertyType;
730 void AssignPropertyFromResources (CodeMemberMethod method, MemberInfo mi, string attvalue)
732 bool isProperty = mi.MemberType == MemberTypes.Property;
733 bool isField = !isProperty && (mi.MemberType == MemberTypes.Field);
735 if (!isProperty && !isField || !IsWritablePropertyOrField (mi))
738 string memberName = mi.Name;
739 string resname = String.Format ("{0}.{1}", attvalue, memberName);
741 // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
742 string inputFile = parser.InputFile;
743 string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
745 if (StrUtils.StartsWith (inputFile, physPath))
746 inputFile = parser.InputFile.Substring (physPath.Length - 1);
750 object obj = HttpContext.GetLocalResourceObject (inputFile, resname);
754 Type member_type = null;
756 member_type = ((PropertyInfo)mi).PropertyType;
758 member_type = ((FieldInfo)mi).FieldType;
760 return; // an "impossible" case
762 Type declaringType = mi.DeclaringType;
763 TypeConverter converter = TypeDescriptor.GetProperties (declaringType) [memberName].Converter;
764 CodeAssignStatement assign = new CodeAssignStatement ();
766 assign.Left = new CodePropertyReferenceExpression (ctrlVar, memberName);
767 assign.Right = ResourceExpressionBuilder.CreateGetLocalResourceObject (mi, resname);
769 method.Statements.Add (assign);
772 void AssignPropertiesFromResources (CodeMemberMethod method, Type controlType, string attvalue)
774 // Process all public fields and properties of the control. We don't use GetMembers to make the code
776 FieldInfo [] fields = controlType.GetFields (
777 BindingFlags.Instance | BindingFlags.Static |
778 BindingFlags.Public | BindingFlags.FlattenHierarchy);
779 PropertyInfo [] properties = controlType.GetProperties (
780 BindingFlags.Instance | BindingFlags.Static |
781 BindingFlags.Public | BindingFlags.FlattenHierarchy);
783 foreach (FieldInfo fi in fields)
784 AssignPropertyFromResources (method, fi, attvalue);
785 foreach (PropertyInfo pi in properties)
786 AssignPropertyFromResources (method, pi, attvalue);
789 void AssignPropertiesFromResources (ControlBuilder builder, string attvalue)
791 if (attvalue == null || attvalue.Length == 0)
794 Type controlType = builder.ControlType;
795 if (controlType == null)
798 AssignPropertiesFromResources (builder.method, controlType, attvalue);
802 void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
804 //"__ctrl.{0} += new {1} (this.{2});"
805 CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
807 CodeDelegateCreateExpression create;
808 create = new CodeDelegateCreateExpression (new CodeTypeReference (type), thisRef, value);
810 CodeAttachEventStatement attach = new CodeAttachEventStatement (evtID, create);
811 method.Statements.Add (attach);
814 void CreateAssignStatementFromAttribute (ControlBuilder builder, string id)
816 EventInfo [] ev_info = null;
817 Type type = builder.ControlType;
819 string attvalue = builder.attribs [id] as string;
820 if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
822 ev_info = type.GetEvents ();
824 string id_as_event = id.Substring (2);
825 foreach (EventInfo ev in ev_info){
826 if (InvariantCompareNoCase (ev.Name, id_as_event)){
827 AddEventAssign (builder.method,
839 if (id.ToLower () == "meta:resourcekey") {
840 AssignPropertiesFromResources (builder, attvalue);
845 int hyphen = id.IndexOf ('-');
848 alt_id = id.Substring (0, hyphen);
850 MemberInfo fop = GetFieldOrProperty (type, alt_id);
852 if (ProcessPropertiesAndFields (builder, fop, id, attvalue, null))
856 if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
857 throw new ParseException (builder.location, "Unrecognized attribute: " + id);
860 CodeMemberMethod method = builder.method;
861 bool databound = IsDataBound (attvalue);
864 val = attvalue.Substring (3);
865 val = val.Substring (0, val.Length - 2);
866 CreateDBAttributeMethod (builder, id, val);
868 CodeCastExpression cast;
869 CodeMethodReferenceExpression methodExpr;
870 CodeMethodInvokeExpression expr;
872 cast = new CodeCastExpression (typeof (IAttributeAccessor), ctrlVar);
873 methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
874 expr = new CodeMethodInvokeExpression (methodExpr);
875 expr.Parameters.Add (new CodePrimitiveExpression (id));
876 expr.Parameters.Add (new CodePrimitiveExpression (attvalue));
877 method.Statements.Add (expr);
882 protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
885 bool haveMetaKey = false;
887 this.dataBoundAtts = 0;
888 IDictionary atts = builder.attribs;
889 if (atts == null || atts.Count == 0)
892 foreach (string id in atts.Keys) {
893 if (InvariantCompareNoCase (id, "runat"))
897 /* we skip SkinID here as it's assigned in BuildControlTree */
898 if (InvariantCompareNoCase (id, "skinid"))
900 if (InvariantCompareNoCase (id, "meta:resourcekey")) {
905 CreateAssignStatementFromAttribute (builder, id);
910 CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
914 void CreateDBAttributeMethod (ControlBuilder builder, string attr, string code)
916 if (code == null || code.Trim () == "")
919 string id = builder.GetNextID (null);
920 string dbMethodName = "__DataBind_" + id;
921 CodeMemberMethod method = builder.method;
922 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
924 method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
925 CodeCastExpression cast;
926 CodeMethodReferenceExpression methodExpr;
927 CodeMethodInvokeExpression expr;
929 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
930 cast = new CodeCastExpression (typeof (IAttributeAccessor), targetExpr);
931 methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
932 expr = new CodeMethodInvokeExpression (methodExpr);
933 expr.Parameters.Add (new CodePrimitiveExpression (attr));
934 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
935 tostring.Method = new CodeMethodReferenceExpression (
936 new CodeTypeReferenceExpression (typeof (Convert)),
938 tostring.Parameters.Add (new CodeSnippetExpression (code));
939 expr.Parameters.Add (tostring);
940 method.Statements.Add (expr);
941 mainClass.Members.Add (method);
944 void AddRenderControl (ControlBuilder builder)
946 CodeIndexerExpression indexer = new CodeIndexerExpression ();
947 indexer.TargetObject = new CodePropertyReferenceExpression (
948 new CodeArgumentReferenceExpression ("parameterContainer"),
951 indexer.Indices.Add (new CodePrimitiveExpression (builder.renderIndex));
953 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
954 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
955 builder.renderMethod.Statements.Add (invoke);
956 builder.renderIndex++;
959 protected void AddChildCall (ControlBuilder parent, ControlBuilder child)
961 if (parent == null || child == null)
963 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
964 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
966 object [] atts = null;
968 if (child.ControlType != null)
969 child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
970 if (atts != null && atts.Length > 0) {
971 PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
972 CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
973 CodeMethodInvokeExpression build = new CodeMethodInvokeExpression (cc, "BuildCachedControl");
974 build.Parameters.Add (new CodeArgumentReferenceExpression("__ctrl"));
975 build.Parameters.Add (new CodePrimitiveExpression (child.ID));
978 build.Parameters.Add (new CodePrimitiveExpression (child.ControlType.GetHashCode ().ToString ()));
981 build.Parameters.Add (new CodePrimitiveExpression (Guid.NewGuid ().ToString ()));
983 build.Parameters.Add (new CodePrimitiveExpression (pca.Duration));
984 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByParams));
985 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByControls));
986 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
987 build.Parameters.Add (new CodeDelegateCreateExpression (
988 new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
989 thisRef, child.method.Name));
991 parent.methodStatements.Add (build);
992 if (parent.HasAspCode)
993 AddRenderControl (parent);
997 if (child.isProperty || parent.ChildrenAsProperties) {
998 expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
999 parent.methodStatements.Add (expr);
1003 parent.methodStatements.Add (expr);
1004 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
1005 if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType)) {
1006 AddParsedSubObjectStmt (parent, field);
1008 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
1009 invoke.Parameters.Add (field);
1010 parent.methodStatements.Add (invoke);
1013 if (parent.HasAspCode)
1014 AddRenderControl (parent);
1017 void AddTemplateInvocation (CodeMemberMethod method, string name, string methodName)
1019 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
1021 CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
1022 new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
1024 CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
1025 newCompiled.Parameters.Add (newBuild);
1027 CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
1028 method.Statements.Add (assign);
1032 void AddBindableTemplateInvocation (CodeMemberMethod method, string name, string methodName, string extractMethodName)
1034 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
1036 CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
1037 new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
1039 CodeDelegateCreateExpression newExtract = new CodeDelegateCreateExpression (
1040 new CodeTypeReference (typeof (ExtractTemplateValuesMethod)), thisRef, extractMethodName);
1042 CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
1043 newCompiled.Parameters.Add (newBuild);
1044 newCompiled.Parameters.Add (newExtract);
1046 CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
1047 method.Statements.Add (assign);
1050 string CreateExtractValuesMethod (TemplateBuilder builder)
1052 CodeMemberMethod method = new CodeMemberMethod ();
1053 method.Name = "__ExtractValues_" + builder.ID;
1054 method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
1055 method.ReturnType = new CodeTypeReference (typeof(IOrderedDictionary));
1057 CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression ();
1058 arg.Type = new CodeTypeReference (typeof (Control));
1059 arg.Name = "__container";
1060 method.Parameters.Add (arg);
1061 mainClass.Members.Add (method);
1063 CodeObjectCreateExpression newTable = new CodeObjectCreateExpression ();
1064 newTable.CreateType = new CodeTypeReference (typeof(OrderedDictionary));
1065 method.Statements.Add (new CodeVariableDeclarationStatement (typeof(OrderedDictionary), "__table", newTable));
1066 CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
1068 if (builder.Bindings != null) {
1069 Hashtable hash = new Hashtable ();
1070 foreach (TemplateBinding binding in builder.Bindings) {
1071 CodeConditionStatement sif;
1072 CodeVariableReferenceExpression control;
1073 CodeAssignStatement assign;
1075 if (hash [binding.ControlId] == null) {
1077 CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
1078 method.Statements.Add (dec);
1079 CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
1080 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
1081 invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
1083 assign = new CodeAssignStatement ();
1084 control = new CodeVariableReferenceExpression (binding.ControlId);
1085 assign.Left = control;
1086 assign.Right = new CodeCastExpression (binding.ControlType, invoke);
1087 method.Statements.Add (assign);
1089 sif = new CodeConditionStatement ();
1090 sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
1092 method.Statements.Add (sif);
1094 hash [binding.ControlId] = sif;
1097 sif = (CodeConditionStatement) hash [binding.ControlId];
1098 control = new CodeVariableReferenceExpression (binding.ControlId);
1099 assign = new CodeAssignStatement ();
1100 assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
1101 assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
1102 sif.TrueStatements.Add (assign);
1106 method.Statements.Add (new CodeMethodReturnStatement (tableExp));
1110 void AddContentTemplateInvocation (ContentBuilderInternal cbuilder, CodeMemberMethod method, string methodName)
1112 CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
1113 new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
1115 CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
1116 newCompiled.Parameters.Add (newBuild);
1118 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (thisRef, "AddContentTemplate");
1119 invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
1120 invoke.Parameters.Add (newCompiled);
1122 method.Statements.Add (invoke);
1126 void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
1128 if (cr.Code == null || cr.Code.Trim () == "")
1132 CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
1133 parent.renderMethod.Statements.Add (code);
1137 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
1138 expr.Method = new CodeMethodReferenceExpression (
1139 new CodeArgumentReferenceExpression ("__output"),
1142 expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
1143 parent.renderMethod.Statements.Add (expr);
1146 static Type GetContainerType (ControlBuilder builder)
1148 TemplateBuilder tb = builder as TemplateBuilder;
1149 if (tb != null && tb.ContainerType != null)
1150 return tb.ContainerType;
1152 return builder.BindingContainerType;
1154 Type type = builder.BindingContainerType;
1156 PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
1160 Type ptype = prop.PropertyType;
1161 if (!typeof (ICollection).IsAssignableFrom (ptype))
1164 prop = ptype.GetProperty ("Item", noCaseFlags & ~BindingFlags.NonPublic);
1168 return prop.PropertyType;
1172 CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
1174 CodeMemberMethod method = new CodeMemberMethod ();
1175 method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1177 method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
1178 method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));
1180 CodeTypeReference containerRef = new CodeTypeReference (container);
1181 CodeTypeReference targetRef = new CodeTypeReference (target);
1183 CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement();
1184 decl.Name = "Container";
1185 decl.Type = containerRef;
1186 method.Statements.Add (decl);
1188 decl = new CodeVariableDeclarationStatement();
1189 decl.Name = "target";
1190 decl.Type = targetRef;
1191 method.Statements.Add (decl);
1193 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1194 CodeAssignStatement assign = new CodeAssignStatement ();
1195 assign.Left = targetExpr;
1196 assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
1197 method.Statements.Add (assign);
1199 assign = new CodeAssignStatement ();
1200 assign.Left = new CodeVariableReferenceExpression ("Container");
1201 assign.Right = new CodeCastExpression (containerRef,
1202 new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
1203 method.Statements.Add (assign);
1208 void AddDataBindingLiteral (ControlBuilder builder, DataBindingBuilder db)
1210 if (db.Code == null || db.Code.Trim () == "")
1214 CreateField (db, false);
1216 string dbMethodName = "__DataBind_" + db.ID;
1217 // Add the method that builds the DataBoundLiteralControl
1218 InitMethod (db, false, false);
1219 CodeMemberMethod method = db.method;
1220 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
1221 method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
1223 // Add the DataBind handler
1224 method = CreateDBMethod (dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
1226 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1227 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
1228 invoke.Method = new CodeMethodReferenceExpression (targetExpr, "SetDataBoundString");
1229 invoke.Parameters.Add (new CodePrimitiveExpression (0));
1231 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
1232 tostring.Method = new CodeMethodReferenceExpression (
1233 new CodeTypeReferenceExpression (typeof (Convert)),
1235 tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
1236 invoke.Parameters.Add (tostring);
1237 method.Statements.Add (invoke);
1239 mainClass.Members.Add (method);
1241 AddChildCall (builder, db);
1244 void FlushText (ControlBuilder builder, StringBuilder sb)
1246 if (sb.Length > 0) {
1247 AddLiteralSubObject (builder, sb.ToString ());
1252 protected void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
1255 bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
1256 if (!isTemplate && !inTemplate) {
1257 CreateField (builder, true);
1258 } else if (!isTemplate) {
1259 builder.ID = builder.GetNextID (null);
1260 CreateField (builder, false);
1263 InitMethod (builder, isTemplate, childrenAsProperties);
1264 if (!isTemplate || builder.GetType () == typeof (RootBuilder))
1265 CreateAssignStatementsFromAttributes (builder);
1267 if (builder.Children != null && builder.Children.Count > 0) {
1268 ArrayList templates = null;
1270 StringBuilder sb = new StringBuilder ();
1271 foreach (object b in builder.Children) {
1274 sb.Append ((string) b);
1278 FlushText (builder, sb);
1279 if (b is ObjectTagBuilder) {
1280 ProcessObjectTag ((ObjectTagBuilder) b);
1284 StringPropertyBuilder pb = b as StringPropertyBuilder;
1286 if (pb.Children != null && pb.Children.Count > 0) {
1287 StringBuilder asb = new StringBuilder ();
1288 foreach (string s in pb.Children)
1290 CodeMemberMethod method = builder.method;
1291 CodeAssignStatement assign = new CodeAssignStatement ();
1292 assign.Left = new CodePropertyReferenceExpression (ctrlVar, pb.PropertyName);
1293 assign.Right = new CodePrimitiveExpression (asb.ToString ());
1294 method.Statements.Add (assign);
1300 if (b is ContentBuilderInternal) {
1301 ContentBuilderInternal cb = (ContentBuilderInternal) b;
1302 CreateControlTree (cb, false, true);
1303 AddContentTemplateInvocation (cb, builder.method, cb.method.Name);
1308 if (b is TemplateBuilder) {
1309 if (templates == null)
1310 templates = new ArrayList ();
1316 if (b is CodeRenderBuilder) {
1317 AddCodeRender (builder, (CodeRenderBuilder) b);
1321 if (b is DataBindingBuilder) {
1322 AddDataBindingLiteral (builder, (DataBindingBuilder) b);
1326 if (b is ControlBuilder) {
1327 ControlBuilder child = (ControlBuilder) b;
1328 CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
1329 AddChildCall (builder, child);
1333 throw new Exception ("???");
1336 FlushText (builder, sb);
1338 if (templates != null) {
1339 foreach (TemplateBuilder b in templates) {
1340 CreateControlTree (b, true, false);
1342 if (b.BindingDirection == BindingDirection.TwoWay) {
1343 string extractMethod = CreateExtractValuesMethod (b);
1344 AddBindableTemplateInvocation (builder.method, b.TagName, b.method.Name, extractMethod);
1348 AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
1354 if (builder.defaultPropertyBuilder != null) {
1355 ControlBuilder b = builder.defaultPropertyBuilder;
1356 CreateControlTree (b, false, true);
1357 AddChildCall (builder, b);
1360 if (builder.HasAspCode) {
1361 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1362 m.TargetObject = thisRef;
1363 m.MethodName = builder.renderMethod.Name;
1365 CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
1366 create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
1367 create.TargetObject = thisRef;
1368 create.MethodName = builder.renderMethod.Name;
1370 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
1371 invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
1372 invoke.Parameters.Add (create);
1374 builder.methodStatements.Add (invoke);
1377 if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
1378 builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
1381 if (builder is RootBuilder)
1382 if (!String.IsNullOrEmpty (parser.MetaResourceKey))
1383 AssignPropertiesFromResources (builder.method, parser.BaseType, parser.MetaResourceKey);
1387 protected internal override void CreateMethods ()
1389 base.CreateMethods ();
1391 CreateProperties ();
1392 CreateControlTree (parser.RootBuilder, false, false);
1393 CreateFrameworkInitializeMethod ();
1396 void CallBaseFrameworkInitialize (CodeMemberMethod method)
1398 CodeBaseReferenceExpression baseRef = new CodeBaseReferenceExpression ();
1399 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (baseRef, "FrameworkInitialize");
1400 method.Statements.Add (invoke);
1403 void CreateFrameworkInitializeMethod ()
1405 CodeMemberMethod method = new CodeMemberMethod ();
1406 method.Name = "FrameworkInitialize";
1407 method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1408 PrependStatementsToFrameworkInitialize (method);
1409 CallBaseFrameworkInitialize (method);
1410 AppendStatementsToFrameworkInitialize (method);
1411 mainClass.Members.Add (method);
1414 protected virtual void PrependStatementsToFrameworkInitialize (CodeMemberMethod method)
1418 protected virtual void AppendStatementsToFrameworkInitialize (CodeMemberMethod method)
1420 if (!parser.EnableViewState) {
1421 CodeAssignStatement stmt = new CodeAssignStatement ();
1422 stmt.Left = new CodePropertyReferenceExpression (thisRef, "EnableViewState");
1423 stmt.Right = new CodePrimitiveExpression (false);
1424 method.Statements.Add (stmt);
1427 CodeMethodReferenceExpression methodExpr;
1428 methodExpr = new CodeMethodReferenceExpression (thisRef, "__BuildControlTree");
1429 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr, thisRef);
1430 method.Statements.Add (new CodeExpressionStatement (expr));
1433 protected override void AddApplicationAndSessionObjects ()
1435 foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.ApplicationObjects) {
1436 CreateFieldForObject (tag.Type, tag.ObjectID);
1437 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, true, false);
1440 foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.SessionObjects) {
1441 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, false, false);
1445 protected void ProcessObjectTag (ObjectTagBuilder tag)
1447 string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
1448 CreatePropertyForObject (tag.Type, tag.ObjectID, fieldName, false);
1451 void CreateProperties ()
1453 if (!parser.AutoEventWireup) {
1454 CreateAutoEventWireup ();
1456 CreateAutoHandlers ();
1459 CreateApplicationInstance ();
1462 void CreateApplicationInstance ()
1464 CodeMemberProperty prop = new CodeMemberProperty ();
1465 Type appType = typeof (HttpApplication);
1466 prop.Type = new CodeTypeReference (appType);
1467 prop.Name = "ApplicationInstance";
1468 prop.Attributes = MemberAttributes.Family | MemberAttributes.Final;
1470 CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression (thisRef, "Context");
1472 propRef = new CodePropertyReferenceExpression (propRef, "ApplicationInstance");
1474 CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
1475 prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
1477 if (partialClass != null)
1478 partialClass.Members.Add (prop);
1481 mainClass.Members.Add (prop);
1484 void CreateAutoHandlers ()
1486 // Create AutoHandlers property
1487 CodeMemberProperty prop = new CodeMemberProperty ();
1488 prop.Type = new CodeTypeReference (typeof (int));
1489 prop.Name = "AutoHandlers";
1490 prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1492 CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
1493 CodeFieldReferenceExpression fldRef ;
1494 fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
1495 ret.Expression = fldRef;
1496 prop.GetStatements.Add (ret);
1497 prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
1500 CodeAttributeDeclaration attr = new CodeAttributeDeclaration ("System.Obsolete");
1501 prop.CustomAttributes.Add (attr);
1504 mainClass.Members.Add (prop);
1506 // Add the __autoHandlers field
1507 CodeMemberField fld = new CodeMemberField (typeof (int), "__autoHandlers");
1508 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
1509 mainClass.Members.Add (fld);
1512 void CreateAutoEventWireup ()
1514 // The getter returns false
1515 CodeMemberProperty prop = new CodeMemberProperty ();
1516 prop.Type = new CodeTypeReference (typeof (bool));
1517 prop.Name = "SupportAutoEvents";
1518 prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1519 prop.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
1520 mainClass.Members.Add (prop);
1524 protected virtual string HandleUrlProperty (string str, MemberInfo member)
1530 CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
1533 bool wasNullable = false;
1535 if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
1536 Type[] types = type.GetGenericArguments();
1537 type = types[0]; // we're interested only in the first type here
1542 if (type == typeof (string)) {
1544 object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
1545 if (urlAttr.Length != 0)
1546 str = HandleUrlProperty (str, member);
1548 return new CodePrimitiveExpression (str);
1551 if (type == typeof (bool)) {
1552 if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
1553 return new CodePrimitiveExpression (true);
1554 else if (InvariantCompareNoCase (str, "false"))
1555 return new CodePrimitiveExpression (false);
1557 else if (wasNullable && InvariantCompareNoCase(str, "null"))
1558 return new CodePrimitiveExpression (null);
1561 throw new ParseException (currentLocation,
1562 "Value '" + str + "' is not a valid boolean.");
1566 return new CodePrimitiveExpression (null);
1568 if (type.IsPrimitive)
1569 return new CodePrimitiveExpression (Convert.ChangeType (str, type, CultureInfo.InvariantCulture));
1571 if (type == typeof (string [])) {
1572 string [] subs = str.Split (',');
1573 CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
1574 expr.CreateType = new CodeTypeReference (typeof (string));
1575 foreach (string v in subs) {
1576 expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
1582 if (type == typeof (Color)){
1583 if (colorConverter == null)
1584 colorConverter = TypeDescriptor.GetConverter (typeof (Color));
1586 if (str.Trim().Length == 0) {
1587 CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
1588 return new CodeFieldReferenceExpression (ft, "Empty");
1593 if (str.IndexOf (',') == -1) {
1594 c = (Color) colorConverter.ConvertFromString (str);
1596 int [] argb = new int [4];
1599 string [] parts = str.Split (',');
1600 int length = parts.Length;
1602 throw new Exception ();
1604 int basei = (length == 4) ? 0 : 1;
1605 for (int i = length - 1; i >= 0; i--) {
1606 argb [basei + i] = (int) Byte.Parse (parts [i]);
1608 c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
1610 } catch (Exception e){
1611 // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
1612 // TypeConverter for Color fails to ConvertFromString.
1613 // Hence this hack...
1614 if (InvariantCompareNoCase ("LightGrey", str)) {
1615 c = Color.LightGray;
1617 throw new ParseException (currentLocation,
1618 "Color " + str + " is not a valid color.", e);
1622 if (c.IsKnownColor){
1623 CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
1624 if (c.IsSystemColor)
1625 type = typeof (SystemColors);
1627 expr.TargetObject = new CodeTypeReferenceExpression (type);
1628 expr.FieldName = c.Name;
1631 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1632 m.TargetObject = new CodeTypeReferenceExpression (type);
1633 m.MethodName = "FromArgb";
1634 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
1635 invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
1636 invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
1637 invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
1638 invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
1643 TypeConverter converter = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
1645 if (converter != null && converter.CanConvertFrom (typeof (string))) {
1646 object value = converter.ConvertFromInvariantString (str);
1648 if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
1649 InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
1650 return GenerateInstance (idesc, true);
1653 CodeExpression exp = GenerateObjectInstance (value, false);
1654 if (exp != null) return exp;
1656 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1657 m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
1658 m.MethodName = "GetConverter";
1659 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
1660 CodeTypeReference tref = new CodeTypeReference (type);
1661 invoke.Parameters.Add (new CodeTypeOfExpression (tref));
1663 invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
1664 invoke.Parameters.Add (new CodePrimitiveExpression (str));
1666 return new CodeCastExpression (tref, invoke);
1669 Console.WriteLine ("Unknown type: " + type + " value: " + str);
1671 return new CodePrimitiveExpression (str);
1674 CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
1676 CodeExpression[] parameters = new CodeExpression [idesc.Arguments.Count];
1678 foreach (object ob in idesc.Arguments) {
1679 CodeExpression exp = GenerateObjectInstance (ob, throwOnError);
1680 if (exp == null) return null;
1681 parameters [n++] = exp;
1684 switch (idesc.MemberInfo.MemberType) {
1685 case MemberTypes.Constructor:
1686 CodeTypeReference tob = new CodeTypeReference (idesc.MemberInfo.DeclaringType);
1687 return new CodeObjectCreateExpression (tob, parameters);
1689 case MemberTypes.Method:
1690 CodeTypeReferenceExpression mt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
1691 return new CodeMethodInvokeExpression (mt, idesc.MemberInfo.Name, parameters);
1693 case MemberTypes.Field:
1694 CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
1695 return new CodeFieldReferenceExpression (ft, idesc.MemberInfo.Name);
1697 case MemberTypes.Property:
1698 CodeTypeReferenceExpression pt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
1699 return new CodePropertyReferenceExpression (pt, idesc.MemberInfo.Name);
1701 throw new ParseException (currentLocation, "Invalid instance type.");
1704 CodeExpression GenerateObjectInstance (object value, bool throwOnError)
1707 return new CodePrimitiveExpression (null);
1709 Type t = value.GetType();
1710 if (t.IsPrimitive || value is string)
1711 return new CodePrimitiveExpression (value);
1714 Array ar = (Array) value;
1715 CodeExpression[] items = new CodeExpression [ar.Length];
1716 for (int n=0; n<ar.Length; n++) {
1717 CodeExpression exp = GenerateObjectInstance (ar.GetValue (n), throwOnError);
1718 if (exp == null) return null;
1721 return new CodeArrayCreateExpression (new CodeTypeReference (t), items);
1724 TypeConverter converter = TypeDescriptor.GetConverter (t);
1725 if (converter != null && converter.CanConvertTo (typeof (InstanceDescriptor))) {
1726 InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
1727 return GenerateInstance (idesc, throwOnError);
1730 InstanceDescriptor desc = GetDefaultInstanceDescriptor (value);
1731 if (desc != null) return GenerateInstance (desc, throwOnError);
1734 throw new ParseException (currentLocation, "Cannot generate an instance for the type: " + t);
1739 InstanceDescriptor GetDefaultInstanceDescriptor (object value)
1741 if (value is System.Web.UI.WebControls.Unit) {
1742 System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
1743 ConstructorInfo c = typeof(System.Web.UI.WebControls.Unit).GetConstructor (
1744 BindingFlags.Instance | BindingFlags.Public,
1746 new Type[] {typeof(double), typeof(System.Web.UI.WebControls.UnitType)},
1749 return new InstanceDescriptor (c, new object[] {s.Value, s.Type});
1752 if (value is System.Web.UI.WebControls.FontUnit) {
1753 System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
1755 Type cParamType = null;
1756 object cParam = null;
1759 case FontSize.AsUnit:
1760 case FontSize.NotSet:
1761 cParamType = typeof (System.Web.UI.WebControls.Unit);
1766 cParamType = typeof (string);
1767 cParam = s.Type.ToString ();
1771 ConstructorInfo c = typeof(System.Web.UI.WebControls.FontUnit).GetConstructor (
1772 BindingFlags.Instance | BindingFlags.Public,
1774 new Type[] {cParamType},
1777 return new InstanceDescriptor (c, new object[] {cParam});