AspElements.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. //
  2. // System.Web.Compilation.AspElements
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2002 Ximian, Inc (http://www.ximian.com)
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.Reflection;
  12. using System.Text;
  13. using System.Web.UI;
  14. using System.Web.UI.HtmlControls;
  15. using System.Web.UI.WebControls;
  16. namespace System.Web.Compilation
  17. {
  18. enum ElementType
  19. {
  20. TAG,
  21. PLAINTEXT
  22. }
  23. abstract class Element
  24. {
  25. private ElementType elementType;
  26. public Element (ElementType type)
  27. {
  28. elementType = type;
  29. }
  30. public ElementType GetElementType
  31. {
  32. get { return elementType; }
  33. }
  34. } // class Element
  35. class PlainText : Element
  36. {
  37. private StringBuilder text;
  38. public PlainText () : base (ElementType.PLAINTEXT)
  39. {
  40. text = new StringBuilder ();
  41. }
  42. public PlainText (StringBuilder text) : base (ElementType.PLAINTEXT)
  43. {
  44. this.text = text;
  45. }
  46. public PlainText (string text) : this ()
  47. {
  48. this.text.Append (text);
  49. }
  50. public void Append (string more)
  51. {
  52. text.Append (more);
  53. }
  54. public string Text
  55. {
  56. get { return text.ToString (); }
  57. }
  58. public override string ToString ()
  59. {
  60. return "PlainText: " + Text;
  61. }
  62. }
  63. enum TagType
  64. {
  65. DIRECTIVE,
  66. HTML,
  67. HTMLCONTROL,
  68. SERVERCONTROL,
  69. INLINEVAR,
  70. INLINECODE,
  71. CLOSING,
  72. SERVEROBJECT,
  73. PROPERTYTAG,
  74. CODERENDER,
  75. DATABINDING,
  76. NOTYET
  77. }
  78. /*
  79. * Attributes and values are stored in a couple of ArrayList in Add ().
  80. * When MakeHash () is called, they are converted to a Hashtable. If there are any
  81. * attributes duplicated it throws an ArgumentException.
  82. *
  83. * The [] operator works with the Hashtable if the values are in it, otherwise
  84. * it uses the ArrayList's.
  85. *
  86. * Why? You can have a tag in HTML like <a att="value" att="xxx">, but not in tags
  87. * marked runat=server and Hashtable requires the key to be unique.
  88. *
  89. */
  90. class TagAttributes
  91. {
  92. private Hashtable atts_hash;
  93. private ArrayList keys;
  94. private ArrayList values;
  95. private bool got_hashed;
  96. public TagAttributes ()
  97. {
  98. got_hashed = false;
  99. keys = new ArrayList ();
  100. values = new ArrayList ();
  101. }
  102. private void MakeHash ()
  103. {
  104. atts_hash = new Hashtable (new CaseInsensitiveHashCodeProvider (),
  105. new CaseInsensitiveComparer ());
  106. for (int i = 0; i < keys.Count; i++)
  107. atts_hash.Add (keys [i], values [i]);
  108. got_hashed = true;
  109. keys = null;
  110. values = null;
  111. }
  112. public bool IsRunAtServer ()
  113. {
  114. return got_hashed;
  115. }
  116. public void Add (object key, object value)
  117. {
  118. if (key != null && value != null &&
  119. 0 == String.Compare ((string) key, "runat", true) &&
  120. 0 == String.Compare ((string) value, "server", true))
  121. MakeHash ();
  122. if (got_hashed)
  123. atts_hash.Add (key, value);
  124. else {
  125. keys.Add (key);
  126. values.Add (value);
  127. }
  128. }
  129. public ICollection Keys
  130. {
  131. get { return (got_hashed ? atts_hash.Keys : keys); }
  132. }
  133. private int CaseInsensitiveSearch (string key)
  134. {
  135. // Hope not to have many attributes when the tag is not a server tag...
  136. for (int i = 0; i < keys.Count; i++){
  137. if (0 == String.Compare ((string) keys [i], key, true))
  138. return i;
  139. }
  140. return -1;
  141. }
  142. public object this [object key]
  143. {
  144. get {
  145. if (got_hashed)
  146. return atts_hash [key];
  147. int idx = CaseInsensitiveSearch ((string) key);
  148. if (idx == -1)
  149. return null;
  150. return values [idx];
  151. }
  152. set {
  153. if (got_hashed)
  154. atts_hash [key] = value;
  155. else {
  156. int idx = CaseInsensitiveSearch ((string) key);
  157. keys [idx] = value;
  158. }
  159. }
  160. }
  161. public int Count
  162. {
  163. get { return (got_hashed ? atts_hash.Count : keys.Count);}
  164. }
  165. public bool IsDataBound (string att)
  166. {
  167. if (att == null || !got_hashed)
  168. return false;
  169. return (att.StartsWith ("<%#") && att.EndsWith ("%>"));
  170. }
  171. public override string ToString ()
  172. {
  173. string ret = "";
  174. string value;
  175. foreach (string key in Keys){
  176. value = (string) this [key];
  177. value = value == null ? "" : value;
  178. ret += key + "=" + value + " ";
  179. }
  180. return ret;
  181. }
  182. }
  183. class Tag : Element
  184. {
  185. protected string tag;
  186. protected TagType tagType;
  187. protected TagAttributes attributes;
  188. protected bool self_closing;
  189. protected bool hasDefaultID;
  190. private static int ctrlNumber = 1;
  191. internal Tag (Tag other) :
  192. this (other.tag, other.attributes, other.self_closing)
  193. {
  194. this.tagType = other.tagType;
  195. }
  196. public Tag (string tag, TagAttributes attributes, bool self_closing) :
  197. base (ElementType.TAG)
  198. {
  199. if (tag == null)
  200. throw new ArgumentNullException ();
  201. this.tag = tag;
  202. this.attributes = attributes;
  203. this.tagType = TagType.NOTYET;
  204. this.self_closing = self_closing;
  205. this.hasDefaultID = false;
  206. }
  207. public string TagID
  208. {
  209. get { return tag; }
  210. }
  211. public TagType TagType
  212. {
  213. get { return tagType; }
  214. }
  215. public bool SelfClosing
  216. {
  217. get { return self_closing; }
  218. }
  219. public TagAttributes Attributes
  220. {
  221. get { return attributes; }
  222. }
  223. public string PlainHtml
  224. {
  225. get {
  226. StringBuilder plain = new StringBuilder ();
  227. plain.Append ('<');
  228. if (tagType == TagType.CLOSING)
  229. plain.Append ('/');
  230. plain.Append (tag);
  231. if (attributes != null){
  232. plain.Append (' ');
  233. foreach (string key in attributes.Keys){
  234. plain.Append (key);
  235. if (attributes [key] != null){
  236. plain.Append ("=\"");
  237. plain.Append ((string) attributes [key]);
  238. plain.Append ("\" ");
  239. }
  240. }
  241. }
  242. if (self_closing)
  243. plain.Append ('/');
  244. plain.Append ('>');
  245. return plain.ToString ();
  246. }
  247. }
  248. public override string ToString ()
  249. {
  250. return TagID + " " + Attributes + " " + self_closing;
  251. }
  252. public bool HasDefaultID
  253. {
  254. get { return hasDefaultID; }
  255. }
  256. protected void SetNewID ()
  257. {
  258. if (attributes == null)
  259. attributes = new TagAttributes ();
  260. attributes.Add ("ID", GetDefaultID ());
  261. hasDefaultID = true;
  262. }
  263. public static string GetDefaultID ()
  264. {
  265. return "_control" + ctrlNumber++;
  266. }
  267. }
  268. class CloseTag : Tag
  269. {
  270. public CloseTag (string tag) : base (tag, null, false)
  271. {
  272. tagType = TagType.CLOSING;
  273. }
  274. }
  275. class Directive : Tag
  276. {
  277. private static Hashtable directivesHash;
  278. private static string [] page_atts = { "AspCompat", "AutoEventWireup ", "Buffer",
  279. "ClassName", "ClientTarget", "CodePage",
  280. "CompilerOptions", "ContentType", "Culture", "Debug",
  281. "Description", "EnableSessionState", "EnableViewState",
  282. "EnableViewStateMac", "ErrorPage", "Explicit",
  283. "Inherits", "Language", "LCID", "ResponseEncoding",
  284. "Src", "SmartNavigation", "Strict", "Trace",
  285. "TraceMode", "Transaction", "UICulture",
  286. "WarningLevel" };
  287. private static string [] control_atts = { "AutoEventWireup", "ClassName", "CompilerOptions",
  288. "Debug", "Description", "EnableViewState",
  289. "Explicit", "Inherits", "Language", "Strict", "Src",
  290. "WarningLevel" };
  291. private static string [] import_atts = { "namespace" };
  292. private static string [] implements_atts = { "interface" };
  293. private static string [] assembly_atts = { "name", "src" };
  294. private static string [] register_atts = { "tagprefix", "tagname", "Namespace",
  295. "Src", "Assembly" };
  296. private static string [] outputcache_atts = { "Duration", "Location", "VaryByControl",
  297. "VaryByCustom", "VaryByHeader", "VaryByParam" };
  298. private static string [] reference_atts = { "page", "control" };
  299. private static string [] webservice_atts = { "class", "codebehind", "debug", "language" };
  300. static Directive ()
  301. {
  302. InitHash ();
  303. }
  304. private static void InitHash ()
  305. {
  306. CaseInsensitiveHashCodeProvider provider = new CaseInsensitiveHashCodeProvider ();
  307. CaseInsensitiveComparer comparer = new CaseInsensitiveComparer ();
  308. directivesHash = new Hashtable (provider, comparer);
  309. // Use Hashtable 'cause is O(1) in Contains (ArrayList is O(n))
  310. Hashtable valid_attributes = new Hashtable (provider, comparer);
  311. foreach (string att in page_atts) valid_attributes.Add (att, null);
  312. directivesHash.Add ("PAGE", valid_attributes);
  313. valid_attributes = new Hashtable (provider, comparer);
  314. foreach (string att in control_atts) valid_attributes.Add (att, null);
  315. directivesHash.Add ("CONTROL", valid_attributes);
  316. valid_attributes = new Hashtable (provider, comparer);
  317. foreach (string att in import_atts) valid_attributes.Add (att, null);
  318. directivesHash.Add ("IMPORT", valid_attributes);
  319. valid_attributes = new Hashtable (provider, comparer);
  320. foreach (string att in implements_atts) valid_attributes.Add (att, null);
  321. directivesHash.Add ("IMPLEMENTS", valid_attributes);
  322. valid_attributes = new Hashtable (provider, comparer);
  323. foreach (string att in register_atts) valid_attributes.Add (att, null);
  324. directivesHash.Add ("REGISTER", valid_attributes);
  325. valid_attributes = new Hashtable (provider, comparer);
  326. foreach (string att in assembly_atts) valid_attributes.Add (att, null);
  327. directivesHash.Add ("ASSEMBLY", valid_attributes);
  328. valid_attributes = new Hashtable (provider, comparer);
  329. foreach (string att in outputcache_atts) valid_attributes.Add (att, null);
  330. directivesHash.Add ("OUTPUTCACHE", valid_attributes);
  331. valid_attributes = new Hashtable (provider, comparer);
  332. foreach (string att in reference_atts) valid_attributes.Add (att, null);
  333. directivesHash.Add ("REFERENCE", valid_attributes);
  334. valid_attributes = new Hashtable (provider, comparer);
  335. foreach (string att in webservice_atts) valid_attributes.Add (att, null);
  336. directivesHash.Add ("WEBSERVICE", valid_attributes);
  337. }
  338. public Directive (string tag, TagAttributes attributes) :
  339. base (tag, attributes, true)
  340. {
  341. CheckAttributes ();
  342. tagType = TagType.DIRECTIVE;
  343. }
  344. private void CheckAttributes ()
  345. {
  346. Hashtable atts;
  347. if (!(directivesHash [tag] is Hashtable))
  348. throw new ApplicationException ("Unknown directive: " + tag);
  349. atts = (Hashtable) directivesHash [tag];
  350. foreach (string att in attributes.Keys){
  351. if (!atts.Contains (att))
  352. throw new ApplicationException ("Attribute " + att +
  353. " not valid for tag " + tag);
  354. }
  355. }
  356. public static bool IsDirectiveID (string id)
  357. {
  358. return directivesHash.Contains (id);
  359. }
  360. public override string ToString ()
  361. {
  362. return "Directive: " + tag;
  363. }
  364. }
  365. class ServerObjectTag : Tag
  366. {
  367. public ServerObjectTag (Tag tag) :
  368. base (tag.TagID, tag.Attributes, tag.SelfClosing)
  369. {
  370. tagType = TagType.SERVEROBJECT;
  371. if (!attributes.IsRunAtServer ())
  372. throw new ApplicationException ("<object> without runat=server");
  373. if (attributes.Count != 3 || !SelfClosing || ObjectID == null || ObjectClass == null)
  374. throw new ApplicationException ("Incorrect syntax: <object id=\"name\" " +
  375. "class=\"full.class.name\" runat=\"server\" />");
  376. }
  377. public string ObjectID
  378. {
  379. get { return (string) attributes ["id"]; }
  380. }
  381. public string ObjectClass
  382. {
  383. get { return (string) attributes ["class"]; }
  384. }
  385. }
  386. class HtmlControlTag : Tag
  387. {
  388. private Type control_type;
  389. private bool is_container;
  390. private static Hashtable controls;
  391. private static Hashtable inputTypes;
  392. private static void InitHash ()
  393. {
  394. controls = new Hashtable (new CaseInsensitiveHashCodeProvider (),
  395. new CaseInsensitiveComparer ());
  396. controls.Add ("A", typeof (HtmlAnchor));
  397. controls.Add ("BUTTON", typeof (HtmlButton));
  398. controls.Add ("FORM", typeof (HtmlForm));
  399. controls.Add ("IMG", typeof (HtmlImage));
  400. controls.Add ("INPUT", "INPUT");
  401. controls.Add ("SELECT", typeof (HtmlSelect));
  402. controls.Add ("TABLE", typeof (HtmlTable));
  403. controls.Add ("TD", typeof (HtmlTableCell));
  404. controls.Add ("TH", typeof (HtmlTableCell));
  405. controls.Add ("TR", typeof (HtmlTableRow));
  406. controls.Add ("TEXTAREA", typeof (HtmlTextArea));
  407. inputTypes = new Hashtable (new CaseInsensitiveHashCodeProvider (),
  408. new CaseInsensitiveComparer ());
  409. inputTypes.Add ("BUTTON", typeof (HtmlInputButton));
  410. inputTypes.Add ("SUBMIT", typeof (HtmlInputButton));
  411. inputTypes.Add ("RESET", typeof (HtmlInputButton));
  412. inputTypes.Add ("CHECKBOX", typeof (HtmlInputCheckBox));
  413. inputTypes.Add ("FILE", typeof (HtmlInputFile));
  414. inputTypes.Add ("HIDDEN", typeof (HtmlInputHidden));
  415. inputTypes.Add ("IMAGE", typeof (HtmlInputImage));
  416. inputTypes.Add ("RADIO", typeof (HtmlInputRadioButton));
  417. inputTypes.Add ("TEXT", typeof (HtmlInputText));
  418. inputTypes.Add ("PASSWORD", typeof (HtmlInputText));
  419. }
  420. static HtmlControlTag ()
  421. {
  422. InitHash ();
  423. }
  424. public HtmlControlTag (string tag, TagAttributes attributes, bool self_closing) :
  425. base (tag, attributes, self_closing)
  426. {
  427. SetData ();
  428. if (attributes == null || attributes ["ID"] == null)
  429. SetNewID ();
  430. }
  431. public HtmlControlTag (Tag source_tag) :
  432. this (source_tag.TagID, source_tag.Attributes, source_tag.SelfClosing)
  433. {
  434. }
  435. private void SetData ()
  436. {
  437. tagType = TagType.HTMLCONTROL;
  438. if (!(controls [tag] is string)){
  439. control_type = (Type) controls [tag];
  440. if (control_type == null)
  441. control_type = typeof (HtmlGenericControl);
  442. is_container = (0 != String.Compare (tag, "img", true));
  443. } else {
  444. string type_value = (string) attributes ["TYPE"];
  445. if (type_value== null)
  446. throw new ArgumentException ("INPUT tag without TYPE attribute!!!");
  447. control_type = (Type) inputTypes [type_value];
  448. //TODO: what does MS with this one?
  449. if (control_type == null)
  450. throw new ArgumentException ("Unknown input type -> " + type_value);
  451. is_container = false;
  452. self_closing = true; // All <input ...> are self-closing
  453. }
  454. }
  455. public Type ControlType
  456. {
  457. get { return control_type; }
  458. }
  459. public string ControlID
  460. {
  461. get { return (string) attributes ["ID"]; }
  462. }
  463. public bool IsContainer
  464. {
  465. get { return is_container; }
  466. }
  467. public override string ToString ()
  468. {
  469. string ret = "HtmlControlTag: " + tag + " Name: " + ControlID + "Type:" +
  470. control_type.ToString () + "\n\tAttributes:\n";
  471. foreach (string key in attributes.Keys){
  472. ret += "\t" + key + "=" + attributes [key];
  473. }
  474. return ret;
  475. }
  476. }
  477. enum ChildrenKind
  478. {
  479. NONE,
  480. /*
  481. * Children must be ASP.NET server controls. Literal text is passed as LiteralControl.
  482. * Child controls and text are added using AddParsedSubObject ().
  483. */
  484. CONTROLS,
  485. /*
  486. * Children must correspond to properties of the parent control. No literal text allowed.
  487. */
  488. PROPERTIES,
  489. /*
  490. * Special case used inside <columns>...</columns>
  491. * Only allow DataGridColumn and derived classes.
  492. */
  493. DBCOLUMNS,
  494. /*
  495. * Special case for list controls (ListBox, DropDownList...)
  496. */
  497. LISTITEM,
  498. /* For HtmlSelect children. They are <option> tags that must
  499. * be treated as ListItem
  500. */
  501. OPTION
  502. }
  503. // TODO: support for ControlBuilderAttribute that may be used in custom controls
  504. class AspComponent : Tag
  505. {
  506. private Type type;
  507. private string alias;
  508. private string control_type;
  509. private bool is_close_tag;
  510. private bool allow_children;
  511. private ChildrenKind children_kind;
  512. private string defaultPropertyName;
  513. private ChildrenKind GuessChildrenKind (Type type)
  514. {
  515. object [] custom_atts = type.GetCustomAttributes (true);
  516. foreach (object custom_att in custom_atts){
  517. if (custom_att is ParseChildrenAttribute){
  518. /* FIXME
  519. * When adding full support for custom controls, we gotta
  520. * bear in mind the pca.DefaultProperty value
  521. */
  522. ParseChildrenAttribute pca = custom_att as ParseChildrenAttribute;
  523. defaultPropertyName = pca.DefaultProperty;
  524. /* this property will be true for all controls derived from
  525. * WebControls. */
  526. if (pca.ChildrenAsProperties == false)
  527. return ChildrenKind.CONTROLS;
  528. else if (defaultPropertyName == "")
  529. return ChildrenKind.PROPERTIES;
  530. else
  531. return ChildrenKind.LISTITEM;
  532. }
  533. }
  534. return ChildrenKind.NONE;
  535. }
  536. private static bool GuessAllowChildren (Type type)
  537. {
  538. PropertyInfo controls = type.GetProperty ("Controls");
  539. if (controls == null)
  540. return false;
  541. MethodInfo getm = controls.GetGetMethod ();
  542. object control_instance = Activator.CreateInstance (type);
  543. object control_collection = getm.Invoke (control_instance, null);
  544. return (!(control_collection is System.Web.UI.EmptyControlCollection));
  545. }
  546. public AspComponent (Tag input_tag, Type type) :
  547. base (input_tag)
  548. {
  549. tagType = TagType.SERVERCONTROL;
  550. this.is_close_tag = input_tag is CloseTag;
  551. this.type = type;
  552. this.defaultPropertyName = "";
  553. this.allow_children = GuessAllowChildren (type);
  554. if (input_tag.SelfClosing)
  555. this.children_kind = ChildrenKind.NONE;
  556. else if (type == typeof (System.Web.UI.WebControls.DataGridColumn) ||
  557. type.IsSubclassOf (typeof (System.Web.UI.WebControls.DataGridColumn)))
  558. this.children_kind = ChildrenKind.PROPERTIES;
  559. else if (type == typeof (System.Web.UI.WebControls.ListItem))
  560. this.children_kind = ChildrenKind.CONTROLS;
  561. else
  562. this.children_kind = GuessChildrenKind (type);
  563. int pos = input_tag.TagID.IndexOf (':');
  564. alias = tag.Substring (0, pos);
  565. control_type = tag.Substring (pos + 1);
  566. if (attributes == null || attributes ["ID"] == null)
  567. SetNewID ();
  568. }
  569. public Type ComponentType
  570. {
  571. get { return type; }
  572. }
  573. public string ControlID
  574. {
  575. get { return (string) attributes ["ID"]; }
  576. }
  577. public bool IsCloseTag
  578. {
  579. get { return is_close_tag; }
  580. }
  581. public bool AllowChildren
  582. {
  583. get { return allow_children; }
  584. }
  585. public ChildrenKind ChildrenKind
  586. {
  587. get { return children_kind; }
  588. }
  589. public string DefaultPropertyName
  590. {
  591. get { return defaultPropertyName; }
  592. }
  593. public override string ToString ()
  594. {
  595. return type.ToString () + " Alias: " + alias + " ID: " + (string) attributes ["id"];
  596. }
  597. }
  598. class PropertyTag : Tag
  599. {
  600. private Type type;
  601. private string name;
  602. public PropertyTag (Tag tag, Type type, string name)
  603. : base (tag)
  604. {
  605. tagType = TagType.PROPERTYTAG;
  606. SetNewID ();
  607. this.name = name;
  608. this.type = type;
  609. }
  610. public Type PropertyType
  611. {
  612. get { return type; }
  613. }
  614. public string PropertyID
  615. {
  616. get { return (string) attributes ["ID"]; }
  617. }
  618. public string PropertyName
  619. {
  620. get { return name; }
  621. }
  622. }
  623. class CodeRenderTag : Tag
  624. {
  625. private string code;
  626. private bool isVarName;
  627. public CodeRenderTag (bool isVarName, string code) : base ("", null, false)
  628. {
  629. tagType = TagType.CODERENDER;
  630. this.isVarName = isVarName;
  631. this.code = code.Trim ();
  632. }
  633. public string Code
  634. {
  635. get { return code; }
  636. }
  637. public bool IsVarName
  638. {
  639. get { return isVarName; }
  640. }
  641. public string AsText
  642. {
  643. get { return "<%" + (IsVarName ? "=" : "") + Code + "%>"; }
  644. }
  645. }
  646. class DataBindingTag : Tag
  647. {
  648. private string data;
  649. public DataBindingTag (string data) : base ("", null, false)
  650. {
  651. tagType = TagType.DATABINDING;
  652. this.data = data.Trim ();
  653. }
  654. public string Data
  655. {
  656. get { return data; }
  657. }
  658. public string AsText
  659. {
  660. get { return "<%#" + Data + "%>"; }
  661. }
  662. }
  663. }