2 // System.Web.UI.WebControls.BaseDataList.cs
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // Copyright (C) 2005-2010 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 static readonly object selectedIndexChangedEvent = new object ();
46 DataKeyCollection keycoll;
49 //string dataSourceId;
50 IDataSource boundDataSource = null;
52 bool requiresDataBinding;
53 DataSourceSelectArguments selectArguments;
56 protected BaseDataList ()
63 [WebSysDescription ("")]
64 [WebCategory ("Accessibility")]
65 public virtual string Caption {
66 get { return ViewState.GetString ("Caption", String.Empty); }
69 ViewState.Remove ("Caption");
71 ViewState ["Caption"] = value;
75 [DefaultValue (TableCaptionAlign.NotSet)]
76 public virtual TableCaptionAlign CaptionAlign {
77 get { return (TableCaptionAlign) ViewState.GetInt ("CaptionAlign", (int)TableCaptionAlign.NotSet); }
79 if ((value < TableCaptionAlign.NotSet) || (value > TableCaptionAlign.Right))
80 throw new ArgumentOutOfRangeException (Locale.GetText ("Invalid TableCaptionAlign value."));
82 ViewState ["CaptionAlign"] = value;
87 [WebSysDescription("")]
88 [WebCategory("Layout")]
89 public virtual int CellPadding {
91 if (!ControlStyleCreated)
92 return -1; // default value
93 return TableStyle.CellPadding;
95 set { TableStyle.CellPadding = value; }
99 [WebSysDescription("")]
100 [WebCategory("Layout")]
101 public virtual int CellSpacing {
103 if (!ControlStyleCreated)
104 return 0; // default value
105 return TableStyle.CellSpacing;
107 set { TableStyle.CellSpacing = value; }
110 public override ControlCollection Controls {
112 EnsureChildControls ();
113 return base.Controls;
119 [MonoTODO ("incomplete")]
120 [WebSysDescription("")]
121 [WebCategory("Data")]
122 public virtual string DataKeyField {
123 get { return ViewState.GetString ("DataKeyField", String.Empty); }
126 ViewState.Remove ("DataKeyField");
128 ViewState ["DataKeyField"] = value;
133 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
134 [WebSysDescription("")]
135 [WebCategory("Data")]
136 public DataKeyCollection DataKeys {
139 keycoll = new DataKeyCollection (DataKeysArray);
144 protected ArrayList DataKeysArray {
146 ArrayList keys = (ArrayList) ViewState ["DataKeys"];
148 keys = new ArrayList ();
149 ViewState ["DataKeys"] = keys;
157 [WebSysDescription("")]
158 [WebCategory("Data")]
159 public string DataMember {
160 get { return ViewState.GetString ("DataMember", String.Empty); }
163 ViewState.Remove ("DataMember");
165 ViewState ["DataMember"] = value;
166 OnDataPropertyChanged ();
171 [DefaultValue (null)]
172 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
174 [WebSysDescription("")]
175 [WebCategory("Data")]
176 public virtual object DataSource {
177 get { return source; }
179 if ((value == null) || (value is IEnumerable) || (value is IListSource)) {
180 // FIXME - can't duplicate in a test case ? LAMESPEC ?
181 // can't duplicate in a test case
182 // if ((dataSourceId != null) && (dataSourceId.Length != 0))
183 // throw new HttpException (Locale.GetText ("DataSourceID is already set."));
187 OnDataPropertyChanged ();
190 string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
191 "IEnumerable", "IListSource");
192 throw new ArgumentException (msg);
197 [DefaultValue (GridLines.Both)]
198 [WebSysDescription("")]
199 [WebCategory("Appearance")]
200 public virtual GridLines GridLines {
202 if (!ControlStyleCreated)
203 return GridLines.Both; // default value
204 return TableStyle.GridLines;
206 set { TableStyle.GridLines = value; }
209 [Category ("Layout")]
210 [DefaultValue (HorizontalAlign.NotSet)]
211 [WebSysDescription("")]
212 public virtual HorizontalAlign HorizontalAlign {
214 if (!ControlStyleCreated)
215 return HorizontalAlign.NotSet; // default value
216 return TableStyle.HorizontalAlign;
218 set { TableStyle.HorizontalAlign = value; }
221 [DefaultValue (false)]
222 public virtual bool UseAccessibleHeader {
223 get { return ViewState.GetBool ("UseAccessibleHeader", false); }
224 set { ViewState ["UseAccessibleHeader"] = value; }
228 [IDReferenceProperty (typeof (DataSourceControl))]
230 public virtual string DataSourceID {
231 get { return ViewState.GetString ("DataSourceID", String.Empty); }
233 // LAMESPEC ? this is documented as an HttpException in beta2
235 throw new InvalidOperationException (Locale.GetText ("DataSource is already set."));
237 ViewState ["DataSourceID"] = value;
239 OnDataPropertyChanged ();
243 protected bool Initialized {
244 get { return initialized; }
247 // as documented in BaseDataBoundControl
248 protected bool IsBoundUsingDataSourceID {
249 get { return (DataSourceID.Length != 0); }
252 // doc says ?automatically? called by ASP.NET
253 protected bool RequiresDataBinding {
254 get { return requiresDataBinding; }
255 set { requiresDataBinding = value; }
258 protected DataSourceSelectArguments SelectArguments {
260 if (selectArguments == null)
261 selectArguments = CreateDataSourceSelectArguments ();
262 return selectArguments;
265 public override bool SupportsDisabledAttribute {
266 get { return RenderingCompatibilityLessThan40; }
268 TableStyle TableStyle {
269 // this will throw an InvalidCasException just like we need
270 get { return (TableStyle) ControlStyle; }
274 protected override void AddParsedSubObject (object obj)
276 // don't accept controls
279 // see Kothari, page 435
280 protected internal override void CreateChildControls ()
282 // We are recreating the children from viewstate
284 base.Controls.Clear();
287 CreateControlHierarchy (false);
288 else if (RequiresDataBinding)
292 protected abstract void CreateControlHierarchy (bool useDataSource);
294 // see Kothari, page 434
295 // see also: Control.DataBind on Fx 2.0 beta2 documentation
296 public override void DataBind ()
298 // unlike most samples we don't call base.OnDataBinding
299 // because we override it in this class
300 OnDataBinding (EventArgs.Empty);
302 // Clear, if required, then recreate the control hierarchy
305 if (HasChildViewState)
306 ClearChildViewState ();
307 if (!IsTrackingViewState)
309 CreateControlHierarchy (true);
311 // Indicate that child controls have been created, preventing
312 // CreateChildControls from getting called.
313 ChildControlsCreated = true;
314 RequiresDataBinding = false;
318 protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
320 return DataSourceSelectArguments.Empty;
323 // best documentation is (again) in BaseDataBoundControl
324 protected void EnsureDataBound ()
326 if (IsBoundUsingDataSourceID && RequiresDataBinding)
330 void SelectCallback (IEnumerable data)
335 protected virtual IEnumerable GetData ()
337 if (DataSourceID.Length == 0)
340 if (boundDataSource == null)
341 ConnectToDataSource ();
343 DataSourceView dsv = boundDataSource.GetView (String.Empty);
344 dsv.Select (SelectArguments, new DataSourceViewSelectCallback (SelectCallback));
350 return ViewState.GetBool ("_DataBound", false);
353 ViewState ["_DataBound"] = value;
357 protected override void OnDataBinding (EventArgs e)
359 base.OnDataBinding (e);
362 protected virtual void OnDataPropertyChanged ()
365 RequiresDataBinding = true;
368 protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
370 RequiresDataBinding = true;
373 protected internal override void OnInit (EventArgs e)
378 page.PreLoad += new EventHandler (OnPagePreLoad);
380 if (!IsViewStateEnabled && page.IsPostBack)
381 RequiresDataBinding = true;
385 void OnPagePreLoad (object sender, EventArgs e)
391 protected internal override void OnLoad (EventArgs e)
403 if (!page.IsPostBack || (IsViewStateEnabled && !IsDataBound))
404 RequiresDataBinding = true;
407 if (IsBoundUsingDataSourceID)
408 ConnectToDataSource ();
413 protected internal override void OnPreRender (EventArgs e)
416 base.OnPreRender (e);
419 protected virtual void OnSelectedIndexChanged (EventArgs e)
421 EventHandler selectedIndexChanged = (EventHandler) Events [selectedIndexChangedEvent];
422 if (selectedIndexChanged != null)
423 selectedIndexChanged (this, e);
426 protected abstract void PrepareControlHierarchy ();
428 protected internal override void Render (HtmlTextWriter writer)
430 PrepareControlHierarchy ();
431 // don't call base class or RenderBegin|EndTag
432 // or we'll get an extra <span></span>
433 RenderContents (writer);
436 [WebSysDescription("")]
437 [WebCategory("Action")]
438 public event EventHandler SelectedIndexChanged {
439 add { Events.AddHandler (selectedIndexChangedEvent, value); }
440 remove { Events.RemoveHandler (selectedIndexChangedEvent, value); }
443 static public bool IsBindableType (Type type)
445 // I can't believe how many NRE are possible in System.Web
446 if (type == null) // Type.GetTypeCode no longer throws when a null is passed.
447 throw new NullReferenceException ();
449 switch (Type.GetTypeCode (type)) {
450 case TypeCode.Boolean:
454 case TypeCode.UInt16:
456 case TypeCode.UInt32:
458 case TypeCode.UInt64:
460 case TypeCode.Double:
461 case TypeCode.Single:
462 case TypeCode.DateTime:
463 case TypeCode.Decimal:
464 case TypeCode.String:
471 void ConnectToDataSource ()
473 if (NamingContainer != null)
474 boundDataSource = (NamingContainer.FindControl (DataSourceID) as IDataSource);
476 if (boundDataSource == null) {
478 boundDataSource = (Parent.FindControl (DataSourceID) as IDataSource);
480 if (boundDataSource == null)
481 throw new HttpException (Locale.GetText ("Coulnd't find a DataSource named '{0}'.", DataSourceID));
483 DataSourceView dsv = boundDataSource.GetView (String.Empty);
484 dsv.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);