1 //------------------------------------------------------------------------------
2 // <copyright file="PagedControl.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 using System;
8 using System.Collections;
9 using System.ComponentModel;
10 using System.Web;
11 using System.Web.UI;
12 using System.Web.UI.WebControls;
13 using System.Diagnostics;
14 using System.Security.Permissions;
15 
16 namespace System.Web.UI.MobileControls
17 {
18     /*
19      * Paged control. Abstract control class inherited by all classes
20      * that are internally paginated.
21      *
22      * Copyright (c) 2000 Microsoft Corporation
23      */
24 
25     /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl"]/*' />
26     [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
27     [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
28     [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
29     public abstract class PagedControl : MobileControl
30     {
31         private static readonly Object EventLoadItems = new Object();
32         private const String _itemCountViewStateKey = "_!PagedControlItemCount";
33         private bool _pagingCharacteristicsChanged = false;
34         int _lastItemIndexLoaded = -1;
35         int _lastItemCountLoaded = -1;
36         Pair _stateLoadItemsArgs = null;
37 
38         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.LoadItems"]/*' />
39         [
40             MobileCategory(SR.Category_Action),
41             MobileSysDescription(SR.PagedControl_OnLoadItems)
42         ]
43         public event LoadItemsEventHandler LoadItems
44         {
45             add
46             {
47                 Events.AddHandler(EventLoadItems, value);
48             }
49             remove
50             {
51                 Events.RemoveHandler(EventLoadItems, value);
52             }
53         }
54 
OnLoadItems()55         private void OnLoadItems()
56         {
57             int index, count;
58 
59             if (_itemPager != null)
60             {
61                 index = PagerItemIndex;
62                 count = PagerItemCount;
63             }
64             else
65             {
66                 index = 0;
67                 count = ItemCount;
68             }
69 
70             OnLoadItems(new LoadItemsEventArgs(index, count));
71         }
72 
73         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.OnLoadItems"]/*' />
OnLoadItems(LoadItemsEventArgs e)74         protected virtual void OnLoadItems(LoadItemsEventArgs e)
75         {
76             if (LoadItemsHandler != null)
77             {
78                 _lastItemIndexLoaded = e.ItemIndex;
79                 _lastItemCountLoaded = e.ItemCount;
80                 LoadItemsHandler(this, e);
81             }
82         }
83 
84         private bool IsCustomPaging
85         {
86             get
87             {
88                 return ItemCount > 0;
89             }
90         }
91 
92         private LoadItemsEventHandler LoadItemsHandler
93         {
94             get
95             {
96                 return (LoadItemsEventHandler)Events[EventLoadItems];
97             }
98         }
99 
100         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.InternalItemCount"]/*' />
101         protected abstract int InternalItemCount { get; }
102 
103 
104         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.ItemCount"]/*' />
105         [
106             Bindable(true),
107             DefaultValue(0),
108             MobileCategory(SR.Category_Paging),
109             MobileSysDescription(SR.PagedControl_ItemCount)
110         ]
111         public int ItemCount
112         {
113             get
114             {
115                 Object count = ViewState[_itemCountViewStateKey];
116                 return  count == null ? 0 : (int) count;
117             }
118             set
119             {
120                 if (value < 0)
121                 {
122                     throw new ArgumentOutOfRangeException("ItemCount",
123                         SR.GetString(SR.PagedControl_ItemCountCantBeNegative,
124                                      value));
125                 }
126                 bool changed = (ItemCount != value);
127                 ViewState[_itemCountViewStateKey] = value;
128                 if (changed)
129                 {
130                     InternalItemCountChangedHandler(value);
131                 }
132                 ConditionalLoadItemsFromPersistedArgs();
133             }
134         }
135 
136         // Allows special handling of set_ItemCount in derived class,
137         // while maintaining API backward compatibility.
InternalItemCountChangedHandler(int newItemCount)138         internal virtual void InternalItemCountChangedHandler(int newItemCount)
139         {}
140 
141         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.ItemsPerPage"]/*' />
142         [
143             Bindable(true),
144             DefaultValue(0),
145             MobileCategory(SR.Category_Paging),
146             MobileSysDescription(SR.PagedControl_ItemsPerPage)
147         ]
148         public int ItemsPerPage
149         {
150             get
151             {
152                 object o = ViewState["ItemsPerPage"];
153                 return (o != null) ? (int)o : 0;
154             }
155             set
156             {
157                 if (value < 0)
158                 {
159                     throw new ArgumentOutOfRangeException("ItemsPerPage",
160                         SR.GetString(SR.PagedControl_ItemsPerPageCantBeNegative,
161                                      value));
162                 }
163                 ViewState["ItemsPerPage"] = value;
164             }
165         }
166 
167         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.ItemWeight"]/*' />
168         protected virtual int ItemWeight
169         {
170             get
171             {
172                 return ControlPager.DefaultWeight;
173             }
174         }
175 
176         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.FirstVisibleItemIndex"]/*' />
177         [
178             Browsable(false),
179             DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
180         ]
181         public int FirstVisibleItemIndex
182         {
183             get
184             {
185                 return (IsCustomPaging || !EnablePagination) ? 0 : PagerItemIndex;
186             }
187         }
188 
189         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.VisibleItemCount"]/*' />
190         [
191             Browsable(false),
192             DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
193         ]
194         public int VisibleItemCount
195         {
196             get
197             {
198                 return (IsCustomPaging || !EnablePagination) ? InternalItemCount : PagerItemCount;
199             }
200         }
201 
202         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.VisibleWeight"]/*' />
203         public override int VisibleWeight
204         {
205             get
206             {
207                 // Paged control should count the weight as sum of its items
208                 int count = VisibleItemCount;
209                 if (count == -1)
210                 {
211                     return 0;  // -1 means control not on the current page
212                 }
213                 else
214                 {
215                     return count * GetItemWeight();
216                 }
217             }
218         }
219 
220         private ItemPager _itemPager;
221         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.PaginateRecursive"]/*' />
PaginateRecursive(ControlPager pager)222         public override void PaginateRecursive(ControlPager pager)
223         {
224             int itemCount = IsCustomPaging ? ItemCount : InternalItemCount;
225             int itemsPerPage = ItemsPerPage;
226             _itemPager = pager.GetItemPager(this, itemCount, itemsPerPage, GetItemWeight());
227         }
228 
GetItemWeight()229         internal int GetItemWeight()
230         {
231             int weight = Adapter.ItemWeight;
232             if (weight == ControlPager.UseDefaultWeight)
233             {
234                 weight = ItemWeight;
235             }
236             return weight;
237         }
238 
239         private int PagerItemIndex
240         {
241             get
242             {
243                 return (_itemPager == null) ? 0 : _itemPager.ItemIndex;
244             }
245         }
246 
247         private int PagerItemCount
248         {
249             get
250             {
251                 return (_itemPager == null) ? InternalItemCount : _itemPager.ItemCount;
252             }
253         }
254 
255         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.OnPageChange"]/*' />
OnPageChange(int oldPageIndex, int newPageIndex)256         protected override void OnPageChange(int oldPageIndex, int newPageIndex)
257         {
258             _pagingCharacteristicsChanged = true;
259         }
260 
261         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.OnPreRender"]/*' />
OnPreRender(EventArgs e)262         protected override void OnPreRender(EventArgs e)
263         {
264             if (IsCustomPaging &&
265                 IsVisibleOnPage(Form.CurrentPage) &&
266                     (!Page.IsPostBack ||
267                     Form.PaginationStateChanged ||
268                     _pagingCharacteristicsChanged ||
269                     !IsViewStateEnabled()))
270             {
271                 OnLoadItems();
272             }
273 
274             base.OnPreRender(e);
275         }
276 
SetControlPage(int page)277         internal override void SetControlPage(int page)
278         {
279             // Custom pagination being turned off.
280 
281             _itemPager = null;
282             _pagingCharacteristicsChanged = true;
283             base.SetControlPage(page);
284         }
285 
IsViewStateEnabled()286         private new bool IsViewStateEnabled()
287         {
288             for (Control ctl = this; ctl != null; ctl = ctl.Parent)
289             {
290                 if (!ctl.EnableViewState)
291                 {
292                     return false;
293                 }
294             }
295             return true;
296         }
297 
298         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.SavePrivateViewState"]/*' />
SavePrivateViewState()299         protected override Object SavePrivateViewState()
300         {
301             // If the base state is non-null, we always return a Pair with the base state as the
302             // first item.
303             Object baseState = base.SavePrivateViewState();
304             if (IsCustomPaging && IsTemplated && !IsViewStateEnabled() && _lastItemCountLoaded != -1)
305             {
306                 return new Pair(baseState, new Pair(_lastItemIndexLoaded, _lastItemCountLoaded));
307             }
308 
309             if (baseState != null)
310             {
311                 return new Pair(baseState, null);
312             }
313 
314             // baseState is null
315             return null;
316         }
317 
318         /// <include file='doc\PagedControl.uex' path='docs/doc[@for="PagedControl.LoadPrivateViewState"]/*' />
LoadPrivateViewState(Object state)319         protected override void LoadPrivateViewState(Object state)
320         {
321             Debug.Assert (state == null || state.GetType() == typeof(Pair),
322                "If the base state is non-null, private viewstate should always be saved as a pair");
323 
324             Pair statePair = state as Pair;
325             if (statePair != null)
326             {
327                 base.LoadPrivateViewState(statePair.First);
328                 _stateLoadItemsArgs = statePair.Second as Pair;
329                 ConditionalLoadItemsFromPersistedArgs();
330             }
331         }
332 
333         // Loads items using view state pair in templated case where custom paging
334         // on, view state off.  In this special case, load items early as
335         // possible to enable events to be raised.
ConditionalLoadItemsFromPersistedArgs()336         private void ConditionalLoadItemsFromPersistedArgs()
337         {
338             if (_stateLoadItemsArgs != null && IsCustomPaging && IsTemplated && !IsViewStateEnabled())
339             {
340                 OnLoadItems(
341                     new LoadItemsEventArgs((int) _stateLoadItemsArgs.First, (int) _stateLoadItemsArgs.Second));
342                 _stateLoadItemsArgs = null;
343             }
344         }
345     }
346 }
347