DataPager.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. //
  2. // System.Web.UI.WebControls.DataPager
  3. //
  4. // Authors:
  5. // Marek Habersack ([email protected])
  6. //
  7. // (C) 2007 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. [ThemeableAttribute(true)]
  38. [ParseChildren (true)]
  39. [PersistChildren (false)]
  40. [SupportsEventValidation]
  41. [AspNetHostingPermissionAttribute(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  42. [AspNetHostingPermissionAttribute(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  43. public class DataPager : Control, IAttributeAccessor, INamingContainer, ICompositeControlDesignerAccessor
  44. {
  45. const int NO_PAGEABLE_ITEM_CONTAINER = 0;
  46. const int NO_DATABOUND_CONTROL = 1;
  47. const int NO_PAGED_CONTAINER_ID = 2;
  48. const int CONTROL_NOT_PAGEABLE = 3;
  49. const int NO_NAMING_CONTAINER = 4;
  50. const int CSTATE_BASE_STATE = 0;
  51. const int CSTATE_TOTAL_ROW_COUNT = 1;
  52. const int CSTATE_MAXIMUM_ROWS = 2;
  53. const int CSTATE_START_ROW_INDEX = 3;
  54. const int CSTATE_COUNT = 4;
  55. string[] _exceptionMessages = {
  56. "No IPageableItemContainer was found. Verify that either the DataPager is inside an IPageableItemContainer or PagedControlID is set to the control ID of an IPageableItemContainer",
  57. "There is no data-bound control associated with the DataPager control.",
  58. "Control with id '{0}' cannot be found in the page",
  59. "Control '{0}' is not pageable",
  60. "DataPager has no naming container"
  61. };
  62. IPageableItemContainer _pageableContainer;
  63. DataPagerFieldCollection _fields;
  64. AttributeCollection _attributes;
  65. int _totalRowCount;
  66. int _startRowIndex;
  67. int _maximumRows = 10;
  68. bool _initDone;
  69. bool _needNewContainerSetup = true;
  70. bool _needSetPageProperties = true;
  71. bool _createPagerFieldsRunning;
  72. public DataPager()
  73. {
  74. _fields = new DataPagerFieldCollection (this);
  75. }
  76. protected virtual void AddAttributesToRender (HtmlTextWriter writer)
  77. {
  78. if (ID != null)
  79. writer.AddAttribute (HtmlTextWriterAttribute.Id, ID);
  80. if (_attributes != null && _attributes.Count > 0) {
  81. foreach (string attr in _attributes.Keys)
  82. writer.AddAttribute (attr, _attributes [attr]);
  83. }
  84. }
  85. protected virtual void ConnectToEvents (IPageableItemContainer container)
  86. {
  87. if (container == null)
  88. throw new ArgumentNullException ("container");
  89. container.TotalRowCountAvailable += new EventHandler <PageEventArgs> (OnTotalRowCountAvailable);
  90. }
  91. protected virtual void CreatePagerFields ()
  92. {
  93. // In theory (on multi-core or SMP machines), OnTotalRowCountAvailable may
  94. // be called asynchronously to this method (since it is a delegate reacting
  95. // to event in the container), so we want to protect ourselves from data
  96. // corruption here. Lock would be an overkill, since we really want to
  97. // create the list only once anyway.
  98. _createPagerFieldsRunning = true;
  99. ControlCollection controls = Controls;
  100. controls.Clear ();
  101. DataPagerFieldItem control;
  102. foreach (DataPagerField dpf in _fields) {
  103. control = new DataPagerFieldItem (dpf, this);
  104. if (dpf.Visible) {
  105. dpf.CreateDataPagers (control, _startRowIndex, _maximumRows, _totalRowCount, _fields.IndexOf (dpf));
  106. control.DataBind ();
  107. }
  108. controls.Add (control);
  109. }
  110. _createPagerFieldsRunning = false;
  111. }
  112. public override void DataBind ()
  113. {
  114. OnDataBinding (EventArgs.Empty);
  115. EnsureChildControls ();
  116. DataBindChildren ();
  117. }
  118. protected virtual IPageableItemContainer FindPageableItemContainer ()
  119. {
  120. string pagedControlID = PagedControlID;
  121. IPageableItemContainer ret = null;
  122. Page page = Page;
  123. Control container;
  124. if (page != null && !String.IsNullOrEmpty (pagedControlID)) {
  125. Control ctl = null;
  126. container = NamingContainer;
  127. while (container != null && container != page) {
  128. ctl = container.FindControl (pagedControlID);
  129. if (ctl != null)
  130. break;
  131. container = container.NamingContainer;
  132. }
  133. if (container == null)
  134. throw new InvalidOperationException (_exceptionMessages [NO_NAMING_CONTAINER]);
  135. if (ctl == null)
  136. throw new InvalidOperationException (String.Format (_exceptionMessages [NO_PAGED_CONTAINER_ID], pagedControlID));
  137. ret = ctl as IPageableItemContainer;
  138. if (ret == null)
  139. throw new InvalidOperationException (String.Format (_exceptionMessages [CONTROL_NOT_PAGEABLE], pagedControlID));
  140. return ret;
  141. }
  142. // No ID set, try to find a container that's pageable
  143. container = NamingContainer;
  144. while (container != page) {
  145. if (container == null)
  146. throw new InvalidOperationException (_exceptionMessages [NO_NAMING_CONTAINER]);
  147. ret = container as IPageableItemContainer;
  148. if (ret != null)
  149. return ret;
  150. container = container.NamingContainer;
  151. }
  152. return ret;
  153. }
  154. protected internal override void LoadControlState (object savedState)
  155. {
  156. object[] state = savedState as object[];
  157. object tmp;
  158. if (state != null && state.Length == CSTATE_COUNT) {
  159. base.LoadControlState (state [CSTATE_BASE_STATE]);
  160. if ((tmp = state [CSTATE_TOTAL_ROW_COUNT]) != null)
  161. _totalRowCount = (int) tmp;
  162. if ((tmp = state [CSTATE_MAXIMUM_ROWS]) != null)
  163. _maximumRows = (int) tmp;
  164. if ((tmp = state [CSTATE_START_ROW_INDEX]) != null)
  165. _startRowIndex = (int) tmp;
  166. }
  167. if (_pageableContainer == null) {
  168. _pageableContainer = FindPageableItemContainer ();
  169. if (_pageableContainer == null)
  170. throw new InvalidOperationException (_exceptionMessages [NO_DATABOUND_CONTROL]);
  171. ConnectToEvents (_pageableContainer);
  172. }
  173. SetUpForNewContainer (false, false);
  174. }
  175. protected override void LoadViewState (object savedState)
  176. {
  177. Pair state = savedState as Pair;
  178. if (state == null)
  179. return;
  180. base.LoadViewState (state.First);
  181. object myState = state.Second;
  182. if (myState != null)
  183. ((IStateManager) Fields).LoadViewState (myState);
  184. }
  185. protected override bool OnBubbleEvent (object source, EventArgs e)
  186. {
  187. DataPagerFieldCommandEventArgs args = e as DataPagerFieldCommandEventArgs;
  188. if (args != null) {
  189. DataPagerFieldItem item = args.Item;
  190. DataPagerField field = item != null ? item.PagerField : null;
  191. if (field != null) {
  192. field.HandleEvent (args);
  193. return true;
  194. }
  195. }
  196. return false;
  197. }
  198. void SetUpForNewContainer (bool dataBind, bool needSetPageProperties)
  199. {
  200. if (_needNewContainerSetup) {
  201. ConnectToEvents (_pageableContainer);
  202. _needNewContainerSetup = false;
  203. }
  204. if (_needSetPageProperties) {
  205. _pageableContainer.SetPageProperties (_startRowIndex, _maximumRows, dataBind);
  206. _needSetPageProperties = needSetPageProperties;
  207. }
  208. }
  209. protected internal override void OnInit (EventArgs e)
  210. {
  211. base.OnInit (e);
  212. Page page = Page;
  213. if (page != null)
  214. page.RegisterRequiresControlState (this);
  215. // It might return null here - there is no guarantee all the controls on the
  216. // page are already initialized by the time this method is loaded. Do not
  217. // throw for that reason.
  218. _pageableContainer = FindPageableItemContainer ();
  219. if (_pageableContainer != null)
  220. // Do not re-bind the data here - not all the controls might be
  221. // initialized (that includes the container may be bound to)
  222. SetUpForNewContainer (false, true);
  223. _initDone = true;
  224. }
  225. protected internal override void OnLoad (EventArgs e)
  226. {
  227. if (_pageableContainer == null)
  228. _pageableContainer = FindPageableItemContainer ();
  229. if (_pageableContainer == null)
  230. throw new InvalidOperationException (_exceptionMessages [NO_PAGEABLE_ITEM_CONTAINER]);
  231. SetUpForNewContainer (false, false);
  232. base.OnLoad (e);
  233. }
  234. protected virtual void OnTotalRowCountAvailable (object sender, PageEventArgs e)
  235. {
  236. _totalRowCount = e.TotalRowCount;
  237. _maximumRows = e.MaximumRows;
  238. _startRowIndex = e.StartRowIndex;
  239. // Sanity checks: if the total row count is less than the current start row
  240. // index, we must adjust and rebind the associated container control
  241. if (_totalRowCount > 0 && (_totalRowCount <= _startRowIndex)) {
  242. // Adjust the container's start row index to the new maximum rows
  243. // count, but do not touch our index - we aren't a "view", so we
  244. // don't want/need to change the start index.
  245. int tmp = _startRowIndex - _maximumRows;
  246. if (tmp < 0 || tmp >= _totalRowCount)
  247. tmp = 0;
  248. // Trigger the databinding, which will call us again, with adjusted
  249. // data, so that we can recreate the pager fields.
  250. _pageableContainer.SetPageProperties (tmp, _maximumRows, true);
  251. } else if (!_createPagerFieldsRunning)
  252. // No adjustments necessary, re-create the pager fields
  253. CreatePagerFields ();
  254. }
  255. protected virtual void RecreateChildControls ()
  256. {
  257. // This is used only by VS designer
  258. throw new NotImplementedException ();
  259. }
  260. protected internal override void Render (HtmlTextWriter writer)
  261. {
  262. RenderBeginTag (writer);
  263. RenderContents (writer);
  264. writer.RenderEndTag ();
  265. }
  266. public virtual void RenderBeginTag (HtmlTextWriter writer)
  267. {
  268. AddAttributesToRender (writer);
  269. writer.RenderBeginTag (TagKey);
  270. }
  271. protected virtual void RenderContents (HtmlTextWriter writer)
  272. {
  273. // Nothing special to render, just child controls
  274. base.Render (writer);
  275. }
  276. protected internal override object SaveControlState ()
  277. {
  278. object[] ret = new object [CSTATE_COUNT];
  279. ret [CSTATE_BASE_STATE] = base.SaveControlState ();
  280. ret [CSTATE_TOTAL_ROW_COUNT] = _totalRowCount <= 0 ? 0 : _totalRowCount;
  281. ret [CSTATE_MAXIMUM_ROWS] = _maximumRows <= 0 ? 0 : _maximumRows;
  282. ret [CSTATE_START_ROW_INDEX] = _startRowIndex <= 0 ? 0 : _startRowIndex;
  283. return ret;
  284. }
  285. protected override object SaveViewState ()
  286. {
  287. Pair ret = new Pair ();
  288. ret.First = base.SaveViewState ();
  289. ret.Second = _fields != null ? ((IStateManager) _fields).SaveViewState () : null;
  290. return ret;
  291. }
  292. public virtual void SetPageProperties (int startRowIndex, int maximumRows, bool databind)
  293. {
  294. if (_pageableContainer == null)
  295. throw new InvalidOperationException (_exceptionMessages [NO_DATABOUND_CONTROL]);
  296. _startRowIndex = startRowIndex;
  297. _maximumRows = maximumRows;
  298. _needSetPageProperties = false;
  299. _pageableContainer.SetPageProperties (startRowIndex, maximumRows, databind);
  300. }
  301. protected override void TrackViewState ()
  302. {
  303. base.TrackViewState ();
  304. if (_fields != null)
  305. ((IStateManager) _fields).TrackViewState ();
  306. }
  307. [BrowsableAttribute(false)]
  308. public AttributeCollection Attributes {
  309. get {
  310. if (_attributes == null)
  311. _attributes = new AttributeCollection (new StateBag ());
  312. return _attributes;
  313. }
  314. }
  315. public override ControlCollection Controls {
  316. get {
  317. EnsureChildControls ();
  318. return base.Controls;
  319. }
  320. }
  321. [PersistenceModeAttribute(PersistenceMode.InnerProperty)]
  322. public virtual DataPagerFieldCollection Fields {
  323. get { return _fields; }
  324. }
  325. [BrowsableAttribute(false)]
  326. public int MaximumRows {
  327. get { return _maximumRows; }
  328. }
  329. [ThemeableAttribute(false)]
  330. public virtual string PagedControlID {
  331. get {
  332. string ret = ViewState ["PagedControlID"] as string;
  333. if (ret == null)
  334. return String.Empty;
  335. return ret;
  336. }
  337. set { ViewState ["PagedControlID"] = value; }
  338. }
  339. public int PageSize {
  340. get { return _maximumRows; }
  341. set {
  342. if (value < 1)
  343. throw new ArgumentOutOfRangeException ("value");
  344. if (value == _maximumRows)
  345. return;
  346. _maximumRows = value;
  347. if (_initDone) {
  348. // We have a source and the page size has changed, update
  349. // the container
  350. CreatePagerFields ();
  351. // Environment has changed, let the container know that it
  352. // needs to rebind.
  353. SetPageProperties (_startRowIndex, _maximumRows, true);
  354. }
  355. }
  356. }
  357. public string QueryStringField {
  358. get {
  359. string ret = ViewState ["QueryStringField"] as string;
  360. if (ret == null)
  361. return String.Empty;
  362. return ret;
  363. }
  364. set { ViewState ["QueryStringField"] = value; }
  365. }
  366. [BrowsableAttribute(false)]
  367. public int StartRowIndex {
  368. get { return _startRowIndex; }
  369. }
  370. [BrowsableAttribute(false)]
  371. protected virtual HtmlTextWriterTag TagKey {
  372. get { return HtmlTextWriterTag.Span; }
  373. }
  374. [BrowsableAttribute(false)]
  375. public int TotalRowCount {
  376. get { return _totalRowCount; }
  377. }
  378. string IAttributeAccessor.GetAttribute (string key)
  379. {
  380. return Attributes [key];
  381. }
  382. void IAttributeAccessor.SetAttribute (string key, string value)
  383. {
  384. Attributes [key] = value;
  385. }
  386. void ICompositeControlDesignerAccessor.RecreateChildControls ()
  387. {
  388. RecreateChildControls ();
  389. }
  390. }
  391. }
  392. #endif