2006-09-20 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / ListControl.cs
index ec70126a43bedbbca1885e105f3969c8225192de..acf4c7c8aefce247336f59936db0335992b6d66a 100644 (file)
 // System.Web.UI.WebControls.ListControl.cs
 //
 // Authors:
-//   Gaurav Vaish (gvaish@iitk.ac.in)
-//   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+//     Jackson Harper (jackson@ximian.com)
 //
-// (C) Gaurav Vaish (2002)
-// (C) 2003 Andreas Nahr
+// (C) 2005 Novell, Inc (http://www.novell.com)
 //
-\r
-using System;\r
-using System.Collections;\r
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Drawing;
+using System.Web.Util;
+using System.Collections;
+using System.Globalization;
 using System.ComponentModel;
-using System.ComponentModel.Design;\r
-using System.Web;\r
-using System.Web.UI;\r
-using System.Web.Util;\r
-\r
-namespace System.Web.UI.WebControls\r
-{\r
-       [DefaultEvent("SelectedIndexChanged")]\r
-       #if !NET_2_0
-       [DefaultProperty("DataSource")]
-       #endif\r
-       [Designer ("System.Web.UI.Design.WebControls.ListControlDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]\r
-       [DataBindingHandler("System.Web.UI.Design.ListControlDataBindingHandler, " + Consts.AssemblySystem_Design)]\r
-       [ParseChildren(true, "Items")]\r
-       public abstract class ListControl : 
-               #if NET_2_0
-                       DataBoundControl
-               #else
-                       WebControl
-               #endif\r
-       {\r
-               private static readonly object SelectedIndexChangedEvent = new object();\r
-
-               #if !NET_2_0\r
-               private object             dataSource;
-               #endif
-               \r
-               private ListItemCollection items;\r
-\r
-               private int cachedSelectedIndex = -1;\r
-               private string cachedSelectedValue;
-
-               #if !NET_2_0\r
-               public ListControl(): base(HtmlTextWriterTag.Select)\r
-               {\r
-               }
-               #else
-               protected override HtmlTextWriterTag TagKey {
-                       get { return HtmlTextWriterTag.Select; }
-               }
-               #endif\r
+using System.Collections.Specialized;
 
-               [WebCategory ("Action")]
-               [WebSysDescription ("Raised when the selected index entry has changed.")]\r
-               public event EventHandler SelectedIndexChanged\r
-               {\r
-                       add\r
-                       {\r
-                               Events.AddHandler(SelectedIndexChangedEvent, value);\r
-                       }\r
-                       remove\r
-                       {\r
-                               Events.RemoveHandler(SelectedIndexChangedEvent, value);\r
-                       }\r
-               }\r
-
-               [DefaultValue (false), WebCategory ("Behavior")]
-               [WebSysDescription ("The control automatically posts back after changing the text.")]\r
-               public virtual bool AutoPostBack\r
-               {\r
-                       get\r
-                       {\r
-                               object o = ViewState["AutoPostBack"];\r
-                               if(o!=null)\r
-                                       return (bool)o;\r
-                               return false;\r
-                       }\r
-                       set\r
-                       {\r
-                               ViewState["AutoPostBack"] = value;\r
-                       }\r
-               }\r
-
-               #if !NET_2_0
-               [DefaultValue (""), WebCategory ("Data")]
-               [WebSysDescription ("The name of the table that is used for binding when a DataSource is specified.")]\r
-               public virtual string DataMember\r
-               {\r
-                       get\r
-                       {\r
-                               object o = ViewState["DataMember"];\r
-                               if(o!=null)\r
-                                       return (string)o;\r
-                               return String.Empty;\r
-                       }\r
-                       set\r
-                       {\r
-                               ViewState["DataMember"] = value;\r
-                       }\r
-               }\r
-
-
-               [DefaultValue (null), Bindable (true), WebCategory ("Data")]
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [WebSysDescription ("The DataSource that is used for data-binding.")]\r
-               public virtual object DataSource\r
-               {\r
-                       get\r
-                       {\r
-                               return dataSource;\r
-                       }\r
-                       set\r
-                       {\r
-                               if(value == null || value is IListSource || value is IEnumerable) {
-                                       dataSource = value;
+namespace System.Web.UI.WebControls {
+
+       [DataBindingHandler("System.Web.UI.Design.WebControls.ListControlDataBindingHandler, " + Consts.AssemblySystem_Design)]
+       [DefaultEventAttribute ("SelectedIndexChanged")]
+#if !NET_2_0
+       [DefaultPropertyAttribute ("DataSource")]
+#endif
+       [Designer("System.Web.UI.Design.WebControls.ListControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+       [ParseChildrenAttribute (true, "Items")]
+#if NET_2_0
+       [ControlValueProperty ("SelectedValue", null)]
+#endif 
+       public abstract class ListControl :
+#if NET_2_0
+       DataBoundControl, IEditableTextControl, ITextControl
+#else          
+       WebControl
+#endif
+       {
+
+               private static readonly object SelectedIndexChangedEvent = new object ();
+#if NET_2_0
+               private static readonly object TextChangedEvent = new object ();
+#endif
+
+               private ListItemCollection items;
+               int saved_selected_index = -2;
+               string saved_selected_value;
+               
+               public ListControl () : base (HtmlTextWriterTag.Select)
+               {
+               }
+
+#if NET_2_0
+               [DefaultValue (false)]
+               [Themeable (false)]
+               [MonoTODO]
+               [WebSysDescription ("")]
+               [WebCategory ("Behavior")]
+               public virtual bool AppendDataBoundItems
+               {
+                       get {
+                               return ViewState.GetBool ("AppendDataBoundItems", false);
+                       }
+                       set {
+                               ViewState ["AppendDataBoundItems"] = value;
+                       }
+               }
+#endif         
+               
+#if NET_2_0
+               [Themeable (false)]
+#endif
+               [DefaultValue(false)]
+               [WebSysDescription ("")]
+               [WebCategory ("Behavior")]
+               public virtual bool AutoPostBack {
+                       get { return ViewState.GetBool ("AutoPostBack", false); }
+                       set { ViewState ["AutoPostBack"] = value; }
+               }
+
+#if ONLY_1_1
+               [DefaultValue("")]
+               [WebSysDescription ("")]
+               [WebCategory ("Data")]
+               public virtual string DataMember {
+                       get { return ViewState.GetString ("DataMember", String.Empty); }
+                       set { ViewState ["DataMember"] = value; }
+               }
+
+               private object data_source;
+
+               [Bindable(true)]
+               [DefaultValue(null)]
+               [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+               [WebSysDescription ("")]
+               [WebCategory ("Data")]
+               public virtual object DataSource {
+                       get { return data_source; }
+                       set { 
+                               if(value == null || value is IListSource || value is IEnumerable) { 
+                                       data_source = value;
+                                       return;
+                               }
+                               throw new ArgumentException("Invalid DataSource Type");
+                       }
+               }
+#endif         
+
+#if NET_2_0
+               [Themeable (false)]
+#endif         
+               [DefaultValue("")]
+               [WebSysDescription ("")]
+               [WebCategory ("Data")]
+               public virtual string DataTextField {
+                       get { return ViewState.GetString ("DataTextField", String.Empty); }
+                       set { ViewState ["DataTextField"] = value; }
+               }
+
+#if NET_2_0
+               [Themeable (false)]
+#endif         
+               [DefaultValue("")]
+               [WebSysDescription ("")]
+               [WebCategory ("Data")]
+               public virtual string DataTextFormatString {
+                       get { return ViewState.GetString ("DataTextFormatString", String.Empty); }
+                       set { ViewState ["DataTextFormatString"] = value; }
+               }
+
+#if NET_2_0
+               [Themeable (false)]
+#endif         
+               [DefaultValue("")]
+               [WebSysDescription ("")]
+               [WebCategory ("Data")]
+               public virtual string DataValueField {
+                       get { return ViewState.GetString ("DataValueField", String.Empty); }
+                       set { ViewState ["DataValueField"] = value; }
+               }
+
+#if NET_2_0
+               [Editor ("System.Web.UI.Design.WebControls.ListItemsCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
+#endif         
+               [DefaultValue(null)]
+               [MergableProperty(false)]
+               [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
+               [WebSysDescription ("")]
+               [WebCategory ("Misc")]
+               public virtual ListItemCollection Items {
+                       get {
+                               if (items == null)
+                                       items = new ListItemCollection ();
+                               return items;
+                       }
+               }
+
+               // I can't find this info stored in the viewstate anywhere
+               // so it must be calculated on the fly.
+               [Bindable(true)]
+               [Browsable(false)]
+               [DefaultValue(0)]
+               [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+#if NET_2_0
+               [Themeable (false)]
+#endif         
+               [WebSysDescription ("")]
+               [WebCategory ("Misc")]
+               public virtual int SelectedIndex {
+                       get {
+                               if (items == null)
+                                       return -1;
+                               for (int i = 0; i < items.Count; i++) {
+                                       if (items [i].Selected)
+                                               return i;
+                               }
+                               return -1;
+                       }
+                       set {
+                               if (items == null || items.Count == 0) {
+                                       // This will happen when assigning this property
+                                       // before DataBind () is called on the control.
+                                       saved_selected_index = value;
                                        return;
                                }
-                               throw new ArgumentException(HttpRuntime.FormatResourceString(ID, "Invalid DataSource Type"));\r
-                       }\r
-               }
-               #endif\r
-
-               [DefaultValue (""), WebCategory ("Data")]
-               [WebSysDescription ("The field in the datatable that provides the text entry.")]\r
-               public virtual string DataTextField\r
-               {\r
-                       get\r
-                       {\r
-                               object o = ViewState["DataTextField"];\r
-                               if(o!=null)\r
-                                       return (string)o;\r
-                               return String.Empty;\r
-                       }\r
-                       set\r
-                       {\r
-                               ViewState["DataTextField"] = value;\r
-                       }\r
-               }\r
-
-               [DefaultValue (""), WebCategory ("Data")]
-               [WebSysDescription ("Specifies a formatting rule for the texts that are returned.")]\r
-               public virtual string DataTextFormatString\r
-               {\r
-                       get\r
-                       {\r
-                               object o = ViewState["DataTextFormatString"];\r
-                               if(o!=null)\r
-                                       return (string)o;\r
-                               return String.Empty;\r
-                       }\r
-                       set\r
-                       {\r
-                               ViewState["DataTextFormatString"] = value;\r
-                       }\r
-               }\r
-
-               [DefaultValue (""), WebCategory ("Data")]
-               [WebSysDescription ("The field in the datatable that provides the entry value.")]\r
-               public virtual string DataValueField\r
-               {\r
-                       get\r
-                       {\r
-                               object o = ViewState["DataValueField"];\r
-                               if(o!=null)\r
-                                       return (string)o;\r
-                               return String.Empty;\r
-                       }\r
-                       set\r
-                       {\r
-                               ViewState["DataValueField"] = value;\r
-                       }\r
-               }\r
-
-               [DefaultValue (null), MergableProperty (false), WebCategory ("Misc")]
-               [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
-               [WebSysDescription ("A collection of all items contained in this list.")]\r
-               public virtual ListItemCollection Items\r
-               {\r
-                       get\r
-                       {\r
-                               if(items==null)\r
-                               {\r
-                                       items = new ListItemCollection();\r
-                                       if(IsTrackingViewState)\r
-                                       {\r
-                                               items.TrackViewState();\r
-                                       }\r
-                               }\r
-                               return items;\r
-                       }\r
-               }\r
-
-               [DefaultValue (0), Bindable (true), WebCategory ("Misc")]
-               [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [WebSysDescription ("The index number of the currently selected ListItem.")]\r
-               public virtual int SelectedIndex\r
-               {\r
-                       get {\r
-                               ListItemCollection items = Items;\r
-                               int last = items.Count;\r
-                               for (int i = 0; i < last; i++) {\r
-                                       if (items [i].Selected)\r
-                                               return i;\r
-                               }\r
-                               return -1;\r
-                       }\r
-                       set {\r
-                               if (Items.Count == 0)\r
-                               {\r
-                                       cachedSelectedIndex = value;\r
-                                       return;\r
-                               }\r
-                               if ((value < -1) || (value >= Items.Count))\r
-                                       throw new ArgumentOutOfRangeException ();\r
-\r
-                               ClearSelection ();\r
-                               if (value != -1)\r
-                                       Items [value].Selected = true;\r
-                       }\r
-               }\r
-
-               [DefaultValue (null), WebCategory ("Misc")]
-               [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [WebSysDescription ("The currently selected ListItem.")]\r
-               public virtual ListItem SelectedItem\r
-               {\r
-                       get\r
-                       {\r
-                               int idx = SelectedIndex;\r
-                               if (idx < 0)\r
-                                       return null;\r
-\r
-                               return Items [idx];\r
-                       }\r
-               }\r
-\r
-#if NET_1_1
-               [DefaultValue (""), Bindable (true), WebCategory ("Misc")]
-               [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [WebSysDescription ("The value of the currently selected ListItem.")]\r
-               public virtual string SelectedValue {\r
-                       get {\r
-                               int idx = SelectedIndex;\r
-                               if (idx == -1)\r
-                                       return "";\r
-\r
-                               return Items [idx].Value;\r
-                       }\r
-\r
-                       set {\r
-                               ListItem item = null;\r
-\r
-                               if (value != null) {\r
-                                       if (Items.Count > 0) {
-                                               item = Items.FindByValue (value);
-                                               if (item == null)
-                                                       throw new ArgumentOutOfRangeException ("value");
-                                       } else {
-                                               cachedSelectedValue = value;
-                                               return;
+
+                               if (value < -1 || value >= Items.Count)
+                                       throw new ArgumentOutOfRangeException ("value");
+
+                               ClearSelection ();
+                               if (value == -1)
+                                       return;
+
+                               items [value].Selected = true;
+
+                               /* you'd think this would be called, but noooo */
+                               //OnSelectedIndexChanged (EventArgs.Empty);
+                       }
+               }
+
+               [Browsable(false)]
+               [DefaultValue(null)]
+               [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+               [WebSysDescription ("")]
+               [WebCategory ("Misc")]
+               public virtual ListItem SelectedItem {
+                       get {
+                               int si = SelectedIndex;
+                               if (si == -1)
+                                       return null;
+                               return Items [si];
+                       }
+               }
+
+#if NET_2_0
+               [Bindable(true, BindingDirection.TwoWay)]
+               [Themeable (false)]
+#else          
+               [Bindable(true)]
+#endif         
+               [Browsable(false)]
+               [DefaultValue("")]
+               [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+               [WebSysDescription ("")]
+               [WebCategory ("Misc")]
+               public virtual string SelectedValue {
+                       get {
+                               int si = SelectedIndex;
+                               if (si == -1)
+                                       return String.Empty;
+                               return Items [si].Value;
+                       }
+                       set {
+                               ClearSelection ();
+                               if (items == null || items.Count == 0) {
+                                       // This will happen when assigning this property
+                                       // before DataBind () is called on the control.
+                                       saved_selected_value = value;
+                                       return;
+                               }
+
+                               int count = Items.Count;
+                               ListItemCollection coll = Items;
+                               bool thr = true;
+                               for (int i = 0; i < count; i++) {
+                                       if (coll [i].Value == value) {
+                                               coll [i].Selected = true;
+                                               thr = false;
                                        }
-                               }\r
-\r
-                               ClearSelection ();\r
-                               if (item != null)\r
-                                       item.Selected = true;\r
-                       }\r
-               }\r
-#endif\r
-               \r
-               internal virtual ArrayList SelectedIndices\r
-               {\r
-                       get\r
-                       {\r
-                               ArrayList si = new ArrayList();\r
-                               for(int i=0; i < Items.Count; i++)\r
-                               {\r
-                                       if(Items[i].Selected)\r
-                                               si.Add(i);\r
-                               }\r
-                               return si;\r
-                       }\r
-               }\r
-\r
-               internal void Select(ArrayList indices)\r
-               {\r
-                       ClearSelection();\r
-                       foreach(object intObj in indices)\r
-                       {\r
-                               int index = (int)intObj;\r
-                               if(index >= 0 && index < Items.Count)\r
-                                       Items[index].Selected = true;\r
-                       }\r
-               }\r
-\r
-               public virtual void ClearSelection()\r
-               {\r
-                       for(int i=0; i < Items.Count; i++)\r
-                       {\r
-                               Items[i].Selected = false;\r
-                       }\r
-               }\r
-\r
-               protected override void LoadViewState(object savedState)\r
-               {\r
-                       //Order: BaseClass, Items (Collection), Indices\r
-                       if(savedState != null && savedState is Triplet)\r
-                       {\r
-                               Triplet state = (Triplet)savedState;\r
-                               base.LoadViewState(state.First);\r
-                               Items.LoadViewState(state.Second);\r
-                               object indices = state.Third;\r
-                               if(indices != null)\r
-                               {\r
-                                       Select((ArrayList)indices);\r
-                               }\r
-                       }\r
-               }\r
-
-               #if NET_2_0
-               protected override void PerformDataBinding ()
+                               }
+
+                               if (thr) {
+                                       string msg = String.Format ("Argument value is out of range: {0}", value);
+                                       throw new ArgumentOutOfRangeException (msg);
+                               }
+                       }
+               }
+
+#if NET_2_0
+               [Themeable (false)]
+               [DefaultValue ("")]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [Browsable (false)]
+               [MonoTODO]
+               [WebSysDescription ("")]
+               [WebCategoryAttribute ("Behavior")]
+               public virtual string Text {
+                       get {
+                               return SelectedValue;
+                       }
+                       set {
+                               SelectedValue = value;
+                               /* you'd think this would be called, but noooo */
+                               //OnTextChanged (EventArgs.Empty);
+                       }
+               }
+
+#if HAVE_CONTROL_ADAPTERS
+               protected virtual new
+#else          
+               protected override
+#endif
+               HtmlTextWriterTag TagKey
+               {
+                       get {
+                               return HtmlTextWriterTag.Select;
+                       }
+               }
+
+               protected override void AddAttributesToRender (HtmlTextWriter w)
                {
-                       base.PerformDataBinding ();
-                       IEnumerable ds = GetResolvedDataSource ();
-               #else\r
-               protected override void OnDataBinding(EventArgs e)\r
-               {\r
-                       base.OnDataBinding(e);\r
-                       IEnumerable ds = DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
-               #endif\r
-                       if(ds != null) {\r
-                               string dtf = DataTextField;\r
-                               string dvf = DataValueField;\r
-                               string dtfs = DataTextFormatString;\r
-                               if (dtfs.Length == 0)\r
-                                       dtfs = "{0}";\r
-\r
-                               Items.Clear();\r
-\r
-                               bool dontUseProperties = (dtf.Length == 0 && dvf.Length == 0);\r
-\r
-                               foreach (object current in ds) {\r
-                                       ListItem li = new ListItem();\r
-                                       if (dontUseProperties){\r
-                                               li.Text  = String.Format (dtfs, current);\r
-                                               li.Value = current.ToString ();\r
-                                               Items.Add (li);\r
-                                               continue;\r
-                                       }\r
-\r
-                                       object o;\r
-                                       if (dtf.Length > 0) {\r
-                                               o = DataBinder.GetPropertyValue (current, dtf, dtfs);\r
-                                               li.Text = o.ToString ();\r
-                                       }\r
-\r
-                                       if (dvf.Length > 0) {\r
-                                               o = DataBinder.GetPropertyValue (current, dvf, null);\r
-                                               li.Value = o.ToString ();\r
-                                       }\r
-\r
-                                       Items.Add(li);\r
-                               }\r
-                       }\r
-
-                       if (cachedSelectedValue != null) {
-                               int index = Items.FindByValueInternal (cachedSelectedValue);
-                               if (index == -1)
-                                       throw new ArgumentOutOfRangeException("value");
-
-                               if (cachedSelectedIndex != -1 && cachedSelectedIndex != index)
-                                       throw new ArgumentException(HttpRuntime.FormatResourceString(
-                                               "Attributes_mutually_exclusive", "Selected Index", "Selected Value"));
-
-                               SelectedIndex = index;
-                               cachedSelectedIndex = -1;
-                               cachedSelectedValue = null;
+                       base.AddAttributesToRender (w);
+               }
+               
+#endif         
+
+               public virtual void ClearSelection ()
+               {
+                       if (items == null)
                                return;
+
+                       int count = Items.Count;
+                       for (int i = 0; i<count; i++)
+                               items [i].Selected = false;
+               }
+
+               protected override void OnDataBinding (EventArgs e)
+               {
+                       base.OnDataBinding (e);
+
+                       IEnumerable list = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
+                       if (list == null)
+                               return;
+
+#if NET_2_0
+                       if (!AppendDataBoundItems)
+#endif
+                               Items.Clear();
+
+#if !NET_2_0
+                       DoDataBinding (list);
+#endif
+                       if (saved_selected_value != null) {
+                               SelectedValue = saved_selected_value;
+                               if (saved_selected_index != -2 && saved_selected_index != SelectedIndex)
+                                       throw new ArgumentException ("SelectedIndex and SelectedValue are mutually exclusive.");
+                       } else if (saved_selected_index != -2) {
+                               SelectedIndex = saved_selected_index;
+                               // No need to check saved_selected_value here, as it's done before.
                        }
+               }
+
+#if NET_2_0
+               protected internal
+#else          
+               protected
+#endif         
+               override void OnPreRender (EventArgs e)
+               {
+                       base.OnPreRender (e);
+               }
+
+               void DoDataBinding (IEnumerable dataSource)
+               {
+                       if (dataSource != null) {
+                               string format = DataTextFormatString;
+                               if (format == "")
+                                       format = null;
+
+                               string text_field = DataTextField;
+                               string value_field = DataValueField;
+                               ListItemCollection coll = Items;
+                               foreach (object container in dataSource) {
+                                       string text;
+                                       string val;
+
+                                       text = val = null;
+                                       if (text_field != "") {
+                                               text = DataBinder.GetPropertyValue (container, text_field, format);
+                                       }
+
+                                       if (value_field != "") {
+                                               val = DataBinder.GetPropertyValue (container, value_field).ToString ();
+                                       } else if (text_field == "") {
+                                               text = val = container.ToString ();
+                                               if (format != null)
+                                                       text = String.Format (format, container);
+                                       } else if (text != null) {
+                                               val = text;
+                                       }
+
+                                       if (text == null)
+                                               text = val;
+
+                                       coll.Add (new ListItem (text, val));
+                               }
+                       }
+               }
+
+#if NET_2_0
+               protected virtual void OnTextChanged (EventArgs e)
+               {
+                       EventHandler handler = (EventHandler) Events [TextChangedEvent];
+                       if (handler != null)
+                               handler (this, e);
+               }
+
+               protected internal override void PerformDataBinding (IEnumerable dataSource)
+               {
+                       base.PerformDataBinding (dataSource);
+
+                       DoDataBinding (dataSource);
+               }
+
+               [MonoTODO ("why override?")]
+               protected override void PerformSelect ()
+               {
+                       base.PerformSelect ();
+               }
+
+               [MonoTODO]
+               protected internal override void RenderContents (HtmlTextWriter w)
+               {
+                       base.RenderContents (w);
+               }
+
+#endif         
+
+               internal ArrayList GetSelectedIndicesInternal ()
+               {
+                       ArrayList selected = null;
+                       if (items != null) {
+                               selected = new ArrayList ();
+                               int count = Items.Count;
+                               for (int i = 0; i < count; i++) {
+                                       if (items [i].Selected)
+                                               selected.Add (i);
+                               }
+                       }
+                       return selected;
+               }
+
+               protected override object SaveViewState ()
+               {
+                       object first = null;
+                       object second = null;
+
+                       first = base.SaveViewState ();
+
+                       IStateManager manager = items as IStateManager;
+                       if (manager != null)
+                               second = manager.SaveViewState ();
+
+                       ArrayList selected = GetSelectedIndicesInternal ();
+
+                       if (first == null && second == null && selected == null)
+                               return null;
+
+                       return new Triplet (first, second, selected);
+               }
+
+               protected override void LoadViewState (object savedState)
+               {
+                       object first = null;
+                       object second = null;
+                       ArrayList indices = null;
+
+                       Triplet triplet = savedState as Triplet;
+                       if (triplet != null) {
+                               first = triplet.First;
+                               second = triplet.Second;
+                               indices = triplet.Third as ArrayList;
+                       }
+
+                       base.LoadViewState (first);
+
+                       if (second != null) {
+                               IStateManager manager = Items as IStateManager;
+                               manager.LoadViewState (second);
+                       }
+
+                       if (indices != null) {
+                               foreach (int index in indices)
+                                       Items [index].Selected = true;
+                       }
+               }
+
+#if NET_2_0
+               [MonoTODO]
+               protected void SetPostDataSelection (int selectedIndex)
+               {
+                       throw new NotImplementedException ();
+               }
+#endif         
+
+               protected override void TrackViewState ()
+               {
+                       base.TrackViewState ();
+                       IStateManager manager = items as IStateManager;
+                       if (manager != null)
+                               manager.TrackViewState ();
+               }
+
+               protected virtual void OnSelectedIndexChanged (EventArgs e)
+               {
+                       EventHandler handler = (EventHandler) Events [SelectedIndexChangedEvent];
+                       if (handler != null)
+                               handler (this, e);
+               }
+
+#if NET_2_0            
+               protected internal virtual void VerifyMultiSelect ()
+               {
+               }
+#endif         
+
+               [WebSysDescription ("")]
+               [WebCategory ("Action")]
+               public event EventHandler SelectedIndexChanged {
+                       add { Events.AddHandler (SelectedIndexChangedEvent, value); }
+                       remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
+               }
+
+#if NET_2_0
+               /* sealed in the docs */
+               public event EventHandler TextChanged {
+                       add {
+                               Events.AddHandler (TextChangedEvent, value);
+                       }
+                       remove {
+                               Events.RemoveHandler (TextChangedEvent, value);
+                       }
+               }
+               
+               
+               [Themeable (false)]
+               [DefaultValue (false)]
+               [WebSysDescription ("")]
+               [WebCategory ("Behavior")]
+               public virtual bool CausesValidation {
+                       get {
+                               return ViewState.GetBool ("CausesValidation", false);
+                       }
+
+                       set {
+                               ViewState ["CausesValidation"] = value;
+                       }
+               }
+
+               [Themeable (false)]
+               [DefaultValue ("")]
+               [WebSysDescription ("")]
+               [WebCategoryAttribute ("Behavior")]
+               public virtual string ValidationGroup {
+                       get {
+                               return ViewState.GetString ("ValidationGroup", "");
+                       }
+                       set {
+                               ViewState ["ValidationGroup"] = value;
+                       }
+               }
+
+       
+#endif
+       }
+}
 
-                       if (cachedSelectedIndex != -1) {\r
-                               SelectedIndex = cachedSelectedIndex;\r
-                               cachedSelectedIndex = -1;\r
-                       }\r
-               }\r
-\r
-               protected virtual void OnSelectedIndexChanged(EventArgs e)\r
-               {\r
-                       if(Events!=null)\r
-                               {\r
-                                       EventHandler eh = (EventHandler)(Events[SelectedIndexChangedEvent]);\r
-                                       if(eh!=null)\r
-                                               eh(this, e);\r
-                               }\r
-               }\r
-\r
-               protected override void OnPreRender (EventArgs e)\r
-               {\r
-                       base.OnPreRender(e);\r
-               }\r
-\r
-               protected override object SaveViewState()\r
-               {\r
-                       //Order: BaseClass, Items (Collection), Indices\r
-                       object vs = base.SaveViewState();\r
-                       object itemSvs = Items.SaveViewState();\r
-                       object indices = null;\r
-                       if (SaveSelectedIndicesViewState)\r
-                               indices = SelectedIndices;\r
-\r
-                       if (vs != null || itemSvs != null || indices != null)\r
-                               return new Triplet(vs, itemSvs, indices);\r
-\r
-                       return null;\r
-               }\r
-\r
-               protected override void TrackViewState()\r
-               {\r
-                       base.TrackViewState();\r
-                       Items.TrackViewState();\r
-               }\r
-\r
-               private bool SaveSelectedIndicesViewState {\r
-                       get {\r
-                               if (Events[SelectedIndexChangedEvent] == null && Enabled && Visible) {\r
-                                       Type t = GetType();\r
-                                       // If I am a derivative, let it take of storing the selected indices.\r
-                                       if (t == typeof(DropDownList) || t == typeof(ListBox) ||\r
-                                           t == typeof(CheckBoxList) || t == typeof(RadioButtonList))\r
-                                               return false;\r
-                               }\r
-                               return true;\r
-                       }\r
-               }\r
-       }\r
-}\r