Merge pull request #2916 from ludovic-henry/fix-40306
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / BaseDataList.cs
index 4f5e814fe880aea24a834e80d07c9c1ff26d7ccf..178c576e6b39ec53e8647b691dc93fe027519bea 100644 (file)
@@ -4,7 +4,7 @@
 // Author:
 //     Sebastien Pouliot  <sebastien@ximian.com>
 //
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2010 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
@@ -30,8 +30,8 @@ using System.Collections;
 using System.ComponentModel;
 using System.Security.Permissions;
 
-namespace System.Web.UI.WebControls {
-
+namespace System.Web.UI.WebControls
+{
        // CAS
        [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
@@ -39,19 +39,19 @@ namespace System.Web.UI.WebControls {
        [DefaultEvent ("SelectedIndexChanged")]
        [DefaultProperty ("DataSource")]
        [Designer ("System.Web.UI.Design.WebControls.BaseDataListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
-       public abstract class BaseDataList : WebControl {
+       public abstract class BaseDataList : WebControl 
+       {
+               static readonly object selectedIndexChangedEvent = new object ();
 
-               private static readonly object selectedIndexChangedEvent = new object ();
+               DataKeyCollection keycoll;
+               object source;
 
-               private DataKeyCollection keycoll;
-               private object source;
-#if NET_2_0
-               //private string dataSourceId;
-               private bool initialized;
-               private bool requiresDataBinding;
-               private DataSourceSelectArguments selectArguments;
-               private IEnumerable data;
-#endif
+               //string dataSourceId;
+               IDataSource boundDataSource = null;
+               bool initialized;
+               bool requiresDataBinding;
+               DataSourceSelectArguments selectArguments;
+               IEnumerable data;
 
                protected BaseDataList ()
                {
@@ -59,16 +59,11 @@ namespace System.Web.UI.WebControls {
 
 
                [DefaultValue ("")]
-#if NET_2_0
                [Localizable (true)]
-#endif
                [WebSysDescription ("")]
                [WebCategory ("Accessibility")]
                public virtual string Caption {
-                       get {
-                               object o = ViewState ["Caption"];
-                               return (o == null) ? String.Empty : (string) o;
-                       }
+                       get { return ViewState.GetString ("Caption", String.Empty); }
                        set {
                                if (value == null)
                                        ViewState.Remove ("Caption");
@@ -79,10 +74,7 @@ namespace System.Web.UI.WebControls {
 
                [DefaultValue (TableCaptionAlign.NotSet)]
                public virtual TableCaptionAlign CaptionAlign {
-                       get {
-                               object o = ViewState ["CaptionAlign"];
-                               return (o == null) ? TableCaptionAlign.NotSet : (TableCaptionAlign) o;
-                       }
+                       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."));
@@ -91,9 +83,6 @@ namespace System.Web.UI.WebControls {
                        }
                }
 
-#if ONLY_1_1
-               [Bindable (true)]
-#endif
                [DefaultValue (-1)]
                [WebSysDescription("")]
                [WebCategory("Layout")]
@@ -106,9 +95,6 @@ namespace System.Web.UI.WebControls {
                        set { TableStyle.CellPadding = value; }
                }
 
-#if ONLY_1_1
-               [Bindable (true)]
-#endif
                [DefaultValue (0)]
                [WebSysDescription("")]
                [WebCategory("Layout")]
@@ -129,17 +115,12 @@ namespace System.Web.UI.WebControls {
                }
 
                [DefaultValue ("")]
-#if NET_2_0
                [Themeable (false)]
-#endif
                [MonoTODO ("incomplete")]
                [WebSysDescription("")]
                [WebCategory("Data")]
                public virtual string DataKeyField {
-                       get {
-                               object o = ViewState ["DataKeyField"];
-                               return (o == null) ? String.Empty : (string) o;
-                       }
+                       get { return ViewState.GetString ("DataKeyField", String.Empty); }
                        set {
                                if (value == null)
                                        ViewState.Remove ("DataKeyField");
@@ -172,64 +153,47 @@ namespace System.Web.UI.WebControls {
                }
 
                [DefaultValue ("")]
-#if NET_2_0
                [Themeable (false)]
-#endif
                [WebSysDescription("")]
                [WebCategory("Data")]
                public string DataMember {
-                       get {
-                               object o = ViewState ["DataMember"];
-                               return (o == null) ? String.Empty : (string) o;
-                       }
+                       get { return ViewState.GetString ("DataMember", String.Empty); }
                        set {
                                if (value == null)
                                        ViewState.Remove ("DataMember");
                                else
                                        ViewState ["DataMember"] = value;
-#if NET_2_0
-                               if (!Initialized)
-                                       OnDataPropertyChanged ();
-#endif
+                               OnDataPropertyChanged ();
                        }
                }
 
                [Bindable (true)]
                [DefaultValue (null)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if NET_2_0
                [Themeable (false)]
-#endif
                [WebSysDescription("")]
                [WebCategory("Data")]
-               public virtual object DataSource {
+                       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."));
+                                       // 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
+                                       OnDataPropertyChanged ();
+
                                } else {
                                        string msg = Locale.GetText ("Invalid data source. This requires an object implementing {0} or {1}.",
-                                               "IEnumerable", "IListSource");
+                                                                    "IEnumerable", "IListSource");
                                        throw new ArgumentException (msg);
                                }
                        }
                }
 
-#if ONLY_1_1
-               [Bindable (true)]
-#endif
                [DefaultValue (GridLines.Both)]
                [WebSysDescription("")]
                [WebCategory("Appearance")]
@@ -242,9 +206,6 @@ namespace System.Web.UI.WebControls {
                        set { TableStyle.GridLines = value; }
                }
 
-#if ONLY_1_1
-               [Bindable (true)]
-#endif
                [Category ("Layout")]
                [DefaultValue (HorizontalAlign.NotSet)]
                [WebSysDescription("")]
@@ -259,21 +220,15 @@ namespace System.Web.UI.WebControls {
 
                [DefaultValue (false)]
                public virtual bool UseAccessibleHeader {
-                       get {
-                               object o = ViewState ["UseAccessibleHeader"];
-                               return (o == null) ? false : (bool) o;
-                       }
+                       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 {
-                               object o = ViewState ["DataSourceID"];
-                               return (o == null) ? String.Empty : (string) o;
-                       }
+                       get { return ViewState.GetString ("DataSourceID", String.Empty); }
                        set {
                                // LAMESPEC ? this is documented as an HttpException in beta2
                                if (source != null)
@@ -281,8 +236,7 @@ namespace System.Web.UI.WebControls {
 
                                ViewState ["DataSourceID"] = value;
 
-                               if (!Initialized)
-                                       OnDataPropertyChanged ();
+                               OnDataPropertyChanged ();
                        }
                }
 
@@ -308,8 +262,10 @@ namespace System.Web.UI.WebControls {
                                return selectArguments;
                        }
                }
-#endif
-               private TableStyle TableStyle {
+               public override bool SupportsDisabledAttribute {
+                       get { return RenderingCompatibilityLessThan40; }
+               }
+               TableStyle TableStyle {
                        // this will throw an InvalidCasException just like we need
                        get { return (TableStyle) ControlStyle; }
                }
@@ -321,20 +277,16 @@ namespace System.Web.UI.WebControls {
                }
 
                // see Kothari, page 435
-#if NET_2_0
-               protected internal
-#else          
-               protected
-#endif         
-               override void CreateChildControls ()
+               protected internal override void CreateChildControls ()
                {
                        // We are recreating the children from viewstate
                        if (HasControls ())
-                               Controls.Clear();
+                               base.Controls.Clear();
 
-                       // If presents, build the children from the viewstate
-                       if (ViewState ["Items"] != null)
+                       if (IsDataBound)
                                CreateControlHierarchy (false);
+                       else if (RequiresDataBinding)
+                               EnsureDataBound ();
                }
 
                protected abstract void CreateControlHierarchy (bool useDataSource);
@@ -359,8 +311,10 @@ namespace System.Web.UI.WebControls {
                        // Indicate that child controls have been created, preventing
                        // CreateChildControls from getting called.
                        ChildControlsCreated = true;    
+                       RequiresDataBinding = false;
+                       IsDataBound = true;
                }
-#if NET_2_0
+
                protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
                {
                        return DataSourceSelectArguments.Empty;
@@ -373,7 +327,7 @@ namespace System.Web.UI.WebControls {
                                DataBind ();
                }
 
-               private void SelectCallback (IEnumerable data)
+               void SelectCallback (IEnumerable data)
                {
                        this.data = data;
                }
@@ -383,26 +337,32 @@ namespace System.Web.UI.WebControls {
                        if (DataSourceID.Length == 0)
                                return null;
 
-                       IDataSource ds = null;
-                       if (Page != null)
-                               ds = (Page.FindControl (DataSourceID) as IDataSource);
+                       if (boundDataSource == null)
+                               ConnectToDataSource ();
 
-                       if (ds == null)
-                               throw new HttpException (Locale.GetText ("Coulnd't find a DataSource named '{0}'.", DataSourceID));
-
-                       DataSourceView dsv = ds.GetView (String.Empty);
+                       DataSourceView dsv = boundDataSource.GetView (String.Empty);
                        dsv.Select (SelectArguments, new DataSourceViewSelectCallback (SelectCallback));
                        return data;
                }
-#endif
+
+               bool IsDataBound {
+                       get {
+                               return ViewState.GetBool ("_DataBound", false);
+                       }
+                       set {
+                               ViewState ["_DataBound"] = value;
+                       }
+               }
 
                protected override void OnDataBinding (EventArgs e)
                {
                        base.OnDataBinding (e);
                }
-#if NET_2_0
+
                protected virtual void OnDataPropertyChanged ()
                {
+                       if (Initialized)
+                               RequiresDataBinding = true;
                }
 
                protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
@@ -413,23 +373,49 @@ namespace System.Web.UI.WebControls {
                protected internal override void OnInit (EventArgs e)
                {
                        base.OnInit (e);
-               }
+                       Page page = Page;
+                       if (page != null) {
+                               page.PreLoad += new EventHandler (OnPagePreLoad);
 
+                               if (!IsViewStateEnabled && page.IsPostBack)
+                                       RequiresDataBinding = true;
+                       }
+               }
+               
+               void OnPagePreLoad (object sender, EventArgs e)
+               {
+                       if (!Initialized)
+                               Initialize ();
+               }
+               
                protected internal override void OnLoad (EventArgs e)
                {
-                       if ((Page != null) && !Page.IsPostBack)
-                               RequiresDataBinding = true;
+                       if (!Initialized)
+                               Initialize ();
 
-                       initialized = true;
                        base.OnLoad (e);
                }
+               
+               void Initialize ()
+               {
+                       Page page = Page;
+                       if (page != null) {
+                               if (!page.IsPostBack || (IsViewStateEnabled && !IsDataBound))
+                                       RequiresDataBinding = true;
+                       }
+
+                       if (IsBoundUsingDataSourceID)
+                               ConnectToDataSource ();
+
+                       initialized = true;
+               }
 
                protected internal override void OnPreRender (EventArgs e)
                {
                        EnsureDataBound ();
                        base.OnPreRender (e);
                }
-#endif
+
                protected virtual void OnSelectedIndexChanged (EventArgs e)
                {
                        EventHandler selectedIndexChanged = (EventHandler) Events [selectedIndexChangedEvent];
@@ -439,12 +425,7 @@ namespace System.Web.UI.WebControls {
 
                protected abstract void PrepareControlHierarchy ();
 
-#if NET_2_0
-               protected internal
-#else          
-               protected
-#endif         
-               override void Render (HtmlTextWriter writer)
+               protected internal override void Render (HtmlTextWriter writer)
                {
                        PrepareControlHierarchy ();
                        // don't call base class or RenderBegin|EndTag
@@ -452,7 +433,6 @@ namespace System.Web.UI.WebControls {
                        RenderContents (writer);
                }
 
-
                [WebSysDescription("")]
                [WebCategory("Action")]
                public event EventHandler SelectedIndexChanged {
@@ -460,7 +440,6 @@ namespace System.Web.UI.WebControls {
                        remove { Events.RemoveHandler (selectedIndexChangedEvent, value); }
                }
 
-
                static public bool IsBindableType (Type type)
                {
                        // I can't believe how many NRE are possible in System.Web
@@ -468,25 +447,41 @@ namespace System.Web.UI.WebControls {
                                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;
+                               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;
+                       }
+               }
+
+               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);
                }
        }
 }