2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / DataBoundControl.cs
1 //
2 // System.Web.UI.WebControls.DataBoundControl
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Sanjay Gupta (gsanjay@novell.com)
7 //
8 // (C) 2003 Ben Maurer
9 // (C) 2004 Novell, Inc. (http://www.novell.com)
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 #if NET_2_0
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.Text;
37 using System.Web.Util;
38 using System.ComponentModel;
39 using System.Security.Permissions;
40 using System.Web.UI.WebControls.Adapters;
41
42 namespace System.Web.UI.WebControls {
43
44         // CAS
45         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47         // attributes
48         [DesignerAttribute ("System.Web.UI.Design.WebControls.DataBoundControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
49         public abstract class DataBoundControl : BaseDataBoundControl
50         {
51                 DataSourceSelectArguments selectArguments;
52                 DataSourceView currentView;
53
54                 protected DataBoundControl ()
55                 {
56                 }
57
58                 /* Used for controls that used to inherit from
59                  * WebControl, so the tag can propagate upwards
60                  */
61                 internal DataBoundControl (HtmlTextWriterTag tag) : base (tag)
62                 {
63                 }
64                 
65                 protected virtual IDataSource GetDataSource ()
66                 {
67                         if (IsBoundUsingDataSourceID) {
68
69                                 Control ctrl = FindDataSource ();
70
71                                 if (ctrl == null)
72                                         throw new HttpException (string.Format ("A control with ID '{0}' could not be found.", DataSourceID));
73                                 if (!(ctrl is IDataSource))
74                                         throw new HttpException (string.Format ("The control with ID '{0}' is not a control of type IDataSource.", DataSourceID));
75                                 return (IDataSource) ctrl;
76                         }
77                         
78                         IDataSource ds = DataSource as IDataSource;
79                         if (ds != null) return ds;
80                         
81                         IEnumerable ie = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
82                         return new CollectionDataSource (ie);
83                 }
84                 
85                 protected virtual DataSourceView GetData ()
86                 {
87                         if (currentView == null)
88                                 UpdateViewData ();
89                         return currentView;
90                 }
91                 
92                 DataSourceView InternalGetData ()
93                 {
94                         if (currentView != null)
95                                 return currentView;
96                         
97                         if (DataSource != null && IsBoundUsingDataSourceID)
98                                 throw new HttpException ("Control bound using both DataSourceID and DataSource properties.");
99                         
100                         IDataSource ds = GetDataSource ();
101                         if (ds != null)
102                                 return ds.GetView (DataMember);
103                         else
104                                 return null; 
105                 }
106                 
107                 protected override void OnDataPropertyChanged ()
108                 {
109                         base.OnDataPropertyChanged ();
110                         currentView = null;
111                 }
112                 
113                 protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
114                 {
115                         RequiresDataBinding = true;
116                 }
117                 
118                 // MSDN: The OnPagePreLoad method is overridden by the DataBoundControl class 
119                 // to set the BaseDataBoundControl.RequiresDataBinding property to true in 
120                 // cases where the HTTP request is a postback and view state is enabled but 
121                 // the data-bound control has not yet been bound.
122                 //
123                 // LAMESPEC: RequiresDataBinding is also set when http request is NOT a postback -
124                 // no matter whether view state is enabled. The correct description should be:
125                 //
126                 // The OnPagePreLoad method is override by the DataBoundControl class 
127                 // to set the BaseDataBoundControl.RequiresDataBinding property to true in 
128                 // cases where the HTTP request is not a postback or it is a postback and view state
129                 // is enabled but the data-bound control has not yet been bound.
130                 protected override void OnPagePreLoad (object sender, EventArgs e)
131                 {
132                         base.OnPagePreLoad (sender, e);
133
134                         Initialize ();
135                 }
136
137                 void Initialize ()
138                 {
139                         Page page = Page;
140                         if (page != null) {
141                                 // LAMESPEC: see the comment above OnPagePreLoad
142                                 if (!page.IsPostBack || (!IsDataBound && IsViewStateEnabled))
143                                         RequiresDataBinding = true;
144                         }
145                         
146                 }
147                 
148                 void UpdateViewData ()
149                 {
150                         if (currentView != null)
151                                 currentView.DataSourceViewChanged -= new EventHandler (OnDataSourceViewChanged);
152                         
153                         DataSourceView view = InternalGetData ();
154                         if (view != currentView)
155                                 currentView = view;
156
157                         if (currentView != null)
158                                 currentView.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);
159                 }
160                 
161                 protected internal override void OnLoad (EventArgs e)
162                 {
163                         UpdateViewData ();
164                         if (!Initialized) {
165                                 Initialize ();
166
167                                 // MSDN: The ConfirmInitState method sets the initialized state of the data-bound 
168                                 // control. The method is called by the DataBoundControl class in its OnLoad
169                                 // method.
170                                 ConfirmInitState ();
171                         }
172                         
173                         base.OnLoad(e);
174                 }
175                 
176                 protected internal virtual void PerformDataBinding (IEnumerable data)
177                 {
178                 }
179
180                 protected override void ValidateDataSource (object dataSource)
181                 {
182                         if (dataSource == null || dataSource is IListSource || dataSource is IEnumerable || dataSource is IDataSource)
183                                 return;
184                         throw new ArgumentException ("Invalid data source source type. The data source must be of type IListSource, IEnumerable or IDataSource.");
185                 }
186
187                 [ThemeableAttribute (false)]
188                 [DefaultValueAttribute ("")]
189                 [WebCategoryAttribute ("Data")]
190                 public virtual string DataMember {
191                         get { return ViewState.GetString ("DataMember", ""); }
192                         set { ViewState["DataMember"] = value; }
193                 }
194
195                 [IDReferencePropertyAttribute (typeof(DataSourceControl))]
196                 public override string DataSourceID {
197                         get { return ViewState.GetString ("DataSourceID", ""); }
198                         set {
199                                 ViewState ["DataSourceID"] = value;
200                                 base.DataSourceID = value;
201                         }
202                 }
203
204 #if NET_4_0
205                 [Browsable (false)]
206                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207                 public
208 #else
209                 internal
210 #endif
211                 IDataSource DataSourceObject {
212                         get { return GetDataSource (); }
213                 }
214                 
215                 // 
216                 // See DataBoundControl.MarkAsDataBound msdn doc for the code example
217                 // 
218                 protected override void PerformSelect ()
219                 {
220                         // Call OnDataBinding here if bound to a data source using the
221                         // DataSource property (instead of a DataSourceID), because the
222                         // databinding statement is evaluated before the call to GetData.       
223                         if (!IsBoundUsingDataSourceID)
224                                 OnDataBinding (EventArgs.Empty);
225
226                         // prevent recursive calls
227                         RequiresDataBinding = false;
228                         SelectArguments = CreateDataSourceSelectArguments ();
229                         GetData ().Select (SelectArguments, new DataSourceViewSelectCallback (OnSelect));
230
231                         // The PerformDataBinding method has completed.
232                         MarkAsDataBound ();
233                         
234                         // Raise the DataBound event.
235                         OnDataBound (EventArgs.Empty);
236                 }
237                 
238                 void OnSelect (IEnumerable data)
239                 {
240                         // Call OnDataBinding only if it has not already been 
241                         // called in the PerformSelect method.
242                         if (IsBoundUsingDataSourceID) {
243                                 OnDataBinding (EventArgs.Empty);
244                         }
245                         // The PerformDataBinding method binds the data in the  
246                         // retrievedData collection to elements of the data-bound control.
247                         InternalPerformDataBinding (data);
248                 }
249
250 #if NET_4_0
251                 internal
252 #else
253                 protected
254 #endif
255                 void InternalPerformDataBinding (IEnumerable data)
256                 {
257                         DataBoundControlAdapter adapter = Adapter as DataBoundControlAdapter;
258                         if (adapter != null)
259                                 adapter.PerformDataBinding (data);
260                         else
261                                 PerformDataBinding (data);
262                 }
263                 
264                 protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
265                 {
266                         return DataSourceSelectArguments.Empty;
267                 }
268                 
269                 protected DataSourceSelectArguments SelectArguments {
270                         get {
271                                 if (selectArguments == null)
272                                         selectArguments = CreateDataSourceSelectArguments ();
273                                 return selectArguments;
274                         }
275                         private set {
276                                 selectArguments = value;
277                         }
278                 }
279
280                 bool IsDataBound {
281                         get {
282                                 object dataBound = ViewState ["DataBound"];
283                                 return dataBound != null ? (bool) dataBound : false;
284                         }
285                         set {
286                                 ViewState ["DataBound"] = value;
287                         }
288                 }
289
290                 protected void MarkAsDataBound ()
291                 {
292                         IsDataBound = true;
293                 }
294         }
295 }
296 #endif
297
298
299
300
301