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;
181 OnDataPropertyChanged ();
187 [DefaultValue (null)]
188 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
192 [WebSysDescription("")]
193 [WebCategory("Data")]
194 public virtual object DataSource {
195 get { return source; }
197 if ((value == null) || (value is IEnumerable) || (value is IListSource)) {
199 // FIXME - can't duplicate in a test case ? LAMESPEC ?
200 // can't duplicate in a test case
201 // if ((dataSourceId != null) && (dataSourceId.Length != 0))
202 // throw new HttpException (Locale.GetText ("DataSourceID is already set."));
207 OnDataPropertyChanged ();
212 string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
213 "IEnumerable", "IListSource");
214 throw new ArgumentException (msg);
222 [DefaultValue (GridLines.Both)]
223 [WebSysDescription("")]
224 [WebCategory("Appearance")]
225 public virtual GridLines GridLines {
227 if (!ControlStyleCreated)
228 return GridLines.Both; // default value
229 return TableStyle.GridLines;
231 set { TableStyle.GridLines = value; }
237 [Category ("Layout")]
238 [DefaultValue (HorizontalAlign.NotSet)]
239 [WebSysDescription("")]
240 public virtual HorizontalAlign HorizontalAlign {
242 if (!ControlStyleCreated)
243 return HorizontalAlign.NotSet; // default value
244 return TableStyle.HorizontalAlign;
246 set { TableStyle.HorizontalAlign = value; }
249 [DefaultValue (false)]
250 public virtual bool UseAccessibleHeader {
251 get { return ViewState.GetBool ("UseAccessibleHeader", false); }
252 set { ViewState ["UseAccessibleHeader"] = value; }
256 [IDReferenceProperty (typeof (DataSourceControl))]
258 public virtual string DataSourceID {
259 get { return ViewState.GetString ("DataSourceID", ""); }
261 // LAMESPEC ? this is documented as an HttpException in beta2
263 throw new InvalidOperationException (Locale.GetText ("DataSource is already set."));
265 ViewState ["DataSourceID"] = value;
268 OnDataPropertyChanged ();
272 protected bool Initialized {
273 get { return initialized; }
276 // as documented in BaseDataBoundControl
277 protected bool IsBoundUsingDataSourceID {
278 get { return (DataSourceID.Length != 0); }
281 // doc says ?automatically? called by ASP.NET
282 protected bool RequiresDataBinding {
283 get { return requiresDataBinding; }
284 set { requiresDataBinding = value; }
287 protected DataSourceSelectArguments SelectArguments {
289 if (selectArguments == null)
290 selectArguments = CreateDataSourceSelectArguments ();
291 return selectArguments;
295 private TableStyle TableStyle {
296 // this will throw an InvalidCasException just like we need
297 get { return (TableStyle) ControlStyle; }
301 protected override void AddParsedSubObject (object obj)
303 // don't accept controls
306 // see Kothari, page 435
312 override void CreateChildControls ()
314 // We are recreating the children from viewstate
318 // If presents, build the children from the viewstate
319 if (ViewState ["Items"] != null)
320 CreateControlHierarchy (false);
323 protected abstract void CreateControlHierarchy (bool useDataSource);
325 // see Kothari, page 434
326 // see also: Control.DataBind on Fx 2.0 beta2 documentation
327 public override void DataBind ()
329 // unlike most samples we don't call base.OnDataBinding
330 // because we override it in this class
331 OnDataBinding (EventArgs.Empty);
333 // Clear, if required, then recreate the control hierarchy
336 if (HasChildViewState)
337 ClearChildViewState ();
338 if (!IsTrackingViewState)
340 CreateControlHierarchy (true);
342 // Indicate that child controls have been created, preventing
343 // CreateChildControls from getting called.
344 ChildControlsCreated = true;
347 protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
349 return DataSourceSelectArguments.Empty;
352 // best documentation is (again) in BaseDataBoundControl
353 protected void EnsureDataBound ()
355 if (IsBoundUsingDataSourceID && RequiresDataBinding)
359 private void SelectCallback (IEnumerable data)
364 protected virtual IEnumerable GetData ()
366 if (DataSourceID.Length == 0)
369 if (boundDataSource == null)
372 DataSourceView dsv = boundDataSource.GetView (String.Empty);
373 dsv.Select (SelectArguments, new DataSourceViewSelectCallback (SelectCallback));
378 protected override void OnDataBinding (EventArgs e)
380 base.OnDataBinding (e);
383 protected virtual void OnDataPropertyChanged ()
387 protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
389 RequiresDataBinding = true;
392 protected internal override void OnInit (EventArgs e)
397 protected internal override void OnLoad (EventArgs e)
399 if ((Page != null) && !Page.IsPostBack)
400 RequiresDataBinding = true;
402 if (IsBoundUsingDataSourceID)
403 ConnectToDataSource ();
409 protected internal override void OnPreRender (EventArgs e)
412 base.OnPreRender (e);
415 protected virtual void OnSelectedIndexChanged (EventArgs e)
417 EventHandler selectedIndexChanged = (EventHandler) Events [selectedIndexChangedEvent];
418 if (selectedIndexChanged != null)
419 selectedIndexChanged (this, e);
422 protected abstract void PrepareControlHierarchy ();
429 override void Render (HtmlTextWriter writer)
431 PrepareControlHierarchy ();
432 // don't call base class or RenderBegin|EndTag
433 // or we'll get an extra <span></span>
434 RenderContents (writer);
438 [WebSysDescription("")]
439 [WebCategory("Action")]
440 public event EventHandler SelectedIndexChanged {
441 add { Events.AddHandler (selectedIndexChangedEvent, value); }
442 remove { Events.RemoveHandler (selectedIndexChangedEvent, value); }
446 static public bool IsBindableType (Type type)
448 // I can't believe how many NRE are possible in System.Web
449 if (type == null) // Type.GetTypeCode no longer throws when a null is passed.
450 throw new NullReferenceException ();
452 switch (Type.GetTypeCode (type)) {
453 case TypeCode.Boolean:
457 case TypeCode.UInt16:
459 case TypeCode.UInt32:
461 case TypeCode.UInt64:
463 case TypeCode.Double:
464 case TypeCode.Single:
465 case TypeCode.DateTime:
466 case TypeCode.Decimal:
467 case TypeCode.String:
474 void ConnectToDataSource ()
476 if (NamingContainer != null)
477 boundDataSource = (NamingContainer.FindControl (DataSourceID) as IDataSource);
479 if (boundDataSource == null) {
481 boundDataSource = (Parent.FindControl (DataSourceID) as IDataSource);
483 if (boundDataSource == null)
484 throw new HttpException (Locale.GetText ("Coulnd't find a DataSource named '{0}'.", DataSourceID));
486 DataSourceView dsv = boundDataSource.GetView (String.Empty);
487 dsv.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);