2 // System.Web.UI.ControlBuilder.cs
5 // Duncan Mak (duncan@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) 2002, 2003 Ximian, Inc. (http://www.ximian.com)
12 using System.Collections;
14 using System.Reflection;
16 using System.Web.Compilation;
18 namespace System.Web.UI {
20 public class ControlBuilder
22 internal static BindingFlags flagsNoCase = BindingFlags.Public |
23 BindingFlags.Instance |
25 BindingFlags.IgnoreCase;
27 TemplateParser parser;
28 internal ControlBuilder parentBuilder;
32 internal IDictionary attribs;
34 internal string fileName;
35 bool childrenAsProperties;
36 bool isIParserAccessor = true;
38 internal ControlBuilder defaultPropertyBuilder;
42 internal bool haveParserVariable;
43 internal CodeMemberMethod method;
44 internal CodeMemberMethod renderMethod;
45 internal int renderIndex;
46 internal bool isProperty;
47 internal ILocation location;
49 public ControlBuilder ()
53 internal ControlBuilder (TemplateParser parser,
54 ControlBuilder parentBuilder,
60 string sourceFileName)
64 this.parentBuilder = parentBuilder;
66 this.tagName = tagName;
68 this.attribs = attribs;
70 this.fileName = sourceFileName;
73 public Type ControlType {
77 protected bool FChildrenAsProperties {
78 get { return childrenAsProperties; }
81 protected bool FIsNonParserAccessor {
82 get { return !isIParserAccessor; }
85 public bool HasAspCode {
86 get { return hasAspCode; }
94 internal ArrayList Children {
95 get { return children; }
98 internal void SetControlType (Type t)
103 protected bool InDesigner {
104 get { return false; }
107 public Type NamingContainerType {
109 if (parentBuilder == null)
110 return typeof (Control);
112 Type ptype = parentBuilder.ControlType;
114 return parentBuilder.NamingContainerType;
116 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
117 return parentBuilder.NamingContainerType;
123 protected TemplateParser Parser {
124 get { return parser; }
127 public string TagName {
128 get { return tagName; }
131 internal RootBuilder Root {
133 if (GetType () == typeof (RootBuilder))
134 return (RootBuilder) this;
136 return (RootBuilder) parentBuilder.Root;
140 internal bool ChildrenAsProperties {
141 get { return childrenAsProperties; }
144 public virtual bool AllowWhitespaceLiterals ()
149 public virtual void AppendLiteralString (string s)
151 if (s == null || s == "")
154 if (childrenAsProperties || !isIParserAccessor) {
155 if (defaultPropertyBuilder != null) {
156 defaultPropertyBuilder.AppendLiteralString (s);
157 } else if (s.Trim () != "") {
158 throw new HttpException ("Literal content not allowed for " + tagName + " " +
159 GetType () + " \"" + s + "\"");
165 if (!AllowWhitespaceLiterals () && s.Trim () == "")
168 if (HtmlDecodeLiterals ())
169 s = HttpUtility.HtmlDecode (s);
171 if (children == null)
172 children = new ArrayList ();
177 public virtual void AppendSubBuilder (ControlBuilder subBuilder)
179 subBuilder.OnAppendToParentBuilder (this);
181 subBuilder.parentBuilder = this;
182 if (childrenAsProperties) {
183 AppendToProperty (subBuilder);
187 if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
188 AppendCode (subBuilder);
192 if (children == null)
193 children = new ArrayList ();
195 children.Add (subBuilder);
198 void AppendToProperty (ControlBuilder subBuilder)
200 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
201 throw new HttpException ("Code render not supported here.");
203 if (defaultPropertyBuilder != null) {
204 defaultPropertyBuilder.AppendSubBuilder (subBuilder);
208 if (children == null)
209 children = new ArrayList ();
211 children.Add (subBuilder);
214 void AppendCode (ControlBuilder subBuilder)
216 if (type != null && !(typeof (Control).IsAssignableFrom (type)))
217 throw new HttpException ("Code render not supported here.");
219 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
222 if (children == null)
223 children = new ArrayList ();
225 children.Add (subBuilder);
228 public virtual void CloseControl ()
232 public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
233 ControlBuilder parentBuilder,
239 string sourceFileName)
241 ControlBuilder builder;
242 object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
243 if (atts != null && atts.Length > 0) {
244 ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
245 builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
247 builder = new ControlBuilder ();
250 builder.Init (parser, parentBuilder, type, tagName, id, attribs);
252 builder.fileName = sourceFileName;
256 public virtual Type GetChildControlType (string tagName, IDictionary attribs)
261 public virtual bool HasBody ()
266 public virtual bool HtmlDecodeLiterals ()
271 ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
273 PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
275 string msg = String.Format ("Property {0} not found in type {1}", propName, type);
276 throw new HttpException (msg);
279 Type propType = prop.PropertyType;
280 ControlBuilder builder = null;
281 if (typeof (ICollection).IsAssignableFrom (propType)) {
282 builder = new CollectionBuilder ();
283 } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
284 builder = new TemplateBuilder ();
286 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
287 null, atts, line, fileName);
288 builder.isProperty = true;
292 builder.Init (parser, this, null, prop.Name, null, atts);
293 builder.fileName = fileName;
295 builder.isProperty = true;
299 public virtual void Init (TemplateParser parser,
300 ControlBuilder parentBuilder,
306 this.parser = parser;
308 this.location = parser.Location;
310 this.parentBuilder = parentBuilder;
312 this.tagName = tagName;
314 this.attribs = attribs;
318 if (this is TemplateBuilder)
321 if (!typeof (IParserAccessor).IsAssignableFrom (type)) {
322 isIParserAccessor = false;
323 childrenAsProperties = true;
325 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
326 if (atts != null && atts.Length > 0) {
327 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
328 childrenAsProperties = att.ChildrenAsProperties;
329 if (childrenAsProperties && att.DefaultProperty != "") {
330 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
337 public virtual bool NeedsTagInnerText ()
342 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
344 if (defaultPropertyBuilder == null)
347 ControlBuilder old = defaultPropertyBuilder;
348 defaultPropertyBuilder = null;
349 AppendSubBuilder (old);
352 public virtual void SetTagInnerText (string text)
356 internal string GetNextID (string proposedID)
358 if (proposedID != null && proposedID.Trim () != "")
361 return "_bctrl_" + nextID++;
364 internal virtual ControlBuilder CreateSubBuilder (string tagid,
367 TemplateParser parser,
370 ControlBuilder childBuilder = null;
371 if (childrenAsProperties) {
372 if (defaultPropertyBuilder == null) {
373 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
375 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
376 null, parser, location);
381 childType = GetChildControlType (tagid, atts);
382 if (childType == null)
385 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
386 location.BeginLine, location.Filename);
391 internal virtual object CreateInstance ()
393 // HtmlGenericControl, HtmlTableCell...
394 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
395 object [] args = null;
396 if (atts != null && atts.Length > 0) {
397 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
399 args = new object [] {tagName};
402 return Activator.CreateInstance (type, args);
405 internal virtual void CreateChildren (object parent)
407 if (children == null || children.Count == 0)
410 IParserAccessor parser = parent as IParserAccessor;
414 foreach (object o in children) {
416 parser.AddParsedSubObject (new LiteralControl ((string) o));
418 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());