1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
|
//------------------------------------------------------------------------------
// <copyright file="ListControl.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.UI.WebControls {
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web;
using System.Web.UI;
using System.Web.UI.Adapters;
using System.Web.Util;
using System.Drawing;
using System.Drawing.Design;
/// <devdoc>
/// <para>An abstract base class. Defines the common
/// properties, methods, and events for all list-type controls.</para>
/// </devdoc>
[
ControlValueProperty("SelectedValue"),
DataBindingHandler("System.Web.UI.Design.WebControls.ListControlDataBindingHandler, " + AssemblyRef.SystemDesign),
DefaultEvent("SelectedIndexChanged"),
ParseChildren(true, "Items"),
Designer("System.Web.UI.Design.WebControls.ListControlDesigner, " + AssemblyRef.SystemDesign)
]
public abstract class ListControl : DataBoundControl, IEditableTextControl {
private static readonly object EventSelectedIndexChanged = new object();
private static readonly object EventTextChanged = new object();
private ListItemCollection items;
private int cachedSelectedIndex;
private string cachedSelectedValue;
private ArrayList cachedSelectedIndices;
private bool _stateLoaded;
private bool _asyncSelectPending;
/// <devdoc>
/// <para>Initializes a new instance of the <see cref='System.Web.UI.WebControls.ListControl'/> class.</para>
/// </devdoc>
public ListControl() {
cachedSelectedIndex = -1;
}
/// <devdoc>
/// <para> Gets or sets a value
/// indicating whether databound items will be added to the list of staticly-declared
/// items in the list.</para>
/// </devdoc>
[
DefaultValue(false),
Themeable(false),
WebCategory("Behavior"),
WebSysDescription(SR.ListControl_AppendDataBoundItems),
]
public virtual bool AppendDataBoundItems {
get {
object o = ViewState["AppendDataBoundItems"];
if (o != null) {
return (bool)o;
}
return false;
}
set {
ViewState["AppendDataBoundItems"] = value;
if (Initialized) {
RequiresDataBinding = true;
}
}
}
/// <devdoc>
/// <para> Gets or sets a value
/// indicating whether an automatic postback to the server will occur whenever the
/// user changes the selection of the list.</para>
/// </devdoc>
[
DefaultValue(false),
WebCategory("Behavior"),
WebSysDescription(SR.ListControl_AutoPostBack),
Themeable(false),
]
public virtual bool AutoPostBack {
get {
object b = ViewState["AutoPostBack"];
return((b == null) ? false : (bool)b);
}
set {
ViewState["AutoPostBack"] = value;
}
}
[
DefaultValue(false),
Themeable(false),
WebCategory("Behavior"),
WebSysDescription(SR.AutoPostBackControl_CausesValidation)
]
public virtual bool CausesValidation {
get {
object b = ViewState["CausesValidation"];
return((b == null) ? false : (bool)b);
}
set {
ViewState["CausesValidation"] = value;
}
}
/// <devdoc>
/// <para> Indicates the field of the
/// data source that provides the text content of the list items.</para>
/// </devdoc>
[
DefaultValue(""),
Themeable(false),
WebCategory("Data"),
WebSysDescription(SR.ListControl_DataTextField)
]
public virtual string DataTextField {
get {
object s = ViewState["DataTextField"];
return((s == null) ? String.Empty : (string)s);
}
set {
ViewState["DataTextField"] = value;
if (Initialized) {
RequiresDataBinding = true;
}
}
}
/// <devdoc>
/// </devdoc>
[
DefaultValue(""),
Themeable(false),
WebCategory("Data"),
WebSysDescription(SR.ListControl_DataTextFormatString)
]
public virtual string DataTextFormatString {
get {
object s = ViewState["DataTextFormatString"];
return ((s == null) ? String.Empty : (string)s);
}
set {
ViewState["DataTextFormatString"] = value;
if (Initialized) {
RequiresDataBinding = true;
}
}
}
/// <devdoc>
/// <para>Indicates the field of the data source that provides the value content of the
/// list items.</para>
/// </devdoc>
[
DefaultValue(""),
Themeable(false),
WebCategory("Data"),
WebSysDescription(SR.ListControl_DataValueField)
]
public virtual string DataValueField {
get {
object s = ViewState["DataValueField"];
return((s == null) ? String.Empty : (string)s);
}
set {
ViewState["DataValueField"] = value;
if (Initialized) {
RequiresDataBinding = true;
}
}
}
/// <devdoc>
/// <para>A protected property. Indicates if the ListControl supports multiple selections</para>
/// </devdoc>
internal virtual bool IsMultiSelectInternal {
get {
return false;
}
}
/// <devdoc>
/// <para>
/// Indicates the collection of items within the list.
/// This property
/// is read-only.</para>
/// </devdoc>
[
WebCategory("Default"),
DefaultValue(null),
Editor("System.Web.UI.Design.WebControls.ListItemsCollectionEditor," + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
MergableProperty(false),
WebSysDescription(SR.ListControl_Items),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public virtual ListItemCollection Items {
get {
if (items == null) {
items = new ListItemCollection();
if (IsTrackingViewState)
items.TrackViewState();
}
return items;
}
}
/// <devdoc>
/// Determines whether the SelectedIndices must be stored in view state, to
/// optimize the size of the saved state.
/// </devdoc>
internal bool SaveSelectedIndicesViewState {
get {
// Must be saved when
// 1. There is a registered event handler for SelectedIndexChanged or TextChanged.
// For our controls, we know for sure that there is no event handler registered for
// SelectedIndexChanged or TextChanged so we can short-circuit that check.
// 2. Control is not enabled or visible, because the browser's post data will not include this control
// 3. The instance is a derived instance, which might be overriding the OnSelectedIndexChanged method
// This is a bit hacky, since we have to cover all the four derived classes we have...
// 4. AutoPostBack is true and Adapter doesn't support JavaScript
// For ListControls to behave the same on mobile devices
// that simulate AutoPostBack by rendering a command button, we need to save
// state.
// 5. The control is paginated.
// 6. The control contains items that are disabled. The browser's post data will not
// include this data for disabled items, so we need to save those selected indices.
//
if ((Events[EventSelectedIndexChanged] != null) ||
(Events[EventTextChanged] != null) ||
(IsEnabled == false) ||
(Visible == false) ||
(AutoPostBack == true && ((Page != null) && !Page.ClientSupportsJavaScript)) ) {
return true;
}
foreach (ListItem item in Items) {
if (item.Enabled == false) {
return true;
}
}
// Note that we added BulletedList that inherits ListControl in
// Whidbey, but since it doesn't support selected index, we don't
// need to check it here.
Type t = this.GetType();
if ((t == typeof(DropDownList)) ||
(t == typeof(ListBox)) ||
(t == typeof(CheckBoxList)) ||
(t == typeof(RadioButtonList))) {
return false;
}
return true;
}
}
/// <devdoc>
/// <para>Indicates the ordinal index of the first selected item within the
/// list.</para>
/// </devdoc>
[
Bindable(true),
Browsable(false),
DefaultValue(0),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Themeable(false),
WebCategory("Behavior"),
WebSysDescription(SR.WebControl_SelectedIndex),
]
public virtual int SelectedIndex {
get {
for (int i=0; i < Items.Count; i++) {
if (Items[i].Selected)
return i;
}
return -1;
}
set {
if (value < -1) {
if (Items.Count == 0) {
// VSW 540083: If there are no items, setting SelectedIndex < -1 is the same as setting it to -1. Don't throw.
value = -1;
}
else {
throw new ArgumentOutOfRangeException("value", SR.GetString(SR.ListControl_SelectionOutOfRange, ID, "SelectedIndex"));
}
}
if ((Items.Count != 0 && value < Items.Count) || value == -1) {
ClearSelection();
if (value >= 0) {
Items[value].Selected = true;
}
}
else {
// if we're in a postback and our state is loaded but the selection doesn't exist in the list of items,
// throw saying we couldn't find the selected item.
if (_stateLoaded) {
throw new ArgumentOutOfRangeException("value", SR.GetString(SR.ListControl_SelectionOutOfRange, ID, "SelectedIndex"));
}
}
// always save the selectedindex
// When we've databound, we'll have items from viewstate on the next postback.
// If we don't cache the selected index and reset it after we databind again,
// the selection goes away. So we always have to save the selectedIndex for restore
// after databind.
cachedSelectedIndex = value;
}
}
/// <devdoc>
/// <para>A protected property. Gets an array of selected
/// indexes within the list. This property is read-only.</para>
/// </devdoc>
internal virtual ArrayList SelectedIndicesInternal {
get {
cachedSelectedIndices = new ArrayList(3);
for (int i=0; i < Items.Count; i++) {
if (Items[i].Selected) {
cachedSelectedIndices.Add(i);
}
}
return cachedSelectedIndices;
}
}
/// <devdoc>
/// <para>Indicates the first selected item within the list.
/// This property is read-only.</para>
/// </devdoc>
[
WebCategory("Behavior"),
Browsable(false),
DefaultValue(null),
WebSysDescription(SR.ListControl_SelectedItem),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public virtual ListItem SelectedItem{
get {
int i = SelectedIndex;
return(i < 0) ? null : Items[i];
}
}
/// <devdoc>
/// <para>Indicates the value of the first selected item within the
/// list.</para>
/// </devdoc>
[
Bindable(true, BindingDirection.TwoWay),
Browsable(false),
DefaultValue(""),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Themeable(false),
WebSysDescription(SR.ListControl_SelectedValue),
WebCategory("Behavior"),
]
public virtual string SelectedValue {
get {
int i = SelectedIndex;
return (i < 0) ? String.Empty : Items[i].Value;
}
set {
if (Items.Count != 0) {
// at design time, a binding on SelectedValue will be reset to the default value on OnComponentChanged
if (value == null || (DesignMode && value.Length == 0)) {
ClearSelection();
return;
}
ListItem selectItem = Items.FindByValue(value);
// if we're in a postback and our state is loaded or the page isn't a postback but all persistance is loaded
// but the selection doesn't exist in the list of items,
// throw saying we couldn't find the selected value.
bool loaded = Page != null && Page.IsPostBack && _stateLoaded;
if (loaded && selectItem == null) {
throw new ArgumentOutOfRangeException("value", SR.GetString(SR.ListControl_SelectionOutOfRange, ID, "SelectedValue"));
}
if (selectItem != null) {
ClearSelection();
selectItem.Selected = true;
}
}
// always save the selectedvalue
// for later databinding in case we have viewstate items or static items
cachedSelectedValue = value;
}
}
[
Browsable(false),
Themeable(false),
DefaultValue(""),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
WebSysDescription(SR.ListControl_Text),
WebCategory("Behavior"),
]
public virtual string Text {
get {
return SelectedValue;
}
set {
SelectedValue = value;
}
}
protected override HtmlTextWriterTag TagKey {
get {
return HtmlTextWriterTag.Select;
}
}
[
WebCategory("Behavior"),
Themeable(false),
DefaultValue(""),
WebSysDescription(SR.PostBackControl_ValidationGroup)
]
public virtual string ValidationGroup {
get {
string s = (string)ViewState["ValidationGroup"];
return((s == null) ? string.Empty : s);
}
set {
ViewState["ValidationGroup"] = value;
}
}
/// <devdoc>
/// Occurs when the list selection is changed upon server
/// postback.
/// </devdoc>
[
WebCategory("Action"),
WebSysDescription(SR.ListControl_OnSelectedIndexChanged)
]
public event EventHandler SelectedIndexChanged {
add {
Events.AddHandler(EventSelectedIndexChanged, value);
}
remove {
Events.RemoveHandler(EventSelectedIndexChanged, value);
}
}
/// <devdoc>
/// <para>Occurs when the content of the text box is
/// changed upon server postback.</para>
/// </devdoc>
[
WebCategory("Action"),
WebSysDescription(SR.ListControl_TextChanged)
]
public event EventHandler TextChanged {
add {
Events.AddHandler(EventTextChanged, value);
}
remove {
Events.RemoveHandler(EventTextChanged, value);
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer) {
// Make sure we are in a form tag with runat=server.
if (Page != null) {
Page.VerifyRenderingInServerForm(this);
}
if (IsMultiSelectInternal) {
writer.AddAttribute(HtmlTextWriterAttribute.Multiple, "multiple");
}
if (AutoPostBack && (Page != null) && Page.ClientSupportsJavaScript) {
string onChange = null;
if (HasAttributes) {
onChange = Attributes["onchange"];
if (onChange != null) {
onChange = Util.EnsureEndWithSemiColon(onChange);
Attributes.Remove("onchange");
}
}
PostBackOptions options = new PostBackOptions(this, String.Empty);
// ASURT 98368
// Need to merge the autopostback script with the user script
if (CausesValidation) {
options.PerformValidation = true;
options.ValidationGroup = ValidationGroup;
}
if (Page.Form != null) {
options.AutoPostBack = true;
}
onChange = Util.MergeScript(onChange, Page.ClientScript.GetPostBackEventReference(options, true));
writer.AddAttribute(HtmlTextWriterAttribute.Onchange, onChange);
if (EnableLegacyRendering) {
writer.AddAttribute("language", "javascript", false);
}
}
if (Enabled && !IsEnabled & SupportsDisabledAttribute) {
// We need to do the cascade effect on the server, because the browser
// only renders as disabled, but doesn't disable the functionality.
writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
}
base.AddAttributesToRender(writer);
}
/// <devdoc>
/// <para> Clears out the list selection and sets the
/// <see cref='System.Web.UI.WebControls.ListItem.Selected'/> property
/// of all items to false.</para>
/// </devdoc>
public virtual void ClearSelection() {
for (int i=0; i < Items.Count; i++)
Items[i].Selected = false;
// Don't clear cachedSelectedIndices here because some databound controls (such as SiteMapPath)
// call databind on all child controls when restoring from viewstate. We need to preserve the
// cachedSelectedIndices and restore them again for the second databinding.
}
/// <internalonly/>
/// <devdoc>
/// Load previously saved state.
/// Overridden to restore selection.
/// </devdoc>
protected override void LoadViewState(object savedState) {
if (savedState != null) {
Triplet stateTriplet = (Triplet)savedState;
base.LoadViewState(stateTriplet.First);
// restore state of items
Items.LoadViewState(stateTriplet.Second);
// restore selected indices
ArrayList selectedIndices = stateTriplet.Third as ArrayList;
if (selectedIndices != null) {
SelectInternal(selectedIndices);
}
}
else {
base.LoadViewState(null);
}
_stateLoaded = true;
}
private void OnDataSourceViewSelectCallback(IEnumerable data) {
_asyncSelectPending = false;
PerformDataBinding(data);
PostPerformDataBindingAction();
}
protected override void OnDataBinding(EventArgs e) {
base.OnDataBinding(e);
DataSourceView view = GetData();
// view could be null when a user implements his own GetData().
if (null == view) {
throw new InvalidOperationException(SR.GetString(SR.DataControl_ViewNotFound, ID));
}
// DevDiv 1036362: enable async model binding for ListControl
bool useAsyncSelect = false;
if (AppSettings.EnableAsyncModelBinding) {
var modelDataView = view as ModelDataSourceView;
useAsyncSelect = modelDataView != null && modelDataView.IsSelectMethodAsync;
}
if (useAsyncSelect) {
_asyncSelectPending = true; // disable post data binding action until the callback is invoked
view.Select(SelectArguments, OnDataSourceViewSelectCallback);
}
else {
IEnumerable data = view.ExecuteSelect(DataSourceSelectArguments.Empty);
PerformDataBinding(data);
}
}
internal void EnsureDataBoundInLoadPostData() {
if (!SkipEnsureDataBoundInLoadPostData) {
EnsureDataBound();
}
}
internal bool SkipEnsureDataBoundInLoadPostData {
get;
set;
}
/// <internalonly/>
protected internal override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
if (Page != null && IsEnabled) {
if (AutoPostBack) {
Page.RegisterPostBackScript();
Page.RegisterFocusScript();
// VSWhidbey 489577
if (CausesValidation && Page.GetValidators(ValidationGroup).Count > 0) {
Page.RegisterWebFormsScript();
}
}
if (SaveSelectedIndicesViewState == false) {
// Store a client-side array of enabled control, so we can re-enable them on
// postback (in case they are disabled client-side)
// Postback is needed when the SelectedIndices are not stored in view state.
Page.RegisterEnabledControl(this);
}
}
}
/// <devdoc>
/// <para> A protected method. Raises the
/// <see langword='SelectedIndexChanged'/> event.</para>
/// </devdoc>
protected virtual void OnSelectedIndexChanged(EventArgs e) {
EventHandler onChangeHandler = (EventHandler)Events[EventSelectedIndexChanged];
if (onChangeHandler != null) onChangeHandler(this, e);
OnTextChanged(e);
}
protected virtual void OnTextChanged(EventArgs e) {
EventHandler onChangeHandler = (EventHandler)Events[EventTextChanged];
if (onChangeHandler != null) onChangeHandler(this,e);
}
/// <internalonly/>
/// <devdoc>
/// </devdoc>
protected internal override void PerformDataBinding(IEnumerable dataSource) {
base.PerformDataBinding(dataSource);
if (dataSource != null) {
bool fieldsSpecified = false;
bool formatSpecified = false;
string textField = DataTextField;
string valueField = DataValueField;
string textFormat = DataTextFormatString;
if (!AppendDataBoundItems) {
Items.Clear();
}
ICollection collection = dataSource as ICollection;
if (collection != null) {
Items.Capacity = collection.Count + Items.Count;
}
if ((textField.Length != 0) || (valueField.Length != 0)) {
fieldsSpecified = true;
}
if (textFormat.Length != 0) {
formatSpecified = true;
}
foreach (object dataItem in dataSource) {
ListItem item = new ListItem();
if (fieldsSpecified) {
if (textField.Length > 0) {
item.Text = DataBinder.GetPropertyValue(dataItem, textField, textFormat);
}
if (valueField.Length > 0) {
item.Value = DataBinder.GetPropertyValue(dataItem, valueField, null);
}
}
else {
if (formatSpecified) {
item.Text = String.Format(CultureInfo.CurrentCulture, textFormat, dataItem);
}
else {
item.Text = dataItem.ToString();
}
item.Value = dataItem.ToString();
}
Items.Add(item);
}
}
// try to apply the cached SelectedIndex and SelectedValue now
if (cachedSelectedValue != null) {
int cachedSelectedValueIndex = -1;
cachedSelectedValueIndex = Items.FindByValueInternal(cachedSelectedValue, true);
if (-1 == cachedSelectedValueIndex) {
throw new ArgumentOutOfRangeException("value", SR.GetString(SR.ListControl_SelectionOutOfRange, ID, "SelectedValue"));
}
if ((cachedSelectedIndex != -1) && (cachedSelectedIndex != cachedSelectedValueIndex)) {
throw new ArgumentException(SR.GetString(SR.Attributes_mutually_exclusive, "SelectedIndex", "SelectedValue"));
}
SelectedIndex = cachedSelectedValueIndex;
cachedSelectedValue = null;
cachedSelectedIndex = -1;
}
else {
if (cachedSelectedIndex != -1) {
SelectedIndex = cachedSelectedIndex;
cachedSelectedIndex = -1;
}
}
}
protected override void PerformSelect() {
// Override PerformSelect and call OnDataBinding because in V1 OnDataBinding was the function that
// performed the databind, and we need to maintain backward compat. OnDataBinding will retrieve the
// data from the view synchronously and call PerformDataBinding with the data, preserving the OM.
OnDataBinding(EventArgs.Empty);
PostPerformDataBindingAction();
}
private void PostPerformDataBindingAction() {
if (_asyncSelectPending)
return;
RequiresDataBinding = false;
MarkAsDataBound();
OnDataBound(EventArgs.Empty);
}
/// <devdoc>
/// <para>This method is used by controls and adapters
/// to render the options inside a select statement.</para>
/// </devdoc>
protected internal override void RenderContents(HtmlTextWriter writer) {
ListItemCollection liCollection = Items;
int n = liCollection.Count;
if (n > 0) {
bool selected = false;
for (int i=0; i < n; i++) {
ListItem li = liCollection[i];
if (li.Enabled == false) {
// the only way to disable an item in a select
// is to hide it
continue;
}
writer.WriteBeginTag("option");
if (li.Selected) {
if (selected) {
VerifyMultiSelect();
}
selected = true;
writer.WriteAttribute("selected", "selected");
}
writer.WriteAttribute("value", li.Value, true /*fEncode*/);
// VSWhidbey 163920 Render expando attributes.
if (li.HasAttributes) {
li.Attributes.Render(writer);
}
if (Page != null) {
Page.ClientScript.RegisterForEventValidation(UniqueID, li.Value);
}
writer.Write(HtmlTextWriter.TagRightChar);
HttpUtility.HtmlEncode(li.Text, writer);
writer.WriteEndTag("option");
writer.WriteLine();
}
}
}
/// <internalonly/>
/// <devdoc>
/// </devdoc>
protected override object SaveViewState() {
object baseState = base.SaveViewState();
object items = Items.SaveViewState();
object selectedIndicesState = null;
if (SaveSelectedIndicesViewState) {
selectedIndicesState = SelectedIndicesInternal;
}
if (selectedIndicesState != null || items != null || baseState != null) {
return new Triplet(baseState, items, selectedIndicesState);
}
return null;
}
/// <devdoc>
/// Sets items within the
/// list to be selected according to the specified array of indexes.
/// </devdoc>
internal void SelectInternal(ArrayList selectedIndices) {
ClearSelection();
for (int i=0; i < selectedIndices.Count; i++) {
int n = (int) selectedIndices[i];
if (n >= 0 && n < Items.Count)
Items[n].Selected = true;
}
cachedSelectedIndices = selectedIndices;
}
internal static void SetControlToRepeatID(Control owner, Control controlToRepeat, int index) {
string idSuffix = index.ToString(NumberFormatInfo.InvariantInfo);
if (owner.EffectiveClientIDMode == ClientIDMode.Static) {
if (String.IsNullOrEmpty(owner.ID)) {
// When IDMode=Static but has no ID, what should the item IDs be? Reverting to AutoID behavior.
controlToRepeat.ID = idSuffix;
controlToRepeat.ClientIDMode = ClientIDMode.AutoID;
}
else {
controlToRepeat.ID = owner.ID + "_" + idSuffix;
controlToRepeat.ClientIDMode = ClientIDMode.Inherit;
}
}
else {
controlToRepeat.ID = idSuffix;
controlToRepeat.ClientIDMode = ClientIDMode.Inherit;
}
}
/// <devdoc>
/// Sets items within the list to be selected from post data.
/// The difference is that these items won't be cached and reset after a databind.
/// </devdoc>
protected void SetPostDataSelection(int selectedIndex) {
if (Items.Count != 0) {
if (selectedIndex < Items.Count) {
ClearSelection();
if (selectedIndex >= 0) {
Items[selectedIndex].Selected = true;
}
}
}
}
/// <internalonly/>
/// <devdoc>
/// </devdoc>
protected override void TrackViewState() {
base.TrackViewState();
Items.TrackViewState();
}
protected internal virtual void VerifyMultiSelect() {
if (!IsMultiSelectInternal) {
throw new HttpException(SR.GetString(SR.Cant_Multiselect_In_Single_Mode));
}
}
}
}
|