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