//
// System.Web.UI.WebControls.BaseDataList.cs
//
-// Authors:
-// Gaurav Vaish (gvaish@iitk.ac.in)
-// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
-// Sanjay Gupta (gsanjay@novell.com)
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
//
-// (C) Gaurav Vaish (2001)
-// (C) 2003 Andreas Nahr
-// (C) 2004 Novell, Inc. (http://www.novell.com)
-//
-
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
-using System.ComponentModel;
-using System.ComponentModel.Design;
using System.Collections;
-using System.Web;
-using System.Web.UI;
-using System.Web.Util;
-
-namespace System.Web.UI.WebControls
-{
- [DefaultEvent("SelectedIndexChanged")]
- [DefaultProperty("DataSource")]
- [Designer("System.Web.UI.Design.WebControls.BaseDataListDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
- public abstract class BaseDataList: WebControl
- {
- private static readonly object SelectedIndexChangedEvent = new object();
- internal static string ItemCountViewStateKey = "_!ItemCount";
-
- private DataKeyCollection dataKeys;
- private object dataSource;
-
+using System.ComponentModel;
+using System.Security.Permissions;
+
+namespace System.Web.UI.WebControls {
+
+ // CAS
+ [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+ [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+ // attributes
+ [DefaultEvent ("SelectedIndexChanged")]
+ [DefaultProperty ("DataSource")]
+ [Designer ("System.Web.UI.Design.WebControls.BaseDataListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+ public abstract class BaseDataList : WebControl {
+
+ private static readonly object selectedIndexChangedEvent = new object ();
+
+ private DataKeyCollection keycoll;
+ private object source;
#if NET_2_0
- bool inited;
- IDataSource currentSource;
- DataSourceSelectArguments selectArguments = null;
- bool requiresDataBinding;
+ //private string dataSourceId;
+ IDataSource boundDataSource = null;
+ private bool initialized;
+ private bool requiresDataBinding;
+ private DataSourceSelectArguments selectArguments;
+ private IEnumerable data;
#endif
- public BaseDataList() : base()
+ protected BaseDataList ()
{
}
- public static bool IsBindableType(Type type)
- {
- if(type.IsPrimitive || type == typeof(string) || type == typeof(DateTime) || type == typeof(Decimal))
- return true;
- return false;
- }
- public override ControlCollection Controls
- {
- get
- {
- EnsureChildControls();
- return base.Controls;
+ [DefaultValue ("")]
+#if NET_2_0
+ [Localizable (true)]
+#endif
+ [WebSysDescription ("")]
+ [WebCategory ("Accessibility")]
+ public virtual string Caption {
+ get { return ViewState.GetString ("Caption", ""); }
+ set {
+ if (value == null)
+ ViewState.Remove ("Caption");
+ else
+ ViewState ["Caption"] = value;
}
}
- public override void DataBind()
- {
- #if NET_2_0
- RequiresDataBinding = false;
- #endif
- OnDataBinding(EventArgs.Empty);
- }
+ [DefaultValue (TableCaptionAlign.NotSet)]
+ public virtual TableCaptionAlign CaptionAlign {
+ get { return (TableCaptionAlign) ViewState.GetInt ("CaptionAlign", (int)TableCaptionAlign.NotSet); }
+ set {
+ if ((value < TableCaptionAlign.NotSet) || (value > TableCaptionAlign.Right))
+ throw new ArgumentOutOfRangeException (Locale.GetText ("Invalid TableCaptionAlign value."));
- [WebCategory("Action")]
- [WebSysDescription("BaseDataList_OnSelectedIndexChanged")]
- public event EventHandler SelectedIndexChanged
- {
- add
- {
- Events.AddHandler(SelectedIndexChangedEvent, value);
- }
- remove
- {
- Events.RemoveHandler(SelectedIndexChangedEvent, value);
+ ViewState ["CaptionAlign"] = value;
}
}
-#if !NET_2_0
- [Bindable(true)]
+#if ONLY_1_1
+ [Bindable (true)]
#endif
- [DefaultValue(-1)]
+ [DefaultValue (-1)]
+ [WebSysDescription("")]
[WebCategory("Layout")]
- [WebSysDescription("BaseDataList_CellPadding")]
- public virtual int CellPadding
- {
- get
- {
- if(!ControlStyleCreated)
- return -1;
- return ((TableStyle)ControlStyle).CellPadding;
- }
- set
- {
- ((TableStyle)ControlStyle).CellPadding = value;
+ public virtual int CellPadding {
+ get {
+ if (!ControlStyleCreated)
+ return -1; // default value
+ return TableStyle.CellPadding;
}
+ set { TableStyle.CellPadding = value; }
}
-#if !NET_2_0
- [Bindable(true)]
+#if ONLY_1_1
+ [Bindable (true)]
#endif
- [DefaultValue(-1)]
+ [DefaultValue (0)]
+ [WebSysDescription("")]
[WebCategory("Layout")]
- [WebSysDescription("BaseDataList_CellSpacing")]
- public virtual int CellSpacing
- {
- get
- {
- if(!ControlStyleCreated)
- return -1;
- return ((TableStyle)ControlStyle).CellSpacing;
+ public virtual int CellSpacing {
+ get {
+ if (!ControlStyleCreated)
+ return 0; // default value
+ return TableStyle.CellSpacing;
}
- set
- {
- ((TableStyle)ControlStyle).CellSpacing = value;
+ set { TableStyle.CellSpacing = value; }
+ }
+
+ public override ControlCollection Controls {
+ get {
+ EnsureChildControls ();
+ return base.Controls;
}
}
+ [DefaultValue ("")]
#if NET_2_0
- [ThemeableAttribute (false)]
+ [Themeable (false)]
#endif
- [DefaultValue("")]
+ [MonoTODO ("incomplete")]
+ [WebSysDescription("")]
[WebCategory("Data")]
- [WebSysDescription("BaseDataList_DataKeyField")]
- public virtual string DataKeyField
- {
- get
- {
- object o = ViewState["DataKeyField"];
- if(o!=null)
- return (string)o;
- return String.Empty;
- }
- set
- {
- ViewState["DataKeyField"] = value;
+ public virtual string DataKeyField {
+ get { return ViewState.GetString ("DataKeyField", ""); }
+ set {
+ if (value == null)
+ ViewState.Remove ("DataKeyField");
+ else
+ ViewState ["DataKeyField"] = value;
}
}
- [Browsable(true)]
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [WebSysDescription("BaseDataList_DataKeys")]
- public DataKeyCollection DataKeys
- {
- get
- {
- if( dataKeys==null )
- dataKeys = new DataKeyCollection(DataKeysArray);
- return dataKeys;
+ [Browsable (false)]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [WebSysDescription("")]
+ [WebCategory("Data")]
+ public DataKeyCollection DataKeys {
+ get {
+ if (keycoll == null)
+ keycoll = new DataKeyCollection (DataKeysArray);
+ return keycoll;
+ }
+ }
+ protected ArrayList DataKeysArray {
+ get {
+ ArrayList keys = (ArrayList) ViewState ["DataKeys"];
+ if (keys == null) {
+ keys = new ArrayList ();
+ ViewState ["DataKeys"] = keys;
+ }
+ return keys;
}
}
+ [DefaultValue ("")]
#if NET_2_0
- [ThemeableAttribute (false)]
+ [Themeable (false)]
#endif
- [DefaultValue("")]
+ [WebSysDescription("")]
[WebCategory("Data")]
- [WebSysDescription("BaseDataList_DataMember")]
- public string DataMember
- {
- get
- {
- object o = ViewState["DataMember"];
- if(o!=null)
- return (string)o;
- return String.Empty;
- }
- set
- {
- ViewState["DataMember"] = value;
+ public string DataMember {
+ get { return ViewState.GetString ("DataMember", ""); }
+ set {
+ if (value == null)
+ ViewState.Remove ("DataMember");
+ else
+ ViewState ["DataMember"] = value;
+#if NET_2_0
+ if (!Initialized)
+ OnDataPropertyChanged ();
+#endif
}
}
+ [Bindable (true)]
+ [DefaultValue (null)]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
#if NET_2_0
- [ThemeableAttribute (false)]
+ [Themeable (false)]
#endif
- [Bindable(true)]
- [DefaultValue(null)]
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ [WebSysDescription("")]
[WebCategory("Data")]
- [WebSysDescription("BaseDataList_DataSource")]
public virtual object DataSource {
- get {
- return dataSource;
- }
+ get { return source; }
set {
- if (value == null || value is IListSource || value is IEnumerable) {
- dataSource = value;
+ if ((value == null) || (value is IEnumerable) || (value is IListSource)) {
#if NET_2_0
- if (inited) OnDataPropertyChanged ();
+// FIXME - can't duplicate in a test case ? LAMESPEC ?
+// can't duplicate in a test case
+// if ((dataSourceId != null) && (dataSourceId.Length != 0))
+// throw new HttpException (Locale.GetText ("DataSourceID is already set."));
+
+ source = value;
+
+ if (!Initialized)
+ OnDataPropertyChanged ();
+#else
+ source = value;
#endif
} else {
- throw new ArgumentException (HttpRuntime.FormatResourceString (
- "Invalid_DataSource_Type", ID));
+ string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
+ "IEnumerable", "IListSource");
+ throw new ArgumentException (msg);
}
}
}
-#if !NET_2_0
- [Bindable(true)]
+#if ONLY_1_1
+ [Bindable (true)]
#endif
- [DefaultValue(GridLines.Both)]
+ [DefaultValue (GridLines.Both)]
+ [WebSysDescription("")]
[WebCategory("Appearance")]
- [WebSysDescription("BaseDataList_GridLines")]
- public virtual GridLines GridLines
- {
- get
- {
- if(ControlStyleCreated)
- return ((TableStyle)ControlStyle).GridLines;
- return GridLines.Both;
+ public virtual GridLines GridLines {
+ get {
+ if (!ControlStyleCreated)
+ return GridLines.Both; // default value
+ return TableStyle.GridLines;
}
- set
- {
- ((TableStyle)ControlStyle).GridLines = value;
+ set { TableStyle.GridLines = value; }
+ }
+
+#if ONLY_1_1
+ [Bindable (true)]
+#endif
+ [Category ("Layout")]
+ [DefaultValue (HorizontalAlign.NotSet)]
+ [WebSysDescription("")]
+ public virtual HorizontalAlign HorizontalAlign {
+ get {
+ if (!ControlStyleCreated)
+ return HorizontalAlign.NotSet; // default value
+ return TableStyle.HorizontalAlign;
}
+ set { TableStyle.HorizontalAlign = value; }
+ }
+
+ [DefaultValue (false)]
+ public virtual bool UseAccessibleHeader {
+ get { return ViewState.GetBool ("UseAccessibleHeader", false); }
+ set { ViewState ["UseAccessibleHeader"] = value; }
}
+#if NET_2_0
+ [DefaultValue ("")]
+ [IDReferenceProperty (typeof (DataSourceControl))]
+ [Themeable (false)]
+ public virtual string DataSourceID {
+ get { return ViewState.GetString ("DataSourceID", ""); }
+ set {
+ // LAMESPEC ? this is documented as an HttpException in beta2
+ if (source != null)
+ throw new InvalidOperationException (Locale.GetText ("DataSource is already set."));
- // LAMESPEC HorizontalAlign has a Category attribute, this should obviously be a WebCategory attribute
- // but is defined incorrectly in the MS framework
+ ViewState ["DataSourceID"] = value;
-#if !NET_2_0
- [Bindable(true)]
-#endif
- [DefaultValue(HorizontalAlign.NotSet)]
- [Category("Layout")]
- [WebSysDescription("BaseDataList_HorizontalAlign")]
- public virtual HorizontalAlign HorizontalAlign
- {
- get
- {
- if(ControlStyleCreated)
- return ((TableStyle)ControlStyle).HorizontalAlign;
- return HorizontalAlign.NotSet;
+ if (!Initialized)
+ OnDataPropertyChanged ();
}
- set
- {
- ((TableStyle)ControlStyle).HorizontalAlign = value;
+ }
+
+ protected bool Initialized {
+ get { return initialized; }
+ }
+
+ // as documented in BaseDataBoundControl
+ protected bool IsBoundUsingDataSourceID {
+ get { return (DataSourceID.Length != 0); }
+ }
+
+ // doc says ?automatically? called by ASP.NET
+ protected bool RequiresDataBinding {
+ get { return requiresDataBinding; }
+ set { requiresDataBinding = value; }
+ }
+
+ protected DataSourceSelectArguments SelectArguments {
+ get {
+ if (selectArguments == null)
+ selectArguments = CreateDataSourceSelectArguments ();
+ return selectArguments;
}
}
+#endif
+ private TableStyle TableStyle {
+ // this will throw an InvalidCasException just like we need
+ get { return (TableStyle) ControlStyle; }
+ }
+
- protected ArrayList DataKeysArray
+ protected override void AddParsedSubObject (object obj)
{
- get
- {
- object o = ViewState["DataKeys"];
- if(o == null)
- {
- o = new ArrayList();
- ViewState["DataKeys"] = o;
- }
- return (ArrayList)o;
- }
+ // don't accept controls
}
- protected override void AddParsedSubObject(object o)
+ // see Kothari, page 435
+#if NET_2_0
+ protected internal
+#else
+ protected
+#endif
+ override void CreateChildControls ()
{
- // Preventing literal controls from being added as children.
+ // We are recreating the children from viewstate
+ if (HasControls ())
+ Controls.Clear();
+
+ // If presents, build the children from the viewstate
+ if (ViewState ["Items"] != null)
+ CreateControlHierarchy (false);
}
- protected override void CreateChildControls()
+ protected abstract void CreateControlHierarchy (bool useDataSource);
+
+ // see Kothari, page 434
+ // see also: Control.DataBind on Fx 2.0 beta2 documentation
+ public override void DataBind ()
{
- Controls.Clear();
- if(ViewState[ItemCountViewStateKey]!=null)
- {
- CreateControlHierarchy(false);
- ClearChildViewState();
- }
+ // unlike most samples we don't call base.OnDataBinding
+ // because we override it in this class
+ OnDataBinding (EventArgs.Empty);
+
+ // Clear, if required, then recreate the control hierarchy
+ if (HasControls ())
+ Controls.Clear ();
+ if (HasChildViewState)
+ ClearChildViewState ();
+ if (!IsTrackingViewState)
+ TrackViewState ();
+ CreateControlHierarchy (true);
+
+ // Indicate that child controls have been created, preventing
+ // CreateChildControls from getting called.
+ ChildControlsCreated = true;
+ }
+#if NET_2_0
+ protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
+ {
+ return DataSourceSelectArguments.Empty;
}
- protected override void OnDataBinding(EventArgs e)
+ // best documentation is (again) in BaseDataBoundControl
+ protected void EnsureDataBound ()
{
- base.OnDataBinding(e);
- Controls.Clear();
- ClearChildViewState();
- CreateControlHierarchy(true);
- ChildControlsCreated = true;
- TrackViewState();
+ if (IsBoundUsingDataSourceID && RequiresDataBinding)
+ DataBind ();
}
- protected virtual void OnSelectedIndexChanged(EventArgs e)
+ private void SelectCallback (IEnumerable data)
{
- if(Events != null)
- {
- EventHandler eh = (EventHandler)(Events[SelectedIndexChangedEvent]);
- if(eh!=null)
- eh(this, e);
- }
+ this.data = data;
}
- protected override void Render(HtmlTextWriter writer)
+ protected virtual IEnumerable GetData ()
{
- PrepareControlHierarchy();
- RenderContents(writer);
- }
-
- protected abstract void PrepareControlHierarchy();
- protected abstract void CreateControlHierarchy(bool useDataSource);
-
- #if NET_2_0
-
- protected override void OnInit (EventArgs e)
- {
- base.OnInit(e);
- Page.PreLoad += new EventHandler (OnPagePreLoad);
- }
-
- void OnPagePreLoad (object sender, EventArgs e)
- {
- SubscribeSourceChangeEvent ();
- inited = true;
- }
-
- void SubscribeSourceChangeEvent ()
- {
- IDataSource ds = GetDataSource ();
-
- if (currentSource != ds && currentSource != null) {
- currentSource.DataSourceChanged -= new EventHandler (OnDataSourceViewChanged);
- currentSource = ds;
- }
-
- if (ds != null)
- ds.DataSourceChanged += new EventHandler (OnDataSourceViewChanged);
- }
-
- protected override void OnLoad (EventArgs e)
- {
- if (IsBoundUsingDataSourceID && (!Page.IsPostBack || !EnableViewState))
- RequiresDataBinding = true;
-
- base.OnLoad(e);
- }
-
- protected override void OnPreRender (EventArgs e)
- {
- EnsureDataBound ();
- base.OnPreRender (e);
- }
-
- protected bool IsBoundUsingDataSourceID {
- get { return DataSourceID.Length > 0; }
- }
-
- protected void EnsureDataBound ()
- {
- if (RequiresDataBinding && IsBoundUsingDataSourceID)
- DataBind ();
- }
-
- IDataSource GetDataSource ()
- {
- if (IsBoundUsingDataSourceID) {
- Control ctrl = NamingContainer.FindControl (DataSourceID);
- if (ctrl == null)
- throw new HttpException (string.Format ("A control with ID '{0}' could not be found.", DataSourceID));
- if (!(ctrl is IDataSource))
- throw new HttpException (string.Format ("The control with ID '{0}' is not a control of type IDataSource.", DataSourceID));
- return (IDataSource) ctrl;
- }
- return DataSource as IDataSource;
- }
-
- protected IEnumerable GetData ()
- {
- if (DataSource != null && IsBoundUsingDataSourceID)
- throw new HttpException ("Control bound using both DataSourceID and DataSource properties.");
-
- IDataSource ds = GetDataSource ();
- if (ds != null)
- return ds.GetView (DataMember).ExecuteSelect (SelectArguments);
-
- IEnumerable ie = DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
- if (ie != null) return ie;
-
- throw new HttpException (string.Format ("Unexpected data source type: {0}", DataSource.GetType()));
- }
-
- protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
- {
- RequiresDataBinding = true;
- }
+ if (DataSourceID.Length == 0)
+ return null;
+
+ if (boundDataSource == null)
+ ConnectToDataSource ();
+
+ DataSourceView dsv = boundDataSource.GetView (String.Empty);
+ dsv.Select (SelectArguments, new DataSourceViewSelectCallback (SelectCallback));
+ return data;
+ }
+#endif
+
+ protected override void OnDataBinding (EventArgs e)
+ {
+ base.OnDataBinding (e);
+ }
+#if NET_2_0
+ protected virtual void OnDataPropertyChanged ()
+ {
+ }
+
+ protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
+ {
+ RequiresDataBinding = true;
+ }
- protected virtual void OnDataPropertyChanged ()
- {
+ protected internal override void OnInit (EventArgs e)
+ {
+ base.OnInit (e);
+ }
+
+ protected internal override void OnLoad (EventArgs e)
+ {
+ if ((Page != null) && !Page.IsPostBack)
RequiresDataBinding = true;
- SubscribeSourceChangeEvent ();
- }
- [DefaultValueAttribute ("")]
- [IDReferencePropertyAttribute (typeof(System.Web.UI.DataSourceControl))]
- [ThemeableAttribute (false)]
- public virtual string DataSourceID {
- get {
- object o = ViewState ["DataSourceID"];
- if (o != null)
- return (string)o;
-
- return String.Empty;
- }
- set {
- ViewState ["DataSourceID"] = value;
- if (inited) OnDataPropertyChanged ();
- }
- }
-
- protected bool Initialized {
- get { return inited; }
- }
-
- protected bool RequiresDataBinding {
- get { return requiresDataBinding; }
- set { requiresDataBinding = value; }
- }
-
- protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
- {
- return DataSourceSelectArguments.Empty;
- }
-
- protected DataSourceSelectArguments SelectArguments {
- get {
- if (selectArguments == null)
- selectArguments = CreateDataSourceSelectArguments ();
- return selectArguments;
- }
- }
-
- internal IEnumerable GetResolvedDataSource ()
- {
- return GetData ();
+ if (IsBoundUsingDataSourceID)
+ ConnectToDataSource ();
+
+ initialized = true;
+ base.OnLoad (e);
+ }
+
+ protected internal override void OnPreRender (EventArgs e)
+ {
+ EnsureDataBound ();
+ base.OnPreRender (e);
+ }
+#endif
+ protected virtual void OnSelectedIndexChanged (EventArgs e)
+ {
+ EventHandler selectedIndexChanged = (EventHandler) Events [selectedIndexChangedEvent];
+ if (selectedIndexChanged != null)
+ selectedIndexChanged (this, e);
+ }
+
+ protected abstract void PrepareControlHierarchy ();
+
+#if NET_2_0
+ protected internal
+#else
+ protected
+#endif
+ override void Render (HtmlTextWriter writer)
+ {
+ PrepareControlHierarchy ();
+ // don't call base class or RenderBegin|EndTag
+ // or we'll get an extra <span></span>
+ RenderContents (writer);
+ }
+
+
+ [WebSysDescription("")]
+ [WebCategory("Action")]
+ public event EventHandler SelectedIndexChanged {
+ add { Events.AddHandler (selectedIndexChangedEvent, value); }
+ remove { Events.RemoveHandler (selectedIndexChangedEvent, value); }
+ }
+
+
+ static public bool IsBindableType (Type type)
+ {
+ // I can't believe how many NRE are possible in System.Web
+ if (type == null) // Type.GetTypeCode no longer throws when a null is passed.
+ throw new NullReferenceException ();
+
+ switch (Type.GetTypeCode (type)) {
+ case TypeCode.Boolean:
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ case TypeCode.Char:
+ case TypeCode.Double:
+ case TypeCode.Single:
+ case TypeCode.DateTime:
+ case TypeCode.Decimal:
+ case TypeCode.String:
+ return true;
+ default:
+ return false;
}
-
- #else
- internal IEnumerable GetResolvedDataSource ()
- {
- if (DataSource != null)
- return DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
- else
- return null;
+ }
+
+#if NET_2_0
+ void ConnectToDataSource ()
+ {
+ if (NamingContainer != null)
+ boundDataSource = (NamingContainer.FindControl (DataSourceID) as IDataSource);
+
+ if (boundDataSource == null) {
+ if (Parent != null)
+ boundDataSource = (Parent.FindControl (DataSourceID) as IDataSource);
+
+ if (boundDataSource == null)
+ throw new HttpException (Locale.GetText ("Coulnd't find a DataSource named '{0}'.", DataSourceID));
}
- #endif
+ DataSourceView dsv = boundDataSource.GetView (String.Empty);
+ dsv.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);
+ }
+#endif
}
}