Page.Validate() is called when CausesValidation=true
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / DataBoundControl.cs
index 06a3c7fb84a1c412263af6ceda17e08b25b6a9f7..9c64bd432f7cefd8abf950c98860e818eacecfc2 100644 (file)
@@ -3,8 +3,31 @@
 //
 // Authors:
 //     Ben Maurer (bmaurer@users.sourceforge.net)
+//     Sanjay Gupta (gsanjay@novell.com)
 //
 // (C) 2003 Ben Maurer
+// (C) 2004 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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
 #if NET_2_0
@@ -13,160 +36,202 @@ using System.Collections.Specialized;
 using System.Text;
 using System.Web.Util;
 using System.ComponentModel;
+using System.Security.Permissions;
 
 namespace System.Web.UI.WebControls {
-       public abstract class DataBoundControl : WebControl
+
+       // CAS
+       [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+       [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+       // attributes
+       [DesignerAttribute ("System.Web.UI.Design.WebControls.DataBoundControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+       public abstract class DataBoundControl : BaseDataBoundControl
        {
-               public event EventHandler DataBound;
-               
+               DataSourceSelectArguments selectArguments;
+               DataSourceView currentView;
+
                protected DataBoundControl ()
                {
                }
-               
-               public sealed override void DataBind ()
+
+               /* Used for controls that used to inherit from
+                * WebControl, so the tag can propagate upwards
+                */
+               internal DataBoundControl (HtmlTextWriterTag tag) : base (tag)
                {
-                       PerformDataBinding ();
-                       RequiresDataBinding = false;
-                       OnDataBound (EventArgs.Empty);
                }
                
-               protected void EnsureDataBound ()
+               
+               protected virtual IDataSource GetDataSource ()
                {
-                       if (RequiresDataBinding && DataSourceID != "")
-                               DataBind ();
-               }
+                       if (IsBoundUsingDataSourceID) {
+                               Control namingContainer;
+                               Control ctrl = null;
 
-               protected virtual object GetDataSourceObject()
-               {
-                       if (DataSourceID != "")
-                               return (IDataSource) NamingContainer.FindControl (DataSourceID);
+                               namingContainer = NamingContainer;
+                               
+                               while (namingContainer != null) {
+                                       ctrl = namingContainer.FindControl (DataSourceID);
+                                       if (ctrl != null)
+                                               break;
+                                       namingContainer = namingContainer.NamingContainer;
+                               }
+
+                               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;
+                       }
+                       
+                       if (DataSource == null) return null;
                        
-                       return DataSource;
+                       IDataSource ds = DataSource as IDataSource;
+                       if (ds != null) return ds;
+                       
+                       IEnumerable ie = DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
+                       if (ie != null) return new CollectionDataSource (ie);
+                       
+                       throw new HttpException (string.Format ("Unexpected data source type: {0}", DataSource.GetType()));
                }
                
+               protected virtual DataSourceView GetData ()
+               {
+                       if (currentView == null)
+                               UpdateViewData ();
+                       return currentView;
+               }
                
-               protected virtual IEnumerable GetResolvedDataSource ()
+               DataSourceView InternalGetData ()
                {
-                       if (DataSource != null && DataSourceID != "")
-                               throw new HttpException ();
+                       if (DataSource != null && IsBoundUsingDataSourceID)
+                               throw new HttpException ("Control bound using both DataSourceID and DataSource properties.");
                        
-                       IDataSource ds = GetDataSourceObject () as IDataSource;
-                       if (ds != null && DataSourceID != "")
-                               return ds.GetView (DataMember).Select ();
-                       else if (DataSource != null)
-                               return DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
+                       IDataSource ds = GetDataSource ();
+                       if (ds != null)
+                               return ds.GetView (DataMember);
                        else
                                return null; 
                }
                
-               protected bool IsBoundToDataSourceControl()
+               protected override void OnDataPropertyChanged ()
                {
-                       return (GetDataSourceObject () is IDataSource) && DataSourceID != "";
+                       base.OnDataPropertyChanged ();
+                       UpdateViewData ();
                }
                
-               protected virtual void OnDataBound(EventArgs e) {
-                       if (DataBound != null)
-                               DataBound (this, e);
-               }
-               
-               protected virtual void OnDataPropertyChanged ()
-               {
-                       this.RequiresDataBinding = true;
-               }
-               
-               protected virtual void OnDataSourceChanged (object sender, EventArgs e)
+               protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
                {
                        RequiresDataBinding = true;
                }
                
-               // should be `internal protected' (why, oh WHY did they do that !?!)
-               protected override void OnInit (EventArgs e)
+               protected override void OnPagePreLoad (object sender, EventArgs e)
                {
-                       base.OnInit(e);
-                       inited = true;
-                       if (!Page.IsPostBack)
-                               RequiresDataBinding = true;
+                       base.OnPagePreLoad (sender, e);
+                       UpdateViewData ();
                }
                
-               // should be `internal protected' (why, oh WHY did they do that !?!)
-               protected override void OnLoad (EventArgs e)
+               void UpdateViewData ()
                {
-                       IDataSource ds = GetDataSourceObject () as IDataSource;
-                       if (ds != null && DataSourceID != "")
-                               ds.DataSourceChanged += new EventHandler (OnDataSourceChanged);
-                       
-                       base.OnLoad(e);
+                       DataSourceView view = InternalGetData ();
+                       if (view == currentView) return;
+
+                       if (currentView != null)
+                               currentView.DataSourceViewChanged -= new EventHandler (OnDataSourceViewChanged);
+
+                       currentView = view;
+
+                       if (view != null)
+                               view.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);
                }
                
-               // should be `internal protected' (why, oh WHY did they do that !?!)
-               protected override void OnPreRender (EventArgs e)
+               protected internal override void OnLoad (EventArgs e)
                {
-                       EnsureDataBound ();
-                       base.OnPreRender (e);
+                       if (!Page.IsPostBack || (IsViewStateEnabled && !IsDataBound))
+                               RequiresDataBinding = true;
+
+                       base.OnLoad(e);
                }
                
-               protected virtual void PerformDataBinding ()
+               protected internal virtual void PerformDataBinding (IEnumerable data)
                {
-                       OnDataBinding(EventArgs.Empty);
                }
 
-               
-               protected virtual void ValidateDataSource (object dataSource)
+               protected override void ValidateDataSource (object dataSource)
                {
-                       if (dataSource is IListSource || dataSource is IEnumerable)
+                       if (dataSource is IListSource || dataSource is IEnumerable || dataSource is IDataSource)
                                return;
-                       throw new ArgumentException ();
+                       throw new ArgumentException ("Invalid data source source type. The data source must be of type IListSource, IEnumerable or IDataSource.");
                }
 
+               [ThemeableAttribute (false)]
+               [DefaultValueAttribute ("")]
+               [WebCategoryAttribute ("Data")]
+               public virtual string DataMember {
+                       get { return ViewState.GetString ("DataMember", ""); }
+                       set { ViewState["DataMember"] = value; }
+               }
 
-               public string DataMember
-               {
-                       get {
-                               object o = ViewState["DataMember"];
-                               if(o!=null)
-                                       return (string)o;
-                               return String.Empty;
-                       }
+               [IDReferencePropertyAttribute (typeof(DataSourceControl))]
+               public override string DataSourceID {
+                       get { return ViewState.GetString ("DataSourceID", ""); }
                        set {
-                               ViewState["DataMember"] = value;
+                               ViewState ["DataSourceID"] = value;
+                               base.DataSourceID = value;
                        }
                }
+               
+               // 
+               // See DataBoundControl.MarkAsDataBound msdn doc for the code example
+               // 
+               protected override void PerformSelect ()
+               {
+                       // Call OnDataBinding here if bound to a data source using the
+                       // DataSource property (instead of a DataSourceID), because the
+                       // databinding statement is evaluated before the call to GetData.       
+                       if (!IsBoundUsingDataSourceID)
+                               OnDataBinding (EventArgs.Empty);
 
-               object dataSource;
-               public virtual object DataSource
+                       DataSourceView view = GetData ();
+                       if (view != null) {
+                               view.Select (SelectArguments, new DataSourceViewSelectCallback (OnSelect));
+                               MarkAsDataBound ();
+                       }
+               }
+               
+               void OnSelect (IEnumerable data)
                {
+                       PerformDataBinding (data);
+                       OnDataBound (EventArgs.Empty);
+               }
+               
+               protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
+               {
+                       return DataSourceSelectArguments.Empty;
+               }
+               
+               protected DataSourceSelectArguments SelectArguments {
                        get {
-                               return dataSource;
-                       }
-                       set {
-                               ValidateDataSource (value);
-                               dataSource = value;
+                               if (selectArguments == null)
+                                       selectArguments = CreateDataSourceSelectArguments ();
+                               return selectArguments;
                        }
                }
-               
-               public virtual string DataSourceID {
+
+               bool IsDataBound {
                        get {
-                               object o = ViewState ["DataSourceID"];
-                               if (o != null)
-                                       return (string)o;
-                               
-                               return String.Empty;
+                               object dataBound = ViewState ["DataBound"];
+                               return dataBound != null ? (bool) dataBound : false;
                        }
                        set {
-                               if (inited)
-                                       RequiresDataBinding = true;
-                               
-                               ViewState ["DataSourceID"] = value;
+                               ViewState ["DataBound"] = value;
                        }
                }
-               
-               bool requiresDataBinding;
-               protected bool RequiresDataBinding {
-                       get { return requiresDataBinding; }
-                       set { requiresDataBinding = value; }
+
+               protected void MarkAsDataBound ()
+               {
+                       IsDataBound = true;
                }
-               
-               protected bool inited;
        }
 }
 #endif