e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
624 lines
21 KiB
C#
624 lines
21 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="List.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Globalization;
|
|
using System.Web;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls;
|
|
using System.Web.UI.HtmlControls;
|
|
using System.Security.Permissions;
|
|
|
|
namespace System.Web.UI.MobileControls
|
|
{
|
|
/*
|
|
* Mobile List class.
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*/
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List"]/*' />
|
|
[
|
|
ControlBuilderAttribute(typeof(ListControlBuilder)),
|
|
DefaultEvent("ItemCommand"),
|
|
DefaultProperty("DataSource"),
|
|
Designer(typeof(System.Web.UI.Design.MobileControls.ListDesigner)),
|
|
DesignerAdapter(typeof(System.Web.UI.Design.MobileControls.Adapters.DesignerListAdapter)),
|
|
Editor(typeof(System.Web.UI.Design.MobileControls.ListComponentEditor), typeof(ComponentEditor)),
|
|
ToolboxData("<{0}:List runat=\"server\"></{0}:List>"),
|
|
ToolboxItem("System.Web.UI.Design.WebControlToolboxItem, " + AssemblyRef.SystemDesign),
|
|
]
|
|
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
|
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
|
[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.")]
|
|
public class List : PagedControl, INamingContainer, IListControl, ITemplateable, IPostBackEventHandler
|
|
{
|
|
private static readonly Object EventItemCommand = new Object();
|
|
private static readonly Object EventItemDataBind = new Object();
|
|
|
|
private ListDataHelper _dataHelper;
|
|
private ListDecoration _decoration = ListDecoration.None;
|
|
|
|
private ListDataHelper DataHelper {
|
|
get {
|
|
if (_dataHelper == null) {
|
|
_dataHelper = new ListDataHelper(this, ViewState);
|
|
}
|
|
|
|
return _dataHelper;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.DataSource"]/*' />
|
|
/// <summary>
|
|
/// <para>
|
|
/// Gets or sets the <see langword='DataSource'/> property of the control which is used to populate
|
|
/// the items within the control.
|
|
/// </para>
|
|
/// </summary>
|
|
[
|
|
Bindable(true),
|
|
DefaultValue(null),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
|
|
MobileCategory(SR.Category_Data),
|
|
MobileSysDescription(SR.List_DataSource)
|
|
]
|
|
public virtual Object DataSource
|
|
{
|
|
get
|
|
{
|
|
return DataHelper.DataSource;
|
|
}
|
|
|
|
set
|
|
{
|
|
DataHelper.DataSource = value;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.DataMember"]/*' />
|
|
[
|
|
Bindable(false),
|
|
DefaultValue(""),
|
|
MobileCategory(SR.Category_Data),
|
|
MobileSysDescription(SR.List_DataMember),
|
|
TypeConverter(typeof(System.Web.UI.Design.MobileControls.Converters.DataMemberConverter))
|
|
]
|
|
public virtual String DataMember
|
|
{
|
|
get
|
|
{
|
|
return DataHelper.DataMember;
|
|
}
|
|
|
|
set
|
|
{
|
|
DataHelper.DataMember = value;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.DataTextField"]/*' />
|
|
[
|
|
DefaultValue(""),
|
|
MobileCategory(SR.Category_Data),
|
|
MobileSysDescription(SR.List_DataTextField),
|
|
TypeConverter(typeof(System.Web.UI.Design.MobileControls.Converters.DataFieldConverter))
|
|
]
|
|
public String DataTextField
|
|
{
|
|
get
|
|
{
|
|
return DataHelper.DataTextField;
|
|
}
|
|
set
|
|
{
|
|
DataHelper.DataTextField = value;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.DataValueField"]/*' />
|
|
[
|
|
DefaultValue(""),
|
|
MobileCategory(SR.Category_Data),
|
|
MobileSysDescription(SR.List_DataValueField),
|
|
TypeConverter(typeof(System.Web.UI.Design.MobileControls.Converters.DataFieldConverter))
|
|
]
|
|
public String DataValueField
|
|
{
|
|
get
|
|
{
|
|
return DataHelper.DataValueField;
|
|
}
|
|
set
|
|
{
|
|
DataHelper.DataValueField = value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.ItemsAsLinks"]/*' />
|
|
[
|
|
Bindable(true),
|
|
DefaultValue(false),
|
|
MobileCategory(SR.Category_Behavior),
|
|
MobileSysDescription(SR.List_ItemsAsLinks)
|
|
]
|
|
public bool ItemsAsLinks
|
|
{
|
|
get
|
|
{
|
|
Object b = ViewState["ItemsAsLinks"];
|
|
return (b != null) ? (bool) b : false;
|
|
}
|
|
set
|
|
{
|
|
ViewState["ItemsAsLinks"] = value;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.Items"]/*' />
|
|
[
|
|
Bindable(false),
|
|
DefaultValue(null),
|
|
Editor(typeof(System.Web.UI.Design.MobileControls.ItemCollectionEditor), typeof(UITypeEditor)),
|
|
MergableProperty(false),
|
|
MobileSysDescription(SR.List_Items),
|
|
PersistenceMode(PersistenceMode.InnerDefaultProperty)
|
|
]
|
|
public MobileListItemCollection Items
|
|
{
|
|
get
|
|
{
|
|
return DataHelper.Items;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.EnsureTemplatedUI"]/*' />
|
|
public override void EnsureTemplatedUI()
|
|
{
|
|
EnsureChildControls();
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.AddParsedSubObject"]/*' />
|
|
protected override void AddParsedSubObject(Object obj)
|
|
{
|
|
if (!(obj is LiteralControl))
|
|
{
|
|
if (obj is MobileListItem)
|
|
{
|
|
DataHelper.AddItem((MobileListItem)obj);
|
|
}
|
|
else
|
|
{
|
|
base.AddParsedSubObject(obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.CreateChildControls"]/*' />
|
|
protected override void CreateChildControls()
|
|
{
|
|
CreateChildControls(false);
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.EnsureChildControls"]/*' />
|
|
protected override void EnsureChildControls()
|
|
{
|
|
// Whenever EnsureChildControls is called before items are created
|
|
// (e.g., at LoadPrivateViewState), there are no controls.
|
|
// Rebuild children for this case by setting ChildControlsCreated to false.
|
|
ChildControlsCreated = ChildControlsCreated && Controls.Count > 0;
|
|
base.EnsureChildControls();
|
|
}
|
|
|
|
private void CreateChildControls(bool doDataBind)
|
|
{
|
|
if (IsTemplated && DataHelper.HasItems() && Items.Count > 0)
|
|
{
|
|
Controls.Clear();
|
|
CreateTemplatedUI(doDataBind);
|
|
}
|
|
ChildControlsCreated = true;
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnDataBinding"]/*' />
|
|
protected override void OnDataBinding(EventArgs e)
|
|
{
|
|
base.OnDataBinding(e);
|
|
if (DataHelper.ResolvedDataSource != null)
|
|
{
|
|
Controls.Clear();
|
|
ClearChildViewState();
|
|
CreateItems(DataHelper.ResolvedDataSource);
|
|
CreateChildControls(true);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.CreateItems"]/*' />
|
|
protected virtual void CreateItems(IEnumerable dataSource)
|
|
{
|
|
DataHelper.CreateItems(dataSource);
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.CreateDefaultTemplatedUI"]/*' />
|
|
public override void CreateDefaultTemplatedUI(bool doDataBind)
|
|
{
|
|
MobileListItemCollection items = Items;
|
|
|
|
ITemplate headerTemplate = GetTemplate(Constants.HeaderTemplateTag);
|
|
ITemplate footerTemplate = GetTemplate(Constants.FooterTemplateTag);
|
|
ITemplate itemTemplate = GetTemplate(Constants.ItemTemplateTag);
|
|
ITemplate separatorTemplate = GetTemplate(Constants.SeparatorTemplateTag);
|
|
ITemplate alternatingItemTemplate = GetTemplate(Constants.AlternatingItemTemplateTag);
|
|
if (alternatingItemTemplate == null)
|
|
{
|
|
alternatingItemTemplate = itemTemplate;
|
|
}
|
|
|
|
CreateControlItem(MobileListItemType.HeaderItem,
|
|
headerTemplate,
|
|
doDataBind);
|
|
for (int i = 0; i < items.Count; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
CreateControlItem(MobileListItemType.SeparatorItem,
|
|
separatorTemplate,
|
|
doDataBind);
|
|
}
|
|
AddItemAsControl(i,
|
|
items[i],
|
|
((i & 1) == 1) ? alternatingItemTemplate : itemTemplate,
|
|
doDataBind);
|
|
}
|
|
CreateControlItem(MobileListItemType.FooterItem,
|
|
footerTemplate,
|
|
doDataBind);
|
|
}
|
|
|
|
private void AddItemAsControl(
|
|
int itemIndex,
|
|
MobileListItem item,
|
|
ITemplate itemTemplate,
|
|
bool doDataBind)
|
|
{
|
|
if (itemTemplate != null)
|
|
{
|
|
item.Controls.Clear();
|
|
CheckedInstantiateTemplate (itemTemplate, item, this);
|
|
Controls.Add(item);
|
|
if (doDataBind)
|
|
{
|
|
item.DataBind();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateControlItem(
|
|
MobileListItemType itemType,
|
|
ITemplate itemTemplate,
|
|
bool doDataBind)
|
|
{
|
|
if (itemTemplate != null)
|
|
{
|
|
MobileListItem item = new MobileListItem(itemType);
|
|
AddItemAsControl(-1, item, itemTemplate, doDataBind);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnPreRender"]/*' />
|
|
protected override void OnPreRender(EventArgs e)
|
|
{
|
|
base.OnPreRender(e);
|
|
|
|
if (IsTemplated)
|
|
{
|
|
int firstVisibleItem = FirstVisibleItemIndex;
|
|
int pageSize = VisibleItemCount;
|
|
int lastVisibleItem = firstVisibleItem + pageSize - 1;
|
|
int itemIndex = 0;
|
|
int separatorIndex = 0;
|
|
foreach(MobileListItem item in Controls)
|
|
{
|
|
if (item.ItemType == MobileListItemType.ListItem)
|
|
{
|
|
item.Visible = itemIndex >= firstVisibleItem && itemIndex <= lastVisibleItem;
|
|
itemIndex++;
|
|
}
|
|
else if (item.ItemType == MobileListItemType.SeparatorItem)
|
|
{
|
|
item.Visible = separatorIndex >= firstVisibleItem &&
|
|
separatorIndex < lastVisibleItem;
|
|
separatorIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.InternalItemCount"]/*' />
|
|
protected override int InternalItemCount
|
|
{
|
|
get
|
|
{
|
|
if (DataHelper.HasItems())
|
|
{
|
|
Debug.Assert (Items.Count >= 0);
|
|
return Items.Count;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnPageChange"]/*' />
|
|
protected override void OnPageChange(int oldPageIndex, int newPageIndex)
|
|
{
|
|
base.OnPageChange(oldPageIndex, newPageIndex);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// EVENT HANDLING
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.ItemCommand"]/*' />
|
|
[
|
|
MobileCategory(SR.Category_Action),
|
|
MobileSysDescription(SR.List_OnItemCommand)
|
|
]
|
|
public event ListCommandEventHandler ItemCommand
|
|
{
|
|
add
|
|
{
|
|
Events.AddHandler(EventItemCommand, value);
|
|
}
|
|
remove
|
|
{
|
|
Events.RemoveHandler(EventItemCommand, value);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnItemCommand"]/*' />
|
|
protected virtual void OnItemCommand(ListCommandEventArgs e)
|
|
{
|
|
ListCommandEventHandler onItemCommandHandler = (ListCommandEventHandler)Events[EventItemCommand];
|
|
if (onItemCommandHandler != null)
|
|
{
|
|
onItemCommandHandler(this, e);
|
|
}
|
|
}
|
|
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.HasItemCommandHandler"]/*' />
|
|
[
|
|
Bindable(false),
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
|
|
]
|
|
public bool HasItemCommandHandler
|
|
{
|
|
get
|
|
{
|
|
return Events[EventItemCommand] != null;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.Decoration"]/*' />
|
|
[
|
|
Bindable(true),
|
|
DefaultValue(ListDecoration.None),
|
|
MobileCategory(SR.Category_Appearance),
|
|
MobileSysDescription(SR.List_Decoration)
|
|
]
|
|
public ListDecoration Decoration
|
|
{
|
|
get
|
|
{
|
|
return _decoration;
|
|
}
|
|
set
|
|
{
|
|
_decoration = value;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.ItemDataBind"]/*' />
|
|
[
|
|
MobileCategory(SR.Category_Action),
|
|
MobileSysDescription(SR.List_OnItemDataBind)
|
|
]
|
|
public event ListDataBindEventHandler ItemDataBind
|
|
{
|
|
add
|
|
{
|
|
Events.AddHandler(EventItemDataBind, value);
|
|
}
|
|
remove
|
|
{
|
|
Events.RemoveHandler(EventItemDataBind, value);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnItemDataBind"]/*' />
|
|
protected virtual void OnItemDataBind(ListDataBindEventArgs e)
|
|
{
|
|
ListDataBindEventHandler onItemDataBindHandler =
|
|
(ListDataBindEventHandler)Events[EventItemDataBind];
|
|
if (onItemDataBindHandler != null)
|
|
{
|
|
onItemDataBindHandler(this, e);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnBubbleEvent"]/*' />
|
|
protected override bool OnBubbleEvent(Object sender, EventArgs e)
|
|
{
|
|
bool handled = false;
|
|
|
|
if (e is ListCommandEventArgs)
|
|
{
|
|
OnItemCommand((ListCommandEventArgs)e);
|
|
handled = true;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
/// <internalonly/>
|
|
protected void RaisePostBackEvent(String eventArgument)
|
|
{
|
|
if(!ItemsAsLinks)
|
|
{
|
|
// Non-templated list got a click event. There really
|
|
// isn't a command source, so we'll set it to the
|
|
// default of null.
|
|
int item = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
|
|
item = TranslateVirtualItemIndex(item);
|
|
OnItemCommand(new ListCommandEventArgs(Items[item], null));
|
|
}
|
|
else
|
|
{
|
|
MobilePage.ActiveForm = MobilePage.GetForm(eventArgument);
|
|
}
|
|
}
|
|
|
|
private int TranslateVirtualItemIndex(int itemIndex)
|
|
{
|
|
// Ensure that the item of the given virtual index is loaded,
|
|
// and translate as necessary to an index within the collection.
|
|
|
|
if (ItemCount > 0)
|
|
{
|
|
if (DataHelper.HasItems() && Items.Count > itemIndex - Items.BaseIndex)
|
|
{
|
|
itemIndex -= Items.BaseIndex;
|
|
}
|
|
else
|
|
{
|
|
OnLoadItems(new LoadItemsEventArgs(itemIndex, 1));
|
|
itemIndex = 0;
|
|
}
|
|
}
|
|
|
|
return itemIndex;
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.OnLoadItems"]/*' />
|
|
protected override void OnLoadItems(LoadItemsEventArgs e)
|
|
{
|
|
// We should only load items if the base index has changed, or if
|
|
// the desired items do not exist in the list. Otherwise, we are making
|
|
// the app reload the same items over and over.
|
|
|
|
if (e.ItemIndex != Items.BaseIndex || e.ItemCount != Items.Count)
|
|
{
|
|
Items.BaseIndex = e.ItemIndex;
|
|
Items.Clear();
|
|
base.OnLoadItems(e);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// STATE MANAGEMENT
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.TrackViewState"]/*' />
|
|
protected override void TrackViewState()
|
|
{
|
|
base.TrackViewState();
|
|
if (DataHelper.HasItems())
|
|
{
|
|
((IStateManager)Items).TrackViewState();
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.SaveViewState"]/*' />
|
|
protected override Object SaveViewState()
|
|
{
|
|
Object baseState, itemsState;
|
|
|
|
if (DataHelper.HasItems())
|
|
{
|
|
itemsState = ((IStateManager)Items).SaveViewState();
|
|
}
|
|
else
|
|
{
|
|
itemsState = null;
|
|
}
|
|
baseState = base.SaveViewState();
|
|
|
|
if (itemsState != null || Decoration != ListDecoration.None )
|
|
{
|
|
return new Object[3] { baseState, itemsState, Decoration };
|
|
}
|
|
else if (baseState != null)
|
|
{
|
|
return new Object[1] { baseState };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.LoadViewState"]/*' />
|
|
protected override void LoadViewState(Object savedState)
|
|
{
|
|
if (savedState != null)
|
|
{
|
|
Object[] state = (Object[])savedState;
|
|
base.LoadViewState(state[0]);
|
|
|
|
if (state.Length > 1)
|
|
{
|
|
((IStateManager)Items).LoadViewState(state[1]);
|
|
Decoration = (ListDecoration) state[2];
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override void InternalItemCountChangedHandler(int newItemCount)
|
|
{
|
|
if (newItemCount == 0)
|
|
{
|
|
Items.Clear();
|
|
Controls.Clear();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// IListControl
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.IListControl.OnItemDataBind"]/*' />
|
|
/// <internalonly/>
|
|
void IListControl.OnItemDataBind(ListDataBindEventArgs e)
|
|
{
|
|
OnItemDataBind(e);
|
|
}
|
|
|
|
/// <include file='doc\List.uex' path='docs/doc[@for="List.IListControl.TrackingViewState"]/*' />
|
|
/// <internalonly/>
|
|
bool IListControl.TrackingViewState
|
|
{
|
|
get
|
|
{
|
|
return IsTrackingViewState;
|
|
}
|
|
}
|
|
|
|
#region IPostBackEventHandler implementation
|
|
void IPostBackEventHandler.RaisePostBackEvent(String eventArgument) {
|
|
RaisePostBackEvent(eventArgument);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|