2 // System.Web.UI.HtmlControls.HtmlSelect.cs
5 // Dick Porter <dick@ximian.com>
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Web.UI.WebControls;
30 using System.Web.Util;
31 using System.ComponentModel;
32 using System.Collections;
33 using System.Collections.Specialized;
34 using System.Globalization;
35 using System.Security.Permissions;
37 namespace System.Web.UI.HtmlControls
40 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
41 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
43 [DefaultEvent ("ServerChange")]
44 [ValidationProperty ("Value")]
45 [ControlBuilder (typeof (HtmlSelectBuilder))]
47 [SupportsEventValidation]
48 public class HtmlSelect : HtmlContainerControl, IPostBackDataHandler, IParserAccessor {
50 DataSourceView _boundDataSourceView;
51 private bool requiresDataBinding;
54 public class HtmlSelect : HtmlContainerControl, IPostBackDataHandler {
56 public HtmlSelect () : base ("select")
61 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
62 [WebSysDescription("")]
64 public virtual string DataMember
67 string member = Attributes["datamember"];
70 return (String.Empty);
77 Attributes.Remove ("datamember");
79 Attributes["datamember"] = value;
87 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
88 [WebSysDescription("")]
90 public virtual object DataSource
96 if ((value != null) &&
97 !(value is IEnumerable) &&
98 !(value is IListSource)) {
99 throw new ArgumentException ();
108 public virtual string DataSourceID
111 return ViewState.GetString ("DataSourceID", "");
114 if (DataSourceID == value)
116 ViewState ["DataSourceID"] = value;
117 if (_boundDataSourceView != null)
118 _boundDataSourceView.DataSourceViewChanged -= OnDataSourceViewChanged;
119 _boundDataSourceView = null;
120 OnDataPropertyChanged ();
127 [WebSysDescription("")]
128 [WebCategory("Data")]
129 public virtual string DataTextField
132 string text = Attributes["datatextfield"];
135 return (String.Empty);
142 Attributes.Remove ("datatextfield");
144 Attributes["datatextfield"] = value;
150 [WebSysDescription("")]
151 [WebCategory("Data")]
152 public virtual string DataValueField
155 string value = Attributes["datavaluefield"];
158 return (String.Empty);
165 Attributes.Remove ("datavaluefield");
167 Attributes["datavaluefield"] = value;
172 public override string InnerHtml
175 throw new NotSupportedException ();
178 throw new NotSupportedException ();
182 public override string InnerText
185 throw new NotSupportedException ();
188 throw new NotSupportedException ();
193 protected bool IsBoundUsingDataSourceID
196 return (DataSourceID.Length != 0);
201 ListItemCollection items;
203 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
205 public ListItemCollection Items
209 items = new ListItemCollection ();
210 if (IsTrackingViewState)
211 ((IStateManager) items).TrackViewState ();
219 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
220 [WebSysDescription("")]
221 [WebCategory("Behavior")]
225 string multi = Attributes["multiple"];
234 if (value == false) {
235 Attributes.Remove ("multiple");
237 Attributes["multiple"] = "multiple";
243 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
244 [WebSysDescription("")]
245 [WebCategory("Behavior")]
257 protected bool RequiresDataBinding
259 get { return requiresDataBinding; }
260 set { requiresDataBinding = value; }
264 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
266 public virtual int SelectedIndex
269 /* Make sure Items has been initialised */
270 ListItemCollection listitems = Items;
272 for (int i = 0; i < listitems.Count; i++) {
273 if (listitems[i].Selected) {
278 /* There is always a selected item in
279 * non-multiple mode, if the size is
282 if (!Multiple && Size <= 1) {
283 /* Select the first item */
284 if (listitems.Count > 0) {
290 listitems[0].Selected = true;
301 if (value == -1 || items == null) {
305 if (value < 0 || value >= items.Count) {
306 throw new ArgumentOutOfRangeException ("value");
309 items[value].Selected = true;
313 /* "internal infrastructure" according to the docs,
314 * but has some documentation in 2.0
316 protected virtual int[] SelectedIndices
319 ArrayList selected = new ArrayList ();
321 int count = Items.Count;
323 for (int i = 0; i < count; i++) {
324 if (Items [i].Selected) {
329 return ((int[])selected.ToArray (typeof (int)));
334 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
338 string size = Attributes["size"];
344 return (Int32.Parse (size, CultureInfo.InvariantCulture));
348 Attributes.Remove ("size");
350 Attributes["size"] = value.ToString ();
355 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
359 int sel = SelectedIndex;
361 if (sel >= 0 && sel < Items.Count) {
362 return (Items[sel].Value);
365 return (String.Empty);
368 int sel = Items.IndexOf (value);
376 private static readonly object EventServerChange = new object ();
378 [WebSysDescription("")]
379 [WebCategory("Action")]
380 public event EventHandler ServerChange
383 Events.AddHandler (EventServerChange, value);
386 Events.RemoveHandler (EventServerChange, value);
390 protected override void AddParsedSubObject (object obj)
392 if (!(obj is ListItem)) {
393 throw new HttpException ("HtmlSelect can only contain ListItem");
396 Items.Add ((ListItem)obj);
398 base.AddParsedSubObject (obj);
401 /* "internal infrastructure" according to the docs,
402 * but has some documentation in 2.0
404 protected virtual void ClearSelection ()
410 int count = items.Count;
411 for (int i = 0; i < count; i++) {
412 items[i].Selected = false;
416 protected override ControlCollection CreateControlCollection ()
418 return (base.CreateControlCollection ());
422 protected void EnsureDataBound ()
424 if (IsBoundUsingDataSourceID && RequiresDataBinding)
428 protected virtual IEnumerable GetData ()
430 if (DataSource != null && IsBoundUsingDataSourceID)
431 throw new HttpException ("Control bound using both DataSourceID and DataSource properties.");
433 if (DataSource != null)
434 return DataSourceResolver.ResolveDataSource (DataSource, DataMember);
436 if (!IsBoundUsingDataSourceID)
439 IEnumerable result = null;
441 DataSourceView boundDataSourceView = ConnectToDataSource ();
442 boundDataSourceView.Select (DataSourceSelectArguments.Empty, delegate (IEnumerable data) { result = data; });
448 protected override void LoadViewState (object savedState)
451 object second = null;
453 Pair pair = savedState as Pair;
456 second = pair.Second;
459 base.LoadViewState (first);
461 if (second != null) {
462 IStateManager manager = Items as IStateManager;
463 manager.LoadViewState (second);
467 protected override void OnDataBinding (EventArgs e)
469 base.OnDataBinding (e);
471 /* Make sure Items has been initialised */
472 ListItemCollection listitems = Items;
481 list = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
488 foreach (object container in list) {
492 if (DataTextField == String.Empty &&
493 DataValueField == String.Empty) {
494 text = container.ToString ();
497 if (DataTextField != String.Empty) {
498 text = DataBinder.Eval (container, DataTextField).ToString ();
501 if (DataValueField != String.Empty) {
502 value = DataBinder.Eval (container, DataValueField).ToString ();
517 value = String.Empty;
520 ListItem item = new ListItem (text, value);
521 listitems.Add (item);
524 RequiresDataBinding = false;
530 protected virtual void OnDataPropertyChanged ()
533 RequiresDataBinding = true;
536 protected virtual void OnDataSourceViewChanged (object sender,
539 RequiresDataBinding = true;
542 protected internal override void OnInit (EventArgs e)
546 Page.PreLoad += new EventHandler (OnPagePreLoad);
549 protected virtual void OnPagePreLoad (object sender, EventArgs e) {
553 protected internal override void OnLoad (EventArgs e)
565 RequiresDataBinding = true;
567 if (IsBoundUsingDataSourceID)
568 ConnectToDataSource ();
573 return ViewState.GetBool ("_DataBound", false);
576 ViewState ["_DataBound"] = value;
580 DataSourceView ConnectToDataSource ()
582 if (_boundDataSourceView != null)
583 return _boundDataSourceView;
585 /* verify that the data source exists and is an IDataSource */
588 ctrl = Page.FindControl (DataSourceID);
590 if (ctrl == null || !(ctrl is IDataSource)) {
594 format = "DataSourceID of '{0}' must be the ID of a control of type IDataSource. A control with ID '{1}' could not be found.";
596 format = "DataSourceID of '{0}' must be the ID of a control of type IDataSource. '{1}' is not an IDataSource.";
598 throw new HttpException (String.Format (format, ID, DataSourceID));
601 _boundDataSourceView = ((IDataSource)ctrl).GetView (String.Empty);
602 _boundDataSourceView.DataSourceViewChanged += OnDataSourceViewChanged;
603 return _boundDataSourceView;
612 override void OnPreRender (EventArgs e)
618 base.OnPreRender (e);
620 if (Page != null && !Disabled) {
621 Page.RegisterRequiresPostBack (this);
623 Page.RegisterEnabledControl (this);
628 protected virtual void OnServerChange (EventArgs e)
630 EventHandler handler = (EventHandler)Events[EventServerChange];
632 if (handler != null) {
637 protected override void RenderAttributes (HtmlTextWriter w)
641 Page.ClientScript.RegisterForEventValidation (this.UniqueID);
643 /* If there is no "name" attribute,
644 * LoadPostData doesn't work...
646 w.WriteAttribute ("name", Name);
647 Attributes.Remove ("name");
649 /* Don't render the databinding attributes */
650 Attributes.Remove ("datamember");
651 Attributes.Remove ("datatextfield");
652 Attributes.Remove ("datavaluefield");
654 base.RenderAttributes (w);
662 override void RenderChildren (HtmlTextWriter w)
664 base.RenderChildren (w);
672 bool done_sel = false;
674 int count = items.Count;
675 for (int i = 0; i < count; i++) {
676 ListItem item = items[i];
679 /* Write the <option> elements this
680 * way so that the output HTML matches
681 * the ms version (can't make
682 * HtmlTextWriterTag.Option an inline
683 * element, cos that breaks other
686 w.WriteBeginTag ("option");
687 if (item.Selected && !done_sel) {
689 w.WriteAttribute ("selected", "selected");
696 w.WriteAttribute ("value", item.Value);
697 w.Write (HtmlTextWriter.TagRightChar);
700 w.WriteEndTag ("option");
707 protected override object SaveViewState ()
710 object second = null;
712 first = base.SaveViewState ();
714 IStateManager manager = items as IStateManager;
715 if (manager != null) {
716 second = manager.SaveViewState ();
719 if (first == null && second == null)
722 return new Pair (first, second);
725 /* "internal infrastructure" according to the docs,
726 * but has some documentation in 2.0
728 protected virtual void Select (int[] selectedIndices)
736 int count = items.Count;
737 foreach (int i in selectedIndices) {
738 if (i >= 0 && i < count) {
739 items[i].Selected = true;
744 protected override void TrackViewState ()
746 base.TrackViewState ();
748 IStateManager manager = items as IStateManager;
749 if (manager != null) {
750 manager.TrackViewState ();
757 void RaisePostDataChangedEvent ()
759 OnServerChange (EventArgs.Empty);
765 bool LoadPostData (string postDataKey, NameValueCollection postCollection)
767 /* postCollection contains the values that are
771 string[] values = postCollection.GetValues (postDataKey);
772 bool changed = false;
774 if (values != null) {
777 * selections. We can't just
778 * set the new list, because
779 * we need to know if the set
780 * has changed from last time
782 int value_len = values.Length;
783 int[] old_sel = SelectedIndices;
784 int[] new_sel = new int[value_len];
785 int old_sel_len = old_sel.Length;
787 for (int i = 0; i < value_len; i++) {
788 new_sel[i] = Items.IndexOf (values[i]);
789 if (old_sel_len != value_len ||
790 old_sel[i] != new_sel[i]) {
799 /* Just take the first one */
800 int sel = Items.IndexOf (values[0]);
802 if (sel != SelectedIndex) {
812 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
814 return LoadPostData (postDataKey, postCollection);
817 void IPostBackDataHandler.RaisePostDataChangedEvent ()
819 RaisePostDataChangedEvent ();