ControlBuilder.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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. protected int line;
  30. protected 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. public bool FChildrenAsProperties {
  68. get { return childrenAsProperties; }
  69. }
  70. public 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. protected void SetControlType (Type t)
  84. {
  85. type = t;
  86. }
  87. [MonoTODO]
  88. public bool InDesigner {
  89. get { return false; }
  90. }
  91. public Type NamingContainerType {
  92. get {
  93. if (parentBuilder == null)
  94. return typeof (Control);
  95. Type ptype = parentBuilder.ControlType;
  96. if (ptype == null)
  97. return parentBuilder.NamingContainerType;
  98. if (!typeof (INamingContainer).IsAssignableFrom (ptype))
  99. return parentBuilder.NamingContainerType;
  100. return ptype;
  101. }
  102. }
  103. protected TemplateParser Parser {
  104. get { return parser; }
  105. }
  106. public string TagName {
  107. get { return tagName; }
  108. }
  109. internal RootBuilder Root {
  110. get {
  111. if (GetType () == typeof (RootBuilder))
  112. return (RootBuilder) this;
  113. return (RootBuilder) parentBuilder.Root;
  114. }
  115. }
  116. public virtual bool AllowWhitespaceLiterals ()
  117. {
  118. return true;
  119. }
  120. public virtual void AppendLiteralString (string s)
  121. {
  122. if (s == null || s == "")
  123. return;
  124. if (childrenAsProperties || !isIParserAccessor) {
  125. if (defaultPropertyBuilder != null) {
  126. defaultPropertyBuilder.AppendLiteralString (s);
  127. } else if (s.Trim () != "") {
  128. throw new HttpException ("Literal content not allowed for " + tagName + " " +
  129. GetType () + " \"" + s + "\"");
  130. }
  131. return;
  132. }
  133. if (!AllowWhitespaceLiterals () && s.Trim () == "")
  134. return;
  135. if (HtmlDecodeLiterals ())
  136. s = HttpUtility.HtmlDecode (s);
  137. if (children == null)
  138. children = new ArrayList ();
  139. children.Add (s);
  140. }
  141. public virtual void AppendSubBuilder (ControlBuilder subBuilder)
  142. {
  143. subBuilder.OnAppendToParentBuilder (this);
  144. subBuilder.parentBuilder = this;
  145. if (childrenAsProperties) {
  146. AppendToProperty (subBuilder);
  147. return;
  148. }
  149. if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
  150. AppendCode (subBuilder);
  151. return;
  152. }
  153. if (children == null)
  154. children = new ArrayList ();
  155. children.Add (subBuilder);
  156. }
  157. void AppendToProperty (ControlBuilder subBuilder)
  158. {
  159. if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
  160. throw new HttpException ("Code render not supported here.");
  161. if (defaultPropertyBuilder != null) {
  162. defaultPropertyBuilder.AppendSubBuilder (subBuilder);
  163. return;
  164. }
  165. if (children == null)
  166. children = new ArrayList ();
  167. children.Add (subBuilder);
  168. }
  169. void AppendCode (ControlBuilder subBuilder)
  170. {
  171. if (type != null && !(typeof (Control).IsAssignableFrom (type)))
  172. throw new HttpException ("Code render not supported here.");
  173. if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
  174. hasAspCode = true;
  175. if (children == null)
  176. children = new ArrayList ();
  177. children.Add (subBuilder);
  178. }
  179. public virtual void CloseControl ()
  180. {
  181. }
  182. public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
  183. ControlBuilder parentBuilder,
  184. Type type,
  185. string tagName,
  186. string id,
  187. IDictionary attribs,
  188. int line,
  189. string sourceFileName)
  190. {
  191. ControlBuilder builder;
  192. object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
  193. if (atts != null && atts.Length > 0) {
  194. ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
  195. builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
  196. } else {
  197. builder = new ControlBuilder ();
  198. }
  199. builder.Init (parser, parentBuilder, type, tagName, id, attribs);
  200. builder.line = line;
  201. builder.fileName = sourceFileName;
  202. return builder;
  203. }
  204. public virtual Type GetChildControlType (string tagName, IDictionary attribs)
  205. {
  206. return null;
  207. }
  208. public virtual bool HasBody ()
  209. {
  210. return true;
  211. }
  212. public virtual bool HtmlDecodeLiterals ()
  213. {
  214. return false;
  215. }
  216. ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
  217. {
  218. PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
  219. if (prop == null) {
  220. string msg = String.Format ("Property {0} not found in type {1}", propName, type);
  221. throw new HttpException (msg);
  222. }
  223. Type propType = prop.PropertyType;
  224. ControlBuilder builder = null;
  225. if (typeof (ICollection).IsAssignableFrom (propType)) {
  226. builder = new CollectionBuilder ();
  227. } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
  228. builder = new TemplateBuilder ();
  229. } else {
  230. builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
  231. null, atts, line, fileName);
  232. builder.isProperty = true;
  233. return builder;
  234. }
  235. builder.Init (parser, this, null, prop.Name, null, atts);
  236. builder.fileName = fileName;
  237. builder.line = line;
  238. builder.isProperty = true;
  239. return builder;
  240. }
  241. public virtual void Init (TemplateParser parser,
  242. ControlBuilder parentBuilder,
  243. Type type,
  244. string tagName,
  245. string id,
  246. IDictionary attribs)
  247. {
  248. this.parser = parser;
  249. if (parser != null)
  250. this.location = parser.Location;
  251. this.parentBuilder = parentBuilder;
  252. this.type = type;
  253. this.tagName = tagName;
  254. this.id = id;
  255. this.attribs = attribs;
  256. if (type == null)
  257. return;
  258. if (this is TemplateBuilder)
  259. return;
  260. if (!typeof (IParserAccessor).IsAssignableFrom (type)) {
  261. isIParserAccessor = false;
  262. childrenAsProperties = true;
  263. } else {
  264. object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
  265. if (atts != null && atts.Length > 0) {
  266. ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
  267. childrenAsProperties = att.ChildrenAsProperties;
  268. if (childrenAsProperties && att.DefaultProperty != "") {
  269. defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
  270. parser, null);
  271. }
  272. }
  273. }
  274. }
  275. public virtual bool NeedsTagInnerText ()
  276. {
  277. return false;
  278. }
  279. public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
  280. {
  281. if (defaultPropertyBuilder == null)
  282. return;
  283. ControlBuilder old = defaultPropertyBuilder;
  284. defaultPropertyBuilder = null;
  285. AppendSubBuilder (old);
  286. }
  287. public virtual void SetTagInnerText (string text)
  288. {
  289. }
  290. internal string GetNextID (string proposedID)
  291. {
  292. if (proposedID != null && proposedID.Trim () != "")
  293. return proposedID;
  294. return "_bctrl_" + nextID++;
  295. }
  296. internal virtual ControlBuilder CreateSubBuilder (string tagid,
  297. Hashtable atts,
  298. Type childType,
  299. TemplateParser parser,
  300. ILocation location)
  301. {
  302. ControlBuilder childBuilder = null;
  303. if (childrenAsProperties) {
  304. if (defaultPropertyBuilder == null) {
  305. childBuilder = CreatePropertyBuilder (tagid, parser, atts);
  306. } else {
  307. childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
  308. null, parser, location);
  309. }
  310. return childBuilder;
  311. }
  312. childType = GetChildControlType (tagid, atts);
  313. if (childType == null)
  314. return null;
  315. childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
  316. location.BeginLine, location.Filename);
  317. return childBuilder;
  318. }
  319. internal virtual object CreateInstance ()
  320. {
  321. // HtmlGenericControl, HtmlTableCell...
  322. object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
  323. object [] args = null;
  324. if (atts != null && atts.Length > 0) {
  325. ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
  326. if (att.NeedsTag)
  327. args = new object [] {tagName};
  328. }
  329. return Activator.CreateInstance (type, args);
  330. }
  331. internal virtual void CreateChildren (object parent)
  332. {
  333. if (children == null || children.Count == 0)
  334. return;
  335. IParserAccessor parser = parent as IParserAccessor;
  336. if (parser == null)
  337. return;
  338. foreach (object o in children) {
  339. if (o is string) {
  340. parser.AddParsedSubObject (new LiteralControl ((string) o));
  341. } else {
  342. parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());
  343. }
  344. }
  345. }
  346. }
  347. }