2008-03-13 Marek Habersack <mhabersack@novell.com>
[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                 
66                 protected virtual IDataSource GetDataSource ()
67                 {
68                         if (IsBoundUsingDataSourceID) {
69
70                                 Control ctrl = FindDataSource ();
71
72                                 if (ctrl == null)
73                                         throw new HttpException (string.Format ("A control with ID '{0}' could not be found.", DataSourceID));
74                                 if (!(ctrl is IDataSource))
75                                         throw new HttpException (string.Format ("The control with ID '{0}' is not a control of type IDataSource.", DataSourceID));
76                                 return (IDataSource) ctrl;
77                         }
78                         
79                         IDataSource ds = DataSource as IDataSource;
80                         if (ds != null) return ds;
81                         
82                         IEnumerable ie = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
83                         return new CollectionDataSource (ie);
84                 }
85                 
86                 protected virtual DataSourceView GetData ()
87                 {
88                         if (currentView == null)
89                                 UpdateViewData ();
90                         return currentView;
91                 }
92                 
93                 DataSourceView InternalGetData ()
94                 {
95                         if (DataSource != null && IsBoundUsingDataSourceID)
96                                 throw new HttpException ("Control bound using both DataSourceID and DataSource properties.");
97                         
98                         IDataSource ds = GetDataSource ();
99                         if (ds != null)
100                                 return ds.GetView (DataMember);
101                         else
102                                 return null; 
103                 }
104                 
105                 protected override void OnDataPropertyChanged ()
106                 {
107                         base.OnDataPropertyChanged ();
108                         currentView = null;
109                 }
110                 
111                 protected virtual void OnDataSourceViewChanged (object sender, EventArgs e)
112                 {
113                         RequiresDataBinding = true;
114                 }
115                 
116                 // MSDN: The OnPagePreLoad method is overridden by the DataBoundControl class 
117                 // to set the BaseDataBoundControl.RequiresDataBinding property to true in 
118                 // cases where the HTTP request is a postback and view state is enabled but 
119                 // the data-bound control has not yet been bound. 
120                 protected override void OnPagePreLoad (object sender, EventArgs e)
121                 {
122                         base.OnPagePreLoad (sender, e);
123
124                         Initialize ();
125                 }
126
127                 private void Initialize ()
128                 {
129                         if (!IsDataBound)
130                                 RequiresDataBinding = true;
131
132                         UpdateViewData ();
133                 }
134                 
135                 void UpdateViewData ()
136                 {
137                         DataSourceView view = InternalGetData ();
138                         if (view == currentView) return;
139
140                         if (currentView != null)
141                                 currentView.DataSourceViewChanged -= new EventHandler (OnDataSourceViewChanged);
142
143                         currentView = view;
144
145                         if (view != null)
146                                 view.DataSourceViewChanged += new EventHandler (OnDataSourceViewChanged);
147                 }
148                 
149                 protected internal override void OnLoad (EventArgs e)
150                 {
151                         if (!Initialized) {
152                                 
153                                 Initialize ();
154
155                                 // MSDN: The ConfirmInitState method sets the initialized state of the data-bound 
156                                 // control. The method is called by the DataBoundControl class in its OnLoad method.
157                                 ConfirmInitState ();
158                         }
159                         base.OnLoad(e);
160                 }
161                 
162                 protected internal virtual void PerformDataBinding (IEnumerable data)
163                 {
164                 }
165
166                 protected override void ValidateDataSource (object dataSource)
167                 {
168                         if (dataSource == null || dataSource is IListSource || dataSource is IEnumerable || dataSource is IDataSource)
169                                 return;
170                         throw new ArgumentException ("Invalid data source source type. The data source must be of type IListSource, IEnumerable or IDataSource.");
171                 }
172
173                 [ThemeableAttribute (false)]
174                 [DefaultValueAttribute ("")]
175                 [WebCategoryAttribute ("Data")]
176                 public virtual string DataMember {
177                         get { return ViewState.GetString ("DataMember", ""); }
178                         set { ViewState["DataMember"] = value; }
179                 }
180
181                 [IDReferencePropertyAttribute (typeof(DataSourceControl))]
182                 public override string DataSourceID {
183                         get { return ViewState.GetString ("DataSourceID", ""); }
184                         set {
185                                 ViewState ["DataSourceID"] = value;
186                                 base.DataSourceID = value;
187                         }
188                 }
189                 
190                 // 
191                 // See DataBoundControl.MarkAsDataBound msdn doc for the code example
192                 // 
193                 protected override void PerformSelect ()
194                 {
195                         // Call OnDataBinding here if bound to a data source using the
196                         // DataSource property (instead of a DataSourceID), because the
197                         // databinding statement is evaluated before the call to GetData.       
198                         if (!IsBoundUsingDataSourceID)
199                                 OnDataBinding (EventArgs.Empty);
200
201                         // prevent recursive calls
202                         RequiresDataBinding = false;
203                         SelectArguments = CreateDataSourceSelectArguments ();
204                         GetData ().Select (SelectArguments, new DataSourceViewSelectCallback (OnSelect));
205
206                         // The PerformDataBinding method has completed.
207                         MarkAsDataBound ();
208                         
209                         // Raise the DataBound event.
210                         OnDataBound (EventArgs.Empty);
211                 }
212                 
213                 void OnSelect (IEnumerable data)
214                 {
215                         // Call OnDataBinding only if it has not already been 
216                         // called in the PerformSelect method.
217                         if (IsBoundUsingDataSourceID) {
218                                 OnDataBinding (EventArgs.Empty);
219                         }
220                         // The PerformDataBinding method binds the data in the  
221                         // retrievedData collection to elements of the data-bound control.
222                         InternalPerformDataBinding (data);
223                 }
224                 
225                 protected void InternalPerformDataBinding (IEnumerable data)
226                 {
227                         DataBoundControlAdapter adapter = (DataBoundControlAdapter)Adapter;
228                         if (adapter != null)
229                                 adapter.PerformDataBinding (data);
230                         else
231                                 PerformDataBinding (data);
232                 }
233                 
234                 protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments ()
235                 {
236                         return DataSourceSelectArguments.Empty;
237                 }
238                 
239                 protected DataSourceSelectArguments SelectArguments {
240                         get {
241                                 if (selectArguments == null)
242                                         selectArguments = CreateDataSourceSelectArguments ();
243                                 return selectArguments;
244                         }
245                         private set {
246                                 selectArguments = value;
247                         }
248                 }
249
250                 bool IsDataBound {
251                         get {
252                                 object dataBound = ViewState ["DataBound"];
253                                 return dataBound != null ? (bool) dataBound : false;
254                         }
255                         set {
256                                 ViewState ["DataBound"] = value;
257                         }
258                 }
259
260                 protected void MarkAsDataBound ()
261                 {
262                         IsDataBound = true;
263                 }
264         }
265 }
266 #endif
267
268
269
270
271