//
// System.Web.UI.WebControls.BaseDataList.cs
//
-// Authors:
-// Gaurav Vaish (gvaish@iitk.ac.in)
-// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
//
-// (C) Gaurav Vaish (2001)
-// (C) 2003 Andreas Nahr
-//\r
-
+// 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
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-\r
-using System;\r
+
+using System.Collections;
using System.ComponentModel;
-using System.ComponentModel.Design;\r
-using System.Collections;\r
-using System.Web;\r
-using System.Web.UI;
-using System.Web.Util;\r
-\r
-namespace System.Web.UI.WebControls\r
-{\r
- [DefaultEvent("SelectedIndexChanged")]\r
- [DefaultProperty("DataSource")]\r
- [Designer("System.Web.UI.Design.WebControls.BaseDataListDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]\r
- public abstract class BaseDataList: WebControl\r
- {\r
- private static readonly object SelectedIndexChangedEvent = new object();\r
- internal static string ItemCountViewStateKey = "_!ItemCount";\r
-\r
- private DataKeyCollection dataKeys;\r
- private object dataSource;\r
-\r
- public BaseDataList() : base()\r
- {\r
- }\r
-\r
- public static bool IsBindableType(Type type)\r
- {\r
- if(type.IsPrimitive || type == typeof(string) || type == typeof(DateTime) || type == typeof(Decimal))\r
- return true;\r
- return false;\r
- }\r
-\r
- public override ControlCollection Controls\r
- {\r
- get\r
- {\r
- EnsureChildControls();\r
- return base.Controls;\r
- }\r
- }\r
-\r
- public override void DataBind()\r
+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
+ //private string dataSourceId;
+ IDataSource boundDataSource = null;
+ private bool initialized;
+ private bool requiresDataBinding;
+ private DataSourceSelectArguments selectArguments;
+ private IEnumerable data;
+#endif
+
+ protected BaseDataList ()
{
- #if NET_2_0
- RequiresDataBinding = false;
- #endif\r
- OnDataBinding(EventArgs.Empty);\r
- }\r
-\r
- [WebCategory("Action")]\r
- [WebSysDescription("BaseDataList_OnSelectedIndexChanged")]\r
- public event EventHandler SelectedIndexChanged\r
- {\r
- add\r
- {\r
- Events.AddHandler(SelectedIndexChangedEvent, value);\r
- }\r
- remove\r
- {\r
- Events.RemoveHandler(SelectedIndexChangedEvent, value);\r
- }\r
- }\r
-\r
- [Bindable(true)]\r
- [DefaultValue(-1)]\r
- [WebCategory("Layout")]\r
- [WebSysDescription("BaseDataList_CellPadding")]\r
- public virtual int CellPadding\r
- {\r
- get\r
- {\r
- if(!ControlStyleCreated)\r
- return -1;\r
- return ((TableStyle)ControlStyle).CellPadding;\r
- }\r
- set\r
- {\r
- ((TableStyle)ControlStyle).CellPadding = value;\r
- }\r
- }\r
-\r
- [Bindable(true)]\r
- [DefaultValue(-1)]\r
- [WebCategory("Layout")]\r
- [WebSysDescription("BaseDataList_CellSpacing")]\r
- public virtual int CellSpacing\r
- {\r
- get\r
- {\r
- if(!ControlStyleCreated)\r
- return -1;\r
- return ((TableStyle)ControlStyle).CellSpacing;\r
- }\r
- set\r
- {\r
- ((TableStyle)ControlStyle).CellSpacing = value;\r
- }\r
- }\r
-\r
- [DefaultValue("")]\r
- [WebCategory("Data")]\r
- [WebSysDescription("BaseDataList_DataKeyField")]\r
- public virtual string DataKeyField\r
- {\r
- get\r
- {\r
- object o = ViewState["DataKeyField"];\r
- if(o!=null)\r
- return (string)o;\r
- return String.Empty;\r
- }\r
- set\r
- {\r
- ViewState["DataKeyField"] = value;\r
- }\r
- }\r
-\r
- [Browsable(true)]\r
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r
- [WebSysDescription("BaseDataList_DataKeys")]\r
- public DataKeyCollection DataKeys\r
- {\r
- get\r
- {\r
- if( dataKeys==null )\r
- dataKeys = new DataKeyCollection(DataKeysArray);\r
- return dataKeys;\r
-\r
- }\r
- }\r
-\r
- [DefaultValue("")]\r
- [WebCategory("Data")]\r
- [WebSysDescription("BaseDataList_DataMember")]\r
- public string DataMember\r
- {\r
- get\r
- {\r
- object o = ViewState["DataMember"];\r
- if(o!=null)\r
- return (string)o;\r
- return String.Empty;\r
- }\r
- set\r
- {\r
- ViewState["DataMember"] = value;\r
- }\r
- }\r
-\r
- [Bindable(true)]\r
- [DefaultValue(null)]\r
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r
- [WebCategory("Data")]\r
- [WebSysDescription("BaseDataList_DataSource")]\r
- public virtual object DataSource {
- get {
- return dataSource;
- }
+ }
+
+
+ [DefaultValue ("")]
+#if NET_2_0
+ [Localizable (true)]
+#endif
+ [WebSysDescription ("")]
+ [WebCategory ("Accessibility")]
+ public virtual string Caption {
+ get { return ViewState.GetString ("Caption", ""); }
set {
- if (value == null || value is IListSource || value is IEnumerable) {
- dataSource = value;
- } else {
- throw new ArgumentException (HttpRuntime.FormatResourceString (
- "Invalid_DataSource_Type", ID));
- }
+ if (value == null)
+ ViewState.Remove ("Caption");
+ else
+ ViewState ["Caption"] = value;
}
}
- [Bindable(true)]\r
- [DefaultValue(GridLines.Both)]\r
- [WebCategory("Appearance")]\r
- [WebSysDescription("BaseDataList_GridLines")]\r
- public virtual GridLines GridLines\r
- {\r
- get\r
- {\r
- if(ControlStyleCreated)\r
- return ((TableStyle)ControlStyle).GridLines;\r
- return GridLines.Both;\r
- }\r
- set\r
- {\r
- ((TableStyle)ControlStyle).GridLines = value;\r
- }\r
- }
-
- // LAMESPEC HorizontalAlign has a Category attribute, this should obviously be a WebCategory attribute
- // but is defined incorrectly in the MS framework\r
-\r
- [Bindable(true)]\r
- [DefaultValue(HorizontalAlign.NotSet)]\r
- [Category("Layout")]\r
- [WebSysDescription("BaseDataList_HorizontalAlign")]\r
- public virtual HorizontalAlign HorizontalAlign\r
- {\r
- get\r
- {\r
- if(ControlStyleCreated)\r
- return ((TableStyle)ControlStyle).HorizontalAlign;\r
- return HorizontalAlign.NotSet;\r
- }\r
- set\r
- {\r
- ((TableStyle)ControlStyle).HorizontalAlign = value;\r
- }\r
- }\r
-\r
- protected ArrayList DataKeysArray\r
- {\r
- get\r
- {\r
- object o = ViewState["DataKeys"];\r
- if(o == null)\r
- {\r
- o = new ArrayList();\r
- ViewState["DataKeys"] = o;\r
- }\r
- return (ArrayList)o;\r
- }\r
- }\r
-\r
- protected override void AddParsedSubObject(object o)\r
- {\r
- // Preventing literal controls from being added as children.\r
- }\r
-\r
- protected override void CreateChildControls()\r
- {\r
- Controls.Clear();\r
- if(ViewState[ItemCountViewStateKey]!=null)\r
- {\r
- CreateControlHierarchy(false);\r
- ClearChildViewState();\r
- }\r
- }\r
-\r
- protected override void OnDataBinding(EventArgs e)\r
- {\r
- base.OnDataBinding(e);\r
- Controls.Clear();\r
- ClearChildViewState();\r
- CreateControlHierarchy(true);\r
- ChildControlsCreated = true;\r
- TrackViewState();\r
- }\r
-\r
- protected virtual void OnSelectedIndexChanged(EventArgs e)\r
- {\r
- if(Events != null)\r
- {\r
- EventHandler eh = (EventHandler)(Events[SelectedIndexChangedEvent]);\r
- if(eh!=null)\r
- eh(this, e);\r
- }\r
- }\r
-\r
- protected override void Render(HtmlTextWriter writer)\r
- {\r
- PrepareControlHierarchy();\r
- RenderContents(writer);\r
- }\r
-\r
- protected abstract void PrepareControlHierarchy();\r
- protected abstract void CreateControlHierarchy(bool useDataSource);
-
- #if NET_2_0
-
-
- // should be `internal protected' (why, oh WHY did they do that !?!)
- protected override void OnInit (EventArgs e)
- {
- base.OnInit(e);
- inited = true;
- if (!Page.IsPostBack)
- RequiresDataBinding = true;
- }
-
- // should be `internal protected' (why, oh WHY did they do that !?!)
- protected override void OnLoad (EventArgs e)
- {
- IDataSource ds = GetDataSourceObject () as IDataSource;
- if (ds != null && DataSourceID != "")
- ds.DataSourceChanged += new EventHandler (OnDataSourceChanged);
-
- base.OnLoad(e);
+ [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."));
+
+ ViewState ["CaptionAlign"] = value;
}
-
- // should be `internal protected' (why, oh WHY did they do that !?!)
- protected override void OnPreRender (EventArgs e)
- {
- EnsureDataBound ();
- base.OnPreRender (e);
+ }
+
+#if ONLY_1_1
+ [Bindable (true)]
+#endif
+ [DefaultValue (-1)]
+ [WebSysDescription("")]
+ [WebCategory("Layout")]
+ public virtual int CellPadding {
+ get {
+ if (!ControlStyleCreated)
+ return -1; // default value
+ return TableStyle.CellPadding;
}
-
- protected void EnsureDataBound ()
- {
- if (RequiresDataBinding && DataSourceID != "")
- DataBind ();
+ set { TableStyle.CellPadding = value; }
+ }
+
+#if ONLY_1_1
+ [Bindable (true)]
+#endif
+ [DefaultValue (0)]
+ [WebSysDescription("")]
+ [WebCategory("Layout")]
+ public virtual int CellSpacing {
+ get {
+ if (!ControlStyleCreated)
+ return 0; // default value
+ return TableStyle.CellSpacing;
}
-
- protected virtual object GetDataSourceObject ()
- {
- if (DataSourceID != "")
- return (IDataSource) NamingContainer.FindControl (DataSourceID);
-
- return DataSource;
+ set { TableStyle.CellSpacing = value; }
+ }
+
+ public override ControlCollection Controls {
+ get {
+ EnsureChildControls ();
+ return base.Controls;
}
-
- protected virtual IEnumerable GetResolvedDataSource ()
- {
- if (DataSource != null && DataSourceID != "")
- throw new HttpException ();
-
- IDataSource ds = this.GetDataSourceObject () as IDataSource;
- if (ds != null && DataSourceID != "")
- return ds.GetView (DataMember).Select ();
- else if (DataSource != null)
- return DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
+ }
+
+ [DefaultValue ("")]
+#if NET_2_0
+ [Themeable (false)]
+#endif
+ [MonoTODO ("incomplete")]
+ [WebSysDescription("")]
+ [WebCategory("Data")]
+ public virtual string DataKeyField {
+ get { return ViewState.GetString ("DataKeyField", ""); }
+ set {
+ if (value == null)
+ ViewState.Remove ("DataKeyField");
else
- return null;
+ ViewState ["DataKeyField"] = value;
}
-
- protected void OnDataSourceChanged (object sender, EventArgs e)
- {
- RequiresDataBinding = true;
+ }
+
+ [Browsable (false)]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [WebSysDescription("")]
+ [WebCategory("Data")]
+ public DataKeyCollection DataKeys {
+ get {
+ if (keycoll == null)
+ keycoll = new DataKeyCollection (DataKeysArray);
+ return keycoll;
}
-
- public virtual string DataSourceID {
- get {
- object o = ViewState ["DataSourceID"];
- if (o != null)
- return (string)o;
-
- return String.Empty;
+ }
+
+ protected ArrayList DataKeysArray {
+ get {
+ ArrayList keys = (ArrayList) ViewState ["DataKeys"];
+ if (keys == null) {
+ keys = new ArrayList ();
+ ViewState ["DataKeys"] = keys;
}
- set {
- if (inited)
- RequiresDataBinding = true;
-
- ViewState ["DataSourceID"] = value;
+ return keys;
+ }
+ }
+
+ [DefaultValue ("")]
+#if NET_2_0
+ [Themeable (false)]
+#endif
+ [WebSysDescription("")]
+ [WebCategory("Data")]
+ 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
+ [Themeable (false)]
+#endif
+ [WebSysDescription("")]
+ [WebCategory("Data")]
+ public virtual object DataSource {
+ get { return source; }
+ set {
+ if ((value == null) || (value is IEnumerable) || (value is IListSource)) {
+#if NET_2_0
+// 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 {
+ string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
+ "IEnumerable", "IListSource");
+ throw new ArgumentException (msg);
}
}
-
- bool requiresDataBinding;
- protected bool RequiresDataBinding {
- get { return requiresDataBinding; }
- set { requiresDataBinding = value; }
+ }
+
+#if ONLY_1_1
+ [Bindable (true)]
+#endif
+ [DefaultValue (GridLines.Both)]
+ [WebSysDescription("")]
+ [WebCategory("Appearance")]
+ public virtual GridLines GridLines {
+ get {
+ if (!ControlStyleCreated)
+ return GridLines.Both; // default value
+ return TableStyle.GridLines;
}
-
- protected bool inited;
-
- #else
- internal IEnumerable GetResolvedDataSource ()
- {
- if (DataSource != null)
- return DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
- else
- return null;
+ 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."));
+
+ ViewState ["DataSourceID"] = value;
+
+ if (!Initialized)
+ OnDataPropertyChanged ();
}
- #endif\r
- }\r
-}\r
+ }
+
+ 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 override void AddParsedSubObject (object obj)
+ {
+ // don't accept controls
+ }
+
+ // see Kothari, page 435
+#if NET_2_0
+ protected internal
+#else
+ protected
+#endif
+ override void CreateChildControls ()
+ {
+ // 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 abstract void CreateControlHierarchy (bool useDataSource);
+
+ // see Kothari, page 434
+ // see also: Control.DataBind on Fx 2.0 beta2 documentation
+ public override void DataBind ()
+ {
+ // 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;
+ }
+
+ // best documentation is (again) in BaseDataBoundControl
+ protected void EnsureDataBound ()
+ {
+ if (IsBoundUsingDataSourceID && RequiresDataBinding)
+ DataBind ();
+ }
+
+ private void SelectCallback (IEnumerable data)
+ {
+ this.data = data;
+ }
+
+ protected virtual IEnumerable GetData ()
+ {
+ 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 internal override void OnInit (EventArgs e)
+ {
+ base.OnInit (e);
+ }
+
+ protected internal override void OnLoad (EventArgs e)
+ {
+ if ((Page != null) && !Page.IsPostBack)
+ RequiresDataBinding = true;
+
+ 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;
+ }
+ }
+
+#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));
+ }
+ DataSourceView dsv = boundDataSource.GetView (String.Empty);
+ dsv.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);
+ }
+#endif
+ }
+}