ControlBuilder.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. //
  2. // System.Web.UI.ControlBuilder.cs
  3. //
  4. // Authors:
  5. // Duncan Mak ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (C) 2002, 2003 Ximian, Inc. (http://www.ximian.com)
  9. //
  10. using System;
  11. using System.Collections;
  12. using System.CodeDom;
  13. using System.Reflection;
  14. using System.Web;
  15. using System.Web.Compilation;
  16. namespace System.Web.UI {
  17. public class ControlBuilder
  18. {
  19. internal static BindingFlags flagsNoCase = BindingFlags.Public |
  20. BindingFlags.Instance |
  21. BindingFlags.Static |
  22. BindingFlags.IgnoreCase;
  23. TemplateParser parser;
  24. internal ControlBuilder parentBuilder;
  25. Type type;
  26. string tagName;
  27. string id;
  28. internal IDictionary attribs;
  29. internal int line;
  30. internal string fileName;
  31. bool childrenAsProperties;
  32. bool isIParserAccessor = true;
  33. bool hasAspCode;
  34. internal ControlBuilder defaultPropertyBuilder;
  35. ArrayList children;
  36. static int nextID;
  37. internal bool haveParserVariable;
  38. internal CodeMemberMethod method;
  39. internal CodeMemberMethod renderMethod;
  40. internal int renderIndex;
  41. internal bool isProperty;
  42. internal ILocation location;
  43. public ControlBuilder ()
  44. {
  45. }
  46. internal ControlBuilder (TemplateParser parser,
  47. ControlBuilder parentBuilder,
  48. Type type,
  49. string tagName,
  50. string id,
  51. IDictionary attribs,
  52. int line,
  53. string sourceFileName)
  54. {
  55. this.parser = parser;
  56. this.parentBuilder = parentBuilder;
  57. this.type = type;
  58. this.tagName = tagName;
  59. this.id = id;
  60. this.attribs = attribs;
  61. this.line = line;
  62. this.fileName = sourceFileName;
  63. }
  64. public Type ControlType {
  65. get { return type; }
  66. }
  67. protected bool FChildrenAsProperties {
  68. get { return childrenAsProperties; }
  69. }
  70. protected bool FIsNonParserAccessor {
  71. get { return !isIParserAccessor; }
  72. }
  73. public bool HasAspCode {
  74. get { return hasAspCode; }
  75. }
  76. public string ID {
  77. get { return id; }
  78. set { id = value; }
  79. }
  80. internal ArrayList Children {
  81. get { return children; }
  82. }
  83. internal void SetControlType (Type t)
  84. {
  85. type = t;
  86. }
  87. protected bool InDesigner {
  88. get { return false; }
  89. }
  90. public Type NamingContainerType {
  91. get {
  92. if (parentBuilder == null)
  93. return typeof (Control);
  94. Type ptype = parentBuilder.ControlType;
  95. if (ptype == null)
  96. return parentBuilder.NamingContainerType;
  97. if (!typeof (INamingContainer).IsAssignableFrom (ptype))
  98. return parentBuilder.NamingContainerType;
  99. return ptype;
  100. }
  101. }
  102. protected TemplateParser Parser {
  103. get { return parser; }
  104. }
  105. public string TagName {
  106. get { return tagName; }
  107. }
  108. internal RootBuilder Root {
  109. get {
  110. if (GetType () == typeof (RootBuilder))
  111. return (RootBuilder) this;
  112. return (RootBuilder) parentBuilder.Root;
  113. }
  114. }
  115. internal bool ChildrenAsProperties {
  116. get { return childrenAsProperties; }
  117. }
  118. public virtual bool AllowWhitespaceLiterals ()
  119. {
  120. return true;
  121. }
  122. public virtual void AppendLiteralString (string s)
  123. {
  124. if (s == null || s == "")
  125. return;
  126. if (childrenAsProperties || !isIParserAccessor) {
  127. if (defaultPropertyBuilder != null) {
  128. defaultPropertyBuilder.AppendLiteralString (s);
  129. } else if (s.Trim () != "") {
  130. throw new HttpException ("Literal content not allowed for " + tagName + " " +
  131. GetType () + " \"" + s + "\"");
  132. }
  133. return;
  134. }
  135. if (!AllowWhitespaceLiterals () && s.Trim () == "")
  136. return;
  137. if (HtmlDecodeLiterals ())
  138. s = HttpUtility.HtmlDecode (s);
  139. if (children == null)
  140. children = new ArrayList ();
  141. children.Add (s);
  142. }
  143. public virtual void AppendSubBuilder (ControlBuilder subBuilder)
  144. {
  145. subBuilder.OnAppendToParentBuilder (this);
  146. subBuilder.parentBuilder = this;
  147. if (childrenAsProperties) {
  148. AppendToProperty (subBuilder);
  149. return;
  150. }
  151. if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
  152. AppendCode (subBuilder);
  153. return;
  154. }
  155. if (children == null)
  156. children = new ArrayList ();
  157. children.Add (subBuilder);
  158. }
  159. void AppendToProperty (ControlBuilder subBuilder)
  160. {
  161. if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
  162. throw new HttpException ("Code render not supported here.");
  163. if (defaultPropertyBuilder != null) {
  164. defaultPropertyBuilder.AppendSubBuilder (subBuilder);
  165. return;
  166. }
  167. if (children == null)
  168. children = new ArrayList ();
  169. children.Add (subBuilder);
  170. }
  171. void AppendCode (ControlBuilder subBuilder)
  172. {
  173. if (type != null && !(typeof (Control).IsAssignableFrom (type)))
  174. throw new HttpException ("Code render not supported here.");
  175. if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
  176. hasAspCode = true;
  177. if (children == null)
  178. children = new ArrayList ();
  179. children.Add (subBuilder);
  180. }
  181. public virtual void CloseControl ()
  182. {
  183. }
  184. public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
  185. ControlBuilder parentBuilder,
  186. Type type,
  187. string tagName,
  188. string id,
  189. IDictionary attribs,
  190. int line,
  191. string sourceFileName)
  192. {
  193. ControlBuilder builder;
  194. object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
  195. if (atts != null && atts.Length > 0) {
  196. ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
  197. builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
  198. } else {
  199. builder = new ControlBuilder ();
  200. }
  201. builder.Init (parser, parentBuilder, type, tagName, id, attribs);
  202. builder.line = line;
  203. builder.fileName = sourceFileName;
  204. return builder;
  205. }
  206. public virtual Type GetChildControlType (string tagName, IDictionary attribs)
  207. {
  208. return null;
  209. }
  210. public virtual bool HasBody ()
  211. {
  212. return true;
  213. }
  214. public virtual bool HtmlDecodeLiterals ()
  215. {
  216. return false;
  217. }
  218. ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
  219. {
  220. PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
  221. if (prop == null) {
  222. string msg = String.Format ("Property {0} not found in type {1}", propName, type);
  223. throw new HttpException (msg);
  224. }
  225. Type propType = prop.PropertyType;
  226. ControlBuilder builder = null;
  227. if (typeof (ICollection).IsAssignableFrom (propType)) {
  228. builder = new CollectionBuilder ();
  229. } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
  230. builder = new TemplateBuilder ();
  231. } else {
  232. builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
  233. null, atts, line, fileName);
  234. builder.isProperty = true;
  235. return builder;
  236. }
  237. builder.Init (parser, this, null, prop.Name, null, atts);
  238. builder.fileName = fileName;
  239. builder.line = line;
  240. builder.isProperty = true;
  241. return builder;
  242. }
  243. public virtual void Init (TemplateParser parser,
  244. ControlBuilder parentBuilder,
  245. Type type,
  246. string tagName,
  247. string id,
  248. IDictionary attribs)
  249. {
  250. this.parser = parser;
  251. if (parser != null)
  252. this.location = parser.Location;
  253. this.parentBuilder = parentBuilder;
  254. this.type = type;
  255. this.tagName = tagName;
  256. this.id = id;
  257. this.attribs = attribs;
  258. if (type == null)
  259. return;
  260. if (this is TemplateBuilder)
  261. return;
  262. if (!typeof (IParserAccessor).IsAssignableFrom (type)) {
  263. isIParserAccessor = false;
  264. childrenAsProperties = true;
  265. } else {
  266. object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
  267. if (atts != null && atts.Length > 0) {
  268. ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
  269. childrenAsProperties = att.ChildrenAsProperties;
  270. if (childrenAsProperties && att.DefaultProperty != "") {
  271. defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
  272. parser, null);
  273. }
  274. }
  275. }
  276. }
  277. public virtual bool NeedsTagInnerText ()
  278. {
  279. return false;
  280. }
  281. public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
  282. {
  283. if (defaultPropertyBuilder == null)
  284. return;
  285. ControlBuilder old = defaultPropertyBuilder;
  286. defaultPropertyBuilder = null;
  287. AppendSubBuilder (old);
  288. }
  289. public virtual void SetTagInnerText (string text)
  290. {
  291. }
  292. internal string GetNextID (string proposedID)
  293. {
  294. if (proposedID != null && proposedID.Trim () != "")
  295. return proposedID;
  296. return "_bctrl_" + nextID++;
  297. }
  298. internal virtual ControlBuilder CreateSubBuilder (string tagid,
  299. Hashtable atts,
  300. Type childType,
  301. TemplateParser parser,
  302. ILocation location)
  303. {
  304. ControlBuilder childBuilder = null;
  305. if (childrenAsProperties) {
  306. if (defaultPropertyBuilder == null) {
  307. childBuilder = CreatePropertyBuilder (tagid, parser, atts);
  308. } else {
  309. childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
  310. null, parser, location);
  311. }
  312. return childBuilder;
  313. }
  314. childType = GetChildControlType (tagid, atts);
  315. if (childType == null)
  316. return null;
  317. childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
  318. location.BeginLine, location.Filename);
  319. return childBuilder;
  320. }
  321. internal virtual object CreateInstance ()
  322. {
  323. // HtmlGenericControl, HtmlTableCell...
  324. object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
  325. object [] args = null;
  326. if (atts != null && atts.Length > 0) {
  327. ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
  328. if (att.NeedsTag)
  329. args = new object [] {tagName};
  330. }
  331. return Activator.CreateInstance (type, args);
  332. }
  333. internal virtual void CreateChildren (object parent)
  334. {
  335. if (children == null || children.Count == 0)
  336. return;
  337. IParserAccessor parser = parent as IParserAccessor;
  338. if (parser == null)
  339. return;
  340. foreach (object o in children) {
  341. if (o is string) {
  342. parser.AddParsedSubObject (new LiteralControl ((string) o));
  343. } else {
  344. parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());
  345. }
  346. }
  347. }
  348. }
  349. }