2 // System.Web.UI.WebControls.BaseDataList.cs
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Security.Permissions;
33 namespace System.Web.UI.WebControls {
36 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
37 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39 [DefaultEvent ("SelectedIndexChanged")]
40 [DefaultProperty ("DataSource")]
41 [Designer ("System.Web.UI.Design.WebControls.BaseDataListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42 public abstract class BaseDataList : WebControl {
44 private static readonly object selectedIndexChangedEvent = new object ();
46 private DataKeyCollection keycoll;
47 private object source;
49 //private string dataSourceId;
50 IDataSource boundDataSource = null;
51 private bool initialized;
52 private bool requiresDataBinding;
53 private DataSourceSelectArguments selectArguments;
54 private IEnumerable data;
57 protected BaseDataList ()
66 [WebSysDescription ("")]
67 [WebCategory ("Accessibility")]
68 public virtual string Caption {
69 get { return ViewState.GetString ("Caption", ""); }
72 ViewState.Remove ("Caption");
74 ViewState ["Caption"] = value;
78 [DefaultValue (TableCaptionAlign.NotSet)]
79 public virtual TableCaptionAlign CaptionAlign {
80 get { return (TableCaptionAlign) ViewState.GetInt ("CaptionAlign", (int)TableCaptionAlign.NotSet); }
82 if ((value < TableCaptionAlign.NotSet) || (value > TableCaptionAlign.Right))
83 throw new ArgumentOutOfRangeException (Locale.GetText ("Invalid TableCaptionAlign value."));
85 ViewState ["CaptionAlign"] = value;
93 [WebSysDescription("")]
94 [WebCategory("Layout")]
95 public virtual int CellPadding {
97 if (!ControlStyleCreated)
98 return -1; // default value
99 return TableStyle.CellPadding;
101 set { TableStyle.CellPadding = value; }
108 [WebSysDescription("")]
109 [WebCategory("Layout")]
110 public virtual int CellSpacing {
112 if (!ControlStyleCreated)
113 return 0; // default value
114 return TableStyle.CellSpacing;
116 set { TableStyle.CellSpacing = value; }
119 public override ControlCollection Controls {
121 EnsureChildControls ();
122 return base.Controls;
130 [MonoTODO ("incomplete")]
131 [WebSysDescription("")]
132 [WebCategory("Data")]
133 public virtual string DataKeyField {
134 get { return ViewState.GetString ("DataKeyField", ""); }
137 ViewState.Remove ("DataKeyField");
139 ViewState ["DataKeyField"] = value;
144 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
145 [WebSysDescription("")]
146 [WebCategory("Data")]
147 public DataKeyCollection DataKeys {
150 keycoll = new DataKeyCollection (DataKeysArray);
155 protected ArrayList DataKeysArray {
157 ArrayList keys = (ArrayList) ViewState ["DataKeys"];
159 keys = new ArrayList ();
160 ViewState ["DataKeys"] = keys;
170 [WebSysDescription("")]
171 [WebCategory("Data")]
172 public string DataMember {
173 get { return ViewState.GetString ("DataMember", ""); }
176 ViewState.Remove ("DataMember");
178 ViewState ["DataMember"] = value;
180 OnDataPropertyChanged ();
186 [DefaultValue (null)]
187 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
191 [WebSysDescription("")]
192 [WebCategory("Data")]
193 public virtual object DataSource {
194 get { return source; }
196 if ((value == null) || (value is IEnumerable) || (value is IListSource)) {
198 // FIXME - can't duplicate in a test case ? LAMESPEC ?
199 // can't duplicate in a test case
200 // if ((dataSourceId != null) && (dataSourceId.Length != 0))
201 // throw new HttpException (Locale.GetText ("DataSourceID is already set."));
205 OnDataPropertyChanged ();
210 string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
211 "IEnumerable", "IListSource");
212 throw new ArgumentException (msg);
220 [DefaultValue (GridLines.Both)]
221 [WebSysDescription("")]
222 [WebCategory("Appearance")]
223 public virtual GridLines GridLines {
225 if (!ControlStyleCreated)
226 return GridLines.Both; // default value
227 return TableStyle.GridLines;
229 set { TableStyle.GridLines = value; }
235 [Category ("Layout")]
236 [DefaultValue (HorizontalAlign.NotSet)]
237 [WebSysDescription("")]
238 public virtual HorizontalAlign HorizontalAlign {
240 if (!ControlStyleCreated)
241 return HorizontalAlign.NotSet; // default value
242 return TableStyle.HorizontalAlign;
244 set { TableStyle.HorizontalAlign = value; }
247 [DefaultValue (false)]
248 public virtual bool UseAccessibleHeader {
249 get { return ViewState.GetBool ("UseAccessibleHeader", false); }
250 set { ViewState ["UseAccessibleHeader"] = value; }
254 [IDReferenceProperty (typeof (DataSourceControl))]
256 public virtual string DataSourceID {
257 get { return ViewState.GetString ("DataSourceID", ""); }
259 // LAMESPEC ? this is documented as an HttpException in beta2
261 throw new InvalidOperationException (Locale.GetText ("DataSource is already set."));
263 ViewState ["DataSourceID"] = value;
265 OnDataPropertyChanged ();
269 protected bool Initialized {
270 get { return initialized; }
273 // as documented in BaseDataBoundControl
274 protected bool IsBoundUsingDataSourceID {
275 get { return (DataSourceID.Length != 0); }
278 // doc says ?automatically? called by ASP.NET
279 protected bool RequiresDataBinding {
280 get { return requiresDataBinding; }
281 set { requiresDataBinding = value; }
284 protected DataSourceSelectArguments SelectArguments {
286 if (selectArguments == null)
287 selectArguments = CreateDataSourceSelectArguments ();
288 return selectArguments;
292 private TableStyle TableStyle {
293 // this will throw an InvalidCasException just like we need
294 get { return (TableStyle) ControlStyle; }
298 protected override void AddParsedSubObject (object obj)
300 // don't accept controls
303 // see Kothari, page 435
309 override void CreateChildControls ()
311 // We are recreating the children from viewstate
313 base.Controls.Clear();
317 CreateControlHierarchy (false);
318 else if (RequiresDataBinding)
321 // If presents, build the children from the viewstate
322 if (ViewState ["Items"] != null)
323 CreateControlHierarchy (false);
327 protected abstract void CreateControlHierarchy (bool useDataSource);
329 // see Kothari, page 434
330 // see also: Control.DataBind on Fx 2.0 beta2 documentation
331 public override void DataBind ()
333 // unlike most samples we don't call base.OnDataBinding
334 // because we override it in this class
335 OnDataBinding (EventArgs.Empty);
337 // Clear, if required, then recreate the control hierarchy
340 if (HasChildViewState)
341 ClearChildViewState ();
342 if (!IsTrackingViewState)
344 CreateControlHierarchy (true);
346 // Indicate that child controls have been created, preventing
347 // CreateChildControls from getting called.
348 ChildControlsCreated = true;
350 RequiresDataBinding = false;
355 protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
357 return DataSourceSelectArguments.Empty;
360 // best documentation is (again) in BaseDataBoundControl
361 protected void EnsureDataBound ()
363 if (IsBoundUsingDataSourceID && RequiresDataBinding)
367 private void SelectCallback (IEnumerable data)
372 protected virtual IEnumerable GetData ()
374 if (DataSourceID.Length == 0)
377 if (boundDataSource == null)
378 ConnectToDataSource ();
380 DataSourceView dsv = boundDataSource.GetView (String.Empty);
381 dsv.Select (SelectArguments, new DataSourceViewSelectCallback (SelectCallback));
387 return ViewState.GetBool ("_DataBound", false);
390 ViewState ["_DataBound"] = value;
396 protected override void OnDataBinding (EventArgs e)
398 base.OnDataBinding (e);
401 protected virtual void OnDataPropertyChanged ()
404 RequiresDataBinding = true;
407 protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
409 RequiresDataBinding = true;
412 protected internal override void OnInit (EventArgs e)
416 Page.PreLoad += new EventHandler (OnPagePreLoad);
418 if (!IsViewStateEnabled && Page.IsPostBack)
419 RequiresDataBinding = true;
423 protected virtual void OnPagePreLoad (object sender, EventArgs e)
428 protected internal override void OnLoad (EventArgs e)
436 private void Initialize ()
439 if (!Page.IsPostBack || (IsViewStateEnabled && !IsDataBound))
440 RequiresDataBinding = true;
443 if (IsBoundUsingDataSourceID)
444 ConnectToDataSource ();
449 protected internal override void OnPreRender (EventArgs e)
452 base.OnPreRender (e);
455 protected virtual void OnSelectedIndexChanged (EventArgs e)
457 EventHandler selectedIndexChanged = (EventHandler) Events [selectedIndexChangedEvent];
458 if (selectedIndexChanged != null)
459 selectedIndexChanged (this, e);
462 protected abstract void PrepareControlHierarchy ();
469 override void Render (HtmlTextWriter writer)
471 PrepareControlHierarchy ();
472 // don't call base class or RenderBegin|EndTag
473 // or we'll get an extra <span></span>
474 RenderContents (writer);
478 [WebSysDescription("")]
479 [WebCategory("Action")]
480 public event EventHandler SelectedIndexChanged {
481 add { Events.AddHandler (selectedIndexChangedEvent, value); }
482 remove { Events.RemoveHandler (selectedIndexChangedEvent, value); }
486 static public bool IsBindableType (Type type)
488 // I can't believe how many NRE are possible in System.Web
489 if (type == null) // Type.GetTypeCode no longer throws when a null is passed.
490 throw new NullReferenceException ();
492 switch (Type.GetTypeCode (type)) {
493 case TypeCode.Boolean:
497 case TypeCode.UInt16:
499 case TypeCode.UInt32:
501 case TypeCode.UInt64:
503 case TypeCode.Double:
504 case TypeCode.Single:
505 case TypeCode.DateTime:
506 case TypeCode.Decimal:
507 case TypeCode.String:
515 void ConnectToDataSource ()
517 if (NamingContainer != null)
518 boundDataSource = (NamingContainer.FindControl (DataSourceID) as IDataSource);
520 if (boundDataSource == null) {
522 boundDataSource = (Parent.FindControl (DataSourceID) as IDataSource);
524 if (boundDataSource == null)
525 throw new HttpException (Locale.GetText ("Coulnd't find a DataSource named '{0}'.", DataSourceID));
527 DataSourceView dsv = boundDataSource.GetView (String.Empty);
528 dsv.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);