2
0

ControlBuilder.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. 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 typeof (Control);
  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. if (childrenAsProperties) {
  145. AppendToProperty (subBuilder);
  146. return;
  147. }
  148. if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
  149. AppendCode (subBuilder);
  150. return;
  151. }
  152. if (children == null)
  153. children = new ArrayList ();
  154. children.Add (subBuilder);
  155. }
  156. void AppendToProperty (ControlBuilder subBuilder)
  157. {
  158. if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
  159. throw new HttpException ("Code render not supported here.");
  160. if (defaultPropertyBuilder != null) {
  161. defaultPropertyBuilder.AppendSubBuilder (subBuilder);
  162. return;
  163. }
  164. if (children == null)
  165. children = new ArrayList ();
  166. children.Add (subBuilder);
  167. }
  168. void AppendCode (ControlBuilder subBuilder)
  169. {
  170. if (type != null && !(typeof (Control).IsAssignableFrom (type)))
  171. throw new HttpException ("Code render not supported here.");
  172. if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
  173. hasAspCode = true;
  174. if (children == null)
  175. children = new ArrayList ();
  176. children.Add (subBuilder);
  177. }
  178. public virtual void CloseControl ()
  179. {
  180. }
  181. public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
  182. ControlBuilder parentBuilder,
  183. Type type,
  184. string tagName,
  185. string id,
  186. IDictionary attribs,
  187. int line,
  188. string sourceFileName)
  189. {
  190. ControlBuilder builder;
  191. object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
  192. if (atts != null && atts.Length > 0) {
  193. ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
  194. builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
  195. } else {
  196. builder = new ControlBuilder ();
  197. }
  198. builder.Init (parser, parentBuilder, type, tagName, id, attribs);
  199. builder.line = line;
  200. builder.fileName = sourceFileName;
  201. return builder;
  202. }
  203. public virtual Type GetChildControlType (string tagName, IDictionary attribs)
  204. {
  205. return null;
  206. }
  207. public virtual bool HasBody ()
  208. {
  209. return true;
  210. }
  211. public virtual bool HtmlDecodeLiterals ()
  212. {
  213. return false;
  214. }
  215. ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
  216. {
  217. PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
  218. if (prop == null) {
  219. string msg = String.Format ("Property {0} not found in type {1}", propName, type);
  220. throw new HttpException (msg);
  221. }
  222. Type propType = prop.PropertyType;
  223. ControlBuilder builder = null;
  224. if (typeof (ICollection).IsAssignableFrom (propType)) {
  225. builder = new CollectionBuilder ();
  226. } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
  227. builder = new TemplateBuilder ();
  228. } else {
  229. builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
  230. null, atts, line, fileName);
  231. builder.isProperty = true;
  232. return builder;
  233. }
  234. builder.Init (parser, this, null, prop.Name, null, atts);
  235. builder.fileName = fileName;
  236. builder.line = line;
  237. builder.isProperty = true;
  238. return builder;
  239. }
  240. public virtual void Init (TemplateParser parser,
  241. ControlBuilder parentBuilder,
  242. Type type,
  243. string tagName,
  244. string id,
  245. IDictionary attribs)
  246. {
  247. this.parser = parser;
  248. if (parser != null)
  249. this.location = parser.Location;
  250. this.parentBuilder = parentBuilder;
  251. this.type = type;
  252. this.tagName = tagName;
  253. this.id = id;
  254. this.attribs = attribs;
  255. if (type == null)
  256. return;
  257. if (this is TemplateBuilder)
  258. return;
  259. if (!typeof (IParserAccessor).IsAssignableFrom (type)) {
  260. isIParserAccessor = false;
  261. childrenAsProperties = true;
  262. } else {
  263. object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
  264. if (atts != null && atts.Length > 0) {
  265. ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
  266. childrenAsProperties = att.ChildrenAsProperties;
  267. if (childrenAsProperties && att.DefaultProperty != "") {
  268. defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
  269. parser, null);
  270. }
  271. }
  272. }
  273. }
  274. public virtual bool NeedsTagInnerText ()
  275. {
  276. return false;
  277. }
  278. public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
  279. {
  280. if (defaultPropertyBuilder == null)
  281. return;
  282. ControlBuilder old = defaultPropertyBuilder;
  283. defaultPropertyBuilder = null;
  284. AppendSubBuilder (old);
  285. }
  286. public virtual void SetTagInnerText (string text)
  287. {
  288. }
  289. internal string GetNextID (string proposedID)
  290. {
  291. if (proposedID != null && proposedID.Trim () != "")
  292. return proposedID;
  293. return "_bctrl_" + nextID++;
  294. }
  295. internal virtual ControlBuilder CreateSubBuilder (string tagid,
  296. Hashtable atts,
  297. Type childType,
  298. TemplateParser parser,
  299. ILocation location)
  300. {
  301. ControlBuilder childBuilder = null;
  302. if (childrenAsProperties) {
  303. if (defaultPropertyBuilder == null) {
  304. childBuilder = CreatePropertyBuilder (tagid, parser, atts);
  305. } else {
  306. childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
  307. null, parser, location);
  308. }
  309. return childBuilder;
  310. }
  311. childType = GetChildControlType (tagid, atts);
  312. if (childType == null)
  313. return null;
  314. childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
  315. location.BeginLine, location.Filename);
  316. return childBuilder;
  317. }
  318. internal virtual object CreateInstance ()
  319. {
  320. // HtmlGenericControl, HtmlTableCell...
  321. object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
  322. object [] args = null;
  323. if (atts != null && atts.Length > 0) {
  324. ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
  325. if (att.NeedsTag)
  326. args = new object [] {tagName};
  327. }
  328. return Activator.CreateInstance (type, args);
  329. }
  330. internal virtual void CreateChildren (object parent)
  331. {
  332. if (children == null || children.Count == 0)
  333. return;
  334. IParserAccessor parser = parent as IParserAccessor;
  335. if (parser == null)
  336. return;
  337. foreach (object o in children) {
  338. if (o is string) {
  339. parser.AddParsedSubObject (new LiteralControl ((string) o));
  340. } else {
  341. parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());
  342. }
  343. }
  344. }
  345. }
  346. }