// // System.Web.UI.HtmlControls.HtmlSelect.cs // // Author: // Dick Porter // // Copyright (C) 2005 Novell, Inc (http://www.novell.com) // // 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.Web.UI.WebControls; using System.Web.Util; using System.ComponentModel; using System.Collections; using System.Collections.Specialized; using System.Globalization; using System.Security.Permissions; namespace System.Web.UI.HtmlControls { // CAS [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] // attributes [DefaultEvent ("ServerChange")] [ValidationProperty ("Value")] [ControlBuilder (typeof (HtmlSelectBuilder))] #if NET_2_0 [SupportsEventValidation] public class HtmlSelect : HtmlContainerControl, IPostBackDataHandler, IParserAccessor { DataSourceView _boundDataSourceView; private bool requiresDataBinding; bool _initialized; #else public class HtmlSelect : HtmlContainerControl, IPostBackDataHandler { #endif public HtmlSelect () : base ("select") { } [DefaultValue ("")] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [WebSysDescription("")] [WebCategory("Data")] public virtual string DataMember { get { string member = Attributes["datamember"]; if (member == null) { return (String.Empty); } return (member); } set { if (value == null) { Attributes.Remove ("datamember"); } else { Attributes["datamember"] = value; } } } object datasource; [DefaultValue (null)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [WebSysDescription("")] [WebCategory("Data")] public virtual object DataSource { get { return (datasource); } set { if ((value != null) && !(value is IEnumerable) && !(value is IListSource)) { throw new ArgumentException (); } datasource = value; } } #if NET_2_0 [DefaultValue ("")] public virtual string DataSourceID { get { return ViewState.GetString ("DataSourceID", ""); } set { if (DataSourceID == value) return; ViewState ["DataSourceID"] = value; if (_boundDataSourceView != null) _boundDataSourceView.DataSourceViewChanged -= OnDataSourceViewChanged; _boundDataSourceView = null; OnDataPropertyChanged (); } } #endif [DefaultValue ("")] [WebSysDescription("")] [WebCategory("Data")] public virtual string DataTextField { get { string text = Attributes["datatextfield"]; if (text == null) { return (String.Empty); } return (text); } set { if (value == null) { Attributes.Remove ("datatextfield"); } else { Attributes["datatextfield"] = value; } } } [DefaultValue ("")] [WebSysDescription("")] [WebCategory("Data")] public virtual string DataValueField { get { string value = Attributes["datavaluefield"]; if (value == null) { return (String.Empty); } return (value); } set { if (value == null) { Attributes.Remove ("datavaluefield"); } else { Attributes["datavaluefield"] = value; } } } public override string InnerHtml { get { throw new NotSupportedException (); } set { throw new NotSupportedException (); } } public override string InnerText { get { throw new NotSupportedException (); } set { throw new NotSupportedException (); } } #if NET_2_0 protected bool IsBoundUsingDataSourceID { get { return (DataSourceID.Length != 0); } } #endif ListItemCollection items; [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [Browsable (false)] public ListItemCollection Items { get { if (items == null) { items = new ListItemCollection (); if (IsTrackingViewState) ((IStateManager) items).TrackViewState (); } return (items); } } [DefaultValue ("")] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [WebSysDescription("")] [WebCategory("Behavior")] public bool Multiple { get { string multi = Attributes["multiple"]; if (multi == null) { return (false); } return (true); } set { if (value == false) { Attributes.Remove ("multiple"); } else { Attributes["multiple"] = "multiple"; } } } [DefaultValue ("")] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [WebSysDescription("")] [WebCategory("Behavior")] public string Name { get { return (UniqueID); } set { /* Do nothing */ } } #if NET_2_0 protected bool RequiresDataBinding { get { return requiresDataBinding; } set { requiresDataBinding = value; } } #endif [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [Browsable (false)] public virtual int SelectedIndex { get { /* Make sure Items has been initialised */ ListItemCollection listitems = Items; for (int i = 0; i < listitems.Count; i++) { if (listitems[i].Selected) { return (i); } } /* There is always a selected item in * non-multiple mode, if the size is * <= 1 */ if (!Multiple && Size <= 1) { /* Select the first item */ if (listitems.Count > 0) { /* And make it stick * if there is * anything in the * list */ listitems[0].Selected = true; } return (0); } return (-1); } set { ClearSelection (); if (value == -1 || items == null) { return; } if (value < 0 || value >= items.Count) { throw new ArgumentOutOfRangeException ("value"); } items[value].Selected = true; } } /* "internal infrastructure" according to the docs, * but has some documentation in 2.0 */ protected virtual int[] SelectedIndices { get { ArrayList selected = new ArrayList (); int count = Items.Count; for (int i = 0; i < count; i++) { if (Items [i].Selected) { selected.Add (i); } } return ((int[])selected.ToArray (typeof (int))); } } [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public int Size { get { string size = Attributes["size"]; if (size == null) { return (-1); } return (Int32.Parse (size, CultureInfo.InvariantCulture)); } set { if (value == -1) { Attributes.Remove ("size"); } else { Attributes["size"] = value.ToString (); } } } [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public string Value { get { int sel = SelectedIndex; if (sel >= 0 && sel < Items.Count) { return (Items[sel].Value); } return (String.Empty); } set { int sel = Items.IndexOf (value); if (sel >= 0) { SelectedIndex = sel; } } } private static readonly object EventServerChange = new object (); [WebSysDescription("")] [WebCategory("Action")] public event EventHandler ServerChange { add { Events.AddHandler (EventServerChange, value); } remove { Events.RemoveHandler (EventServerChange, value); } } protected override void AddParsedSubObject (object obj) { if (!(obj is ListItem)) { throw new HttpException ("HtmlSelect can only contain ListItem"); } Items.Add ((ListItem)obj); base.AddParsedSubObject (obj); } /* "internal infrastructure" according to the docs, * but has some documentation in 2.0 */ protected virtual void ClearSelection () { if (items == null) { return; } int count = items.Count; for (int i = 0; i < count; i++) { items[i].Selected = false; } } protected override ControlCollection CreateControlCollection () { return (base.CreateControlCollection ()); } #if NET_2_0 protected void EnsureDataBound () { if (IsBoundUsingDataSourceID && RequiresDataBinding) DataBind (); } protected virtual IEnumerable GetData () { if (DataSource != null && IsBoundUsingDataSourceID) throw new HttpException ("Control bound using both DataSourceID and DataSource properties."); if (DataSource != null) return DataSourceResolver.ResolveDataSource (DataSource, DataMember); if (!IsBoundUsingDataSourceID) return null; IEnumerable result = null; DataSourceView boundDataSourceView = ConnectToDataSource (); boundDataSourceView.Select (DataSourceSelectArguments.Empty, delegate (IEnumerable data) { result = data; }); return result; } #endif protected override void LoadViewState (object savedState) { object first = null; object second = null; Pair pair = savedState as Pair; if (pair != null) { first = pair.First; second = pair.Second; } base.LoadViewState (first); if (second != null) { IStateManager manager = Items as IStateManager; manager.LoadViewState (second); } } protected override void OnDataBinding (EventArgs e) { base.OnDataBinding (e); /* Make sure Items has been initialised */ ListItemCollection listitems = Items; listitems.Clear (); IEnumerable list; #if NET_2_0 list = GetData (); #else list = DataSourceResolver.ResolveDataSource (DataSource, DataMember); #endif if (list == null) { return; } foreach (object container in list) { string text = null; string value = null; if (DataTextField == String.Empty && DataValueField == String.Empty) { text = container.ToString (); value = text; } else { if (DataTextField != String.Empty) { text = DataBinder.Eval (container, DataTextField).ToString (); } if (DataValueField != String.Empty) { value = DataBinder.Eval (container, DataValueField).ToString (); } else { value = text; } if (text == null && value != null) { text = value; } } if (text == null) { text = String.Empty; } if (value == null) { value = String.Empty; } ListItem item = new ListItem (text, value); listitems.Add (item); } #if NET_2_0 RequiresDataBinding = false; IsDataBound = true; #endif } #if NET_2_0 protected virtual void OnDataPropertyChanged () { if (_initialized) RequiresDataBinding = true; } protected virtual void OnDataSourceViewChanged (object sender, EventArgs e) { RequiresDataBinding = true; } protected internal override void OnInit (EventArgs e) { base.OnInit (e); Page.PreLoad += new EventHandler (OnPagePreLoad); } protected virtual void OnPagePreLoad (object sender, EventArgs e) { Initialize (); } protected internal override void OnLoad (EventArgs e) { if (!_initialized) Initialize (); base.OnLoad (e); } void Initialize () { _initialized = true; if (!IsDataBound) RequiresDataBinding = true; if (IsBoundUsingDataSourceID) ConnectToDataSource (); } bool IsDataBound { get { return ViewState.GetBool ("_DataBound", false); } set { ViewState ["_DataBound"] = value; } } DataSourceView ConnectToDataSource () { if (_boundDataSourceView != null) return _boundDataSourceView; /* verify that the data source exists and is an IDataSource */ object ctrl = null; if (Page != null) ctrl = Page.FindControl (DataSourceID); if (ctrl == null || !(ctrl is IDataSource)) { string format; if (ctrl == null) format = "DataSourceID of '{0}' must be the ID of a control of type IDataSource. A control with ID '{1}' could not be found."; else format = "DataSourceID of '{0}' must be the ID of a control of type IDataSource. '{1}' is not an IDataSource."; throw new HttpException (String.Format (format, ID, DataSourceID)); } _boundDataSourceView = ((IDataSource)ctrl).GetView (String.Empty); _boundDataSourceView.DataSourceViewChanged += OnDataSourceViewChanged; return _boundDataSourceView; } #endif #if NET_2_0 protected internal #else protected #endif override void OnPreRender (EventArgs e) { #if NET_2_0 EnsureDataBound (); #endif base.OnPreRender (e); if (Page != null && !Disabled) { Page.RegisterRequiresPostBack (this); #if NET_2_0 Page.RegisterEnabledControl (this); #endif } } protected virtual void OnServerChange (EventArgs e) { EventHandler handler = (EventHandler)Events[EventServerChange]; if (handler != null) { handler (this, e); } } protected override void RenderAttributes (HtmlTextWriter w) { #if NET_2_0 if (Page != null) Page.ClientScript.RegisterForEventValidation (UniqueID); #endif /* If there is no "name" attribute, * LoadPostData doesn't work... */ w.WriteAttribute ("name", Name); Attributes.Remove ("name"); /* Don't render the databinding attributes */ Attributes.Remove ("datamember"); Attributes.Remove ("datatextfield"); Attributes.Remove ("datavaluefield"); base.RenderAttributes (w); } #if NET_2_0 protected internal #else protected #endif override void RenderChildren (HtmlTextWriter w) { base.RenderChildren (w); if (items == null) { return; } w.WriteLine (); bool done_sel = false; int count = items.Count; for (int i = 0; i < count; i++) { ListItem item = items[i]; w.Indent++; /* Write the