5511381d25a131b6c54ca0130493959f26cbc120
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / BaseDataBoundControl.cs
1 //
2 // System.Web.UI.WebControls.BaseDataBoundControl.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // Copyright (C) 2004-2010 Novell, Inc (http://www.novell.com)
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Security.Permissions;
32
33 namespace System.Web.UI.WebControls
34 {
35         // CAS
36         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
37         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
38         // attributes
39         [DefaultProperty ("DataSourceID")]
40         [DesignerAttribute ("System.Web.UI.Design.WebControls.BaseDataBoundControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
41         public abstract class BaseDataBoundControl: WebControl
42         {
43                 static readonly object dataBoundEvent = new object ();
44
45                 EventHandlerList events = new EventHandlerList ();
46                 object dataSource;
47                 bool initialized;
48                 bool preRendered;
49                 bool requiresDataBinding;
50                 
51                 public event EventHandler DataBound {
52                         add { events.AddHandler (dataBoundEvent, value); }
53                         remove { events.RemoveHandler (dataBoundEvent, value); }
54                 }
55                 
56                 protected BaseDataBoundControl ()
57                 {
58                 }
59
60                 /* Used for controls that used to inherit from
61                  * WebControl, so the tag can propagate upwards
62                  */
63                 internal BaseDataBoundControl (HtmlTextWriterTag tag) : base (tag)
64                 {
65                 }
66                 
67                 [BindableAttribute (true)]
68                 [ThemeableAttribute (false)]
69                 [DefaultValueAttribute (null)]
70                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
71                 public virtual object DataSource {
72                         get { return dataSource; }
73                         set {
74                                 if(value!=null)
75                                         ValidateDataSource (value);
76                                 dataSource = value;
77                                 OnDataPropertyChanged ();
78                         }
79                 }
80                 
81                 [DefaultValueAttribute ("")]
82                 [ThemeableAttribute (false)]
83                 public virtual string DataSourceID {
84                         get { return ViewState.GetString ("DataSourceID", String.Empty); }
85                         set {
86                                 ViewState["DataSourceID"] = value;
87                                 OnDataPropertyChanged ();
88                         }
89                 }
90                 
91                 protected bool Initialized {
92                         get { return initialized; }
93                 }
94                 
95                 protected bool IsBoundUsingDataSourceID {
96                         get { return DataSourceID.Length > 0; }
97                 }
98                 
99                 protected bool RequiresDataBinding {
100                         get { return requiresDataBinding; }
101                         set {
102                                 // MSDN: If you set the RequiresDataBinding
103                                 // property to true when the data-bound control
104                                 // has already begun to render its output to the
105                                 // page, the current HTTP request is not a
106                                 // callback, and you are using the DataSourceID
107                                 // property to identify the data source control
108                                 // to bind to, the DataBind method is called
109                                 // immediately. In this case, the
110                                 // RequiresDataBinding property is _not_ actually
111                                 // set to true.
112                                 //
113                                 // LAMESPEC, the docs quoted above mention that
114                                 // DataBind is called in the described
115                                 // case. This is wrong since that way we don't
116                                 // break recursion when the property is set from
117                                 // within the OnSelect handler in user's
118                                 // code. EnsureDataBound makes sure that no
119                                 // recursive binding is performed. Also the
120                                 // property DOES get set in this case (according
121                                 // to tests)
122                                 if (value && preRendered && IsBoundUsingDataSourceID && Page != null && !Page.IsCallback) {
123                                         requiresDataBinding = true;
124                                         EnsureDataBound ();
125                                 } else
126                                         requiresDataBinding = value;
127                         }
128                 }
129 #if NET_4_0
130                 public override bool SupportsDisabledAttribute {
131                         get { return RenderingCompatibilityLessThan40; }
132                 }
133 #endif
134                 protected void ConfirmInitState ()
135                 {
136                         initialized = true;
137                 }
138                 
139                 public override void DataBind ()
140                 {
141                         PerformSelect ();
142                 }
143
144                 protected virtual void EnsureDataBound ()
145                 {
146                         if (RequiresDataBinding && IsBoundUsingDataSourceID)
147                                 DataBind ();
148                 }
149                 
150                 protected virtual void OnDataBound (EventArgs e)
151                 {
152                         EventHandler eh = events [dataBoundEvent] as EventHandler;
153                         if (eh != null)
154                                 eh (this, e);
155                 }
156
157                 protected virtual void OnDataPropertyChanged ()
158                 {
159                         if (Initialized)
160                                 RequiresDataBinding = true;
161                 }
162                 
163                 protected internal override void OnInit (EventArgs e)
164                 {
165                         base.OnInit (e);
166                         Page.PreLoad += new EventHandler (OnPagePreLoad);
167
168                         if (!IsViewStateEnabled && Page != null && Page.IsPostBack)
169                                 RequiresDataBinding = true;
170                 }
171                 
172                 protected virtual void OnPagePreLoad (object sender, EventArgs e)
173                 {
174                         ConfirmInitState ();
175                 }
176                 
177                 protected internal override void OnPreRender (EventArgs e)
178                 {
179                         preRendered = true;
180                         EnsureDataBound ();
181                         base.OnPreRender (e);
182                 }
183
184                 internal Control FindDataSource ()
185                 {
186                         Control ctrl;
187                         Control namingContainer = NamingContainer;
188                         string dataSourceID = DataSourceID;
189                         
190                         while (namingContainer != null) {
191                                 ctrl = namingContainer.FindControl (dataSourceID);
192                                 if (ctrl != null)
193                                         return ctrl;
194                                 namingContainer = namingContainer.NamingContainer;
195                         }
196
197                         return null;
198                 }
199                 
200                 protected abstract void PerformSelect ();
201                 
202                 protected abstract void ValidateDataSource (object dataSource);
203                 
204         }
205 }