//
// System.Web.UI.WebControls.DataPager
//
// Authors:
// Marek Habersack (mhabersack@novell.com)
//
// (C) 2007-2008 Novell, Inc
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#if NET_3_5
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
namespace System.Web.UI.WebControls{
// [ToolboxBitmap (typeof (System.Web.UI.WebControls.DataPager), "DataPager.ico")]
[ToolboxItemFilter ("System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", ToolboxItemFilterType.Require)]
[SupportsEventValidation]
[Themeable (true)]
[ParseChildren (true)]
[Designer ("System.Web.UI.Design.WebControls.DataPagerDesigner, System.Web.Extensions.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
[PersistChildren (false)]
public class DataPager : Control, IAttributeAccessor, INamingContainer, ICompositeControlDesignerAccessor
{
const int NO_PAGEABLE_ITEM_CONTAINER = 0;
const int NO_DATABOUND_CONTROL = 1;
const int NO_PAGED_CONTAINER_ID = 2;
const int CONTROL_NOT_PAGEABLE = 3;
const int NO_NAMING_CONTAINER = 4;
const int CSTATE_BASE_STATE = 0;
const int CSTATE_TOTAL_ROW_COUNT = 1;
const int CSTATE_MAXIMUM_ROWS = 2;
const int CSTATE_START_ROW_INDEX = 3;
const int CSTATE_COUNT = 4;
string[] _exceptionMessages = {
"No IPageableItemContainer was found. Verify that either the DataPager is inside an IPageableItemContainer or PagedControlID is set to the control ID of an IPageableItemContainer",
"There is no data-bound control associated with the DataPager control.",
"Control with id '{0}' cannot be found in the page",
"Control '{0}' is not pageable",
"DataPager has no naming container"
};
IPageableItemContainer _pageableContainer;
DataPagerFieldCollection _fields;
AttributeCollection _attributes;
int _totalRowCount;
int _startRowIndex;
int _maximumRows = 10;
bool _initDone;
bool _needNewContainerSetup = true;
bool _needSetPageProperties = true;
bool _createPagerFieldsRunning;
public DataPager()
{
_fields = new DataPagerFieldCollection (this);
}
protected virtual void AddAttributesToRender (HtmlTextWriter writer)
{
if (ID != null)
writer.AddAttribute (HtmlTextWriterAttribute.Id, ID);
if (_attributes != null && _attributes.Count > 0) {
foreach (string attr in _attributes.Keys)
writer.AddAttribute (attr, _attributes [attr]);
}
}
protected virtual void ConnectToEvents (IPageableItemContainer container)
{
if (container == null)
throw new ArgumentNullException ("container");
container.TotalRowCountAvailable += new EventHandler <PageEventArgs> (OnTotalRowCountAvailable);
}
protected virtual void CreatePagerFields ()
{
// In theory (on multi-core or SMP machines), OnTotalRowCountAvailable may
// be called asynchronously to this method (since it is a delegate reacting
// to event in the container), so we want to protect ourselves from data
// corruption here. Lock would be an overkill, since we really want to
// create the list only once anyway.
_createPagerFieldsRunning = true;
ControlCollection controls = Controls;
controls.Clear ();
DataPagerFieldItem control;
foreach (DataPagerField dpf in _fields) {
control = new DataPagerFieldItem (dpf, this);
controls.Add (control);
if (dpf.Visible) {
dpf.CreateDataPagers (control, _startRowIndex, _maximumRows, _totalRowCount, _fields.IndexOf (dpf));
control.DataBind ();
}
}
_createPagerFieldsRunning = false;
}
public override void DataBind ()
{
OnDataBinding (EventArgs.Empty);
EnsureChildControls ();
DataBindChildren ();
}
protected virtual IPageableItemContainer FindPageableItemContainer ()
{
string pagedControlID = PagedControlID;
IPageableItemContainer ret = null;
Page page = Page;
Control container;
if (page != null && !String.IsNullOrEmpty (pagedControlID)) {
Control ctl = null;
container = NamingContainer;
while (container != null) {
ctl = container.FindControl (pagedControlID);
if (ctl != null)
break;
if (container == page)
break;
container = container.NamingContainer;
}
if (container == null)
throw new InvalidOperationException (_exceptionMessages [NO_NAMING_CONTAINER]);
if (ctl == null)
throw new InvalidOperationException (String.Format (_exceptionMessages [NO_PAGED_CONTAINER_ID], pagedControlID));
ret = ctl as IPageableItemContainer;
if (ret == null)
throw new InvalidOperationException (String.Format (_exceptionMessages [CONTROL_NOT_PAGEABLE], pagedControlID));
return ret;
}
// No ID set, try to find a container that's pageable
container = NamingContainer;
while (container != page) {
if (container == null)
throw new InvalidOperationException (_exceptionMessages [NO_NAMING_CONTAINER]);
ret = container as IPageableItemContainer;
if (ret != null)
return ret;
container = container.NamingContainer;
}
return ret;
}
protected internal override void LoadControlState (object savedState)
{
object[] state = savedState as object[];
object tmp;
if (state != null && state.Length == CSTATE_COUNT) {
base.LoadControlState (state [CSTATE_BASE_STATE]);
if ((tmp = state [CSTATE_TOTAL_ROW_COUNT]) != null)
_totalRowCount = (int) tmp;
if ((tmp = state [CSTATE_MAXIMUM_ROWS]) != null)
_maximumRows = (int) tmp;
if ((tmp = state [CSTATE_START_ROW_INDEX]) != null)
_startRowIndex = (int) tmp;
}
if (_pageableContainer == null) {
_pageableContainer = FindPageableItemContainer ();
if (_pageableContainer == null)
throw new InvalidOperationException (_exceptionMessages [NO_DATABOUND_CONTROL]);
ConnectToEvents (_pageableContainer);
}
SetUpForNewContainer (false, false);
}
protected override void LoadViewState (object savedState)
{
var state = savedState as object[];
if (state == null || state.Length != 2)
return;
base.LoadViewState (state [0]);
object myState = state [1];
if (myState != null)
((IStateManager) Fields).LoadViewState (myState);
}
protected override bool OnBubbleEvent (object source, EventArgs e)
{
DataPagerFieldCommandEventArgs args = e as DataPagerFieldCommandEventArgs;
if (args != null) {
DataPagerFieldItem item = args.Item;
DataPagerField field = item != null ? item.PagerField : null;
if (field != null) {
field.HandleEvent (args);
return true;
}
}
return false;
}
void SetUpForNewContainer (bool dataBind, bool needSetPageProperties)
{
if (_needNewContainerSetup) {
ConnectToEvents (_pageableContainer);
_needNewContainerSetup = false;
}
if (_needSetPageProperties) {
_pageableContainer.SetPageProperties (_startRowIndex, _maximumRows, dataBind);
_needSetPageProperties = needSetPageProperties;
}
}
protected internal override void OnInit (EventArgs e)
{
base.OnInit (e);
Page page = Page;
if (page != null)
page.RegisterRequiresControlState (this);
// It might return null here - there is no guarantee all the controls on the
// page are already initialized by the time this method is loaded. Do not
// throw for that reason.
_pageableContainer = FindPageableItemContainer ();
if (_pageableContainer != null)
// Do not re-bind the data here - not all the controls might be
// initialized (that includes the container may be bound to)
SetUpForNewContainer (false, true);
_initDone = true;
}
protected internal override void OnLoad (EventArgs e)
{
if (_pageableContainer == null)
_pageableContainer = FindPageableItemContainer ();
if (_pageableContainer == null)
throw new InvalidOperationException (_exceptionMessages [NO_PAGEABLE_ITEM_CONTAINER]);
SetUpForNewContainer (false, false);
base.OnLoad (e);
}
protected virtual void OnTotalRowCountAvailable (object sender, PageEventArgs e)
{
_totalRowCount = e.TotalRowCount;
_maximumRows = e.MaximumRows;
_startRowIndex = e.StartRowIndex;
// Sanity checks: if the total row count is less than the current start row
// index, we must adjust and rebind the associated container control
if (_totalRowCount > 0 && (_totalRowCount <= _startRowIndex)) {
// Adjust the container's start row index to the new maximum rows
// count, but do not touch our index - we aren't a "view", so we
// don't want/need to change the start index.
int tmp = _startRowIndex - _maximumRows;
if (tmp < 0 || tmp >= _totalRowCount)
tmp = 0;
// Trigger the databinding, which will call us again, with adjusted
// data, so that we can recreate the pager fields.
_pageableContainer.SetPageProperties (tmp, _maximumRows, true);
} else if (!_createPagerFieldsRunning)
// No adjustments necessary, re-create the pager fields
CreatePagerFields ();
}
protected virtual void RecreateChildControls ()
{
// This is used only by VS designer
throw new NotImplementedException ();
}
protected internal override void Render (HtmlTextWriter writer)
{
RenderBeginTag (writer);
RenderContents (writer);
writer.RenderEndTag ();
}
public virtual void RenderBeginTag (HtmlTextWriter writer)
{
AddAttributesToRender (writer);
writer.RenderBeginTag (TagKey);
}
protected virtual void RenderContents (HtmlTextWriter writer)
{
// Nothing special to render, just child controls
base.Render (writer);
}
protected internal override object SaveControlState ()
{
object[] ret = new object [CSTATE_COUNT];
ret [CSTATE_BASE_STATE] = base.SaveControlState ();
ret [CSTATE_TOTAL_ROW_COUNT] = _totalRowCount <= 0 ? 0 : _totalRowCount;
ret [CSTATE_MAXIMUM_ROWS] = _maximumRows <= 0 ? 0 : _maximumRows;
ret [CSTATE_START_ROW_INDEX] = _startRowIndex <= 0 ? 0 : _startRowIndex;
return ret;
}
protected override object SaveViewState ()
{
var ret = new object [2];
ret [0] = base.SaveViewState ();
ret [1] = _fields != null ? ((IStateManager) _fields).SaveViewState () : null;
return ret;
}
public virtual void SetPageProperties (int startRowIndex, int maximumRows, bool databind)
{
if (_pageableContainer == null)
throw new InvalidOperationException (_exceptionMessages [NO_DATABOUND_CONTROL]);
_startRowIndex = startRowIndex;
_maximumRows = maximumRows;
_needSetPageProperties = false;
_pageableContainer.SetPageProperties (startRowIndex, maximumRows, databind);
}
protected override void TrackViewState ()
{
base.TrackViewState ();
if (_fields != null)
((IStateManager) _fields).TrackViewState ();
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public AttributeCollection Attributes {
get {
if (_attributes == null)
_attributes = new AttributeCollection (new StateBag ());
return _attributes;
}
}
public override ControlCollection Controls {
get {
EnsureChildControls ();
return base.Controls;
}
}
[Category ("Default")]
[PersistenceMode (PersistenceMode.InnerProperty)]
[DefaultValue ("")]
[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))]
[MergableProperty (false)]
public virtual DataPagerFieldCollection Fields {
get { return _fields; }
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public int MaximumRows {
get { return _maximumRows; }
}
[WebCategory ("Paging")]
[IDReferenceProperty (typeof (System.Web.UI.WebControls.IPageableItemContainer))]
[DefaultValue ("")]
[Themeable (false)]
public virtual string PagedControlID {
get {
string ret = ViewState ["PagedControlID"] as string;
if (ret == null)
return String.Empty;
return ret;
}
set { ViewState ["PagedControlID"] = value; }
}
[DefaultValue (10)]
[WebCategory ("Paging")]
public int PageSize {
get { return _maximumRows; }
set {
if (value < 1)
throw new ArgumentOutOfRangeException ("value");
if (value == _maximumRows)
return;
_maximumRows = value;
if (_initDone) {
// We have a source and the page size has changed, update
// the container
CreatePagerFields ();
// Environment has changed, let the container know that it
// needs to rebind.
SetPageProperties (_startRowIndex, _maximumRows, true);
}
}
}
[DefaultValue ("")]
[WebCategory ("Paging")]
public string QueryStringField {
get {
string ret = ViewState ["QueryStringField"] as string;
if (ret == null)
return String.Empty;
return ret;
}
set { ViewState ["QueryStringField"] = value; }
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public int StartRowIndex {
get { return _startRowIndex; }
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
protected virtual HtmlTextWriterTag TagKey {
get { return HtmlTextWriterTag.Span; }
}
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[Browsable (false)]
public int TotalRowCount {
get { return _totalRowCount; }
}
string IAttributeAccessor.GetAttribute (string key)
{
return Attributes [key];
}
void IAttributeAccessor.SetAttribute (string key, string value)
{
Attributes [key] = value;
}
void ICompositeControlDesignerAccessor.RecreateChildControls ()
{
RecreateChildControls ();
}
}
}
#endif
|