BaseDataList.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. //
  2. // System.Web.UI.WebControls.BaseDataList.cs
  3. //
  4. // Author:
  5. // Sebastien Pouliot <[email protected]>
  6. //
  7. // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System.Collections;
  29. using System.ComponentModel;
  30. using System.Security.Permissions;
  31. namespace System.Web.UI.WebControls {
  32. // CAS
  33. [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  34. [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  35. // attributes
  36. [DefaultEvent ("SelectedIndexChanged")]
  37. [DefaultProperty ("DataSource")]
  38. [Designer ("System.Web.UI.Design.WebControls.BaseDataListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
  39. public abstract class BaseDataList : WebControl {
  40. private static readonly object selectedIndexChangedEvent = new object ();
  41. private ArrayList keys;
  42. private DataKeyCollection keycoll;
  43. private object source;
  44. #if NET_2_0
  45. private string dataSourceId;
  46. private bool initialized;
  47. private bool requiresDataBinding;
  48. private DataSourceSelectArguments selectArguments;
  49. private IEnumerable data;
  50. #endif
  51. protected BaseDataList ()
  52. {
  53. }
  54. [DefaultValue ("")]
  55. #if NET_2_0
  56. [Localizable (true)]
  57. #endif
  58. [WebSysDescription ("")]
  59. [WebCategory ("Accessibility")]
  60. public virtual string Caption {
  61. get {
  62. object o = ViewState ["Caption"];
  63. return (o == null) ? String.Empty : (string) o;
  64. }
  65. set {
  66. if (value == null)
  67. ViewState.Remove ("Caption");
  68. else
  69. ViewState ["Caption"] = value;
  70. }
  71. }
  72. [DefaultValue (TableCaptionAlign.NotSet)]
  73. public virtual TableCaptionAlign CaptionAlign {
  74. get {
  75. object o = ViewState ["CaptionAlign"];
  76. return (o == null) ? TableCaptionAlign.NotSet : (TableCaptionAlign) o;
  77. }
  78. set {
  79. if ((value < TableCaptionAlign.NotSet) || (value > TableCaptionAlign.Right))
  80. throw new ArgumentOutOfRangeException (Locale.GetText ("Invalid TableCaptionAlign value."));
  81. ViewState ["CaptionAlign"] = value;
  82. }
  83. }
  84. #if ONLY_1_1
  85. [Bindable (true)]
  86. #endif
  87. [DefaultValue (-1)]
  88. [WebSysDescription("")]
  89. [WebCategory("Layout")]
  90. public virtual int CellPadding {
  91. get {
  92. if (!ControlStyleCreated)
  93. return -1; // default value
  94. return TableStyle.CellPadding;
  95. }
  96. set { TableStyle.CellPadding = value; }
  97. }
  98. #if ONLY_1_1
  99. [Bindable (true)]
  100. #endif
  101. [DefaultValue (0)]
  102. [WebSysDescription("")]
  103. [WebCategory("Layout")]
  104. public virtual int CellSpacing {
  105. get {
  106. if (!ControlStyleCreated)
  107. return 0; // default value
  108. return TableStyle.CellSpacing;
  109. }
  110. set { TableStyle.CellSpacing = value; }
  111. }
  112. public override ControlCollection Controls {
  113. get {
  114. EnsureChildControls ();
  115. return base.Controls;
  116. }
  117. }
  118. [DefaultValue ("")]
  119. #if NET_2_0
  120. [Themeable (false)]
  121. #endif
  122. [MonoTODO ("incomplete")]
  123. [WebSysDescription("")]
  124. [WebCategory("Data")]
  125. public virtual string DataKeyField {
  126. get {
  127. object o = ViewState ["DataKeyField"];
  128. return (o == null) ? String.Empty : (string) o;
  129. }
  130. set {
  131. if (value == null)
  132. ViewState.Remove ("DataKeyField");
  133. else
  134. ViewState ["DataKeyField"] = value;
  135. }
  136. }
  137. [Browsable (false)]
  138. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  139. [WebSysDescription("")]
  140. [WebCategory("Data")]
  141. public DataKeyCollection DataKeys {
  142. get {
  143. if (keycoll == null) {
  144. keycoll = new DataKeyCollection (DataKeysArray);
  145. ViewState ["DataKeys"] = keycoll;
  146. }
  147. return keycoll;
  148. }
  149. }
  150. protected ArrayList DataKeysArray {
  151. get {
  152. if (keys == null)
  153. keys = new ArrayList ();
  154. return keys;
  155. }
  156. }
  157. [DefaultValue ("")]
  158. #if NET_2_0
  159. [Themeable (false)]
  160. #endif
  161. [WebSysDescription("")]
  162. [WebCategory("Data")]
  163. public string DataMember {
  164. get {
  165. object o = ViewState ["DataMember"];
  166. return (o == null) ? String.Empty : (string) o;
  167. }
  168. set {
  169. if (value == null)
  170. ViewState.Remove ("DataMember");
  171. else
  172. ViewState ["DataMember"] = value;
  173. #if NET_2_0
  174. if (!Initialized)
  175. OnDataPropertyChanged ();
  176. #endif
  177. }
  178. }
  179. [Bindable (true)]
  180. [DefaultValue (null)]
  181. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  182. #if NET_2_0
  183. [Themeable (false)]
  184. #endif
  185. [WebSysDescription("")]
  186. [WebCategory("Data")]
  187. public virtual object DataSource {
  188. get { return source; }
  189. set {
  190. if ((value == null) || (value is IEnumerable) || (value is IListSource)) {
  191. #if NET_2_0
  192. // FIXME - can't duplicate in a test case ? LAMESPEC ?
  193. // can't duplicate in a test case
  194. // if ((dataSourceId != null) && (dataSourceId.Length != 0))
  195. // throw new HttpException (Locale.GetText ("DataSourceID is already set."));
  196. source = value;
  197. if (!Initialized)
  198. OnDataPropertyChanged ();
  199. #else
  200. source = value;
  201. #endif
  202. } else {
  203. string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
  204. "IEnumerable", "IListSource");
  205. throw new ArgumentException (msg);
  206. }
  207. }
  208. }
  209. #if ONLY_1_1
  210. [Bindable (true)]
  211. #endif
  212. [DefaultValue (GridLines.Both)]
  213. [WebSysDescription("")]
  214. [WebCategory("Appearance")]
  215. public virtual GridLines GridLines {
  216. get {
  217. if (!ControlStyleCreated)
  218. return GridLines.Both; // default value
  219. return TableStyle.GridLines;
  220. }
  221. set { TableStyle.GridLines = value; }
  222. }
  223. #if ONLY_1_1
  224. [Bindable (true)]
  225. #endif
  226. [Category ("Layout")]
  227. [DefaultValue (HorizontalAlign.NotSet)]
  228. [WebSysDescription("")]
  229. public virtual HorizontalAlign HorizontalAlign {
  230. get {
  231. if (!ControlStyleCreated)
  232. return HorizontalAlign.NotSet; // default value
  233. return TableStyle.HorizontalAlign;
  234. }
  235. set { TableStyle.HorizontalAlign = value; }
  236. }
  237. [DefaultValue (false)]
  238. public virtual bool UseAccessibleHeader {
  239. get {
  240. object o = ViewState ["UseAccessibleHeader"];
  241. return (o == null) ? false : (bool) o;
  242. }
  243. set { ViewState ["UseAccessibleHeader"] = value; }
  244. }
  245. #if NET_2_0
  246. [DefaultValue ("")]
  247. [IDReferenceProperty (typeof (DataSourceControl))]
  248. [Themeable (false)]
  249. public virtual string DataSourceID {
  250. get {
  251. object o = ViewState ["DataSourceID"];
  252. return (o == null) ? String.Empty : (string) o;
  253. }
  254. set {
  255. // LAMESPEC ? this is documented as an HttpException in beta2
  256. if (source != null)
  257. throw new InvalidOperationException (Locale.GetText ("DataSource is already set."));
  258. ViewState ["DataSourceID"] = value;
  259. if (!Initialized)
  260. OnDataPropertyChanged ();
  261. }
  262. }
  263. protected bool Initialized {
  264. get { return initialized; }
  265. }
  266. // as documented in BaseDataBoundControl
  267. protected bool IsBoundUsingDataSourceID {
  268. get { return (DataSourceID.Length != 0); }
  269. }
  270. // doc says ?automatically? called by ASP.NET
  271. protected bool RequiresDataBinding {
  272. get { return requiresDataBinding; }
  273. set { requiresDataBinding = value; }
  274. }
  275. protected DataSourceSelectArguments SelectArguments {
  276. get {
  277. if (selectArguments == null)
  278. selectArguments = CreateDataSourceSelectArguments ();
  279. return selectArguments;
  280. }
  281. }
  282. #endif
  283. private TableStyle TableStyle {
  284. // this will throw an InvalidCasException just like we need
  285. get { return (TableStyle) ControlStyle; }
  286. }
  287. protected override void AddParsedSubObject (object obj)
  288. {
  289. // don't accept controls
  290. }
  291. // see Kothari, page 435
  292. #if NET_2_0
  293. protected internal
  294. #else
  295. protected
  296. #endif
  297. override void CreateChildControls ()
  298. {
  299. // We are recreating the children from viewstate
  300. if (HasControls ())
  301. Controls.Clear();
  302. // If presents, build the children from the viewstate
  303. if (ViewState ["Items"] != null)
  304. CreateControlHierarchy (false);
  305. }
  306. protected abstract void CreateControlHierarchy (bool useDataSource);
  307. // see Kothari, page 434
  308. // see also: Control.DataBind on Fx 2.0 beta2 documentation
  309. public override void DataBind ()
  310. {
  311. // unlike most samples we don't call base.OnDataBinding
  312. // because we override it in this class
  313. OnDataBinding (EventArgs.Empty);
  314. // Clear, if required, then recreate the control hierarchy
  315. if (HasControls ())
  316. Controls.Clear ();
  317. if (HasChildViewState)
  318. ClearChildViewState ();
  319. if (!IsTrackingViewState)
  320. TrackViewState ();
  321. CreateControlHierarchy (true);
  322. // Indicate that child controls have been created, preventing
  323. // CreateChildControls from getting called.
  324. ChildControlsCreated = true;
  325. }
  326. #if NET_2_0
  327. protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
  328. {
  329. return DataSourceSelectArguments.Empty;
  330. }
  331. // best documentation is (again) in BaseDataBoundControl
  332. protected void EnsureDataBound ()
  333. {
  334. if (IsBoundUsingDataSourceID && RequiresDataBinding)
  335. DataBind ();
  336. }
  337. private void SelectCallback (IEnumerable data)
  338. {
  339. this.data = data;
  340. }
  341. protected virtual IEnumerable GetData ()
  342. {
  343. if (DataSourceID.Length == 0)
  344. return null;
  345. IDataSource ds = null;
  346. if (Page != null)
  347. ds = (Page.FindControl (DataSourceID) as IDataSource);
  348. if (ds == null)
  349. throw new HttpException (Locale.GetText ("Coulnd't find a DataSource named '{0}'.", DataSourceID));
  350. DataSourceView dsv = ds.GetView (String.Empty);
  351. dsv.Select (SelectArguments, new DataSourceViewSelectCallback (SelectCallback));
  352. return data;
  353. }
  354. #endif
  355. protected override void OnDataBinding (EventArgs e)
  356. {
  357. base.OnDataBinding (e);
  358. }
  359. #if NET_2_0
  360. protected virtual void OnDataPropertyChanged ()
  361. {
  362. }
  363. protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
  364. {
  365. RequiresDataBinding = true;
  366. }
  367. protected internal override void OnInit (EventArgs e)
  368. {
  369. base.OnInit (e);
  370. }
  371. protected internal override void OnLoad (EventArgs e)
  372. {
  373. if ((Page != null) && !Page.IsPostBack)
  374. RequiresDataBinding = true;
  375. initialized = true;
  376. base.OnLoad (e);
  377. }
  378. protected internal override void OnPreRender (EventArgs e)
  379. {
  380. EnsureDataBound ();
  381. base.OnPreRender (e);
  382. }
  383. #endif
  384. protected virtual void OnSelectedIndexChanged (EventArgs e)
  385. {
  386. EventHandler selectedIndexChanged = (EventHandler) Events [selectedIndexChangedEvent];
  387. if (selectedIndexChanged != null)
  388. selectedIndexChanged (this, e);
  389. }
  390. protected abstract void PrepareControlHierarchy ();
  391. #if NET_2_0
  392. protected internal
  393. #else
  394. protected
  395. #endif
  396. override void Render (HtmlTextWriter writer)
  397. {
  398. PrepareControlHierarchy ();
  399. // don't call base class or RenderBegin|EndTag
  400. // or we'll get an extra <span></span>
  401. RenderContents (writer);
  402. }
  403. [WebSysDescription("")]
  404. [WebCategory("Action")]
  405. public event EventHandler SelectedIndexChanged {
  406. add { Events.AddHandler (selectedIndexChangedEvent, value); }
  407. remove { Events.RemoveHandler (selectedIndexChangedEvent, value); }
  408. }
  409. static public bool IsBindableType (Type type)
  410. {
  411. // I can't believe how many NRE are possible in System.Web
  412. switch (Type.GetTypeCode (type)) {
  413. case TypeCode.Boolean:
  414. case TypeCode.Byte:
  415. case TypeCode.SByte:
  416. case TypeCode.Int16:
  417. case TypeCode.UInt16:
  418. case TypeCode.Int32:
  419. case TypeCode.UInt32:
  420. case TypeCode.Int64:
  421. case TypeCode.UInt64:
  422. case TypeCode.Char:
  423. case TypeCode.Double:
  424. case TypeCode.Single:
  425. case TypeCode.DateTime:
  426. case TypeCode.Decimal:
  427. case TypeCode.String:
  428. return true;
  429. default:
  430. return false;
  431. }
  432. }
  433. }
  434. }