2004-05-26 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / ListControl.cs
1 //
2 // System.Web.UI.WebControls.ListControl.cs
3 //
4 // Authors:
5 //   Gaurav Vaish (gvaish@iitk.ac.in)
6 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //
8 // (C) Gaurav Vaish (2002)
9 // (C) 2003 Andreas Nahr
10 //
11 \r
12 using System;\r
13 using System.Collections;\r
14 using System.ComponentModel;
15 using System.ComponentModel.Design;\r
16 using System.Web;\r
17 using System.Web.UI;\r
18 using System.Web.Util;\r
19 \r
20 namespace System.Web.UI.WebControls\r
21 {\r
22         [DefaultEvent("SelectedIndexChanged")]\r
23         #if !NET_2_0
24         [DefaultProperty("DataSource")]
25         #endif\r
26         [Designer ("System.Web.UI.Design.WebControls.ListControlDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]\r
27         [DataBindingHandler("System.Web.UI.Design.ListControlDataBindingHandler, " + Consts.AssemblySystem_Design)]\r
28         [ParseChildren(true, "Items")]\r
29         public abstract class ListControl : 
30                 #if NET_2_0
31                         DataBoundControl
32                 #else
33                         WebControl
34                 #endif\r
35         {\r
36                 private static readonly object SelectedIndexChangedEvent = new object();\r
37
38                 #if !NET_2_0\r
39                 private object             dataSource;
40                 #endif
41                 \r
42                 private ListItemCollection items;\r
43 \r
44                 private int cachedSelectedIndex = -1;\r
45                 private string cachedSelectedValue;
46
47                 #if !NET_2_0\r
48                 public ListControl(): base(HtmlTextWriterTag.Select)\r
49                 {\r
50                 }
51                 #else
52                 protected override HtmlTextWriterTag TagKey {
53                         get { return HtmlTextWriterTag.Select; }
54                 }
55                 #endif\r
56
57                 [WebCategory ("Action")]
58                 [WebSysDescription ("Raised when the selected index entry has changed.")]\r
59                 public event EventHandler SelectedIndexChanged\r
60                 {\r
61                         add\r
62                         {\r
63                                 Events.AddHandler(SelectedIndexChangedEvent, value);\r
64                         }\r
65                         remove\r
66                         {\r
67                                 Events.RemoveHandler(SelectedIndexChangedEvent, value);\r
68                         }\r
69                 }\r
70
71                 [DefaultValue (false), WebCategory ("Behavior")]
72                 [WebSysDescription ("The control automatically posts back after changing the text.")]\r
73                 public virtual bool AutoPostBack\r
74                 {\r
75                         get\r
76                         {\r
77                                 object o = ViewState["AutoPostBack"];\r
78                                 if(o!=null)\r
79                                         return (bool)o;\r
80                                 return false;\r
81                         }\r
82                         set\r
83                         {\r
84                                 ViewState["AutoPostBack"] = value;\r
85                         }\r
86                 }\r
87
88                 #if !NET_2_0
89                 [DefaultValue (""), WebCategory ("Data")]
90                 [WebSysDescription ("The name of the table that is used for binding when a DataSource is specified.")]\r
91                 public virtual string DataMember\r
92                 {\r
93                         get\r
94                         {\r
95                                 object o = ViewState["DataMember"];\r
96                                 if(o!=null)\r
97                                         return (string)o;\r
98                                 return String.Empty;\r
99                         }\r
100                         set\r
101                         {\r
102                                 ViewState["DataMember"] = value;\r
103                         }\r
104                 }\r
105
106
107                 [DefaultValue (null), Bindable (true), WebCategory ("Data")]
108                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
109                 [WebSysDescription ("The DataSource that is used for data-binding.")]\r
110                 public virtual object DataSource\r
111                 {\r
112                         get\r
113                         {\r
114                                 return dataSource;\r
115                         }\r
116                         set\r
117                         {\r
118                                 if(value == null || value is IListSource || value is IEnumerable) {
119                                         dataSource = value;
120                                         return;
121                                 }
122                                 throw new ArgumentException(HttpRuntime.FormatResourceString(ID, "Invalid DataSource Type"));\r
123                         }\r
124                 }
125                 #endif\r
126
127                 [DefaultValue (""), WebCategory ("Data")]
128                 [WebSysDescription ("The field in the datatable that provides the text entry.")]\r
129                 public virtual string DataTextField\r
130                 {\r
131                         get\r
132                         {\r
133                                 object o = ViewState["DataTextField"];\r
134                                 if(o!=null)\r
135                                         return (string)o;\r
136                                 return String.Empty;\r
137                         }\r
138                         set\r
139                         {\r
140                                 ViewState["DataTextField"] = value;\r
141                         }\r
142                 }\r
143
144                 [DefaultValue (""), WebCategory ("Data")]
145                 [WebSysDescription ("Specifies a formatting rule for the texts that are returned.")]\r
146                 public virtual string DataTextFormatString\r
147                 {\r
148                         get\r
149                         {\r
150                                 object o = ViewState["DataTextFormatString"];\r
151                                 if(o!=null)\r
152                                         return (string)o;\r
153                                 return String.Empty;\r
154                         }\r
155                         set\r
156                         {\r
157                                 ViewState["DataTextFormatString"] = value;\r
158                         }\r
159                 }\r
160
161                 [DefaultValue (""), WebCategory ("Data")]
162                 [WebSysDescription ("The field in the datatable that provides the entry value.")]\r
163                 public virtual string DataValueField\r
164                 {\r
165                         get\r
166                         {\r
167                                 object o = ViewState["DataValueField"];\r
168                                 if(o!=null)\r
169                                         return (string)o;\r
170                                 return String.Empty;\r
171                         }\r
172                         set\r
173                         {\r
174                                 ViewState["DataValueField"] = value;\r
175                         }\r
176                 }\r
177
178                 [DefaultValue (null), MergableProperty (false), WebCategory ("Misc")]
179                 [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
180                 [WebSysDescription ("A collection of all items contained in this list.")]\r
181                 public virtual ListItemCollection Items\r
182                 {\r
183                         get\r
184                         {\r
185                                 if(items==null)\r
186                                 {\r
187                                         items = new ListItemCollection();\r
188                                         if(IsTrackingViewState)\r
189                                         {\r
190                                                 items.TrackViewState();\r
191                                         }\r
192                                 }\r
193                                 return items;\r
194                         }\r
195                 }\r
196
197                 [DefaultValue (0), Bindable (true), WebCategory ("Misc")]
198                 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
199                 [WebSysDescription ("The index number of the currently selected ListItem.")]\r
200                 public virtual int SelectedIndex\r
201                 {\r
202                         get {\r
203                                 ListItemCollection items = Items;\r
204                                 int last = items.Count;\r
205                                 for (int i = 0; i < last; i++) {\r
206                                         if (items [i].Selected)\r
207                                                 return i;\r
208                                 }\r
209                                 return -1;\r
210                         }\r
211                         set {\r
212                                 if (Items.Count == 0)\r
213                                 {\r
214                                         cachedSelectedIndex = value;\r
215                                         return;\r
216                                 }\r
217                                 if ((value < -1) || (value >= Items.Count))\r
218                                         throw new ArgumentOutOfRangeException ();\r
219 \r
220                                 ClearSelection ();\r
221                                 if (value != -1)\r
222                                         Items [value].Selected = true;\r
223                         }\r
224                 }\r
225
226                 [DefaultValue (null), WebCategory ("Misc")]
227                 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
228                 [WebSysDescription ("The currently selected ListItem.")]\r
229                 public virtual ListItem SelectedItem\r
230                 {\r
231                         get\r
232                         {\r
233                                 int idx = SelectedIndex;\r
234                                 if (idx < 0)\r
235                                         return null;\r
236 \r
237                                 return Items [idx];\r
238                         }\r
239                 }\r
240 \r
241 #if NET_1_1
242                 [DefaultValue (""), Bindable (true), WebCategory ("Misc")]
243                 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
244                 [WebSysDescription ("The value of the currently selected ListItem.")]\r
245                 public virtual string SelectedValue {\r
246                         get {\r
247                                 int idx = SelectedIndex;\r
248                                 if (idx == -1)\r
249                                         return "";\r
250 \r
251                                 return Items [idx].Value;\r
252                         }\r
253 \r
254                         set {\r
255                                 ListItem item = null;\r
256 \r
257                                 if (value != null) {\r
258                                         if (Items.Count > 0) {
259                                                 item = Items.FindByValue (value);
260                                                 if (item == null)
261                                                         throw new ArgumentOutOfRangeException ("value");
262                                         } else {
263                                                 cachedSelectedValue = value;
264                                                 return;
265                                         }
266                                 }\r
267 \r
268                                 ClearSelection ();\r
269                                 if (item != null)\r
270                                         item.Selected = true;\r
271                         }\r
272                 }\r
273 #endif\r
274                 \r
275                 internal virtual ArrayList SelectedIndices\r
276                 {\r
277                         get\r
278                         {\r
279                                 ArrayList si = new ArrayList();\r
280                                 for(int i=0; i < Items.Count; i++)\r
281                                 {\r
282                                         if(Items[i].Selected)\r
283                                                 si.Add(i);\r
284                                 }\r
285                                 return si;\r
286                         }\r
287                 }\r
288 \r
289                 internal void Select(ArrayList indices)\r
290                 {\r
291                         ClearSelection();\r
292                         foreach(object intObj in indices)\r
293                         {\r
294                                 int index = (int)intObj;\r
295                                 if(index >= 0 && index < Items.Count)\r
296                                         Items[index].Selected = true;\r
297                         }\r
298                 }\r
299 \r
300                 public virtual void ClearSelection()\r
301                 {\r
302                         for(int i=0; i < Items.Count; i++)\r
303                         {\r
304                                 Items[i].Selected = false;\r
305                         }\r
306                 }\r
307 \r
308                 protected override void LoadViewState(object savedState)\r
309                 {\r
310                         //Order: BaseClass, Items (Collection), Indices\r
311                         if(savedState != null && savedState is Triplet)\r
312                         {\r
313                                 Triplet state = (Triplet)savedState;\r
314                                 base.LoadViewState(state.First);\r
315                                 Items.LoadViewState(state.Second);\r
316                                 object indices = state.Third;\r
317                                 if(indices != null)\r
318                                 {\r
319                                         Select((ArrayList)indices);\r
320                                 }\r
321                         }\r
322                 }\r
323
324                 #if NET_2_0
325                 protected override void PerformDataBinding ()
326                 {
327                         base.PerformDataBinding ();
328                         IEnumerable ds = GetResolvedDataSource ();
329                 #else\r
330                 protected override void OnDataBinding(EventArgs e)\r
331                 {\r
332                         base.OnDataBinding(e);\r
333                         IEnumerable ds = DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
334                 #endif\r
335                         if(ds != null) {\r
336                                 string dtf = DataTextField;\r
337                                 string dvf = DataValueField;\r
338                                 string dtfs = DataTextFormatString;\r
339                                 if (dtfs.Length == 0)\r
340                                         dtfs = "{0}";\r
341 \r
342                                 Items.Clear();\r
343 \r
344                                 bool dontUseProperties = (dtf.Length == 0 && dvf.Length == 0);\r
345 \r
346                                 foreach (object current in ds) {\r
347                                         ListItem li = new ListItem();\r
348                                         if (dontUseProperties){\r
349                                                 li.Text  = String.Format (dtfs, current);\r
350                                                 li.Value = current.ToString ();\r
351                                                 Items.Add (li);\r
352                                                 continue;\r
353                                         }\r
354 \r
355                                         object o;\r
356                                         if (dtf.Length > 0) {\r
357                                                 o = DataBinder.GetPropertyValue (current, dtf, dtfs);\r
358                                                 li.Text = o.ToString ();\r
359                                         }\r
360 \r
361                                         if (dvf.Length > 0) {\r
362                                                 o = DataBinder.GetPropertyValue (current, dvf, null);\r
363                                                 li.Value = o.ToString ();\r
364                                         }\r
365 \r
366                                         Items.Add(li);\r
367                                 }\r
368                         }\r
369
370                         if (cachedSelectedValue != null) {
371                                 int index = Items.FindByValueInternal (cachedSelectedValue);
372                                 if (index == -1)
373                                         throw new ArgumentOutOfRangeException("value");
374
375                                 if (cachedSelectedIndex != -1 && cachedSelectedIndex != index)
376                                         throw new ArgumentException(HttpRuntime.FormatResourceString(
377                                                 "Attributes_mutually_exclusive", "Selected Index", "Selected Value"));
378
379                                 SelectedIndex = index;
380                                 cachedSelectedIndex = -1;
381                                 cachedSelectedValue = null;
382                                 return;
383                         }
384
385                         if (cachedSelectedIndex != -1) {\r
386                                 SelectedIndex = cachedSelectedIndex;\r
387                                 cachedSelectedIndex = -1;\r
388                         }\r
389                 }\r
390 \r
391                 protected virtual void OnSelectedIndexChanged(EventArgs e)\r
392                 {\r
393                         if(Events!=null)\r
394                                 {\r
395                                         EventHandler eh = (EventHandler)(Events[SelectedIndexChangedEvent]);\r
396                                         if(eh!=null)\r
397                                                 eh(this, e);\r
398                                 }\r
399                 }\r
400 \r
401                 protected override void OnPreRender (EventArgs e)\r
402                 {\r
403                         base.OnPreRender(e);\r
404                 }\r
405 \r
406                 protected override object SaveViewState()\r
407                 {\r
408                         //Order: BaseClass, Items (Collection), Indices\r
409                         object vs = base.SaveViewState();\r
410                         object itemSvs = Items.SaveViewState();\r
411                         object indices = null;\r
412                         if (SaveSelectedIndicesViewState)\r
413                                 indices = SelectedIndices;\r
414 \r
415                         if (vs != null || itemSvs != null || indices != null)\r
416                                 return new Triplet(vs, itemSvs, indices);\r
417 \r
418                         return null;\r
419                 }\r
420 \r
421                 protected override void TrackViewState()\r
422                 {\r
423                         base.TrackViewState();\r
424                         Items.TrackViewState();\r
425                 }\r
426 \r
427                 private bool SaveSelectedIndicesViewState {\r
428                         get {\r
429                                 if (Events[SelectedIndexChangedEvent] == null && Enabled && Visible) {\r
430                                         Type t = GetType();\r
431                                         // If I am a derivative, let it take of storing the selected indices.\r
432                                         if (t == typeof(DropDownList) || t == typeof(ListBox) ||\r
433                                             t == typeof(CheckBoxList) || t == typeof(RadioButtonList))\r
434                                                 return false;\r
435                                 }\r
436                                 return true;\r
437                         }\r
438                 }\r
439         }\r
440 }\r