DataPager.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. //
  2. // System.Web.UI.WebControls.DataPager
  3. //
  4. // Authors:
  5. // Marek Habersack ([email protected])
  6. //
  7. // (C) 2007-2008 Novell, Inc
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. #if NET_3_5
  30. using System;
  31. using System.ComponentModel;
  32. using System.Security.Permissions;
  33. using System.Web;
  34. using System.Web.UI;
  35. namespace System.Web.UI.WebControls
  36. {
  37. // [ToolboxBitmap (typeof (System.Web.UI.WebControls.DataPager), "DataPager.ico")]
  38. [ToolboxItemFilter ("System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", ToolboxItemFilterType.Require)]
  39. [SupportsEventValidation]
  40. [Themeable (true)]
  41. [ParseChildren (true)]
  42. [Designer ("System.Web.UI.Design.WebControls.DataPagerDesigner, System.Web.Extensions.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
  43. [PersistChildren (false)]
  44. public class DataPager : Control, IAttributeAccessor, INamingContainer, ICompositeControlDesignerAccessor
  45. {
  46. const int NO_PAGEABLE_ITEM_CONTAINER = 0;
  47. const int NO_DATABOUND_CONTROL = 1;
  48. const int NO_PAGED_CONTAINER_ID = 2;
  49. const int CONTROL_NOT_PAGEABLE = 3;
  50. const int NO_NAMING_CONTAINER = 4;
  51. const int CSTATE_BASE_STATE = 0;
  52. const int CSTATE_TOTAL_ROW_COUNT = 1;
  53. const int CSTATE_MAXIMUM_ROWS = 2;
  54. const int CSTATE_START_ROW_INDEX = 3;
  55. const int CSTATE_COUNT = 4;
  56. string[] _exceptionMessages = {
  57. "No IPageableItemContainer was found. Verify that either the DataPager is inside an IPageableItemContainer or PagedControlID is set to the control ID of an IPageableItemContainer",
  58. "There is no data-bound control associated with the DataPager control.",
  59. "Control with id '{0}' cannot be found in the page",
  60. "Control '{0}' is not pageable",
  61. "DataPager has no naming container"
  62. };
  63. IPageableItemContainer _pageableContainer;
  64. DataPagerFieldCollection _fields;
  65. AttributeCollection _attributes;
  66. int _totalRowCount;
  67. int _startRowIndex;
  68. int _maximumRows = 10;
  69. bool _initDone;
  70. bool _needNewContainerSetup = true;
  71. bool _needSetPageProperties = true;
  72. bool _createPagerFieldsRunning;
  73. public DataPager()
  74. {
  75. _fields = new DataPagerFieldCollection (this);
  76. }
  77. protected virtual void AddAttributesToRender (HtmlTextWriter writer)
  78. {
  79. if (ID != null)
  80. writer.AddAttribute (HtmlTextWriterAttribute.Id, ID);
  81. if (_attributes != null && _attributes.Count > 0) {
  82. foreach (string attr in _attributes.Keys)
  83. writer.AddAttribute (attr, _attributes [attr]);
  84. }
  85. }
  86. protected virtual void ConnectToEvents (IPageableItemContainer container)
  87. {
  88. if (container == null)
  89. throw new ArgumentNullException ("container");
  90. container.TotalRowCountAvailable += new EventHandler <PageEventArgs> (OnTotalRowCountAvailable);
  91. }
  92. protected virtual void CreatePagerFields ()
  93. {
  94. // In theory (on multi-core or SMP machines), OnTotalRowCountAvailable may
  95. // be called asynchronously to this method (since it is a delegate reacting
  96. // to event in the container), so we want to protect ourselves from data
  97. // corruption here. Lock would be an overkill, since we really want to
  98. // create the list only once anyway.
  99. _createPagerFieldsRunning = true;
  100. ControlCollection controls = Controls;
  101. controls.Clear ();
  102. DataPagerFieldItem control;
  103. foreach (DataPagerField dpf in _fields) {
  104. control = new DataPagerFieldItem (dpf, this);
  105. controls.Add (control);
  106. if (dpf.Visible) {
  107. dpf.CreateDataPagers (control, _startRowIndex, _maximumRows, _totalRowCount, _fields.IndexOf (dpf));
  108. control.DataBind ();
  109. }
  110. }
  111. _createPagerFieldsRunning = false;
  112. }
  113. public override void DataBind ()
  114. {
  115. OnDataBinding (EventArgs.Empty);
  116. EnsureChildControls ();
  117. DataBindChildren ();
  118. }
  119. protected virtual IPageableItemContainer FindPageableItemContainer ()
  120. {
  121. string pagedControlID = PagedControlID;
  122. IPageableItemContainer ret = null;
  123. Page page = Page;
  124. Control container;
  125. if (page != null && !String.IsNullOrEmpty (pagedControlID)) {
  126. Control ctl = null;
  127. container = NamingContainer;
  128. while (container != null) {
  129. ctl = container.FindControl (pagedControlID);
  130. if (ctl != null)
  131. break;
  132. if (container == page)
  133. break;
  134. container = container.NamingContainer;
  135. }
  136. if (container == null)
  137. throw new InvalidOperationException (_exceptionMessages [NO_NAMING_CONTAINER]);
  138. if (ctl == null)
  139. throw new InvalidOperationException (String.Format (_exceptionMessages [NO_PAGED_CONTAINER_ID], pagedControlID));
  140. ret = ctl as IPageableItemContainer;
  141. if (ret == null)
  142. throw new InvalidOperationException (String.Format (_exceptionMessages [CONTROL_NOT_PAGEABLE], pagedControlID));
  143. return ret;
  144. }
  145. // No ID set, try to find a container that's pageable
  146. container = NamingContainer;
  147. while (container != page) {
  148. if (container == null)
  149. throw new InvalidOperationException (_exceptionMessages [NO_NAMING_CONTAINER]);
  150. ret = container as IPageableItemContainer;
  151. if (ret != null)
  152. return ret;
  153. container = container.NamingContainer;
  154. }
  155. return ret;
  156. }
  157. protected internal override void LoadControlState (object savedState)
  158. {
  159. object[] state = savedState as object[];
  160. object tmp;
  161. if (state != null && state.Length == CSTATE_COUNT) {
  162. base.LoadControlState (state [CSTATE_BASE_STATE]);
  163. if ((tmp = state [CSTATE_TOTAL_ROW_COUNT]) != null)
  164. _totalRowCount = (int) tmp;
  165. if ((tmp = state [CSTATE_MAXIMUM_ROWS]) != null)
  166. _maximumRows = (int) tmp;
  167. if ((tmp = state [CSTATE_START_ROW_INDEX]) != null)
  168. _startRowIndex = (int) tmp;
  169. }
  170. if (_pageableContainer == null) {
  171. _pageableContainer = FindPageableItemContainer ();
  172. if (_pageableContainer == null)
  173. throw new InvalidOperationException (_exceptionMessages [NO_DATABOUND_CONTROL]);
  174. ConnectToEvents (_pageableContainer);
  175. }
  176. SetUpForNewContainer (false, false);
  177. }
  178. protected override void LoadViewState (object savedState)
  179. {
  180. var state = savedState as object[];
  181. if (state == null || state.Length != 2)
  182. return;
  183. base.LoadViewState (state [0]);
  184. object myState = state [1];
  185. if (myState != null)
  186. ((IStateManager) Fields).LoadViewState (myState);
  187. }
  188. protected override bool OnBubbleEvent (object source, EventArgs e)
  189. {
  190. DataPagerFieldCommandEventArgs args = e as DataPagerFieldCommandEventArgs;
  191. if (args != null) {
  192. DataPagerFieldItem item = args.Item;
  193. DataPagerField field = item != null ? item.PagerField : null;
  194. if (field != null) {
  195. field.HandleEvent (args);
  196. return true;
  197. }
  198. }
  199. return false;
  200. }
  201. void SetUpForNewContainer (bool dataBind, bool needSetPageProperties)
  202. {
  203. if (_needNewContainerSetup) {
  204. ConnectToEvents (_pageableContainer);
  205. _needNewContainerSetup = false;
  206. }
  207. if (_needSetPageProperties) {
  208. _pageableContainer.SetPageProperties (_startRowIndex, _maximumRows, dataBind);
  209. _needSetPageProperties = needSetPageProperties;
  210. }
  211. }
  212. protected internal override void OnInit (EventArgs e)
  213. {
  214. base.OnInit (e);
  215. Page page = Page;
  216. if (page != null)
  217. page.RegisterRequiresControlState (this);
  218. // It might return null here - there is no guarantee all the controls on the
  219. // page are already initialized by the time this method is loaded. Do not
  220. // throw for that reason.
  221. _pageableContainer = FindPageableItemContainer ();
  222. if (_pageableContainer != null)
  223. // Do not re-bind the data here - not all the controls might be
  224. // initialized (that includes the container may be bound to)
  225. SetUpForNewContainer (false, true);
  226. _initDone = true;
  227. }
  228. protected internal override void OnLoad (EventArgs e)
  229. {
  230. if (_pageableContainer == null)
  231. _pageableContainer = FindPageableItemContainer ();
  232. if (_pageableContainer == null)
  233. throw new InvalidOperationException (_exceptionMessages [NO_PAGEABLE_ITEM_CONTAINER]);
  234. SetUpForNewContainer (false, false);
  235. base.OnLoad (e);
  236. }
  237. protected virtual void OnTotalRowCountAvailable (object sender, PageEventArgs e)
  238. {
  239. _totalRowCount = e.TotalRowCount;
  240. _maximumRows = e.MaximumRows;
  241. _startRowIndex = e.StartRowIndex;
  242. // Sanity checks: if the total row count is less than the current start row
  243. // index, we must adjust and rebind the associated container control
  244. if (_totalRowCount > 0 && (_totalRowCount <= _startRowIndex)) {
  245. // Adjust the container's start row index to the new maximum rows
  246. // count, but do not touch our index - we aren't a "view", so we
  247. // don't want/need to change the start index.
  248. int tmp = _startRowIndex - _maximumRows;
  249. if (tmp < 0 || tmp >= _totalRowCount)
  250. tmp = 0;
  251. // Trigger the databinding, which will call us again, with adjusted
  252. // data, so that we can recreate the pager fields.
  253. _pageableContainer.SetPageProperties (tmp, _maximumRows, true);
  254. } else if (!_createPagerFieldsRunning)
  255. // No adjustments necessary, re-create the pager fields
  256. CreatePagerFields ();
  257. }
  258. protected virtual void RecreateChildControls ()
  259. {
  260. // This is used only by VS designer
  261. throw new NotImplementedException ();
  262. }
  263. protected internal override void Render (HtmlTextWriter writer)
  264. {
  265. RenderBeginTag (writer);
  266. RenderContents (writer);
  267. writer.RenderEndTag ();
  268. }
  269. public virtual void RenderBeginTag (HtmlTextWriter writer)
  270. {
  271. AddAttributesToRender (writer);
  272. writer.RenderBeginTag (TagKey);
  273. }
  274. protected virtual void RenderContents (HtmlTextWriter writer)
  275. {
  276. // Nothing special to render, just child controls
  277. base.Render (writer);
  278. }
  279. protected internal override object SaveControlState ()
  280. {
  281. object[] ret = new object [CSTATE_COUNT];
  282. ret [CSTATE_BASE_STATE] = base.SaveControlState ();
  283. ret [CSTATE_TOTAL_ROW_COUNT] = _totalRowCount <= 0 ? 0 : _totalRowCount;
  284. ret [CSTATE_MAXIMUM_ROWS] = _maximumRows <= 0 ? 0 : _maximumRows;
  285. ret [CSTATE_START_ROW_INDEX] = _startRowIndex <= 0 ? 0 : _startRowIndex;
  286. return ret;
  287. }
  288. protected override object SaveViewState ()
  289. {
  290. var ret = new object [2];
  291. ret [0] = base.SaveViewState ();
  292. ret [1] = _fields != null ? ((IStateManager) _fields).SaveViewState () : null;
  293. return ret;
  294. }
  295. public virtual void SetPageProperties (int startRowIndex, int maximumRows, bool databind)
  296. {
  297. if (_pageableContainer == null)
  298. throw new InvalidOperationException (_exceptionMessages [NO_DATABOUND_CONTROL]);
  299. _startRowIndex = startRowIndex;
  300. _maximumRows = maximumRows;
  301. _needSetPageProperties = false;
  302. _pageableContainer.SetPageProperties (startRowIndex, maximumRows, databind);
  303. }
  304. protected override void TrackViewState ()
  305. {
  306. base.TrackViewState ();
  307. if (_fields != null)
  308. ((IStateManager) _fields).TrackViewState ();
  309. }
  310. [Browsable (false)]
  311. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  312. public AttributeCollection Attributes {
  313. get {
  314. if (_attributes == null)
  315. _attributes = new AttributeCollection (new StateBag ());
  316. return _attributes;
  317. }
  318. }
  319. public override ControlCollection Controls {
  320. get {
  321. EnsureChildControls ();
  322. return base.Controls;
  323. }
  324. }
  325. [Category ("Default")]
  326. [PersistenceMode (PersistenceMode.InnerProperty)]
  327. [DefaultValue ("")]
  328. [Editor ("System.Web.UI.Design.WebControls.DataPagerFieldTypeEditor, System.Web.Extensions.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", typeof (System.Drawing.Design.UITypeEditor))]
  329. [MergableProperty (false)]
  330. public virtual DataPagerFieldCollection Fields {
  331. get { return _fields; }
  332. }
  333. [Browsable (false)]
  334. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  335. public int MaximumRows {
  336. get { return _maximumRows; }
  337. }
  338. [WebCategory ("Paging")]
  339. [IDReferenceProperty (typeof (System.Web.UI.WebControls.IPageableItemContainer))]
  340. [DefaultValue ("")]
  341. [Themeable (false)]
  342. public virtual string PagedControlID {
  343. get {
  344. string ret = ViewState ["PagedControlID"] as string;
  345. if (ret == null)
  346. return String.Empty;
  347. return ret;
  348. }
  349. set { ViewState ["PagedControlID"] = value; }
  350. }
  351. [DefaultValue (10)]
  352. [WebCategory ("Paging")]
  353. public int PageSize {
  354. get { return _maximumRows; }
  355. set {
  356. if (value < 1)
  357. throw new ArgumentOutOfRangeException ("value");
  358. if (value == _maximumRows)
  359. return;
  360. _maximumRows = value;
  361. if (_initDone) {
  362. // We have a source and the page size has changed, update
  363. // the container
  364. CreatePagerFields ();
  365. // Environment has changed, let the container know that it
  366. // needs to rebind.
  367. SetPageProperties (_startRowIndex, _maximumRows, true);
  368. }
  369. }
  370. }
  371. [DefaultValue ("")]
  372. [WebCategory ("Paging")]
  373. public string QueryStringField {
  374. get {
  375. string ret = ViewState ["QueryStringField"] as string;
  376. if (ret == null)
  377. return String.Empty;
  378. return ret;
  379. }
  380. set { ViewState ["QueryStringField"] = value; }
  381. }
  382. [Browsable (false)]
  383. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  384. public int StartRowIndex {
  385. get { return _startRowIndex; }
  386. }
  387. [Browsable (false)]
  388. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  389. protected virtual HtmlTextWriterTag TagKey {
  390. get { return HtmlTextWriterTag.Span; }
  391. }
  392. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  393. [Browsable (false)]
  394. public int TotalRowCount {
  395. get { return _totalRowCount; }
  396. }
  397. string IAttributeAccessor.GetAttribute (string key)
  398. {
  399. return Attributes [key];
  400. }
  401. void IAttributeAccessor.SetAttribute (string key, string value)
  402. {
  403. Attributes [key] = value;
  404. }
  405. void ICompositeControlDesignerAccessor.RecreateChildControls ()
  406. {
  407. RecreateChildControls ();
  408. }
  409. }
  410. }
  411. #endif