2 // System.Web.Compilation.TemplateControlCompiler
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Marek Habersack (mhabersack@novell.com)
8 // (C) 2003 Ximian, Inc (http://www.ximian.com)
9 // (C) 2004-2008 Novell, Inc (http://novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Collections
;
34 using System
.ComponentModel
;
35 using System
.Configuration
;
36 using System
.Collections
.Specialized
;
37 using System
.Collections
.Generic
;
39 using System
.Globalization
;
40 using System
.Reflection
;
41 using System
.Resources
;
44 using System
.Web
.Caching
;
45 using System
.Web
.Configuration
;
47 using System
.Web
.UI
.WebControls
;
48 using System
.Web
.Util
;
49 using System
.ComponentModel
.Design
.Serialization
;
50 using System
.Text
.RegularExpressions
;
52 namespace System
.Web
.Compilation
54 class TemplateControlCompiler
: BaseCompiler
56 static BindingFlags noCaseFlags
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
57 BindingFlags
.Instance
| BindingFlags
.IgnoreCase
;
58 static Type monoTypeType
= Type
.GetType ("System.MonoType");
60 TemplateControlParser parser
;
62 internal ILocation currentLocation
;
64 static TypeConverter colorConverter
;
66 internal static CodeVariableReferenceExpression ctrlVar
= new CodeVariableReferenceExpression ("__ctrl");
68 List
<string> masterPageContentPlaceHolders
;
69 static Regex startsWithBindRegex
= new Regex (@"^Bind\s*\(", RegexOptions
.Compiled
| RegexOptions
.IgnoreCase
);
70 // When modifying those, make sure to look at the SanitizeBindCall to make sure it
71 // picks up correct groups.
72 static Regex bindRegex
= new Regex (@"Bind\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)\s*%>", RegexOptions
.Compiled
| RegexOptions
.IgnoreCase
);
73 static Regex bindRegexInValue
= new Regex (@"Bind\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)\s*$", RegexOptions
.Compiled
| RegexOptions
.IgnoreCase
);
74 static Regex evalRegexInValue
= new Regex (@"(.*)Eval\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)(.*)", RegexOptions
.Compiled
| RegexOptions
.IgnoreCase
);
76 List
<string> MasterPageContentPlaceHolders
{
78 if (masterPageContentPlaceHolders
== null)
79 masterPageContentPlaceHolders
= new List
<string> ();
80 return masterPageContentPlaceHolders
;
84 public TemplateControlCompiler (TemplateControlParser parser
)
90 protected void EnsureID (ControlBuilder builder
)
92 string id
= builder
.ID
;
93 if (id
== null || id
.Trim () == String
.Empty
)
94 builder
.ID
= builder
.GetNextID (null);
97 void CreateField (ControlBuilder builder
, bool check
)
99 if (builder
== null || builder
.ID
== null || builder
.ControlType
== null)
102 if (partialNameOverride
[builder
.ID
] != null)
105 MemberAttributes ma
= MemberAttributes
.Family
;
106 currentLocation
= builder
.Location
;
107 if (check
&& CheckBaseFieldOrProperty (builder
.ID
, builder
.ControlType
, ref ma
))
108 return; // The field or property already exists in a base class and is accesible.
110 CodeMemberField field
;
111 field
= new CodeMemberField (builder
.ControlType
.FullName
, builder
.ID
);
112 field
.Attributes
= ma
;
113 field
.Type
.Options
|= CodeTypeReferenceOptions
.GlobalReference
;
115 if (partialClass
!= null)
116 partialClass
.Members
.Add (AddLinePragma (field
, builder
));
118 mainClass
.Members
.Add (AddLinePragma (field
, builder
));
121 bool CheckBaseFieldOrProperty (string id
, Type type
, ref MemberAttributes ma
)
123 FieldInfo fld
= parser
.BaseType
.GetField (id
, noCaseFlags
);
126 if (fld
== null || fld
.IsPrivate
) {
127 PropertyInfo prop
= parser
.BaseType
.GetProperty (id
, noCaseFlags
);
129 MethodInfo setm
= prop
.GetSetMethod (true);
131 other
= prop
.PropertyType
;
134 other
= fld
.FieldType
;
140 if (!other
.IsAssignableFrom (type
)) {
141 ma
|= MemberAttributes
.New
;
148 void AddParsedSubObjectStmt (ControlBuilder builder
, CodeExpression expr
)
150 if (!builder
.HaveParserVariable
) {
151 CodeVariableDeclarationStatement p
= new CodeVariableDeclarationStatement();
153 p
.Type
= new CodeTypeReference (typeof (IParserAccessor
));
154 p
.InitExpression
= new CodeCastExpression (typeof (IParserAccessor
), ctrlVar
);
155 builder
.MethodStatements
.Add (p
);
156 builder
.HaveParserVariable
= true;
159 CodeVariableReferenceExpression
var = new CodeVariableReferenceExpression ("__parser");
160 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (var, "AddParsedSubObject");
161 invoke
.Parameters
.Add (expr
);
162 builder
.MethodStatements
.Add (AddLinePragma (invoke
, builder
));
165 CodeStatement
CreateControlVariable (Type type
, ControlBuilder builder
, CodeMemberMethod method
, CodeTypeReference ctrlTypeRef
)
167 CodeObjectCreateExpression newExpr
= new CodeObjectCreateExpression (ctrlTypeRef
);
169 object [] atts
= type
!= null ? type
.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute
), true) : null;
170 if (atts
!= null && atts
.Length
> 0) {
171 ConstructorNeedsTagAttribute att
= (ConstructorNeedsTagAttribute
) atts
[0];
173 newExpr
.Parameters
.Add (new CodePrimitiveExpression (builder
.TagName
));
174 } else if (builder
is DataBindingBuilder
) {
175 newExpr
.Parameters
.Add (new CodePrimitiveExpression (0));
176 newExpr
.Parameters
.Add (new CodePrimitiveExpression (1));
179 method
.Statements
.Add (new CodeVariableDeclarationStatement (ctrlTypeRef
, "__ctrl"));
180 CodeAssignStatement assign
= new CodeAssignStatement ();
181 assign
.Left
= ctrlVar
;
182 assign
.Right
= newExpr
;
187 void InitMethod (ControlBuilder builder
, bool isTemplate
, bool childrenAsProperties
)
189 currentLocation
= builder
.Location
;
190 bool inBuildControlTree
= builder
is RootBuilder
;
191 string tailname
= (inBuildControlTree
? "Tree" : ("_" + builder
.ID
));
192 // bool isProperty = builder.IsProperty;
193 CodeMemberMethod method
= new CodeMemberMethod ();
194 builder
.Method
= method
;
195 builder
.MethodStatements
= method
.Statements
;
197 method
.Name
= "__BuildControl" + tailname
;
198 method
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Final
;
199 Type type
= builder
.ControlType
;
201 /* in the case this is the __BuildControlTree
202 * method, allow subclasses to insert control
204 if (inBuildControlTree
) {
205 SetCustomAttributes (method
);
206 AddStatementsToInitMethodTop (builder
, method
);
209 if (builder
.HasAspCode
) {
210 CodeMemberMethod renderMethod
= new CodeMemberMethod ();
211 builder
.RenderMethod
= renderMethod
;
212 renderMethod
.Name
= "__Render" + tailname
;
213 renderMethod
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Final
;
214 CodeParameterDeclarationExpression arg1
= new CodeParameterDeclarationExpression ();
215 arg1
.Type
= new CodeTypeReference (typeof (HtmlTextWriter
));
216 arg1
.Name
= "__output";
217 CodeParameterDeclarationExpression arg2
= new CodeParameterDeclarationExpression ();
218 arg2
.Type
= new CodeTypeReference (typeof (Control
));
219 arg2
.Name
= "parameterContainer";
220 renderMethod
.Parameters
.Add (arg1
);
221 renderMethod
.Parameters
.Add (arg2
);
222 mainClass
.Members
.Add (renderMethod
);
225 if (childrenAsProperties
|| type
== null) {
227 bool isGlobal
= true;
230 if (builder
is RootBuilder
) {
231 typeString
= parser
.ClassName
;
233 returnsControl
= false;
235 returnsControl
= builder
.PropertyBuilderShouldReturnValue
;
236 if (type
!= null && builder
.IsProperty
&& !typeof (ITemplate
).IsAssignableFrom (type
)) {
237 typeString
= type
.FullName
;
238 isGlobal
= !type
.IsPrimitive
;
240 typeString
= "System.Web.UI.Control";
241 ProcessTemplateChildren (builder
);
243 CodeTypeReference ctrlTypeRef
= new CodeTypeReference (typeString
);
245 ctrlTypeRef
.Options
|= CodeTypeReferenceOptions
.GlobalReference
;
247 if (returnsControl
) {
248 method
.ReturnType
= ctrlTypeRef
;
250 // $controlType _ctrl = new $controlType ($parameters);
252 method
.Statements
.Add (CreateControlVariable (type
, builder
, method
, ctrlTypeRef
));
254 method
.Parameters
.Add (new CodeParameterDeclarationExpression (typeString
, "__ctrl"));
256 CodeTypeReference ctrlTypeRef
= new CodeTypeReference (type
.FullName
);
257 if (!type
.IsPrimitive
)
258 ctrlTypeRef
.Options
|= CodeTypeReferenceOptions
.GlobalReference
;
260 if (typeof (Control
).IsAssignableFrom (type
))
261 method
.ReturnType
= ctrlTypeRef
;
263 // $controlType _ctrl = new $controlType ($parameters);
265 method
.Statements
.Add (AddLinePragma (CreateControlVariable (type
, builder
, method
, ctrlTypeRef
), builder
));
267 // this.$builderID = _ctrl;
269 CodeFieldReferenceExpression builderID
= new CodeFieldReferenceExpression ();
270 builderID
.TargetObject
= thisRef
;
271 builderID
.FieldName
= builder
.ID
;
272 CodeAssignStatement assign
= new CodeAssignStatement ();
273 assign
.Left
= builderID
;
274 assign
.Right
= ctrlVar
;
275 method
.Statements
.Add (AddLinePragma (assign
, builder
));
277 if (typeof (UserControl
).IsAssignableFrom (type
)) {
278 CodeMethodReferenceExpression mref
= new CodeMethodReferenceExpression ();
279 mref
.TargetObject
= builderID
;
280 mref
.MethodName
= "InitializeAsUserControl";
281 CodeMethodInvokeExpression initAsControl
= new CodeMethodInvokeExpression (mref
);
282 initAsControl
.Parameters
.Add (new CodePropertyReferenceExpression (thisRef
, "Page"));
283 method
.Statements
.Add (initAsControl
);
286 if (builder
.ParentTemplateBuilder
is System
.Web
.UI
.WebControls
.ContentBuilderInternal
) {
290 pi
= type
.GetProperty ("TemplateControl");
291 } catch (Exception
) {
295 if (pi
!= null && pi
.CanWrite
) {
296 // __ctrl.TemplateControl = this;
297 assign
= new CodeAssignStatement ();
298 assign
.Left
= new CodePropertyReferenceExpression (ctrlVar
, "TemplateControl");;
299 assign
.Right
= thisRef
;
300 method
.Statements
.Add (assign
);
304 // _ctrl.SkinID = $value
305 // _ctrl.ApplyStyleSheetSkin (this);
307 // the SkinID assignment needs to come
308 // before the call to
309 // ApplyStyleSheetSkin, for obvious
310 // reasons. We skip SkinID in
311 // CreateAssignStatementsFromAttributes
314 string skinid
= builder
.GetAttribute ("skinid");
315 if (!String
.IsNullOrEmpty (skinid
))
316 CreateAssignStatementFromAttribute (builder
, "skinid");
318 if (typeof (WebControl
).IsAssignableFrom (type
)) {
319 CodeMethodInvokeExpression applyStyleSheetSkin
= new CodeMethodInvokeExpression (ctrlVar
, "ApplyStyleSheetSkin");
320 if (typeof (Page
).IsAssignableFrom (parser
.BaseType
))
321 applyStyleSheetSkin
.Parameters
.Add (thisRef
);
323 applyStyleSheetSkin
.Parameters
.Add (new CodePropertyReferenceExpression (thisRef
, "Page"));
324 method
.Statements
.Add (applyStyleSheetSkin
);
327 // Process template children before anything else
328 ProcessTemplateChildren (builder
);
330 // process ID here. It should be set before any other attributes are
331 // assigned, since the control code may rely on ID being set. We
332 // skip ID in CreateAssignStatementsFromAttributes
333 string ctl_id
= builder
.GetAttribute ("id");
334 if (ctl_id
!= null && ctl_id
.Length
!= 0)
335 CreateAssignStatementFromAttribute (builder
, "id");
337 if (typeof (ContentPlaceHolder
).IsAssignableFrom (type
)) {
338 List
<string> placeHolderIds
= MasterPageContentPlaceHolders
;
339 string cphID
= builder
.ID
;
341 if (!placeHolderIds
.Contains (cphID
))
342 placeHolderIds
.Add (cphID
);
344 CodeConditionStatement condStatement
;
346 // Add the __Template_* field
347 string templateField
= "__Template_" + cphID
;
348 CodeMemberField fld
= new CodeMemberField (typeof (ITemplate
), templateField
);
349 fld
.Attributes
= MemberAttributes
.Private
;
350 mainClass
.Members
.Add (fld
);
352 CodeFieldReferenceExpression templateID
= new CodeFieldReferenceExpression ();
353 templateID
.TargetObject
= thisRef
;
354 templateID
.FieldName
= templateField
;
356 CreateContentPlaceHolderTemplateProperty (templateField
, "Template_" + cphID
);
358 // if ((this.ContentTemplates != null)) {
359 // this.__Template_$builder.ID = ((System.Web.UI.ITemplate)(this.ContentTemplates["$builder.ID"]));
362 CodeFieldReferenceExpression contentTemplates
= new CodeFieldReferenceExpression ();
363 contentTemplates
.TargetObject
= thisRef
;
364 contentTemplates
.FieldName
= "ContentTemplates";
366 CodeIndexerExpression indexer
= new CodeIndexerExpression ();
367 indexer
.TargetObject
= new CodePropertyReferenceExpression (thisRef
, "ContentTemplates");
368 indexer
.Indices
.Add (new CodePrimitiveExpression (cphID
));
370 assign
= new CodeAssignStatement ();
371 assign
.Left
= templateID
;
372 assign
.Right
= new CodeCastExpression (new CodeTypeReference (typeof (ITemplate
)), indexer
);
374 condStatement
= new CodeConditionStatement (new CodeBinaryOperatorExpression (contentTemplates
,
375 CodeBinaryOperatorType
.IdentityInequality
,
376 new CodePrimitiveExpression (null)),
379 method
.Statements
.Add (condStatement
);
381 // if ((this.__Template_mainContent != null)) {
382 // this.__Template_mainContent.InstantiateIn(__ctrl);
384 // and also set things up such that any additional code ends up in:
389 CodeMethodReferenceExpression methodRef
= new CodeMethodReferenceExpression ();
390 methodRef
.TargetObject
= templateID
;
391 methodRef
.MethodName
= "InstantiateIn";
393 CodeMethodInvokeExpression instantiateInInvoke
;
394 instantiateInInvoke
= new CodeMethodInvokeExpression (methodRef
, ctrlVar
);
396 condStatement
= new CodeConditionStatement (new CodeBinaryOperatorExpression (templateID
,
397 CodeBinaryOperatorType
.IdentityInequality
,
398 new CodePrimitiveExpression (null)),
399 new CodeExpressionStatement (instantiateInInvoke
));
400 method
.Statements
.Add (condStatement
);
402 // this is the bit that causes the following stuff to end up in the else { }
403 builder
.MethodStatements
= condStatement
.FalseStatements
;
407 if (inBuildControlTree
)
408 AddStatementsToInitMethodBottom (builder
, method
);
410 mainClass
.Members
.Add (method
);
413 void ProcessTemplateChildren (ControlBuilder builder
)
415 ArrayList templates
= builder
.TemplateChildren
;
416 if (templates
!= null && templates
.Count
> 0) {
417 foreach (TemplateBuilder tb
in templates
) {
418 CreateControlTree (tb
, true, false);
419 if (tb
.BindingDirection
== BindingDirection
.TwoWay
) {
420 string extractMethod
= CreateExtractValuesMethod (tb
);
421 AddBindableTemplateInvocation (builder
, tb
.TagName
, tb
.Method
.Name
, extractMethod
);
423 AddTemplateInvocation (builder
, tb
.TagName
, tb
.Method
.Name
);
428 void SetCustomAttribute (CodeMemberMethod method
, UnknownAttributeDescriptor uad
)
430 CodeAssignStatement assign
= new CodeAssignStatement ();
431 assign
.Left
= new CodePropertyReferenceExpression (
432 new CodeArgumentReferenceExpression("__ctrl"),
434 assign
.Right
= GetExpressionFromString (uad
.Value
.GetType (), uad
.Value
.ToString (), uad
.Info
);
436 method
.Statements
.Add (assign
);
439 void SetCustomAttributes (CodeMemberMethod method
)
441 Type baseType
= parser
.BaseType
;
442 if (baseType
== null)
445 List
<UnknownAttributeDescriptor
> attrs
= parser
.UnknownMainAttributes
;
446 if (attrs
== null || attrs
.Count
== 0)
449 foreach (UnknownAttributeDescriptor uad
in attrs
)
450 SetCustomAttribute (method
, uad
);
453 protected virtual void AddStatementsToInitMethodTop (ControlBuilder builder
, CodeMemberMethod method
)
455 ClientIDMode
? mode
= parser
.ClientIDMode
;
457 var cimRef
= new CodeTypeReferenceExpression (typeof (ClientIDMode
));
458 cimRef
.Type
.Options
= CodeTypeReferenceOptions
.GlobalReference
;
460 var assign
= new CodeAssignStatement ();
461 assign
.Left
= new CodePropertyReferenceExpression (thisRef
, "ClientIDMode");
462 assign
.Right
= new CodeFieldReferenceExpression (cimRef
, mode
.Value
.ToString ());
464 method
.Statements
.Add (assign
);
468 protected virtual void AddStatementsToInitMethodBottom (ControlBuilder builder
, CodeMemberMethod method
)
472 void AddLiteralSubObject (ControlBuilder builder
, string str
)
474 if (!builder
.HasAspCode
) {
475 CodeObjectCreateExpression expr
;
476 expr
= new CodeObjectCreateExpression (typeof (LiteralControl
), new CodePrimitiveExpression (str
));
477 AddParsedSubObjectStmt (builder
, expr
);
479 CodeMethodReferenceExpression methodRef
= new CodeMethodReferenceExpression ();
480 methodRef
.TargetObject
= new CodeArgumentReferenceExpression ("__output");
481 methodRef
.MethodName
= "Write";
483 CodeMethodInvokeExpression expr
;
484 expr
= new CodeMethodInvokeExpression (methodRef
, new CodePrimitiveExpression (str
));
485 builder
.RenderMethod
.Statements
.Add (expr
);
489 string TrimDB (string value, bool trimTail
)
491 string str
= value.Trim ();
492 int len
= str
.Length
;
493 int idx
= str
.IndexOf ('#', 2) + 1;
499 return str
.Substring (idx
, len
- idx
).Trim ();
502 CodeExpression
CreateEvalInvokeExpression (Regex regex
, string value, bool isBind
)
504 Match match
= regex
.Match (value);
505 if (!match
.Success
) {
507 throw new HttpParseException ("Bind invocation wasn't formatted properly.");
511 string sanitizedSnippet
;
513 sanitizedSnippet
= SanitizeBindCall (match
);
515 sanitizedSnippet
= value;
517 return new CodeSnippetExpression (sanitizedSnippet
);
520 string SanitizeBindCall (Match match
)
522 GroupCollection groups
= match
.Groups
;
523 StringBuilder sb
= new StringBuilder ("Eval(\"" + groups
[1] + "\"");
524 Group second
= groups
[4];
525 if (second
!= null) {
526 string v
= second
.Value
;
527 if (v
!= null && v
.Length
> 0)
528 sb
.Append (",\"" + second
+ "\"");
532 return sb
.ToString ();
535 string DataBoundProperty (ControlBuilder builder
, Type type
, string varName
, string value)
537 value = TrimDB (value, true);
538 CodeMemberMethod method
;
539 string dbMethodName
= builder
.Method
.Name
+ "_DB_" + dataBoundAtts
++;
540 CodeExpression valueExpression
= null;
541 value = value.Trim ();
543 bool need_if
= false;
544 if (startsWithBindRegex
.Match (value).Success
) {
545 valueExpression
= CreateEvalInvokeExpression (bindRegexInValue
, value, true);
546 if (valueExpression
!= null)
549 if (StrUtils
.StartsWith (value, "Eval", true))
550 valueExpression
= CreateEvalInvokeExpression (evalRegexInValue
, value, false);
552 if (valueExpression
== null)
553 valueExpression
= new CodeSnippetExpression (value);
555 method
= CreateDBMethod (builder
, dbMethodName
, GetContainerType (builder
), builder
.ControlType
);
556 CodeVariableReferenceExpression targetExpr
= new CodeVariableReferenceExpression ("target");
558 // This should be a CodePropertyReferenceExpression for properties... but it works anyway
559 CodeFieldReferenceExpression field
= new CodeFieldReferenceExpression (targetExpr
, varName
);
562 if (type
== typeof (string)) {
563 CodeMethodInvokeExpression tostring
= new CodeMethodInvokeExpression ();
564 CodeTypeReferenceExpression conv
= new CodeTypeReferenceExpression (typeof (Convert
));
565 tostring
.Method
= new CodeMethodReferenceExpression (conv
, "ToString");
566 tostring
.Parameters
.Add (valueExpression
);
569 expr
= new CodeCastExpression (type
, valueExpression
);
571 CodeAssignStatement assign
= new CodeAssignStatement (field
, expr
);
573 CodeExpression page
= new CodePropertyReferenceExpression (thisRef
, "Page");
574 CodeExpression left
= new CodeMethodInvokeExpression (page
, "GetDataItem");
575 CodeBinaryOperatorExpression ce
= new CodeBinaryOperatorExpression (left
, CodeBinaryOperatorType
.IdentityInequality
, new CodePrimitiveExpression (null));
576 CodeConditionStatement ccs
= new CodeConditionStatement (ce
, assign
);
577 method
.Statements
.Add (ccs
);
579 method
.Statements
.Add (assign
);
581 mainClass
.Members
.Add (method
);
585 void AddCodeForPropertyOrField (ControlBuilder builder
, Type type
, string var_name
, string att
, MemberInfo member
, bool isDataBound
, bool isExpression
)
587 CodeMemberMethod method
= builder
.Method
;
588 bool isWritable
= IsWritablePropertyOrField (member
);
590 if (isDataBound
&& isWritable
) {
591 string dbMethodName
= DataBoundProperty (builder
, type
, var_name
, att
);
592 AddEventAssign (method
, builder
, "DataBinding", typeof (EventHandler
), dbMethodName
);
594 } else if (isExpression
&& isWritable
) {
595 AddExpressionAssign (method
, builder
, member
, type
, var_name
, att
);
599 CodeAssignStatement assign
= new CodeAssignStatement ();
600 assign
.Left
= new CodePropertyReferenceExpression (ctrlVar
, var_name
);
601 currentLocation
= builder
.Location
;
602 assign
.Right
= GetExpressionFromString (type
, att
, member
);
604 method
.Statements
.Add (AddLinePragma (assign
, builder
));
607 void RegisterBindingInfo (ControlBuilder builder
, string propName
, ref string value)
609 string str
= TrimDB (value, false);
610 if (StrUtils
.StartsWith (str
, "Bind", true)) {
611 Match match
= bindRegex
.Match (str
);
613 string bindingName
= match
.Groups
[1].Value
;
614 TemplateBuilder templateBuilder
= builder
.ParentTemplateBuilder
;
616 if (templateBuilder
== null)
617 throw new HttpException ("Bind expression not allowed in this context.");
619 if (templateBuilder
.BindingDirection
== BindingDirection
.OneWay
)
622 string id
= builder
.GetAttribute ("ID");
623 if (String
.IsNullOrEmpty (id
))
624 throw new HttpException ("Control of type '" + builder
.ControlType
+ "' using two-way binding on property '" + propName
+ "' must have an ID.");
626 templateBuilder
.RegisterBoundProperty (builder
.ControlType
, propName
, id
, bindingName
);
632 static bool InvariantCompare (string a, string b)
634 return (0 == String.Compare (a, b, false, Helpers.InvariantCulture));
638 static bool InvariantCompareNoCase (string a
, string b
)
640 return (0 == String
.Compare (a
, b
, true, Helpers
.InvariantCulture
));
643 internal static MemberInfo
GetFieldOrProperty (Type type
, string name
)
645 MemberInfo member
= null;
647 member
= type
.GetProperty (name
, noCaseFlags
& ~BindingFlags
.NonPublic
);
654 member
= type
.GetField (name
, noCaseFlags
& ~BindingFlags
.NonPublic
);
660 static bool IsWritablePropertyOrField (MemberInfo member
)
662 PropertyInfo pi
= member
as PropertyInfo
;
664 return pi
.GetSetMethod (false) != null;
665 FieldInfo fi
= member
as FieldInfo
;
667 return !fi
.IsInitOnly
;
668 throw new ArgumentException ("Argument must be of PropertyInfo or FieldInfo type", "member");
671 bool ProcessPropertiesAndFields (ControlBuilder builder
, MemberInfo member
, string id
,
672 string attValue
, string prefix
)
674 int hyphen
= id
.IndexOf ('-');
675 bool isPropertyInfo
= (member
is PropertyInfo
);
676 bool isDataBound
= BaseParser
.IsDataBound (attValue
);
677 bool isExpression
= !isDataBound
&& BaseParser
.IsExpression (attValue
);
679 if (isPropertyInfo
) {
680 type
= ((PropertyInfo
) member
).PropertyType
;
682 type
= ((FieldInfo
) member
).FieldType
;
685 if (InvariantCompareNoCase (member
.Name
, id
)) {
687 RegisterBindingInfo (builder
, member
.Name
, ref attValue
);
689 if (!IsWritablePropertyOrField (member
))
692 AddCodeForPropertyOrField (builder
, type
, member
.Name
, attValue
, member
, isDataBound
, isExpression
);
699 string prop_field
= id
.Replace ('-', '.');
700 string [] parts
= prop_field
.Split (new char [] {'.'}
);
701 int length
= parts
.Length
;
703 if (length
< 2 || !InvariantCompareNoCase (member
.Name
, parts
[0]))
707 MemberInfo sub_member
= GetFieldOrProperty (type
, parts
[1]);
708 if (sub_member
== null)
711 string new_prefix
= prefix
+ member
.Name
+ ".";
712 string new_id
= id
.Substring (hyphen
+ 1);
713 return ProcessPropertiesAndFields (builder
, sub_member
, new_id
, attValue
, new_prefix
);
716 MemberInfo subpf
= GetFieldOrProperty (type
, parts
[1]);
717 if (!(subpf
is PropertyInfo
))
720 PropertyInfo subprop
= (PropertyInfo
) subpf
;
721 if (subprop
.CanWrite
== false)
724 bool is_bool
= (subprop
.PropertyType
== typeof (bool));
725 if (!is_bool
&& attValue
== null)
726 return false; // Font-Size -> Font-Size="" as html
728 string val
= attValue
;
729 if (attValue
== null && is_bool
)
730 val
= "true"; // Font-Bold <=> Font-Bold="true"
733 RegisterBindingInfo (builder
, prefix
+ member
.Name
+ "." + subprop
.Name
, ref attValue
);
735 AddCodeForPropertyOrField (builder
, subprop
.PropertyType
,
736 prefix
+ member
.Name
+ "." + subprop
.Name
,
737 val
, subprop
, isDataBound
, isExpression
);
742 internal CodeExpression
CompileExpression (MemberInfo member
, Type type
, string value, bool useSetAttribute
)
744 // First let's find the correct expression builder
745 value = value.Substring (3, value.Length
- 5).Trim ();
746 int colon
= value.IndexOf (':');
749 string prefix
= value.Substring (0, colon
).Trim ();
750 string expr
= value.Substring (colon
+ 1).Trim ();
752 CompilationSection cs
= (CompilationSection
)WebConfigurationManager
.GetWebApplicationSection ("system.web/compilation");
756 if (cs
.ExpressionBuilders
== null || cs
.ExpressionBuilders
.Count
== 0)
759 System
.Web
.Configuration
.ExpressionBuilder ceb
= cs
.ExpressionBuilders
[prefix
];
763 string builderType
= ceb
.Type
;
767 t
= HttpApplication
.LoadType (builderType
, true);
768 } catch (Exception e
) {
769 throw new HttpException (String
.Format ("Failed to load expression builder type `{0}'", builderType
), e
);
772 if (!typeof (System
.Web
.Compilation
.ExpressionBuilder
).IsAssignableFrom (t
))
773 throw new HttpException (String
.Format ("Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder", builderType
));
775 System
.Web
.Compilation
.ExpressionBuilder eb
= null;
777 ExpressionBuilderContext ctx
;
780 eb
= Activator
.CreateInstance (t
) as System
.Web
.Compilation
.ExpressionBuilder
;
781 ctx
= new ExpressionBuilderContext (HttpContext
.Current
.Request
.FilePath
);
782 parsedData
= eb
.ParseExpression (expr
, type
, ctx
);
783 } catch (Exception e
) {
784 throw new HttpException (String
.Format ("Failed to create an instance of type `{0}'", builderType
), e
);
787 BoundPropertyEntry bpe
= CreateBoundPropertyEntry (member
as PropertyInfo
, prefix
, expr
, useSetAttribute
);
788 return eb
.GetCodeExpression (bpe
, parsedData
, ctx
);
791 void AddExpressionAssign (CodeMemberMethod method
, ControlBuilder builder
, MemberInfo member
, Type type
, string name
, string value)
793 CodeExpression expr
= CompileExpression (member
, type
, value, false);
798 CodeAssignStatement assign
= new CodeAssignStatement ();
799 assign
.Left
= new CodePropertyReferenceExpression (ctrlVar
, name
);
801 TypeCode typeCode
= Type
.GetTypeCode (type
);
802 if (typeCode
!= TypeCode
.Empty
&& typeCode
!= TypeCode
.Object
&& typeCode
!= TypeCode
.DBNull
)
803 assign
.Right
= CreateConvertToCall (typeCode
, expr
);
805 assign
.Right
= new CodeCastExpression (type
, expr
);
807 builder
.Method
.Statements
.Add (AddLinePragma (assign
, builder
));
810 internal static CodeMethodInvokeExpression
CreateConvertToCall (TypeCode typeCode
, CodeExpression expr
)
812 var ret
= new CodeMethodInvokeExpression ();
816 case TypeCode
.Boolean
:
817 methodName
= "ToBoolean";
821 methodName
= "ToChar";
825 methodName
= "ToSByte";
829 methodName
= "ToByte";
833 methodName
= "ToInt16";
836 case TypeCode
.UInt16
:
837 methodName
= "ToUInt16";
841 methodName
= "ToInt32";
844 case TypeCode
.UInt32
:
845 methodName
= "ToUInt32";
849 methodName
= "ToInt64";
852 case TypeCode
.UInt64
:
853 methodName
= "ToUInt64";
856 case TypeCode
.Single
:
857 methodName
= "ToSingle";
860 case TypeCode
.Double
:
861 methodName
= "ToDouble";
864 case TypeCode
.Decimal
:
865 methodName
= "ToDecimal";
868 case TypeCode
.DateTime
:
869 methodName
= "ToDateTime";
872 case TypeCode
.String
:
873 methodName
= "ToString";
877 throw new InvalidOperationException (String
.Format ("Unsupported TypeCode '{0}'", typeCode
));
880 var typeRef
= new CodeTypeReferenceExpression (typeof (Convert
));
881 typeRef
.Type
.Options
= CodeTypeReferenceOptions
.GlobalReference
;
883 ret
.Method
= new CodeMethodReferenceExpression (typeRef
, methodName
);
884 ret
.Parameters
.Add (expr
);
885 ret
.Parameters
.Add (new CodePropertyReferenceExpression (new CodeTypeReferenceExpression (typeof (System
.Globalization
.CultureInfo
)), "CurrentCulture"));
890 BoundPropertyEntry
CreateBoundPropertyEntry (PropertyInfo pi
, string prefix
, string expr
, bool useSetAttribute
)
892 BoundPropertyEntry ret
= new BoundPropertyEntry ();
893 ret
.Expression
= expr
;
894 ret
.ExpressionPrefix
= prefix
;
895 ret
.Generated
= false;
898 ret
.PropertyInfo
= pi
;
899 ret
.Type
= pi
.PropertyType
;
901 ret
.UseSetAttribute
= useSetAttribute
;
906 bool ResourceProviderHasObject (string key
)
908 IResourceProvider rp
= HttpContext
.GetResourceProvider (InputVirtualPath
.Absolute
, true);
912 IResourceReader rr
= rp
.ResourceReader
;
917 IDictionaryEnumerator ide
= rr
.GetEnumerator ();
922 while (ide
.MoveNext ()) {
923 dictKey
= ide
.Key
as string;
924 if (String
.IsNullOrEmpty (dictKey
))
926 if (String
.Compare (key
, dictKey
, StringComparison
.Ordinal
) == 0)
936 void AssignPropertyFromResources (ControlBuilder builder
, MemberInfo mi
, string attvalue
)
938 bool isProperty
= mi
.MemberType
== MemberTypes
.Property
;
939 bool isField
= !isProperty
&& (mi
.MemberType
== MemberTypes
.Field
);
941 if (!isProperty
&& !isField
|| !IsWritablePropertyOrField (mi
))
944 object[] attrs
= mi
.GetCustomAttributes (typeof (LocalizableAttribute
), true);
945 if (attrs
!= null && attrs
.Length
> 0 && !((LocalizableAttribute
)attrs
[0]).IsLocalizable
)
948 string memberName
= mi
.Name
;
949 string resname
= String
.Concat (attvalue
, ".", memberName
);
951 if (!ResourceProviderHasObject (resname
))
954 // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
955 string inputFile
= parser
.InputFile
;
956 string physPath
= HttpContext
.Current
.Request
.PhysicalApplicationPath
;
958 if (StrUtils
.StartsWith (inputFile
, physPath
)) {
959 string appVirtualPath
= HttpRuntime
.AppDomainAppVirtualPath
;
960 inputFile
= parser
.InputFile
.Substring (physPath
.Length
- 1);
961 if (appVirtualPath
!= "/")
962 inputFile
= appVirtualPath
+ inputFile
;
966 char dsc
= System
.IO
.Path
.DirectorySeparatorChar
;
968 inputFile
= inputFile
.Replace (dsc
, '/');
970 object obj
= HttpContext
.GetLocalResourceObject (inputFile
, resname
);
974 if (!isProperty
&& !isField
)
975 return; // an "impossible" case
977 CodeAssignStatement assign
= new CodeAssignStatement ();
979 assign
.Left
= new CodePropertyReferenceExpression (ctrlVar
, memberName
);
980 assign
.Right
= ResourceExpressionBuilder
.CreateGetLocalResourceObject (mi
, resname
);
982 builder
.Method
.Statements
.Add (AddLinePragma (assign
, builder
));
985 void AssignPropertiesFromResources (ControlBuilder builder
, Type controlType
, string attvalue
)
987 // Process all public fields and properties of the control. We don't use GetMembers to make the code
989 FieldInfo
[] fields
= controlType
.GetFields (
990 BindingFlags
.Instance
| BindingFlags
.Static
|
991 BindingFlags
.Public
| BindingFlags
.FlattenHierarchy
);
992 PropertyInfo
[] properties
= controlType
.GetProperties (
993 BindingFlags
.Instance
| BindingFlags
.Static
|
994 BindingFlags
.Public
| BindingFlags
.FlattenHierarchy
);
996 foreach (FieldInfo fi
in fields
)
997 AssignPropertyFromResources (builder
, fi
, attvalue
);
998 foreach (PropertyInfo pi
in properties
)
999 AssignPropertyFromResources (builder
, pi
, attvalue
);
1002 void AssignPropertiesFromResources (ControlBuilder builder
, string attvalue
)
1004 if (attvalue
== null || attvalue
.Length
== 0)
1007 Type controlType
= builder
.ControlType
;
1008 if (controlType
== null)
1011 AssignPropertiesFromResources (builder
, controlType
, attvalue
);
1014 void AddEventAssign (CodeMemberMethod method
, ControlBuilder builder
, string name
, Type type
, string value)
1016 //"__ctrl.{0} += new {1} (this.{2});"
1017 CodeEventReferenceExpression evtID
= new CodeEventReferenceExpression (ctrlVar
, name
);
1019 CodeDelegateCreateExpression create
;
1020 create
= new CodeDelegateCreateExpression (new CodeTypeReference (type
), thisRef
, value);
1022 CodeAttachEventStatement attach
= new CodeAttachEventStatement (evtID
, create
);
1023 method
.Statements
.Add (attach
);
1026 void CreateAssignStatementFromAttribute (ControlBuilder builder
, string id
)
1028 EventInfo
[] ev_info
= null;
1029 Type type
= builder
.ControlType
;
1031 string attvalue
= builder
.GetAttribute (id
);
1032 if (id
.Length
> 2 && String
.Compare (id
.Substring (0, 2), "ON", true, Helpers
.InvariantCulture
) == 0){
1033 if (ev_info
== null)
1034 ev_info
= type
.GetEvents ();
1036 string id_as_event
= id
.Substring (2);
1037 foreach (EventInfo ev
in ev_info
){
1038 if (InvariantCompareNoCase (ev
.Name
, id_as_event
)){
1039 AddEventAssign (builder
.Method
,
1042 ev
.EventHandlerType
,
1051 if (String
.Compare (id
, "meta:resourcekey", StringComparison
.OrdinalIgnoreCase
) == 0) {
1052 AssignPropertiesFromResources (builder
, attvalue
);
1056 int hyphen
= id
.IndexOf ('-');
1059 alt_id
= id
.Substring (0, hyphen
);
1061 MemberInfo fop
= GetFieldOrProperty (type
, alt_id
);
1063 if (ProcessPropertiesAndFields (builder
, fop
, id
, attvalue
, null))
1067 if (!typeof (IAttributeAccessor
).IsAssignableFrom (type
))
1068 throw new ParseException (builder
.Location
, "Unrecognized attribute: " + id
);
1070 CodeMemberMethod method
= builder
.Method
;
1071 bool isDatabound
= BaseParser
.IsDataBound (attvalue
);
1072 bool isExpression
= !isDatabound
&& BaseParser
.IsExpression (attvalue
);
1075 string value = attvalue
.Substring (3, attvalue
.Length
- 5).Trim ();
1076 CodeExpression valueExpression
= null;
1077 if (startsWithBindRegex
.Match (value).Success
)
1078 valueExpression
= CreateEvalInvokeExpression (bindRegexInValue
, value, true);
1080 if (StrUtils
.StartsWith (value, "Eval", true))
1081 valueExpression
= CreateEvalInvokeExpression (evalRegexInValue
, value, false);
1083 if (valueExpression
== null && value != null && value.Trim () != String
.Empty
)
1084 valueExpression
= new CodeSnippetExpression (value);
1086 CreateDBAttributeMethod (builder
, id
, valueExpression
);
1088 CodeCastExpression cast
;
1089 CodeMethodReferenceExpression methodExpr
;
1090 CodeMethodInvokeExpression expr
;
1092 cast
= new CodeCastExpression (typeof (IAttributeAccessor
), ctrlVar
);
1093 methodExpr
= new CodeMethodReferenceExpression (cast
, "SetAttribute");
1094 expr
= new CodeMethodInvokeExpression (methodExpr
);
1095 expr
.Parameters
.Add (new CodePrimitiveExpression (id
));
1097 CodeExpression valueExpr
= null;
1099 valueExpr
= CompileExpression (null, typeof (string), attvalue
, true);
1101 if (valueExpr
== null)
1102 valueExpr
= new CodePrimitiveExpression (attvalue
);
1104 expr
.Parameters
.Add (valueExpr
);
1105 method
.Statements
.Add (AddLinePragma (expr
, builder
));
1109 protected void CreateAssignStatementsFromAttributes (ControlBuilder builder
)
1111 this.dataBoundAtts
= 0;
1112 IDictionary atts
= builder
.Attributes
;
1113 if (atts
== null || atts
.Count
== 0)
1116 foreach (string id
in atts
.Keys
) {
1117 if (InvariantCompareNoCase (id
, "runat"))
1119 // ID is assigned in BuildControltree
1120 if (InvariantCompareNoCase (id
, "id"))
1123 /* we skip SkinID here as it's assigned in BuildControlTree */
1124 if (InvariantCompareNoCase (id
, "skinid"))
1126 if (InvariantCompareNoCase (id
, "meta:resourcekey"))
1127 continue; // ignore, this one's processed at the very end of
1129 CreateAssignStatementFromAttribute (builder
, id
);
1133 void CreateDBAttributeMethod (ControlBuilder builder
, string attr
, CodeExpression code
)
1138 string id
= builder
.GetNextID (null);
1139 string dbMethodName
= "__DataBind_" + id
;
1140 CodeMemberMethod method
= builder
.Method
;
1141 AddEventAssign (method
, builder
, "DataBinding", typeof (EventHandler
), dbMethodName
);
1143 method
= CreateDBMethod (builder
, dbMethodName
, GetContainerType (builder
), builder
.ControlType
);
1144 builder
.DataBindingMethod
= method
;
1146 CodeCastExpression cast
;
1147 CodeMethodReferenceExpression methodExpr
;
1148 CodeMethodInvokeExpression expr
;
1150 CodeVariableReferenceExpression targetExpr
= new CodeVariableReferenceExpression ("target");
1151 cast
= new CodeCastExpression (typeof (IAttributeAccessor
), targetExpr
);
1152 methodExpr
= new CodeMethodReferenceExpression (cast
, "SetAttribute");
1153 expr
= new CodeMethodInvokeExpression (methodExpr
);
1154 expr
.Parameters
.Add (new CodePrimitiveExpression (attr
));
1155 CodeMethodInvokeExpression tostring
= new CodeMethodInvokeExpression ();
1156 tostring
.Method
= new CodeMethodReferenceExpression (
1157 new CodeTypeReferenceExpression (typeof (Convert
)),
1159 tostring
.Parameters
.Add (code
);
1160 expr
.Parameters
.Add (tostring
);
1161 method
.Statements
.Add (expr
);
1162 mainClass
.Members
.Add (method
);
1165 void AddRenderControl (ControlBuilder builder
)
1167 CodeIndexerExpression indexer
= new CodeIndexerExpression ();
1168 indexer
.TargetObject
= new CodePropertyReferenceExpression (
1169 new CodeArgumentReferenceExpression ("parameterContainer"),
1172 indexer
.Indices
.Add (new CodePrimitiveExpression (builder
.RenderIndex
));
1174 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (indexer
, "RenderControl");
1175 invoke
.Parameters
.Add (new CodeArgumentReferenceExpression ("__output"));
1176 builder
.RenderMethod
.Statements
.Add (invoke
);
1177 builder
.IncreaseRenderIndex ();
1180 protected void AddChildCall (ControlBuilder parent
, ControlBuilder child
)
1182 if (parent
== null || child
== null)
1185 CodeStatementCollection methodStatements
= parent
.MethodStatements
;
1186 CodeMethodReferenceExpression m
= new CodeMethodReferenceExpression (thisRef
, child
.Method
.Name
);
1187 CodeMethodInvokeExpression expr
= new CodeMethodInvokeExpression (m
);
1189 object [] atts
= null;
1191 if (child
.ControlType
!= null)
1192 atts
= child
.ControlType
.GetCustomAttributes (typeof (PartialCachingAttribute
), true);
1194 if (atts
!= null && atts
.Length
> 0) {
1195 PartialCachingAttribute pca
= (PartialCachingAttribute
) atts
[0];
1196 CodeTypeReferenceExpression cc
= new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
1197 CodeMethodInvokeExpression build
= new CodeMethodInvokeExpression (cc
, "BuildCachedControl");
1198 CodeExpressionCollection parms
= build
.Parameters
;
1200 parms
.Add (new CodeArgumentReferenceExpression("__ctrl"));
1201 parms
.Add (new CodePrimitiveExpression (child
.ID
));
1204 parms
.Add (new CodePrimitiveExpression (child
.ControlType
.GetHashCode ().ToString ()));
1206 parms
.Add (new CodePrimitiveExpression (Guid
.NewGuid ().ToString ()));
1208 parms
.Add (new CodePrimitiveExpression (pca
.Duration
));
1209 parms
.Add (new CodePrimitiveExpression (pca
.VaryByParams
));
1210 parms
.Add (new CodePrimitiveExpression (pca
.VaryByControls
));
1211 parms
.Add (new CodePrimitiveExpression (pca
.VaryByCustom
));
1212 parms
.Add (new CodePrimitiveExpression (pca
.SqlDependency
));
1213 parms
.Add (new CodeDelegateCreateExpression (
1214 new CodeTypeReference (typeof (System
.Web
.UI
.BuildMethod
)),
1215 thisRef
, child
.Method
.Name
));
1216 string value = pca
.ProviderName
;
1217 if (!String
.IsNullOrEmpty (value) && String
.Compare (OutputCache
.DEFAULT_PROVIDER_NAME
, value, StringComparison
.Ordinal
) != 0)
1218 parms
.Add (new CodePrimitiveExpression (value));
1220 parms
.Add (new CodePrimitiveExpression (null));
1221 methodStatements
.Add (AddLinePragma (build
, parent
));
1222 if (parent
.HasAspCode
)
1223 AddRenderControl (parent
);
1227 if (child
.IsProperty
|| parent
.ChildrenAsProperties
) {
1228 if (!child
.PropertyBuilderShouldReturnValue
) {
1229 expr
.Parameters
.Add (new CodeFieldReferenceExpression (ctrlVar
, child
.TagName
));
1230 parent
.MethodStatements
.Add (AddLinePragma (expr
, parent
));
1232 string localVarName
= parent
.GetNextLocalVariableName ("__ctrl");
1233 methodStatements
.Add (new CodeVariableDeclarationStatement (child
.Method
.ReturnType
, localVarName
));
1234 CodeVariableReferenceExpression localVarRef
= new CodeVariableReferenceExpression (localVarName
);
1235 CodeAssignStatement assign
= new CodeAssignStatement ();
1236 assign
.Left
= localVarRef
;
1237 assign
.Right
= expr
;
1238 methodStatements
.Add (AddLinePragma (assign
, parent
));
1240 assign
= new CodeAssignStatement ();
1241 assign
.Left
= new CodeFieldReferenceExpression (ctrlVar
, child
.TagName
);
1242 assign
.Right
= localVarRef
;
1243 methodStatements
.Add (AddLinePragma (assign
, parent
));
1249 methodStatements
.Add (AddLinePragma (expr
, parent
));
1250 CodeFieldReferenceExpression field
= new CodeFieldReferenceExpression (thisRef
, child
.ID
);
1251 if (parent
.ControlType
== null || typeof (IParserAccessor
).IsAssignableFrom (parent
.ControlType
))
1252 AddParsedSubObjectStmt (parent
, field
);
1254 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (ctrlVar
, "Add");
1255 invoke
.Parameters
.Add (field
);
1256 methodStatements
.Add (AddLinePragma (invoke
, parent
));
1259 if (parent
.HasAspCode
)
1260 AddRenderControl (parent
);
1263 void AddTemplateInvocation (ControlBuilder builder
, string name
, string methodName
)
1265 CodePropertyReferenceExpression prop
= new CodePropertyReferenceExpression (ctrlVar
, name
);
1267 CodeDelegateCreateExpression newBuild
= new CodeDelegateCreateExpression (
1268 new CodeTypeReference (typeof (BuildTemplateMethod
)), thisRef
, methodName
);
1270 CodeObjectCreateExpression newCompiled
= new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder
));
1271 newCompiled
.Parameters
.Add (newBuild
);
1273 CodeAssignStatement assign
= new CodeAssignStatement (prop
, newCompiled
);
1274 builder
.Method
.Statements
.Add (AddLinePragma (assign
, builder
));
1277 void AddBindableTemplateInvocation (ControlBuilder builder
, string name
, string methodName
, string extractMethodName
)
1279 CodePropertyReferenceExpression prop
= new CodePropertyReferenceExpression (ctrlVar
, name
);
1281 CodeDelegateCreateExpression newBuild
= new CodeDelegateCreateExpression (
1282 new CodeTypeReference (typeof (BuildTemplateMethod
)), thisRef
, methodName
);
1284 CodeDelegateCreateExpression newExtract
= new CodeDelegateCreateExpression (
1285 new CodeTypeReference (typeof (ExtractTemplateValuesMethod
)), thisRef
, extractMethodName
);
1287 CodeObjectCreateExpression newCompiled
= new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder
));
1288 newCompiled
.Parameters
.Add (newBuild
);
1289 newCompiled
.Parameters
.Add (newExtract
);
1291 CodeAssignStatement assign
= new CodeAssignStatement (prop
, newCompiled
);
1292 builder
.Method
.Statements
.Add (AddLinePragma (assign
, builder
));
1295 string CreateExtractValuesMethod (TemplateBuilder builder
)
1297 CodeMemberMethod method
= new CodeMemberMethod ();
1298 method
.Name
= "__ExtractValues_" + builder
.ID
;
1299 method
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Final
;
1300 method
.ReturnType
= new CodeTypeReference (typeof(IOrderedDictionary
));
1302 CodeParameterDeclarationExpression arg
= new CodeParameterDeclarationExpression ();
1303 arg
.Type
= new CodeTypeReference (typeof (Control
));
1304 arg
.Name
= "__container";
1305 method
.Parameters
.Add (arg
);
1306 mainClass
.Members
.Add (method
);
1308 CodeObjectCreateExpression newTable
= new CodeObjectCreateExpression ();
1309 newTable
.CreateType
= new CodeTypeReference (typeof(OrderedDictionary
));
1310 method
.Statements
.Add (new CodeVariableDeclarationStatement (typeof(OrderedDictionary
), "__table", newTable
));
1311 CodeVariableReferenceExpression tableExp
= new CodeVariableReferenceExpression ("__table");
1313 if (builder
.Bindings
!= null) {
1314 Hashtable hash
= new Hashtable ();
1315 foreach (TemplateBinding binding
in builder
.Bindings
) {
1316 CodeConditionStatement sif
;
1317 CodeVariableReferenceExpression control
;
1318 CodeAssignStatement assign
;
1320 if (hash
[binding
.ControlId
] == null) {
1322 CodeVariableDeclarationStatement dec
= new CodeVariableDeclarationStatement (binding
.ControlType
, binding
.ControlId
);
1323 method
.Statements
.Add (dec
);
1324 CodeVariableReferenceExpression cter
= new CodeVariableReferenceExpression ("__container");
1325 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (cter
, "FindControl");
1326 invoke
.Parameters
.Add (new CodePrimitiveExpression (binding
.ControlId
));
1328 assign
= new CodeAssignStatement ();
1329 control
= new CodeVariableReferenceExpression (binding
.ControlId
);
1330 assign
.Left
= control
;
1331 assign
.Right
= new CodeCastExpression (binding
.ControlType
, invoke
);
1332 method
.Statements
.Add (assign
);
1334 sif
= new CodeConditionStatement ();
1335 sif
.Condition
= new CodeBinaryOperatorExpression (control
, CodeBinaryOperatorType
.IdentityInequality
, new CodePrimitiveExpression (null));
1337 method
.Statements
.Add (sif
);
1339 hash
[binding
.ControlId
] = sif
;
1342 sif
= (CodeConditionStatement
) hash
[binding
.ControlId
];
1343 control
= new CodeVariableReferenceExpression (binding
.ControlId
);
1344 assign
= new CodeAssignStatement ();
1345 assign
.Left
= new CodeIndexerExpression (tableExp
, new CodePrimitiveExpression (binding
.FieldName
));
1346 assign
.Right
= new CodePropertyReferenceExpression (control
, binding
.ControlProperty
);
1347 sif
.TrueStatements
.Add (assign
);
1351 method
.Statements
.Add (new CodeMethodReturnStatement (tableExp
));
1355 void AddContentTemplateInvocation (ContentBuilderInternal cbuilder
, CodeMemberMethod method
, string methodName
)
1357 CodeDelegateCreateExpression newBuild
= new CodeDelegateCreateExpression (
1358 new CodeTypeReference (typeof (BuildTemplateMethod
)), thisRef
, methodName
);
1360 CodeObjectCreateExpression newCompiled
= new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder
));
1361 newCompiled
.Parameters
.Add (newBuild
);
1363 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (thisRef
, "AddContentTemplate");
1364 invoke
.Parameters
.Add (new CodePrimitiveExpression (cbuilder
.ContentPlaceHolderID
));
1365 invoke
.Parameters
.Add (newCompiled
);
1367 method
.Statements
.Add (AddLinePragma (invoke
, cbuilder
));
1370 void AddCodeRender (ControlBuilder parent
, CodeRenderBuilder cr
)
1372 if (cr
.Code
== null || cr
.Code
.Trim () == "")
1376 CodeSnippetStatement code
= new CodeSnippetStatement (cr
.Code
);
1377 parent
.RenderMethod
.Statements
.Add (AddLinePragma (code
, cr
));
1381 CodeMethodInvokeExpression expr
= new CodeMethodInvokeExpression ();
1382 expr
.Method
= new CodeMethodReferenceExpression (
1383 new CodeArgumentReferenceExpression ("__output"),
1386 expr
.Parameters
.Add (GetWrappedCodeExpression (cr
));
1387 parent
.RenderMethod
.Statements
.Add (AddLinePragma (expr
, cr
));
1390 CodeExpression
GetWrappedCodeExpression (CodeRenderBuilder cr
)
1392 var ret
= new CodeSnippetExpression (cr
.Code
);
1393 if (cr
.HtmlEncode
) {
1394 var encodeRef
= new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (typeof (HttpUtility
)), "HtmlEncode");
1395 return new CodeMethodInvokeExpression (encodeRef
, new CodeExpression
[] { ret }
);
1400 static Type
GetContainerType (ControlBuilder builder
)
1402 return builder
.BindingContainerType
;
1405 CodeMemberMethod
CreateDBMethod (ControlBuilder builder
, string name
, Type container
, Type target
)
1407 CodeMemberMethod method
= new CodeMemberMethod ();
1408 method
.Attributes
= MemberAttributes
.Public
| MemberAttributes
.Final
;
1410 method
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
1411 method
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (EventArgs
), "e"));
1413 CodeTypeReference containerRef
= new CodeTypeReference (container
);
1414 CodeTypeReference targetRef
= new CodeTypeReference (target
);
1416 CodeVariableDeclarationStatement decl
= new CodeVariableDeclarationStatement();
1417 decl
.Name
= "Container";
1418 decl
.Type
= containerRef
;
1419 method
.Statements
.Add (decl
);
1421 decl
= new CodeVariableDeclarationStatement();
1422 decl
.Name
= "target";
1423 decl
.Type
= targetRef
;
1424 method
.Statements
.Add (decl
);
1426 CodeVariableReferenceExpression targetExpr
= new CodeVariableReferenceExpression ("target");
1427 CodeAssignStatement assign
= new CodeAssignStatement ();
1428 assign
.Left
= targetExpr
;
1429 assign
.Right
= new CodeCastExpression (targetRef
, new CodeArgumentReferenceExpression ("sender"));
1430 method
.Statements
.Add (AddLinePragma (assign
, builder
));
1432 assign
= new CodeAssignStatement ();
1433 assign
.Left
= new CodeVariableReferenceExpression ("Container");
1434 assign
.Right
= new CodeCastExpression (containerRef
,
1435 new CodePropertyReferenceExpression (targetExpr
, "BindingContainer"));
1436 method
.Statements
.Add (AddLinePragma (assign
, builder
));
1441 void AddDataBindingLiteral (ControlBuilder builder
, DataBindingBuilder db
)
1443 if (db
.Code
== null || db
.Code
.Trim () == "")
1447 CreateField (db
, false);
1449 string dbMethodName
= "__DataBind_" + db
.ID
;
1450 // Add the method that builds the DataBoundLiteralControl
1451 InitMethod (db
, false, false);
1452 CodeMemberMethod method
= db
.Method
;
1453 AddEventAssign (method
, builder
, "DataBinding", typeof (EventHandler
), dbMethodName
);
1454 method
.Statements
.Add (new CodeMethodReturnStatement (ctrlVar
));
1456 // Add the DataBind handler
1457 method
= CreateDBMethod (builder
, dbMethodName
, GetContainerType (builder
), typeof (DataBoundLiteralControl
));
1458 builder
.DataBindingMethod
= method
;
1460 CodeVariableReferenceExpression targetExpr
= new CodeVariableReferenceExpression ("target");
1461 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression ();
1462 invoke
.Method
= new CodeMethodReferenceExpression (targetExpr
, "SetDataBoundString");
1463 invoke
.Parameters
.Add (new CodePrimitiveExpression (0));
1465 CodeMethodInvokeExpression tostring
= new CodeMethodInvokeExpression ();
1466 tostring
.Method
= new CodeMethodReferenceExpression (
1467 new CodeTypeReferenceExpression (typeof (Convert
)),
1469 tostring
.Parameters
.Add (new CodeSnippetExpression (db
.Code
));
1470 invoke
.Parameters
.Add (tostring
);
1471 method
.Statements
.Add (AddLinePragma (invoke
, builder
));
1473 mainClass
.Members
.Add (method
);
1475 AddChildCall (builder
, db
);
1478 void FlushText (ControlBuilder builder
, StringBuilder sb
)
1480 if (sb
.Length
> 0) {
1481 AddLiteralSubObject (builder
, sb
.ToString ());
1486 protected void CreateControlTree (ControlBuilder builder
, bool inTemplate
, bool childrenAsProperties
)
1489 bool isTemplate
= builder
.IsTemplate
;
1491 if (!isTemplate
&& !inTemplate
) {
1492 CreateField (builder
, true);
1493 } else if (!isTemplate
) {
1494 bool doCheck
= false;
1495 bool singleInstance
= false;
1496 ControlBuilder pb
= builder
.ParentBuilder
;
1497 TemplateBuilder tpb
;
1498 while (pb
!= null) {
1499 tpb
= pb
as TemplateBuilder
;
1501 pb
= pb
.ParentBuilder
;
1505 if (tpb
.TemplateInstance
== TemplateInstance
.Single
)
1506 singleInstance
= true;
1510 if (!singleInstance
)
1511 builder
.ID
= builder
.GetNextID (null);
1515 CreateField (builder
, doCheck
);
1518 InitMethod (builder
, isTemplate
, childrenAsProperties
);
1519 if (!isTemplate
|| builder
.GetType () == typeof (RootBuilder
))
1520 CreateAssignStatementsFromAttributes (builder
);
1522 if (builder
.Children
!= null && builder
.Children
.Count
> 0) {
1523 StringBuilder sb
= new StringBuilder ();
1524 foreach (object b
in builder
.Children
) {
1526 sb
.Append ((string) b
);
1530 FlushText (builder
, sb
);
1531 if (b
is ObjectTagBuilder
) {
1532 ProcessObjectTag ((ObjectTagBuilder
) b
);
1533 } else if (b
is StringPropertyBuilder
) {
1534 StringPropertyBuilder pb
= b
as StringPropertyBuilder
;
1535 if (pb
.Children
!= null && pb
.Children
.Count
> 0) {
1536 StringBuilder asb
= new StringBuilder ();
1537 foreach (string s
in pb
.Children
)
1539 CodeMemberMethod method
= builder
.Method
;
1540 CodeAssignStatement assign
= new CodeAssignStatement ();
1541 assign
.Left
= new CodePropertyReferenceExpression (ctrlVar
, pb
.PropertyName
);
1542 assign
.Right
= new CodePrimitiveExpression (asb
.ToString ());
1543 method
.Statements
.Add (AddLinePragma (assign
, builder
));
1545 } else if (b
is ContentBuilderInternal
) {
1546 ContentBuilderInternal cb
= (ContentBuilderInternal
) b
;
1547 CreateControlTree (cb
, false, true);
1548 AddContentTemplateInvocation (cb
, builder
.Method
, cb
.Method
.Name
);
1552 // Ignore TemplateBuilders - they are processed in InitMethod
1553 else if (b
is TemplateBuilder
) {
1554 } else if (b
is CodeRenderBuilder
) {
1555 AddCodeRender (builder
, (CodeRenderBuilder
) b
);
1556 } else if (b
is DataBindingBuilder
) {
1557 AddDataBindingLiteral (builder
, (DataBindingBuilder
) b
);
1558 } else if (b
is ControlBuilder
) {
1559 ControlBuilder child
= (ControlBuilder
) b
;
1560 CreateControlTree (child
, inTemplate
, builder
.ChildrenAsProperties
);
1561 AddChildCall (builder
, child
);
1564 throw new Exception ("???");
1566 ControlBuilder bldr
= b
as ControlBuilder
;
1567 bldr
.ProcessGeneratedCode (CompileUnit
, BaseType
, DerivedType
, bldr
.Method
, bldr
.DataBindingMethod
);
1570 FlushText (builder
, sb
);
1573 ControlBuilder defaultPropertyBuilder
= builder
.DefaultPropertyBuilder
;
1574 if (defaultPropertyBuilder
!= null) {
1575 CreateControlTree (defaultPropertyBuilder
, false, true);
1576 AddChildCall (builder
, defaultPropertyBuilder
);
1579 if (builder
.HasAspCode
) {
1580 CodeMemberMethod renderMethod
= builder
.RenderMethod
;
1581 CodeMethodReferenceExpression m
= new CodeMethodReferenceExpression ();
1582 m
.TargetObject
= thisRef
;
1583 m
.MethodName
= renderMethod
.Name
;
1585 CodeDelegateCreateExpression create
= new CodeDelegateCreateExpression ();
1586 create
.DelegateType
= new CodeTypeReference (typeof (RenderMethod
));
1587 create
.TargetObject
= thisRef
;
1588 create
.MethodName
= renderMethod
.Name
;
1590 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression ();
1591 invoke
.Method
= new CodeMethodReferenceExpression (ctrlVar
, "SetRenderMethodDelegate");
1592 invoke
.Parameters
.Add (create
);
1594 builder
.MethodStatements
.Add (invoke
);
1597 if (builder
is RootBuilder
)
1598 if (!String
.IsNullOrEmpty (parser
.MetaResourceKey
))
1599 AssignPropertiesFromResources (builder
, parser
.BaseType
, parser
.MetaResourceKey
);
1601 if ((!isTemplate
|| builder
is RootBuilder
) && !String
.IsNullOrEmpty (builder
.GetAttribute ("meta:resourcekey")))
1602 CreateAssignStatementFromAttribute (builder
, "meta:resourcekey");
1604 if ((childrenAsProperties
&& builder
.PropertyBuilderShouldReturnValue
) || (!childrenAsProperties
&& typeof (Control
).IsAssignableFrom (builder
.ControlType
)))
1605 builder
.Method
.Statements
.Add (new CodeMethodReturnStatement (ctrlVar
));
1607 builder
.ProcessGeneratedCode (CompileUnit
, BaseType
, DerivedType
, builder
.Method
, builder
.DataBindingMethod
);
1610 protected override void AddStatementsToConstructor (CodeConstructor ctor
)
1612 if (masterPageContentPlaceHolders
== null || masterPageContentPlaceHolders
.Count
== 0)
1615 var ilist
= new CodeVariableDeclarationStatement ();
1616 ilist
.Name
= "__contentPlaceHolders";
1617 ilist
.Type
= new CodeTypeReference (typeof (IList
));
1618 ilist
.InitExpression
= new CodePropertyReferenceExpression (thisRef
, "ContentPlaceHolders");
1620 var ilistRef
= new CodeVariableReferenceExpression ("__contentPlaceHolders");
1621 CodeStatementCollection statements
= ctor
.Statements
;
1622 statements
.Add (ilist
);
1624 CodeMethodInvokeExpression mcall
;
1625 foreach (string id
in masterPageContentPlaceHolders
) {
1626 mcall
= new CodeMethodInvokeExpression (ilistRef
, "Add");
1627 mcall
.Parameters
.Add (new CodePrimitiveExpression (id
.ToLowerInvariant ()));
1628 statements
.Add (mcall
);
1632 protected internal override void CreateMethods ()
1634 base.CreateMethods ();
1636 CreateProperties ();
1637 CreateControlTree (parser
.RootBuilder
, false, false);
1638 CreateFrameworkInitializeMethod ();
1641 protected override void InitializeType ()
1643 List
<string> registeredTagNames
= parser
.RegisteredTagNames
;
1644 RootBuilder rb
= parser
.RootBuilder
;
1645 if (rb
== null || registeredTagNames
== null || registeredTagNames
.Count
== 0)
1648 AspComponent component
;
1649 foreach (string tagName
in registeredTagNames
) {
1650 component
= rb
.Foundry
.GetComponent (tagName
);
1651 if (component
== null || component
.Type
== null) // unlikely
1652 throw new HttpException ("Custom control '" + tagName
+ "' cannot be found.");
1653 if (!(typeof (UserControl
).IsAssignableFrom (component
.Type
)))
1654 throw new ParseException (parser
.Location
, "Type '" + component
.Type
.ToString () + "' does not derive from 'System.Web.UI.UserControl'.");
1655 AddReferencedAssembly (component
.Type
.Assembly
);
1659 void CallBaseFrameworkInitialize (CodeMemberMethod method
)
1661 CodeBaseReferenceExpression baseRef
= new CodeBaseReferenceExpression ();
1662 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (baseRef
, "FrameworkInitialize");
1663 method
.Statements
.Add (invoke
);
1666 void CallSetStringResourcePointer (CodeMemberMethod method
)
1668 CodeFieldReferenceExpression stringResource
= GetMainClassFieldReferenceExpression ("__stringResource");
1669 method
.Statements
.Add (
1670 new CodeMethodInvokeExpression (
1672 "SetStringResourcePointer",
1673 new CodeExpression
[] {stringResource, new CodePrimitiveExpression (0)}
)
1677 void CreateFrameworkInitializeMethod ()
1679 CodeMemberMethod method
= new CodeMemberMethod ();
1680 method
.Name
= "FrameworkInitialize";
1681 method
.Attributes
= MemberAttributes
.Family
| MemberAttributes
.Override
;
1682 PrependStatementsToFrameworkInitialize (method
);
1683 CallBaseFrameworkInitialize (method
);
1684 CallSetStringResourcePointer (method
);
1685 AppendStatementsToFrameworkInitialize (method
);
1686 mainClass
.Members
.Add (method
);
1689 protected virtual void PrependStatementsToFrameworkInitialize (CodeMemberMethod method
)
1693 protected virtual void AppendStatementsToFrameworkInitialize (CodeMemberMethod method
)
1695 if (!parser
.EnableViewState
) {
1696 CodeAssignStatement stmt
= new CodeAssignStatement ();
1697 stmt
.Left
= new CodePropertyReferenceExpression (thisRef
, "EnableViewState");
1698 stmt
.Right
= new CodePrimitiveExpression (false);
1699 method
.Statements
.Add (stmt
);
1702 CodeMethodReferenceExpression methodExpr
;
1703 methodExpr
= new CodeMethodReferenceExpression (thisRef
, "__BuildControlTree");
1704 CodeMethodInvokeExpression expr
= new CodeMethodInvokeExpression (methodExpr
, thisRef
);
1705 method
.Statements
.Add (new CodeExpressionStatement (expr
));
1708 protected override void AddApplicationAndSessionObjects ()
1710 foreach (ObjectTagBuilder tag
in GlobalAsaxCompiler
.ApplicationObjects
) {
1711 CreateFieldForObject (tag
.Type
, tag
.ObjectID
);
1712 CreateApplicationOrSessionPropertyForObject (tag
.Type
, tag
.ObjectID
, true, false);
1715 foreach (ObjectTagBuilder tag
in GlobalAsaxCompiler
.SessionObjects
) {
1716 CreateApplicationOrSessionPropertyForObject (tag
.Type
, tag
.ObjectID
, false, false);
1720 protected override void CreateStaticFields ()
1722 base.CreateStaticFields ();
1724 CodeMemberField fld
= new CodeMemberField (typeof (object), "__stringResource");
1725 fld
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Static
;
1726 fld
.InitExpression
= new CodePrimitiveExpression (null);
1727 mainClass
.Members
.Add (fld
);
1730 protected void ProcessObjectTag (ObjectTagBuilder tag
)
1732 string fieldName
= CreateFieldForObject (tag
.Type
, tag
.ObjectID
);
1733 CreatePropertyForObject (tag
.Type
, tag
.ObjectID
, fieldName
, false);
1736 void CreateProperties ()
1738 if (!parser
.AutoEventWireup
) {
1739 CreateAutoEventWireup ();
1741 CreateAutoHandlers ();
1744 CreateApplicationInstance ();
1747 void CreateApplicationInstance ()
1749 CodeMemberProperty prop
= new CodeMemberProperty ();
1750 Type appType
= typeof (HttpApplication
);
1751 prop
.Type
= new CodeTypeReference (appType
);
1752 prop
.Name
= "ApplicationInstance";
1753 prop
.Attributes
= MemberAttributes
.Family
| MemberAttributes
.Final
;
1755 CodePropertyReferenceExpression propRef
= new CodePropertyReferenceExpression (thisRef
, "Context");
1757 propRef
= new CodePropertyReferenceExpression (propRef
, "ApplicationInstance");
1759 CodeCastExpression cast
= new CodeCastExpression (appType
.FullName
, propRef
);
1760 prop
.GetStatements
.Add (new CodeMethodReturnStatement (cast
));
1761 if (partialClass
!= null)
1762 partialClass
.Members
.Add (prop
);
1764 mainClass
.Members
.Add (prop
);
1767 void CreateContentPlaceHolderTemplateProperty (string backingField
, string name
)
1769 CodeMemberProperty prop
= new CodeMemberProperty ();
1770 prop
.Type
= new CodeTypeReference (typeof (ITemplate
));
1772 prop
.Attributes
= MemberAttributes
.Public
;
1774 var ret
= new CodeMethodReturnStatement ();
1775 var fldRef
= new CodeFieldReferenceExpression (thisRef
, backingField
);
1776 ret
.Expression
= fldRef
;
1777 prop
.GetStatements
.Add (ret
);
1778 prop
.SetStatements
.Add (new CodeAssignStatement (fldRef
, new CodePropertySetValueReferenceExpression ()));
1780 prop
.CustomAttributes
.Add (new CodeAttributeDeclaration ("TemplateContainer", new CodeAttributeArgument
[] {
1781 new CodeAttributeArgument (new CodeTypeOfExpression (new CodeTypeReference (typeof (MasterPage
))))
1786 var enumValueRef
= new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typeof (TemplateInstance
)), "Single");
1787 prop
.CustomAttributes
.Add (new CodeAttributeDeclaration ("TemplateInstanceAttribute", new CodeAttributeArgument
[] {
1788 new CodeAttributeArgument (enumValueRef
)
1793 mainClass
.Members
.Add (prop
);
1796 void CreateAutoHandlers ()
1798 // Create AutoHandlers property
1799 CodeMemberProperty prop
= new CodeMemberProperty ();
1800 prop
.Type
= new CodeTypeReference (typeof (int));
1801 prop
.Name
= "AutoHandlers";
1802 prop
.Attributes
= MemberAttributes
.Family
| MemberAttributes
.Override
;
1804 CodeMethodReturnStatement ret
= new CodeMethodReturnStatement ();
1805 CodeFieldReferenceExpression fldRef
;
1806 fldRef
= new CodeFieldReferenceExpression (mainClassExpr
, "__autoHandlers");
1807 ret
.Expression
= fldRef
;
1808 prop
.GetStatements
.Add (ret
);
1809 prop
.SetStatements
.Add (new CodeAssignStatement (fldRef
, new CodePropertySetValueReferenceExpression ()));
1811 CodeAttributeDeclaration attr
= new CodeAttributeDeclaration ("System.Obsolete");
1812 prop
.CustomAttributes
.Add (attr
);
1813 mainClass
.Members
.Add (prop
);
1815 // Add the __autoHandlers field
1816 CodeMemberField fld
= new CodeMemberField (typeof (int), "__autoHandlers");
1817 fld
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Static
;
1818 mainClass
.Members
.Add (fld
);
1821 void CreateAutoEventWireup ()
1823 // The getter returns false
1824 CodeMemberProperty prop
= new CodeMemberProperty ();
1825 prop
.Type
= new CodeTypeReference (typeof (bool));
1826 prop
.Name
= "SupportAutoEvents";
1827 prop
.Attributes
= MemberAttributes
.Family
| MemberAttributes
.Override
;
1828 prop
.GetStatements
.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
1829 mainClass
.Members
.Add (prop
);
1832 protected virtual string HandleUrlProperty (string str
, MemberInfo member
)
1837 TypeConverter
GetConverterForMember (MemberInfo member
)
1839 TypeDescriptionProvider prov
= TypeDescriptor
.GetProvider (member
.ReflectedType
);
1843 ICustomTypeDescriptor desc
= prov
.GetTypeDescriptor (member
.ReflectedType
);
1844 PropertyDescriptorCollection coll
= desc
!= null ? desc
.GetProperties () : null;
1846 if (coll
== null || coll
.Count
== 0)
1849 PropertyDescriptor pd
= coll
.Find (member
.Name
, false);
1853 return pd
.Converter
;
1856 CodeExpression
CreateNullableExpression (Type type
, CodeExpression inst
, bool nullable
)
1861 return new CodeObjectCreateExpression (type
, new CodeExpression
[] {inst}
);
1864 bool SafeCanConvertFrom (Type type
, TypeConverter cvt
)
1867 return cvt
.CanConvertFrom (type
);
1868 } catch (NotImplementedException
) {
1873 bool SafeCanConvertTo (Type type
, TypeConverter cvt
)
1876 return cvt
.CanConvertTo (type
);
1877 } catch (NotImplementedException
) {
1882 CodeExpression
GetExpressionFromString (Type type
, string str
, MemberInfo member
)
1884 TypeConverter cvt
= GetConverterForMember (member
);
1885 if (cvt
!= null && !SafeCanConvertFrom (typeof (string), cvt
))
1888 object convertedFromAttr
= null;
1889 bool preConverted
= false;
1890 if (cvt
!= null && str
!= null) {
1891 convertedFromAttr
= cvt
.ConvertFromInvariantString (str
);
1892 if (convertedFromAttr
!= null) {
1893 type
= convertedFromAttr
.GetType ();
1894 preConverted
= true;
1898 bool wasNullable
= false;
1899 Type originalType
= type
;
1901 if (type
.IsGenericType
&& type
.GetGenericTypeDefinition() == typeof(Nullable
<>)) {
1902 Type
[] types
= type
.GetGenericArguments();
1903 originalType
= type
;
1904 type
= types
[0]; // we're interested only in the first type here
1908 if (type
== typeof (string)) {
1909 object[] urlAttr
= member
.GetCustomAttributes (typeof (UrlPropertyAttribute
), true);
1910 if (urlAttr
.Length
!= 0)
1911 str
= HandleUrlProperty ((preConverted
&& convertedFromAttr
is string) ? (string)convertedFromAttr
: str
, member
);
1912 else if (preConverted
)
1913 return CreateNullableExpression (originalType
,
1914 new CodePrimitiveExpression ((string) convertedFromAttr
),
1917 return CreateNullableExpression (originalType
, new CodePrimitiveExpression (str
), wasNullable
);
1918 } else if (type
== typeof (bool)) {
1920 return CreateNullableExpression (originalType
,
1921 new CodePrimitiveExpression ((bool) convertedFromAttr
),
1924 if (str
== null || str
== "" || InvariantCompareNoCase (str
, "true"))
1925 return CreateNullableExpression (originalType
, new CodePrimitiveExpression (true), wasNullable
);
1926 else if (InvariantCompareNoCase (str
, "false"))
1927 return CreateNullableExpression (originalType
, new CodePrimitiveExpression (false), wasNullable
);
1928 else if (wasNullable
&& InvariantCompareNoCase(str
, "null"))
1929 return new CodePrimitiveExpression (null);
1931 throw new ParseException (currentLocation
,
1932 "Value '" + str
+ "' is not a valid boolean.");
1933 } else if (type
== monoTypeType
)
1934 type
= typeof (System
.Type
);
1937 return new CodePrimitiveExpression (null);
1939 if (type
.IsPrimitive
)
1940 return CreateNullableExpression (originalType
,
1941 new CodePrimitiveExpression (
1942 Convert
.ChangeType (preConverted
? convertedFromAttr
: str
,
1943 type
, Helpers
.InvariantCulture
)),
1946 if (type
== typeof (string [])) {
1950 subs
= (string[])convertedFromAttr
;
1952 subs
= str
.Split (',');
1953 CodeArrayCreateExpression expr
= new CodeArrayCreateExpression ();
1954 expr
.CreateType
= new CodeTypeReference (typeof (string));
1955 foreach (string v
in subs
)
1956 expr
.Initializers
.Add (new CodePrimitiveExpression (v
.Trim ()));
1958 return CreateNullableExpression (originalType
, expr
, wasNullable
);
1961 if (type
== typeof (Color
)) {
1964 if (!preConverted
) {
1965 if (colorConverter
== null)
1966 colorConverter
= TypeDescriptor
.GetConverter (typeof (Color
));
1968 if (str
.Trim().Length
== 0) {
1969 CodeTypeReferenceExpression ft
= new CodeTypeReferenceExpression (typeof (Color
));
1970 return CreateNullableExpression (originalType
,
1971 new CodeFieldReferenceExpression (ft
, "Empty"),
1976 if (str
.IndexOf (',') == -1) {
1977 c
= (Color
) colorConverter
.ConvertFromString (str
);
1979 int [] argb
= new int [4];
1982 string [] parts
= str
.Split (',');
1983 int length
= parts
.Length
;
1985 throw new Exception ();
1987 int basei
= (length
== 4) ? 0 : 1;
1988 for (int i
= length
- 1; i
>= 0; i
--) {
1989 argb
[basei
+ i
] = (int) Byte
.Parse (parts
[i
]);
1991 c
= Color
.FromArgb (argb
[0], argb
[1], argb
[2], argb
[3]);
1993 } catch (Exception e
) {
1994 // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
1995 // TypeConverter for Color fails to ConvertFromString.
1996 // Hence this hack...
1997 if (InvariantCompareNoCase ("LightGrey", str
)) {
1998 c
= Color
.LightGray
;
2000 throw new ParseException (currentLocation
,
2001 "Color " + str
+ " is not a valid color.", e
);
2005 c
= (Color
)convertedFromAttr
;
2007 if (c
.IsKnownColor
) {
2008 CodeFieldReferenceExpression expr
= new CodeFieldReferenceExpression ();
2009 if (c
.IsSystemColor
)
2010 type
= typeof (SystemColors
);
2012 expr
.TargetObject
= new CodeTypeReferenceExpression (type
);
2013 expr
.FieldName
= c
.Name
;
2014 return CreateNullableExpression (originalType
, expr
, wasNullable
);
2016 CodeMethodReferenceExpression m
= new CodeMethodReferenceExpression ();
2017 m
.TargetObject
= new CodeTypeReferenceExpression (type
);
2018 m
.MethodName
= "FromArgb";
2019 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (m
);
2020 invoke
.Parameters
.Add (new CodePrimitiveExpression (c
.A
));
2021 invoke
.Parameters
.Add (new CodePrimitiveExpression (c
.R
));
2022 invoke
.Parameters
.Add (new CodePrimitiveExpression (c
.G
));
2023 invoke
.Parameters
.Add (new CodePrimitiveExpression (c
.B
));
2024 return CreateNullableExpression (originalType
, invoke
, wasNullable
);
2028 TypeConverter converter
= preConverted
? cvt
: wasNullable
? TypeDescriptor
.GetConverter (type
) : null;
2029 if (converter
== null) {
2030 PropertyDescriptor pdesc
= TypeDescriptor
.GetProperties (member
.DeclaringType
) [member
.Name
];
2032 converter
= pdesc
.Converter
;
2035 switch (member
.MemberType
) {
2036 case MemberTypes
.Field
:
2037 memberType
= ((FieldInfo
)member
).FieldType
;
2040 case MemberTypes
.Property
:
2041 memberType
= ((PropertyInfo
)member
).PropertyType
;
2049 if (memberType
== null)
2052 converter
= TypeDescriptor
.GetConverter (memberType
);
2056 if (preConverted
|| (converter
!= null && SafeCanConvertFrom (typeof (string), converter
))) {
2057 object value = preConverted
? convertedFromAttr
: converter
.ConvertFromInvariantString (str
);
2059 if (SafeCanConvertTo (typeof (InstanceDescriptor
), converter
)) {
2060 InstanceDescriptor idesc
= (InstanceDescriptor
) converter
.ConvertTo (value, typeof(InstanceDescriptor
));
2062 return CreateNullableExpression (originalType
, GenerateInstance (idesc
, true),
2065 CodeExpression instance
= GenerateInstance (idesc
, true);
2067 return new CodeCastExpression (type
, instance
);
2072 CodeExpression exp
= GenerateObjectInstance (value, false);
2074 return CreateNullableExpression (originalType
, exp
, wasNullable
);
2076 CodeMethodReferenceExpression m
= new CodeMethodReferenceExpression ();
2077 m
.TargetObject
= new CodeTypeReferenceExpression (typeof (TypeDescriptor
));
2078 m
.MethodName
= "GetConverter";
2079 CodeMethodInvokeExpression invoke
= new CodeMethodInvokeExpression (m
);
2080 CodeTypeReference tref
= new CodeTypeReference (type
);
2081 invoke
.Parameters
.Add (new CodeTypeOfExpression (tref
));
2083 invoke
= new CodeMethodInvokeExpression (invoke
, "ConvertFrom");
2084 invoke
.Parameters
.Add (new CodePrimitiveExpression (str
));
2087 return CreateNullableExpression (originalType
, invoke
, wasNullable
);
2089 return new CodeCastExpression (type
, invoke
);
2092 Console
.WriteLine ("Unknown type: " + type
+ " value: " + str
);
2094 return CreateNullableExpression (originalType
, new CodePrimitiveExpression (str
), wasNullable
);
2097 CodeExpression
GenerateInstance (InstanceDescriptor idesc
, bool throwOnError
)
2099 CodeExpression
[] parameters
= new CodeExpression
[idesc
.Arguments
.Count
];
2101 foreach (object ob
in idesc
.Arguments
) {
2102 CodeExpression exp
= GenerateObjectInstance (ob
, throwOnError
);
2103 if (exp
== null) return null;
2104 parameters
[n
++] = exp
;
2107 switch (idesc
.MemberInfo
.MemberType
) {
2108 case MemberTypes
.Constructor
:
2109 CodeTypeReference tob
= new CodeTypeReference (idesc
.MemberInfo
.DeclaringType
);
2110 return new CodeObjectCreateExpression (tob
, parameters
);
2112 case MemberTypes
.Method
:
2113 CodeTypeReferenceExpression mt
= new CodeTypeReferenceExpression (idesc
.MemberInfo
.DeclaringType
);
2114 return new CodeMethodInvokeExpression (mt
, idesc
.MemberInfo
.Name
, parameters
);
2116 case MemberTypes
.Field
:
2117 CodeTypeReferenceExpression ft
= new CodeTypeReferenceExpression (idesc
.MemberInfo
.DeclaringType
);
2118 return new CodeFieldReferenceExpression (ft
, idesc
.MemberInfo
.Name
);
2120 case MemberTypes
.Property
:
2121 CodeTypeReferenceExpression pt
= new CodeTypeReferenceExpression (idesc
.MemberInfo
.DeclaringType
);
2122 return new CodePropertyReferenceExpression (pt
, idesc
.MemberInfo
.Name
);
2124 throw new ParseException (currentLocation
, "Invalid instance type.");
2127 CodeExpression
GenerateObjectInstance (object value, bool throwOnError
)
2130 return new CodePrimitiveExpression (null);
2132 if (value is System
.Type
) {
2133 CodeTypeReference tref
= new CodeTypeReference (value.ToString ());
2134 return new CodeTypeOfExpression (tref
);
2137 Type t
= value.GetType ();
2139 if (t
.IsPrimitive
|| value is string)
2140 return new CodePrimitiveExpression (value);
2143 Array ar
= (Array
) value;
2144 CodeExpression
[] items
= new CodeExpression
[ar
.Length
];
2145 for (int n
=0; n
<ar
.Length
; n
++) {
2146 CodeExpression exp
= GenerateObjectInstance (ar
.GetValue (n
), throwOnError
);
2147 if (exp
== null) return null;
2150 return new CodeArrayCreateExpression (new CodeTypeReference (t
), items
);
2153 TypeConverter converter
= TypeDescriptor
.GetConverter (t
);
2154 if (converter
!= null && converter
.CanConvertTo (typeof (InstanceDescriptor
))) {
2155 InstanceDescriptor idesc
= (InstanceDescriptor
) converter
.ConvertTo (value, typeof(InstanceDescriptor
));
2156 return GenerateInstance (idesc
, throwOnError
);
2159 InstanceDescriptor desc
= GetDefaultInstanceDescriptor (value);
2160 if (desc
!= null) return GenerateInstance (desc
, throwOnError
);
2163 throw new ParseException (currentLocation
, "Cannot generate an instance for the type: " + t
);
2168 InstanceDescriptor
GetDefaultInstanceDescriptor (object value)
2170 if (value is System
.Web
.UI
.WebControls
.Unit
) {
2171 System
.Web
.UI
.WebControls
.Unit s
= (System
.Web
.UI
.WebControls
.Unit
) value;
2173 FieldInfo f
= typeof (Unit
).GetField ("Empty");
2174 return new InstanceDescriptor (f
, null);
2176 ConstructorInfo c
= typeof(System
.Web
.UI
.WebControls
.Unit
).GetConstructor (
2177 BindingFlags
.Instance
| BindingFlags
.Public
,
2179 new Type
[] {typeof(double), typeof(System.Web.UI.WebControls.UnitType)}
,
2182 return new InstanceDescriptor (c
, new object[] {s.Value, s.Type}
);
2185 if (value is System
.Web
.UI
.WebControls
.FontUnit
) {
2186 System
.Web
.UI
.WebControls
.FontUnit s
= (System
.Web
.UI
.WebControls
.FontUnit
) value;
2188 FieldInfo f
= typeof (FontUnit
).GetField ("Empty");
2189 return new InstanceDescriptor (f
, null);
2192 Type cParamType
= null;
2193 object cParam
= null;
2196 case FontSize
.AsUnit
:
2197 case FontSize
.NotSet
:
2198 cParamType
= typeof (System
.Web
.UI
.WebControls
.Unit
);
2203 cParamType
= typeof (string);
2204 cParam
= s
.Type
.ToString ();
2208 ConstructorInfo c
= typeof(System
.Web
.UI
.WebControls
.FontUnit
).GetConstructor (
2209 BindingFlags
.Instance
| BindingFlags
.Public
,
2211 new Type
[] {cParamType}
,
2214 return new InstanceDescriptor (c
, new object[] {cParam}
);
2220 CodeMethodInvokeExpression
CreateConsoleWriteLineCall (string format
, params CodeExpression
[] parms
)
2222 CodeMethodReferenceExpression cwl
= new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (typeof (System
.Console
)), "WriteLine");
2223 CodeMethodInvokeExpression cwlCall
= new CodeMethodInvokeExpression (cwl
);
2225 cwlCall
.Parameters
.Add (new CodePrimitiveExpression (format
));
2226 if (parms
!= null && parms
.Length
> 0)
2227 foreach (CodeExpression expr
in parms
)
2228 cwlCall
.Parameters
.Add (expr
);