File: winforms\Managed\System\WinForms\ListBox.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ListBox.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
/*
 */
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Remoting;
    using System.Runtime.InteropServices;
 
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
 
    using System;
    using System.Security;
    using System.Security.Permissions;
    using System.Globalization;
    using System.Windows.Forms.Layout;
 
    using System.Drawing.Design;
    using System.ComponentModel;
    using System.Windows.Forms.ComponentModel;
    using System.Windows.Forms.VisualStyles;
 
    using System.Collections;
    using System.Drawing;
    using Microsoft.Win32;
    using System.Text;
 
    /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox"]/*' />
    /// <devdoc>
    ///
    ///     This is a control that presents a list of items to the user.  They may be
    ///     navigated using the keyboard, or the scrollbar on the right side of the
    ///     control.  One or more items may be selected as well.
    /// <para>
    ///
    ///     The preferred way to add items is to set them all via an array at once,
    ///     which is definitely the most efficient way.  The following is an example
    ///     of this:
    /// </para>
    /// <code>
    ///     ListBox lb = new ListBox();
    ///     //     set up properties on the listbox here.
    ///     lb.Items.All = new String [] {
    ///     "A",
    ///     "B",
    ///     "C",
    ///     "D"};
    /// </code>
    /// </devdoc>
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    Designer("System.Windows.Forms.Design.ListBoxDesigner, " + AssemblyRef.SystemDesign),
    DefaultEvent("SelectedIndexChanged"),
    DefaultProperty("Items"),
    DefaultBindingProperty("SelectedValue"),
    SRDescription(SR.DescriptionListBox)
    ]
    public class ListBox : ListControl {
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.NoMatches"]/*' />
        /// <devdoc>
        ///     while doing a search, if no matches are found, this is returned
        /// </devdoc>
        public const int NoMatches = NativeMethods.LB_ERR;
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.DefaultItemHeight"]/*' />
        /// <devdoc>
        ///     The default item height for an owner-draw ListBox.
        /// </devdoc>
        public const int DefaultItemHeight = 13; // 13 == listbox's non-ownerdraw item height.  That's with Win2k and
        // the default font; on other platforms and with other fonts, it may be different.
 
        private const int maxWin9xHeight = 32767; //Win9x doesn't deal with height > 32K
 
        private static readonly object EVENT_SELECTEDINDEXCHANGED = new object();
        private static readonly object EVENT_DRAWITEM             = new object();
        private static readonly object EVENT_MEASUREITEM          = new object();
 
        static bool checkedOS = false;
        static bool runningOnWin2K = true;
 
        SelectedObjectCollection selectedItems;
        SelectedIndexCollection selectedIndices;
        ObjectCollection itemsCollection;
 
        // 
 
        int itemHeight = DefaultItemHeight;
        int columnWidth;
        int requestedHeight;
        int topIndex;
        int horizontalExtent = 0;
        int maxWidth = -1;
        int updateCount = 0;
 
        bool sorted = false;
        bool scrollAlwaysVisible = false;
        bool integralHeight = true;
        bool integralHeightAdjust = false;
        bool multiColumn = false;
        bool horizontalScrollbar = false;
        bool useTabStops = true;
        bool useCustomTabOffsets = false;
        bool fontIsChanged = false;
        bool doubleClickFired = false;
        bool selectedValueChangedFired = false;
 
        DrawMode drawMode = System.Windows.Forms.DrawMode.Normal;
        BorderStyle borderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
        SelectionMode selectionMode = System.Windows.Forms.SelectionMode.One;
 
        // VsWhidbey : 447524
        SelectionMode cachedSelectionMode = System.Windows.Forms.SelectionMode.One;
        //We need to know that we are in middle of handleRecreate through Setter of SelectionMode. 
        //In this case we set a bool denoting that we are changing SelectionMode and 
        //in this case we should always use the cachedValue instead of the currently set value. 
        //We need to change this in the count as well as SelectedIndex code where we access the SelectionMode.
        private bool selectionModeChanging = false;
 
        /// <devdoc>
        ///     This value stores the array of custom tabstops in the listbox. the array should be populated by
        ///     integers in a ascending order.
        /// </devdoc>
        private IntegerCollection customTabOffsets;
 
        /// <summary>
        /// Default start position of items in the checked list box
        /// </summary>
        private const int defaultListItemStartPos = 1;
 
        /// <summary>
        /// Borders are 1 pixel height.
        /// </summary>
        private const int defaultListItemBorderHeight = 1;
 
        /// <summary>
        /// Borders are 1 pixel width and a pixel buffer 
        /// </summary>
        private const int defaultListItemPaddingBuffer = 3;
 
 
        internal int scaledListItemStartPosition = defaultListItemStartPos;
        internal int scaledListItemBordersHeight = 2 * defaultListItemBorderHeight;
        internal int scaledListItemPaddingBuffer = defaultListItemPaddingBuffer;
 
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ListBox"]/*' />
        /// <devdoc>
        ///     Creates a basic win32 list box with default values for everything.
        /// </devdoc>
        public ListBox() : base() {
            SetStyle(ControlStyles.UserPaint | 
                     ControlStyles.StandardClick | 
                     ControlStyles.UseTextForAccessibility, false);
 
            // this class overrides GetPreferredSizeCore, let Control automatically cache the result
            SetState2(STATE2_USEPREFERREDSIZECACHE, true);  
 
            SetBounds(0, 0, 120, 96);
 
            requestedHeight = Height;
 
            PrepareForDrawing();
        }
 
        protected override void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) {
            base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew);
            PrepareForDrawing();
        }
 
        private void PrepareForDrawing() {
            // Scale paddings
            if (DpiHelper.EnableCheckedListBoxHighDpiImprovements) {
                scaledListItemStartPosition = LogicalToDeviceUnits(defaultListItemStartPos);
 
                // height inlude 2 borders ( top and bottom). we are using multiplication by 2 instead of scaling doubled value to get an even number 
                // that might helps us in positioning control in the center for list items.
                scaledListItemBordersHeight = 2 * LogicalToDeviceUnits(defaultListItemBorderHeight);
                scaledListItemPaddingBuffer = LogicalToDeviceUnits(defaultListItemPaddingBuffer);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BackColor"]/*' />
        public override Color BackColor {
            get {
                if (ShouldSerializeBackColor()) {
                    return base.BackColor;
                }
                else {
                    return SystemColors.Window;
                }
            }
            set {
                base.BackColor = value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BackgroundImage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage {
            get {
                return base.BackgroundImage;
            }
            set {
                base.BackgroundImage = value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BackgroundImageChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageChanged {
            add {
                base.BackgroundImageChanged += value;
            }
            remove {
                base.BackgroundImageChanged -= value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BackgroundImageLayout"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override ImageLayout BackgroundImageLayout {
            get {
                return base.BackgroundImageLayout;
            }
            set {
                base.BackgroundImageLayout = value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BackgroundImageLayoutChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageLayoutChanged {
            add {
                base.BackgroundImageLayoutChanged += value;
            }
            remove {
                base.BackgroundImageLayoutChanged -= value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BorderStyle"]/*' />
        /// <devdoc>
        ///     Retrieves the current border style.  Values for this are taken from
        ///     The System.Windows.Forms.BorderStyle enumeration.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(BorderStyle.Fixed3D),
        DispId(NativeMethods.ActiveX.DISPID_BORDERSTYLE),
        SRDescription(SR.ListBoxBorderDescr)
        ]
        public BorderStyle BorderStyle {
            get {
                return borderStyle;
            }
 
            set {
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)BorderStyle.None, (int)BorderStyle.Fixed3D)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle));
                }
 
                if (value != borderStyle) {
                    borderStyle = value;
                    RecreateHandle();
                    // Avoid the listbox and textbox behavior in Collection editors
                    //
                    integralHeightAdjust = true;
                    try {
                        Height = requestedHeight;
                    }
                    finally {
                        integralHeightAdjust = false;
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ColumnWidth"]/*' />
        /// <devdoc>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        Localizable(true),
        DefaultValue(0),
        SRDescription(SR.ListBoxColumnWidthDescr)
        ]
        public int ColumnWidth {
            get {
                return columnWidth;
            }
 
            set {
                if (value < 0) {
                    throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgumentEx, "value",
                                                             (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
                }
                if (columnWidth != value) {
                    columnWidth = value;
                    // if it's zero, we need to reset, and only way to do
                    // that is to recreate the handle.
                    if (columnWidth == 0) {
                        RecreateHandle();
                    }
                    else if (IsHandleCreated) {
                        SendMessage(NativeMethods.LB_SETCOLUMNWIDTH, columnWidth, 0);
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.CreateParams"]/*' />
        /// <devdoc>
        ///     Retrieves the parameters needed to create the handle.  Inheriting classes
        ///     can override this to provide extra functionality.  They should not,
        ///     however, forget to call base.getCreateParams() first to get the struct
        ///     filled up with the basic info.
        /// </devdoc>
        /// <internalonly/>
        protected override CreateParams CreateParams {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get {
                CreateParams cp = base.CreateParams;
                cp.ClassName = "LISTBOX";
 
                cp.Style |= NativeMethods.WS_VSCROLL | NativeMethods.LBS_NOTIFY | NativeMethods.LBS_HASSTRINGS;
                if (scrollAlwaysVisible) cp.Style |= NativeMethods.LBS_DISABLENOSCROLL;
                if (!integralHeight) cp.Style |= NativeMethods.LBS_NOINTEGRALHEIGHT;
                if (useTabStops) cp.Style |= NativeMethods.LBS_USETABSTOPS;
 
                switch (borderStyle) {
                    case BorderStyle.Fixed3D:
                        cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
                        break;
                    case BorderStyle.FixedSingle:
                        cp.Style |= NativeMethods.WS_BORDER;
                        break;
                }
 
                if (multiColumn) {
                    cp.Style |= NativeMethods.LBS_MULTICOLUMN | NativeMethods.WS_HSCROLL;
                }
                else if (horizontalScrollbar) {
                    cp.Style |= NativeMethods.WS_HSCROLL;
                }
 
                switch (selectionMode) {
                    case SelectionMode.None:
                        cp.Style |= NativeMethods.LBS_NOSEL;
                        break;
                    case SelectionMode.MultiSimple:
                        cp.Style |= NativeMethods.LBS_MULTIPLESEL;
                        break;
                    case SelectionMode.MultiExtended:
                        cp.Style |= NativeMethods.LBS_EXTENDEDSEL;
                        break;
                    case SelectionMode.One:
                        break;
                }
 
                switch (drawMode) {
                    case DrawMode.Normal:
                        break;
                    case DrawMode.OwnerDrawFixed:
                        cp.Style |= NativeMethods.LBS_OWNERDRAWFIXED;
                        break;
                    case DrawMode.OwnerDrawVariable:
                        cp.Style |= NativeMethods.LBS_OWNERDRAWVARIABLE;
                        break;
                }
 
                return cp;
            }
        }
 
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.UseCustomTabOffsets"]/*' />
        /// <devdoc>
        ///     Enables a list box to recognize and expand tab characters when drawing
        ///     its strings using the CustomTabOffsets integer array.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        Browsable(false)
        ]
        public bool UseCustomTabOffsets {
            get {
                return useCustomTabOffsets;
            }
            set {
                if (useCustomTabOffsets != value) {
                    useCustomTabOffsets = value;
                    RecreateHandle();
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.DefaultSize"]/*' />
        protected override Size DefaultSize {
            get {
                return new Size(120, 96);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.DrawMode"]/*' />
        /// <devdoc>
        ///     Retrieves the style of the listbox.  This will indicate if the system
        ///     draws it, or if the user paints each item manually.  It also indicates
        ///     whether or not items have to be of the same height.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(DrawMode.Normal),
        SRDescription(SR.ListBoxDrawModeDescr),
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public virtual DrawMode DrawMode {
            get {
                return drawMode;
            }
 
            set {
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)DrawMode.Normal, (int)DrawMode.OwnerDrawVariable))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DrawMode));
                }
                if (drawMode != value) {
                    if (MultiColumn && value == DrawMode.OwnerDrawVariable) {
                        throw new ArgumentException(SR.GetString(SR.ListBoxVarHeightMultiCol), "value");
                    }
                    drawMode = value;
                    RecreateHandle();
                    if (drawMode == DrawMode.OwnerDrawVariable) {
                        // VSWhidbey 139179 - force a layout after RecreateHandle() completes because now
                        // the LB is definitely fully populated and can report a preferred size accurately.
                        LayoutTransaction.DoLayoutIf(AutoSize, this.ParentInternal, this, PropertyNames.DrawMode);
                    }
                }
            }
        }
 
        // Used internally to find the currently focused item
        //
        internal int FocusedIndex {
            get {
                if (IsHandleCreated) {
                    return unchecked( (int) (long)SendMessage(NativeMethods.LB_GETCARETINDEX, 0, 0));
                }
 
                return -1;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Font"]/*' />
        // VSWhidbey 95179: The scroll bars don't display properly when the IntegralHeight == false
        // and the control is resized before the font size is change and the new font size causes
        // the height of all the items to exceed the new height of the control. This is a bug in
        // the control, but can be easily worked around by removing and re-adding all the items.
        public override Font Font {
            get {
                return base.Font;
            }
            set {
                base.Font = value;
 
                if (false == integralHeight) {
                    // VSWhidbey 95179: Refresh the list to force the scroll bars to display
                    // when the integral height is false.
                    RefreshItems();
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ForeColor"]/*' />
        public override Color ForeColor {
            get {
                if (ShouldSerializeForeColor()) {
                    return base.ForeColor;
                }
                else {
                    return SystemColors.WindowText;
                }
            }
            set {
                base.ForeColor = value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.HorizontalExtent"]/*' />
        /// <devdoc>
        ///     Indicates the width, in pixels, by which a list box can be scrolled horizontally (the scrollable width).
        ///     This property will only have an effect if HorizontalScrollbars is true.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(0),
        Localizable(true),
        SRDescription(SR.ListBoxHorizontalExtentDescr)
        ]
        public int HorizontalExtent {
            get {
                return horizontalExtent;
            }
 
            set {
                if (value != horizontalExtent) {
                    horizontalExtent = value;
                    UpdateHorizontalExtent();
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.HorizontalScrollbar"]/*' />
        /// <devdoc>
        ///     Indicates whether or not the ListBox should display a horizontal scrollbar
        ///     when the items extend beyond the right edge of the ListBox.
        ///     If true, the scrollbar will automatically set its extent depending on the length
        ///     of items in the ListBox. The exception is if the ListBox is owner-draw, in
        ///     which case HorizontalExtent will need to be explicitly set.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        Localizable(true),
        SRDescription(SR.ListBoxHorizontalScrollbarDescr)
        ]
        public bool HorizontalScrollbar {
            get {
                return horizontalScrollbar;
            }
 
            set {
                if (value != horizontalScrollbar) {
                    horizontalScrollbar = value;
 
                    // There seems to be a bug in the native ListBox in that the addition
                    // of the horizontal scroll bar does not get reflected in the control
                    // rightaway. So, we refresh the items here.
                    RefreshItems();
 
                    // Only need to recreate the handle if not MultiColumn
                    // (HorizontalScrollbar has no effect on a MultiColumn listbox)
                    //
                    if (!MultiColumn) {
                        RecreateHandle();
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegralHeight"]/*' />
        /// <devdoc>
        ///     Indicates if the listbox should avoid showing partial Items.  If so,
        ///     then only full items will be displayed, and the listbox will be resized
        ///     to prevent partial items from being shown.  Otherwise, they will be
        ///     shown
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        Localizable(true),
        SRDescription(SR.ListBoxIntegralHeightDescr),
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool IntegralHeight {
            get {
                return integralHeight;
            }
 
            set {
                if (integralHeight != value) {
                    integralHeight = value;
                    RecreateHandle();
                    // Avoid the listbox and textbox behaviour in Collection editors
                    //
 
                    integralHeightAdjust = true;
                    try {
                        Height = requestedHeight;
                    }
                    finally {
                        integralHeightAdjust = false;
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ItemHeight"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Returns
        ///       the height of an item in an owner-draw list box.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(DefaultItemHeight),
        Localizable(true),
        SRDescription(SR.ListBoxItemHeightDescr),
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public virtual int ItemHeight {
            get {
                if (drawMode == DrawMode.OwnerDrawFixed ||
                    drawMode == DrawMode.OwnerDrawVariable) {
                    return itemHeight;
                }
 
                return GetItemHeight(0);
            }
 
            set {
                if (value < 1 || value > 255) {
                    throw new ArgumentOutOfRangeException("ItemHeight", SR.GetString(SR.InvalidExBoundArgument, "ItemHeight", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture), "256"));
                }
                if (itemHeight != value) {
                    itemHeight = value;
                    if (drawMode == DrawMode.OwnerDrawFixed && IsHandleCreated) {
                        BeginUpdate();
                        SendMessage(NativeMethods.LB_SETITEMHEIGHT, 0, value);
 
                        // Changing the item height might require a resize for IntegralHeight list boxes
                        //
                        if (IntegralHeight) {
                            Size oldSize = Size;
                            Size = new Size(oldSize.Width + 1, oldSize.Height);
                            Size = oldSize;
                        }
 
                        EndUpdate();
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Items"]/*' />
        /// <devdoc>
        ///     Collection of items in this listbox.
        /// </devdoc>
        [
        SRCategory(SR.CatData),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Localizable(true),
        SRDescription(SR.ListBoxItemsDescr),
        Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        MergableProperty(false)
        ]
        public ObjectCollection Items {
            get {
                if (itemsCollection == null) {
                    itemsCollection = CreateItemCollection();
                }
                return itemsCollection;
            }
        }
 
        // Computes the maximum width of all items in the ListBox
        //
        internal virtual int MaxItemWidth {
            get {
 
                if (horizontalExtent > 0) {
                    return horizontalExtent;
                }
 
                if (DrawMode != DrawMode.Normal) {
                    return -1;
                }
 
                // Return cached maxWidth if available
                //
                if (maxWidth > -1) {
                    return maxWidth;
                }
 
                // Compute maximum width
                //
                maxWidth = ComputeMaxItemWidth(maxWidth);
 
                return maxWidth;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.MultiColumn"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Indicates if the listbox is multi-column
        ///       or not.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListBoxMultiColumnDescr)
        ]
        public bool MultiColumn {
            get {
                return multiColumn;
            }
            set {
                if (multiColumn != value) {
                    if (value && drawMode == DrawMode.OwnerDrawVariable) {
                        throw new ArgumentException(SR.GetString(SR.ListBoxVarHeightMultiCol), "value");
                    }
                    multiColumn = value;
                    RecreateHandle();
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.PreferredHeight"]/*' />
        /// <devdoc>
        ///     The total height of the items in the list box.
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListBoxPreferredHeightDescr)
        ]
        public int PreferredHeight {
            get {
                int height = 0;
 
                if (drawMode == DrawMode.OwnerDrawVariable) {
                    // VSWhidbey 139179 - don't try to get item heights from the LB when items haven't been
                    // added to the LB yet. Just return current height.
                    if (RecreatingHandle || GetState(STATE_CREATINGHANDLE)) {
                        height = this.Height;
                    }
                    else {
                        if (itemsCollection != null) {
                            int cnt = itemsCollection.Count;
                            for (int i = 0; i < cnt; i++) {
                                height += GetItemHeight(i);
                            }
                        }
                    }
                }
                else {
                    //VSWhidbey #148270
                    //When the list is empty, we don't want to multiply by 0 here.
                    int cnt = (itemsCollection == null || itemsCollection.Count == 0) ? 1 : itemsCollection.Count;
                    height = GetItemHeight(0) * cnt;
                }
 
                if (borderStyle != BorderStyle.None) {
                    height += SystemInformation.BorderSize.Height * 4 + 3;
                }
 
                return height;
            }
        }
 
        internal override Size GetPreferredSizeCore(Size proposedConstraints)
        {
            int height = PreferredHeight;
            int width;
 
            // Convert with a dummy height to add space required for borders
            // VSWhidbey #151141 -PreferredSize should return either the new
            // size of the control, or the default size if the handle has not been
            // created
            if (IsHandleCreated)
            {
                width = SizeFromClientSize(new Size(MaxItemWidth, height)).Width;
                width += SystemInformation.VerticalScrollBarWidth + 4;
            }
            else
            {
                return DefaultSize;
            }
            return new Size(width, height) + Padding.Size;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.RightToLeft"]/*' />
        public override RightToLeft RightToLeft {
            get {
                if (!RunningOnWin2K) {
                    return RightToLeft.No;
                }
                return base.RightToLeft;
            }
            set {
                base.RightToLeft = value;
            }
        }
 
        static bool RunningOnWin2K {
            get {
                if (!checkedOS) {
                    if (Environment.OSVersion.Platform != System.PlatformID.Win32NT ||
                        Environment.OSVersion.Version.Major < 5) {
                        runningOnWin2K = false;
                        checkedOS = true;
                    }
                }
                return runningOnWin2K;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ScrollAlwaysVisible"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets whether the scrollbar is shown at all times.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        Localizable(true),
        SRDescription(SR.ListBoxScrollIsVisibleDescr)
        ]
        public bool ScrollAlwaysVisible {
            get {
                return scrollAlwaysVisible;
            }
            set {
                if (scrollAlwaysVisible != value) {
                    scrollAlwaysVisible = value;
                    RecreateHandle();
                }
            }
        }
 
        /// <include file='doc\ListControl.uex' path='docs/doc[@for="ListControl.AllowSelection"]/*' />
        /// <devdoc>
        ///    Indicates whether list currently allows selection of list items.
        ///    For ListBox, this returns true unless SelectionMode is SelectionMode.None.
        /// </devdoc>
        protected override bool AllowSelection {
            get {
                return selectionMode != SelectionMode.None;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndex"]/*' />
        /// <devdoc>
        ///     The index of the currently selected item in the list, if there
        ///     is one.  If the value is -1, there is currently no selection.  If the
        ///     value is 0 or greater, than the value is the index of the currently
        ///     selected item.  If the MultiSelect property on the ListBox is true,
        ///     then a non-zero value for this property is the index of the first
        ///     selection
        /// </devdoc>
        [
        Browsable(false),
        Bindable(true),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListBoxSelectedIndexDescr)
        ]
        public override int SelectedIndex {
            get {
 
                SelectionMode current = (selectionModeChanging) ? cachedSelectionMode : selectionMode;
                
                if (current == SelectionMode.None) {
                    return -1;
                }
 
                if (current == SelectionMode.One && IsHandleCreated) {
                    return unchecked( (int) (long)SendMessage(NativeMethods.LB_GETCURSEL, 0, 0));
                }
 
                if (itemsCollection != null && SelectedItems.Count > 0) {
                    return Items.IndexOfIdentifier(SelectedItems.GetObjectAt(0));
                }
 
                return -1;
            }
            set {
 
                int itemCount = (itemsCollection == null) ? 0 : itemsCollection.Count;
 
                if (value < -1 || value >= itemCount) {
                    throw new ArgumentOutOfRangeException("SelectedIndex", SR.GetString(SR.InvalidArgument, "SelectedIndex", (value).ToString(CultureInfo.CurrentCulture)));
                }
 
                if (selectionMode == SelectionMode.None) {
                    throw new ArgumentException(SR.GetString(SR.ListBoxInvalidSelectionMode), "SelectedIndex");
                }
 
                if (selectionMode == SelectionMode.One && value != -1) {
 
                    // Single select an individual value.
                    int currentIndex = SelectedIndex;
 
                    if (currentIndex != value) {
                        if (currentIndex != -1) {
                            SelectedItems.SetSelected(currentIndex, false);
                        }
                        SelectedItems.SetSelected(value, true);
 
                        if (IsHandleCreated) {
                            NativeSetSelected(value, true);
                        }
 
                        OnSelectedIndexChanged(EventArgs.Empty);
                    }
                }
                else if (value == -1) {
                    if (SelectedIndex != -1) {
                        ClearSelected();
                        // ClearSelected raises OnSelectedIndexChanged for us
                    }
                }
                else {
                    if (!SelectedItems.GetSelected(value)) {
 
                        // Select this item while keeping any previously selected items selected.
                        //
                        SelectedItems.SetSelected(value, true);
                        if (IsHandleCreated) {
                            NativeSetSelected(value, true);
                        }
                        OnSelectedIndexChanged(EventArgs.Empty);
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndices"]/*' />
        /// <devdoc>
        ///     A collection of the indices of the selected items in the
        ///     list box. If there are no selected items in the list box, the result is
        ///     an empty collection.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListBoxSelectedIndicesDescr)
        ]
        public SelectedIndexCollection SelectedIndices {
            get {
                if (selectedIndices == null) {
                    selectedIndices = new SelectedIndexCollection(this);
                }
                return selectedIndices;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedItem"]/*' />
        /// <devdoc>
        ///     The value of the currently selected item in the list, if there
        ///     is one.  If the value is null, there is currently no selection.  If the
        ///     value is non-null, then the value is that of the currently selected
        ///     item. If the MultiSelect property on the ListBox is true, then a
        ///     non-null return value for this method is the value of the first item
        ///     selected
        /// </devdoc>
        [
        Browsable(false),
        Bindable(true),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListBoxSelectedItemDescr)
        ]
        public object SelectedItem {
            get {
                if (SelectedItems.Count > 0) {
                    return SelectedItems[0];
                }
 
                return null;
            }
            set {
                if (itemsCollection != null) {
                    if (value != null) {
                        int index = itemsCollection.IndexOf(value);
                        if (index != -1) {
                            SelectedIndex = index;
                        }
                    }
                    else {
                        SelectedIndex = -1;
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedItems"]/*' />
        /// <devdoc>
        ///     The collection of selected items.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListBoxSelectedItemsDescr)
        ]
        public SelectedObjectCollection SelectedItems {
            get {
                if (selectedItems == null) {
                    selectedItems = new SelectedObjectCollection(this);
                }
                return selectedItems;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectionMode"]/*' />
        /// <devdoc>
        ///     Controls how many items at a time can be selected in the listbox. Valid
        ///     values are from the System.Windows.Forms.SelectionMode enumeration.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(SelectionMode.One),
        SRDescription(SR.ListBoxSelectionModeDescr)
        ]
        public virtual SelectionMode SelectionMode {
            get {
                return selectionMode;
            }
            set {
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)SelectionMode.None, (int)SelectionMode.MultiExtended))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(SelectionMode));
                }
 
                if (selectionMode != value) {
                    SelectedItems.EnsureUpToDate();
                    selectionMode = value;
                    try
                    {
                        selectionModeChanging = true;
                        RecreateHandle();
                    }
                    finally
                    {
                        selectionModeChanging = false;
                        cachedSelectionMode = selectionMode;
                        // update the selectedItems list and SelectedItems index collection
                        if (IsHandleCreated)
                        {
                            NativeUpdateSelection();
                        }
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Sorted"]/*' />
        /// <devdoc>
        ///     Indicates if the ListBox is sorted or not.  'true' means that strings in
        ///     the list will be sorted alphabetically
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListBoxSortedDescr)
        ]
        public bool Sorted {
            get {
                return sorted;
            }
            set {
                if (sorted != value) {
                    sorted = value;
 
                    if (sorted && itemsCollection != null && itemsCollection.Count >= 1) {
                        Sort();
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Text"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        Bindable(false)
        ]
        public override string Text {
            get {
                if (SelectionMode != SelectionMode.None && SelectedItem != null) {
                    if (FormattingEnabled) {
                        return GetItemText(SelectedItem);
                    } else {
                        return FilterItemOnProperty(SelectedItem).ToString();
                    }
                }
                else {
                    return base.Text;
                }
            }
            set {
                base.Text = value;
 
                // Scan through the list items looking for the supplied text string.  If we find it,
                // select it.
                //
                if (SelectionMode != SelectionMode.None && value != null && (SelectedItem == null || !value.Equals(GetItemText(SelectedItem)))) {
 
                    int cnt = Items.Count;
                    for (int index=0; index < cnt; ++index) {
                        if (String.Compare(value, GetItemText(Items[index]), true, CultureInfo.CurrentCulture) == 0) {
                            SelectedIndex = index;
                            return;
                        }
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.TextChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        new public event EventHandler TextChanged {
            add {
                base.TextChanged += value;
            }
            remove {
                base.TextChanged -= value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.TopIndex"]/*' />
        /// <devdoc>
        ///     The index of the first visible item in a list box. Initially
        ///     the item with index 0 is at the top of the list box, but if the list
        ///     box contents have been scrolled another item may be at the top.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListBoxTopIndexDescr)
        ]
        public int TopIndex {
            get {
                if (IsHandleCreated) {
                    return unchecked( (int) (long)SendMessage(NativeMethods.LB_GETTOPINDEX, 0, 0));
                }
                else {
                    return topIndex;
                }
            }
            set {
                if (IsHandleCreated) {
                    SendMessage(NativeMethods.LB_SETTOPINDEX, value, 0);
                }
                else {
                    topIndex = value;
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.UseTabStops"]/*' />
        /// <devdoc>
        ///     Enables a list box to recognize and expand tab characters when drawing
        ///     its strings.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.ListBoxUseTabStopsDescr)
        ]
        public bool UseTabStops {
            get {
                return useTabStops;
            }
            set {
                if (useTabStops != value) {
                    useTabStops = value;
                    RecreateHandle();
                }
            }
        }
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.CustomTabOffsets"]/*' />
        /// <devdoc>
        ///     Allows to set the width of the tabs between the items in the list box.
        ///     The integer array should have the tab spaces in the ascending order.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.ListBoxCustomTabOffsetsDescr),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Browsable(false)
        ]
        public IntegerCollection CustomTabOffsets {
            get {
                if (customTabOffsets == null) {
                    customTabOffsets = new IntegerCollection(this);
                }
                return customTabOffsets;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.AddItemsCore"]/*' />
        /// <devdoc>
        ///     Performs the work of adding the specified items to the Listbox
        /// </devdoc>
        [Obsolete("This method has been deprecated.  There is no replacement.  http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void AddItemsCore(object[] value) {
            int count = value == null? 0: value.Length;
            if (count == 0) {
                return;
            }
 
            Items.AddRangeInternal(value);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Click"]/*' />
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler Click {
            add {
                base.Click += value;
            }
            remove {
                base.Click -= value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.MouseClick"]/*' />
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public new event MouseEventHandler MouseClick {
            add {
                base.MouseClick += value;
            }
            remove {
                base.MouseClick -= value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Padding"]/*' />
        /// <devdoc>
        ///    <para>
        ///    <para>[To be supplied.]</para>
        ///    </para>
        /// </devdoc>
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public new Padding Padding {
            get { return base.Padding; }
            set { base.Padding = value;}
        }
 
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never)
        ]
        public new event EventHandler PaddingChanged {
            add { base.PaddingChanged += value; }
            remove { base.PaddingChanged -= value; }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnPaint"]/*' />
        /// <devdoc>
        ///     ListBox / CheckedListBox Onpaint.
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event PaintEventHandler Paint {
            add {
                base.Paint += value;
            }
            remove {
                base.Paint -= value;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.DrawItem"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.drawItemEventDescr)]
        public event DrawItemEventHandler DrawItem {
            add {
                Events.AddHandler(EVENT_DRAWITEM, value);
            }
            remove {
                Events.RemoveHandler(EVENT_DRAWITEM, value);
            }
        }
 
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.MeasureItem"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.measureItemEventDescr)]
        public event MeasureItemEventHandler MeasureItem {
            add {
                Events.AddHandler(EVENT_MEASUREITEM, value);
            }
            remove {
                Events.RemoveHandler(EVENT_MEASUREITEM, value);
            }
        }
 
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.selectedIndexChangedEventDescr)]
        public event EventHandler SelectedIndexChanged {
            add {
                Events.AddHandler(EVENT_SELECTEDINDEXCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_SELECTEDINDEXCHANGED, value);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.BeginUpdate"]/*' />
        /// <devdoc>
        ///     While the preferred way to insert items is to set Items.All,
        ///     and set all the items at once, there are times when you may wish to
        ///     insert each item one at a time.  To help with the performance of this,
        ///     it is desirable to prevent the ListBox from painting during these
        ///     operations.  This method, along with EndUpdate, is the preferred
        ///     way of doing this.  Don't forget to call EndUpdate when you're done,
        ///     or else the ListBox won't paint properly afterwards.
        /// </devdoc>
        public void BeginUpdate() {
            BeginUpdateInternal();
            updateCount++;
        }
 
        private void CheckIndex(int index) {
            if (index < 0 || index >= Items.Count)
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)));
        }
 
        private void CheckNoDataSource() {
            if (DataSource != null)
                throw new ArgumentException(SR.GetString(SR.DataSourceLocksItems));
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.CreateItemCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected virtual ObjectCollection CreateItemCollection() {
            return new ObjectCollection(this);
        }
 
        internal virtual int ComputeMaxItemWidth(int oldMax) {
            // pass LayoutUtils the collection of strings
            string[] strings = new string[this.Items.Count];
 
            for (int i = 0; i < Items.Count; i ++) {
                strings[i] = GetItemText(Items[i]);
            }
 
            Size textSize = LayoutUtils.OldGetLargestStringSizeInCollection(Font, strings);
            return Math.Max(oldMax, textSize.Width);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ClearSelected"]/*' />
        /// <devdoc>
        ///     Unselects all currently selected items.
        /// </devdoc>
        public void ClearSelected() {
 
            bool hadSelection = false;
 
            int itemCount = (itemsCollection == null) ? 0 : itemsCollection.Count;
            for (int x = 0; x < itemCount;x++) {
                if (SelectedItems.GetSelected(x)) {
                    hadSelection = true;
                    SelectedItems.SetSelected(x, false);
                    if (IsHandleCreated) {
                        NativeSetSelected(x, false);
                    }
                }
            }
 
            if (hadSelection) {
                OnSelectedIndexChanged(EventArgs.Empty);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.EndUpdate"]/*' />
        /// <devdoc>
        ///     While the preferred way to insert items is to set Items.All,
        ///     and set all the items at once, there are times when you may wish to
        ///     insert each item one at a time.  To help with the performance of this,
        ///     it is desirable to prevent the ListBox from painting during these
        ///     operations.  This method, along with BeginUpdate, is the preferred
        ///     way of doing this.  BeginUpdate should be called first, and this method
        ///     should be called when you want the control to start painting again.
        /// </devdoc>
        public void EndUpdate() {
            EndUpdateInternal();
            --updateCount;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.FindString"]/*' />
        /// <devdoc>
        ///     Finds the first item in the list box that starts with the given string.
        ///     The search is not case sensitive.
        /// </devdoc>
        public int FindString(string s) {
            return FindString(s, -1);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.FindString1"]/*' />
        /// <devdoc>
        ///     Finds the first item after the given index which starts with the given
        ///     string. The search is not case sensitive.
        /// </devdoc>
        public int FindString(string s, int startIndex) {
            if (s == null) return -1;
 
            int itemCount = (itemsCollection == null) ? 0 : itemsCollection.Count;
 
            if (itemCount == 0) {
                return -1;
            }
 
            // VSWhidbey 95158: The last item in the list is still a valid starting point for a search.
            if (startIndex < -1 || startIndex >= itemCount) {
                throw new ArgumentOutOfRangeException("startIndex");
            }
 
            // Always use the managed FindStringInternal instead of LB_FINDSTRING.
            // The managed version correctly handles Turkish I.
            return FindStringInternal(s, Items, startIndex, false);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.FindStringExact"]/*' />
        /// <devdoc>
        ///     Finds the first item in the list box that matches the given string.
        ///     The strings must match exactly, except for differences in casing.
        /// </devdoc>
        public int FindStringExact(string s) {
            return FindStringExact(s, -1);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.FindStringExact1"]/*' />
        /// <devdoc>
        ///     Finds the first item after the given index that matches the given
        ///     string. The strings must match excatly, except for differences in
        ///     casing.
        /// </devdoc>
        public int FindStringExact(string s, int startIndex) {
            if (s == null) return -1;
 
            int itemCount = (itemsCollection == null) ? 0 : itemsCollection.Count;
 
            if (itemCount == 0) {
                return -1;
            }
 
            // VSWhidbey 95158: The last item in the list is still a valid starting point for a search.
            if (startIndex < -1 || startIndex >= itemCount) {
                throw new ArgumentOutOfRangeException("startIndex");
            }
 
            // Always use the managed FindStringInternal instead of LB_FINDSTRING.
            // The managed version correctly handles Turkish I.
            //
            return FindStringInternal(s, Items, startIndex, true);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.GetItemHeight"]/*' />
        /// <devdoc>
        ///     Returns the height of the given item in a list box. The index parameter
        ///     is ignored if drawMode is not OwnerDrawVariable.
        /// </devdoc>
        public int GetItemHeight(int index) {
            int itemCount = (itemsCollection == null) ? 0 : itemsCollection.Count;
 
            // Note: index == 0 is OK even if the ListBox currently has
            // no items.
            //
            if (index < 0 || (index > 0 && index >= itemCount))
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
 
            if (drawMode != DrawMode.OwnerDrawVariable) index = 0;
 
            if (IsHandleCreated) {
                int h = unchecked( (int) (long)SendMessage(NativeMethods.LB_GETITEMHEIGHT, index, 0));
                if (h == -1)
                    throw new Win32Exception();
                return h;
            }
 
            return itemHeight;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.GetItemRectangle"]/*' />
        /// <devdoc>
        ///     Retrieves a Rectangle object which describes the bounding rectangle
        ///     around an item in the list.  If the item in question is not visible,
        ///     the rectangle will be outside the visible portion of the control.
        /// </devdoc>
        public Rectangle GetItemRectangle(int index) {
            CheckIndex(index);
            NativeMethods.RECT rect = new NativeMethods.RECT();
            SendMessage(NativeMethods.LB_GETITEMRECT, index, ref rect);
            return Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
        }
 
        /// <devdoc>
        ///     List box overrides GetScaledBounds to ensure we always scale the requested
        ///     height, not the current height.
        /// </devdoc>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override Rectangle GetScaledBounds(Rectangle bounds, SizeF factor, BoundsSpecified specified) {
            // update bounds' height to use the requested height, not the current height.  These
            // can be different if integral height is turned on.
            bounds.Height = requestedHeight;
            return base.GetScaledBounds(bounds, factor, specified);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.GetSelected"]/*' />
        /// <devdoc>
        ///     Tells you whether or not the item at the supplied index is selected
        ///     or not.
        /// </devdoc>
        public bool GetSelected(int index) {
            CheckIndex(index);
            return GetSelectedInternal(index);
        }
 
        private bool GetSelectedInternal(int index) {
            if (IsHandleCreated) {
                int sel = unchecked( (int) (long)SendMessage(NativeMethods.LB_GETSEL, index, 0));
                if (sel == -1) {
                    throw new Win32Exception();
                }
                return sel > 0;
            }
            else {
                if (itemsCollection != null && SelectedItems.GetSelected(index)) {
                    return true;
                }
                return false;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IndexFromPoint"]/*' />
        /// <devdoc>
        ///     Retrieves the index of the item at the given coordinates.
        /// </devdoc>
        public int IndexFromPoint(Point p) {
            return IndexFromPoint(p.X, p.Y);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IndexFromPoint1"]/*' />
        /// <devdoc>
        ///     Retrieves the index of the item at the given coordinates.
        /// </devdoc>
        public int IndexFromPoint(int x, int y) {
            //NT4 SP6A : SendMessage Fails. So First check whether the point is in Client Co-ordinates and then
            //call Sendmessage.
            //
            NativeMethods.RECT r = new NativeMethods.RECT();
            UnsafeNativeMethods.GetClientRect(new HandleRef(this, Handle), ref r);
            if (r.left <= x && x < r.right && r.top <= y && y < r.bottom) {
                int index = unchecked( (int) (long)SendMessage(NativeMethods.LB_ITEMFROMPOINT, 0, unchecked( (int) (long)NativeMethods.Util.MAKELPARAM(x, y))));
                if (NativeMethods.Util.HIWORD(index) == 0) {
                    // Inside ListBox client area
                    return NativeMethods.Util.LOWORD(index);
                }
            }
 
            return NoMatches;
        }
 
        /// <devdoc>
        ///     Adds the given item to the native combo box.  This asserts if the handle hasn't been
        ///     created.
        /// </devdoc>
        private int NativeAdd(object item) {
            Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created.");
            int insertIndex = unchecked( (int) (long)SendMessage(NativeMethods.LB_ADDSTRING, 0, GetItemText(item)));
 
            if (insertIndex == NativeMethods.LB_ERRSPACE) {
                throw new OutOfMemoryException();
            }
 
            if (insertIndex == NativeMethods.LB_ERR) {
                // On some platforms (e.g. Win98), the ListBox control
                // appears to return LB_ERR if there are a large number (>32000)
                // of items. It doesn't appear to set error codes appropriately,
                // so we'll have to assume that LB_ERR corresponds to item
                // overflow.
                //
                throw new OutOfMemoryException(SR.GetString(SR.ListBoxItemOverflow));
            }
 
            return insertIndex;
        }
 
        /// <devdoc>
        ///     Clears the contents of the combo box.
        /// </devdoc>
        private void NativeClear() {
            Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created.");
            SendMessage(NativeMethods.LB_RESETCONTENT, 0, 0);
        }
 
        /// <devdoc>
        ///     Get the text stored by the native control for the specified list item.
        /// </devdoc>
        internal string NativeGetItemText(int index) {
            int len = unchecked( (int) (long)SendMessage(NativeMethods.LB_GETTEXTLEN, index, 0));
            StringBuilder sb = new StringBuilder(len + 1);
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LB_GETTEXT, index, sb);
            return sb.ToString();
        }
 
        /// <devdoc>
        ///     Inserts the given item to the native combo box at the index.  This asserts if the handle hasn't been
        ///     created or if the resulting insert index doesn't match the passed in index.
        /// </devdoc>
        private int NativeInsert(int index, object item) {
            Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created.");
            int insertIndex = unchecked( (int) (long)SendMessage(NativeMethods.LB_INSERTSTRING, index, GetItemText(item)));
 
            if (insertIndex == NativeMethods.LB_ERRSPACE) {
                throw new OutOfMemoryException();
            }
 
            if (insertIndex == NativeMethods.LB_ERR) {
                // On some platforms (e.g. Win98), the ListBox control
                // appears to return LB_ERR if there are a large number (>32000)
                // of items. It doesn't appear to set error codes appropriately,
                // so we'll have to assume that LB_ERR corresponds to item
                // overflow.
                //
                throw new OutOfMemoryException(SR.GetString(SR.ListBoxItemOverflow));
            }
 
            Debug.Assert(insertIndex == index, "NativeListBox inserted at " + insertIndex + " not the requested index of " + index);
            return insertIndex;
        }
 
        /// <devdoc>
        ///     Removes the native item from the given index.
        /// </devdoc>
        private void NativeRemoveAt(int index) {
            Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created.");
 
            bool selected = (unchecked( (int) (long)SendMessage(NativeMethods.LB_GETSEL, (IntPtr)index, IntPtr.Zero)) > 0);
            SendMessage(NativeMethods.LB_DELETESTRING, index, 0);
 
            //If the item currently selected is removed then we should fire a Selectionchanged event...
            //as the next time selected index returns -1...
 
            if (selected) {
                OnSelectedIndexChanged(EventArgs.Empty);
            }
        }
 
        /// <devdoc>
        ///     Sets the selection of the given index to the native window.  This does not change
        ///     the collection; you must update the collection yourself.
        /// </devdoc>
        private void NativeSetSelected(int index, bool value) {
            Debug.Assert(IsHandleCreated, "Should only call Native methods after the handle has been created");
            Debug.Assert(selectionMode != SelectionMode.None, "Guard against setting selection for None selection mode outside this code.");
 
            if (selectionMode == SelectionMode.One) {
                SendMessage(NativeMethods.LB_SETCURSEL, (value ? index : -1), 0);
            }
            else {
                SendMessage(NativeMethods.LB_SETSEL, value? -1: 0, index);
            }
        }
 
        /// <devdoc>
        ///     This is called by the SelectedObjectCollection in response to the first
        ///     query on that collection after we have called Dirty().  Dirty() is called
        ///     when we receive a LBN_SELCHANGE message.
        /// </devdoc>
        private void NativeUpdateSelection() {
            Debug.Assert(IsHandleCreated, "Should only call native methods if handle is created");
 
            // Clear the selection state.
            //
            int cnt = Items.Count;
            for (int i = 0; i < cnt; i++) {
                SelectedItems.SetSelected(i, false);
            }
 
            int[] result = null;
 
            switch (selectionMode) {
 
                case SelectionMode.One:
                    int index = unchecked( (int) (long)SendMessage(NativeMethods.LB_GETCURSEL, 0, 0));
                    if (index >= 0) result = new int[] {index};
                    break;
 
                case SelectionMode.MultiSimple:
                case SelectionMode.MultiExtended:
                    int count = unchecked( (int) (long)SendMessage(NativeMethods.LB_GETSELCOUNT, 0, 0));
                    if (count > 0) {
                        result = new int[count];
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LB_GETSELITEMS, count, result);
                    }
                    break;
            }
 
            // Now set the selected state on the appropriate items.
            //
            if (result != null) {
                foreach(int i in result) {
                    SelectedItems.SetSelected(i, true);
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnChangeUICues"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnChangeUICues(UICuesEventArgs e) {
 
            // ListBox seems to get a bit confused when the UI cues change for the first
            // time - it draws the focus rect when it shouldn't and vice-versa. So when
            // the UI cues change, we just do an extra invalidate to get it into the
            // right state.
            //
            Invalidate();
 
            base.OnChangeUICues(e);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnDrawItem"]/*' />
        /// <devdoc>
        ///     Actually goes and fires the drawItem event.  Inheriting controls
        ///     should use this to know when the event is fired [this is preferable to
        ///     adding an event handler yourself for this event].  They should,
        ///     however, remember to call base.onDrawItem(e); to ensure the event is
        ///     still fired to external listeners
        /// </devdoc>
        protected virtual void OnDrawItem(DrawItemEventArgs e) {
            DrawItemEventHandler handler = (DrawItemEventHandler)Events[EVENT_DRAWITEM];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnHandleCreated"]/*' />
        /// <devdoc>
        ///     We need to know when the window handle has been created so we can
        ///     set up a few things, like column width, etc!  Inheriting classes should
        ///     not forget to call base.OnHandleCreated().
        /// </devdoc>
        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
 
            
            //for getting the current Locale to set the Scrollbars...
            //
            SendMessage(NativeMethods.LB_SETLOCALE, CultureInfo.CurrentCulture.LCID, 0);
 
            if (columnWidth != 0) {
                SendMessage(NativeMethods.LB_SETCOLUMNWIDTH, columnWidth, 0);
            }
            if (drawMode == DrawMode.OwnerDrawFixed) {
                SendMessage(NativeMethods.LB_SETITEMHEIGHT, 0, ItemHeight);
            }
 
            if (topIndex != 0) {
                SendMessage(NativeMethods.LB_SETTOPINDEX, topIndex, 0);
            }
 
            if (UseCustomTabOffsets && CustomTabOffsets != null) {
                int wpar = CustomTabOffsets.Count;
                int[] offsets = new int[wpar];
                CustomTabOffsets.CopyTo(offsets, 0);
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LB_SETTABSTOPS, wpar, offsets);
            }
 
            if (itemsCollection != null) {
 
                int count = itemsCollection.Count;
 
                for(int i = 0; i < count; i++) {
                    NativeAdd(itemsCollection[i]);
 
                    if (selectionMode != SelectionMode.None) {
                        if (selectedItems != null) {
                            selectedItems.PushSelectionIntoNativeListBox(i);
                        }
                    }
                }
            }
            if (selectedItems != null) {
                if (selectedItems.Count > 0 && selectionMode == SelectionMode.One) {
                    SelectedItems.Dirty();
                    SelectedItems.EnsureUpToDate();
                }
            }
            UpdateHorizontalExtent();
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnHandleDestroyed"]/*' />
        /// <devdoc>
        ///     Overridden to make sure that we set up and clear out items
        ///     correctly.  Inheriting controls should not forget to call
        ///     base.OnHandleDestroyed()
        /// </devdoc>
        protected override void OnHandleDestroyed(EventArgs e) {
            SelectedItems.EnsureUpToDate();
            if (Disposing) {
                itemsCollection = null;
            }
            base.OnHandleDestroyed(e);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnMeasureItem"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected virtual void OnMeasureItem(MeasureItemEventArgs e) {
            MeasureItemEventHandler handler = (MeasureItemEventHandler)Events[EVENT_MEASUREITEM];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnFontChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnFontChanged(EventArgs e) {
            base.OnFontChanged(e);
 
            // Changing the font causes us to resize, always rounding down.
            // Make sure we do this after base.OnPropertyChanged, which sends the WM_SETFONT message
 
            // Avoid the listbox and textbox behaviour in Collection editors
            //
            UpdateFontCache();
        }
 
       
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnParentChanged"]/*' />
        /// <devdoc>
        ///    <para>We override this so we can re-create the handle if the parent has changed.</para>
        /// </devdoc>
        protected override void OnParentChanged(EventArgs e) {
            base.OnParentChanged(e);
            //No need to RecreateHandle if we are removing the Listbox from controls collection...
            //so check the parent before recreating the handle...
            if (this.ParentInternal != null) {
                RecreateHandle();
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnResize"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnResize(EventArgs e) {
 
            base.OnResize(e);
 
            // There are some repainting issues for RightToLeft - so invalidate when we resize.
            //
            if (RightToLeft == RightToLeft.Yes || this.HorizontalScrollbar) {
                Invalidate();
            }
 
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnSelectedIndexChanged"]/*' />
        /// <devdoc>
        ///     Actually goes and fires the selectedIndexChanged event.  Inheriting controls
        ///     should use this to know when the event is fired [this is preferable to
        ///     adding an event handler on yourself for this event].  They should,
        ///     however, remember to call base.OnSelectedIndexChanged(e); to ensure the event is
        ///     still fired to external listeners
        /// </devdoc>
        protected override void OnSelectedIndexChanged(EventArgs e) {
            base.OnSelectedIndexChanged(e);
 
            // set the position in the dataSource, if there is any
            // we will only set the position in the currencyManager if it is different
            // from the SelectedIndex. Setting CurrencyManager::Position (even w/o changing it)
            // calls CurrencyManager::EndCurrentEdit, and that will pull the dataFrom the controls
            // into the backEnd. We do not need to do that.
            //
            if (this.DataManager != null && DataManager.Position != SelectedIndex) {
                //read this as "if everett or   (whidbey and selindex is valid)"
                if (!FormattingEnabled || this.SelectedIndex != -1)
                {
                    // VSWhidbey 95176: don't change dataManager position if we simply unselected everything.
                    // (Doing so would cause the first LB item to be selected...)
                    this.DataManager.Position = this.SelectedIndex;
                }
            }
 
            // VSWhidbey 163411: Call the handler after updating the DataManager's position so that
            // the DataManager's selected index will be correct in an event handler.
            EventHandler handler = (EventHandler)Events[EVENT_SELECTEDINDEXCHANGED];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnSelectedValueChanged"]/*' />
        protected override void OnSelectedValueChanged(EventArgs e) {
            base.OnSelectedValueChanged(e);
            selectedValueChangedFired = true;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnDataSourceChanged"]/*' />
        protected override void OnDataSourceChanged(EventArgs e) {
            if (DataSource == null)
            {
                BeginUpdate();
                SelectedIndex = -1;
                Items.ClearInternal();
                EndUpdate();
            }
            base.OnDataSourceChanged(e);
            RefreshItems();
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.OnDisplayMemberChanged"]/*' />
        protected override void OnDisplayMemberChanged(EventArgs e) {
            base.OnDisplayMemberChanged(e);
 
            // we want to use the new DisplayMember even if there is no data source
            RefreshItems();
 
            if (SelectionMode != SelectionMode.None && this.DataManager != null)
                this.SelectedIndex = this.DataManager.Position;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Refresh"]/*' />
        /// <devdoc>
        ///     Forces the ListBox to invalidate and immediately
        ///     repaint itself and any children if OwnerDrawVariable.
        /// </devdoc>
        public override void Refresh() {
            if (drawMode == DrawMode.OwnerDrawVariable) {
                //Fire MeasureItem for Each Item in the Listbox...
                int cnt = Items.Count;
                Graphics graphics = CreateGraphicsInternal();
 
                try
                {
                    for (int i = 0; i < cnt; i++) {
                        MeasureItemEventArgs mie = new MeasureItemEventArgs(graphics, i, ItemHeight);
                        OnMeasureItem(mie);
                    }
                }
                finally {
                    graphics.Dispose();
                }
 
            }
            base.Refresh();
        }
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.RefreshItems"]/*' />
        /// <devdoc>
        /// Reparses the objects, getting new text strings for them.
        /// </devdoc>
        /// <internalonly/>
        protected override void RefreshItems() {
 
            // Store the currently selected object collection.
            //
            ObjectCollection savedItems = itemsCollection;
 
            // Clear the items.
            //
            itemsCollection = null;
            selectedIndices = null;
 
            if (IsHandleCreated) {
                NativeClear();
            }
 
            object[] newItems = null;
 
            // if we have a dataSource and a DisplayMember, then use it
            // to populate the Items collection
            //
            if (this.DataManager != null && this.DataManager.Count != -1) {
                newItems = new object[this.DataManager.Count];
                for(int i = 0; i < newItems.Length; i++) {
                    newItems[i] = this.DataManager[i];
                }
            }
            else if (savedItems != null) {
                newItems = new object[savedItems.Count];
                savedItems.CopyTo(newItems, 0);
            }
 
            // Store the current list of items
            //
            if (newItems != null) {
                Items.AddRangeInternal(newItems);
            }
 
            // Restore the selected indices if SelectionMode allows it.
            //
            if (SelectionMode != SelectionMode.None) {
                if (this.DataManager != null) {
                    // put the selectedIndex in sync w/ the position in the dataManager
                    this.SelectedIndex = this.DataManager.Position;
                }
                else {
                    if (savedItems != null) {
                        int cnt = savedItems.Count;
                        for(int index = 0; index < cnt; index++) {
                            if (savedItems.InnerArray.GetState(index, SelectedObjectCollection.SelectedObjectMask)) {
                                SelectedItem = savedItems[index];
                            }
                        }
                    }
                }
            }
 
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.RefreshItem"]/*' />
        /// <devdoc>
        /// Reparses the object at the given index, getting new text string for it.
        /// </devdoc>
        /// <internalonly/>
        protected override void RefreshItem(int index) {
            Items.SetItemInternal(index, Items[index]);
        }
 
        public override void ResetBackColor() {
            base.ResetBackColor();
        }
 
        public override void ResetForeColor() {
            base.ResetForeColor();
        }
 
 
        private void ResetItemHeight() {
            itemHeight = DefaultItemHeight;
        }
      
       [SuppressMessage("Microsoft.Portability", "CA1902:AvoidTestingForFloatingPointEquality")]
       protected override void ScaleControl(SizeF factor, BoundsSpecified specified) {
           
           if (factor.Width != 1F && factor.Height != 1F) {
               UpdateFontCache();
           }
           base.ScaleControl(factor, specified);
       }
 
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SetBoundsCore"]/*' />
        /// <devdoc>
        ///     Overrides Control.SetBoundsCore to remember the requestedHeight.
        /// </devdoc>
        /// <internalonly/>
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
 
            // Avoid the listbox and textbox behaviour in Collection editors
            //
 
 
            if (!integralHeightAdjust && height != Height)
                requestedHeight = height;
            base.SetBoundsCore(x, y, width, height, specified);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SetItemsCore"]/*' />
        /// <devdoc>
        ///     Performs the work of setting the specified items into the ListBox.
        /// </devdoc>
        protected override void SetItemsCore(IList value) {
                BeginUpdate();
                Items.ClearInternal();
                Items.AddRangeInternal(value);
 
                this.SelectedItems.Dirty();
 
                // if the list changed, we want to keep the same selected index
                // CurrencyManager will provide the PositionChanged event
                // it will be provided before changing the list though...
                if (this.DataManager != null) {
                    if (this.DataSource is ICurrencyManagerProvider) {
                        // Everett ListControl's had a bug where they would not fire
                        // OnSelectedValueChanged if their list of items were refreshed.
                        // We fix this post-Everett.
                        // However, for APPCOMPAT reasons, we only want to fix it when binding to 
                        // Whidbey components.
                        // vsw 547279.
                        this.selectedValueChangedFired = false;
                    }
 
                    if (IsHandleCreated) {
                        SendMessage(NativeMethods.LB_SETCURSEL, DataManager.Position, 0);
                    }
 
                    // if the list changed and we still did not fire the
                    // onselectedChanged event, then fire it now;
                    if (!selectedValueChangedFired) {
                        OnSelectedValueChanged(EventArgs.Empty);
                        selectedValueChangedFired = false;
                    }
                }
                EndUpdate();
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SetItemCore"]/*' />
        protected override void SetItemCore(int index, object value) {
            Items.SetItemInternal(index, value);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SetSelected"]/*' />
        /// <devdoc>
        ///     Allows the user to set an item as being selected or not.  This should
        ///     only be used with ListBoxes that allow some sort of multi-selection.
        /// </devdoc>
        public void SetSelected(int index, bool value) {
            int itemCount = (itemsCollection == null) ? 0: itemsCollection.Count;
            if (index < 0 || index >= itemCount)
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
 
            if (selectionMode == SelectionMode.None)
                throw new InvalidOperationException(SR.GetString(SR.ListBoxInvalidSelectionMode));
 
            SelectedItems.SetSelected(index, value);
            if (IsHandleCreated) {
                NativeSetSelected(index, value);
            }
            SelectedItems.Dirty();
            OnSelectedIndexChanged(EventArgs.Empty);
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.Sort"]/*' />
        /// <devdoc>
        ///     Sorts the items in the listbox.
        /// </devdoc>
        protected virtual void Sort() {
            // This will force the collection to add each item back to itself
            // if sorted is now true, then the add method will insert the item
            // into the correct position
            //
            CheckNoDataSource();
 
            SelectedObjectCollection currentSelections = SelectedItems;
            currentSelections.EnsureUpToDate();
 
            if (sorted && itemsCollection != null) {
                itemsCollection.InnerArray.Sort();
 
                // Now that we've sorted, update our handle
                // if it has been created.
                if (IsHandleCreated) {
                    NativeClear();
                    int count = itemsCollection.Count;
                    for(int i = 0; i < count; i++) {
                        NativeAdd(itemsCollection[i]);
                        if (currentSelections.GetSelected(i)) {
                            NativeSetSelected(i, true);
                        }
                    }
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ToString"]/*' />
        /// <devdoc>
        ///     Returns a string representation for this control.
        /// </devdoc>
        /// <internalonly/>
        public override string ToString() {
 
            string s = base.ToString();
            if (itemsCollection != null) {
                s += ", Items.Count: " + Items.Count.ToString(CultureInfo.CurrentCulture);
                if (Items.Count > 0) {
                    string z = GetItemText(Items[0]);
                    string txt = (z.Length > 40) ? z.Substring(0, 40) : z;
                    s += ", Items[0]: " + txt;
                }
            }
            return s;
        }
        private void UpdateFontCache() {
            fontIsChanged = true;
            integralHeightAdjust = true;
            try {
                Height = requestedHeight;
            }
            finally {
                integralHeightAdjust = false;
            }
            maxWidth = -1;
            UpdateHorizontalExtent();
            // clear the preferred size cache.
            CommonProperties.xClearPreferredSizeCache(this);
 
        }
 
        private void UpdateHorizontalExtent() {
            if (!multiColumn && horizontalScrollbar && IsHandleCreated) {
                int width = horizontalExtent;
                if (width == 0) {
                    width = MaxItemWidth;
                }
                SendMessage(NativeMethods.LB_SETHORIZONTALEXTENT, width, 0);
            }
        }
 
        // Updates the cached max item width
        //
        private void UpdateMaxItemWidth(object item, bool removing) {
 
            // We shouldn't be caching maxWidth if we don't have horizontal scrollbars,
            // or horizontal extent has been set
            //
            if (!horizontalScrollbar || horizontalExtent > 0) {
                maxWidth = -1;
                return;
            }
 
            // Only update if we are currently caching maxWidth
            //
            if (maxWidth > -1) {
 
                // Compute item width
                //
                int width;
                using (Graphics graphics = CreateGraphicsInternal()) {
                    width = (int)(Math.Ceiling(graphics.MeasureString(GetItemText(item), this.Font).Width));
                }
 
                if (removing) {
                    // We're removing this item, so if it's the longest
                    // in the list, reset the cache
                    //
                    if (width >= maxWidth) {
                        maxWidth = -1;
                    }
                }
                else {
                    // We're adding or inserting this item - update the cache
                    //
                    if (width > maxWidth) {
                        maxWidth = width;
                    }
                }
            }
        }
 
        // Updates the Custom TabOffsets
        //
 
        private  void UpdateCustomTabOffsets() {
            if (IsHandleCreated && UseCustomTabOffsets && CustomTabOffsets != null) {
                int wpar = CustomTabOffsets.Count;
                int[] offsets = new int[wpar];
                CustomTabOffsets.CopyTo(offsets, 0);
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LB_SETTABSTOPS, wpar, offsets);
                Invalidate();
            }
        }
 
        private void WmPrint(ref Message m) {
            base.WndProc(ref m);
            if ((NativeMethods.PRF_NONCLIENT & (int)m.LParam) != 0 && Application.RenderWithVisualStyles && this.BorderStyle == BorderStyle.Fixed3D) {
                IntSecurity.UnmanagedCode.Assert();
                try {
                    using (Graphics g = Graphics.FromHdc(m.WParam)) {
                        Rectangle rect = new Rectangle(0, 0, this.Size.Width - 1, this.Size.Height - 1);
                        using (Pen pen = new Pen(VisualStyleInformation.TextControlBorder)) {
                            g.DrawRectangle(pen, rect);
                        }
                        rect.Inflate(-1, -1);
                        g.DrawRectangle(SystemPens.Window, rect);
                    }
                }
                finally {
                    CodeAccessPermission.RevertAssert();
                }
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.WmReflectCommand"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        [
        System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode),
        System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
        ]
        protected virtual void WmReflectCommand(ref Message m) {
            switch (NativeMethods.Util.HIWORD(m.WParam)) {
                case NativeMethods.LBN_SELCHANGE:
                    if (selectedItems != null) {
                        selectedItems.Dirty();
                    }
                    OnSelectedIndexChanged(EventArgs.Empty);
                    break;
                case NativeMethods.LBN_DBLCLK:
                    // Handle this inside WM_LBUTTONDBLCLK
                    // OnDoubleClick(EventArgs.Empty);
                    break;
            }
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.WmReflectDrawItem"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        private void WmReflectDrawItem(ref Message m) {
            NativeMethods.DRAWITEMSTRUCT dis = (NativeMethods.DRAWITEMSTRUCT)m.GetLParam(typeof(NativeMethods.DRAWITEMSTRUCT));
            IntPtr dc = dis.hDC;
            IntPtr oldPal = SetUpPalette(dc, false /*force*/, false /*realize*/);
            try {
                Graphics g = Graphics.FromHdcInternal(dc);
 
                try {
                    Rectangle bounds = Rectangle.FromLTRB(dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom);
                    
                    if (HorizontalScrollbar) {
                        if (MultiColumn) {
                            bounds.Width = Math.Max(ColumnWidth, bounds.Width);
                        }
                        else {
                            bounds.Width = Math.Max(MaxItemWidth, bounds.Width);
                        }
                    }
                    
 
                    OnDrawItem(new DrawItemEventArgs(g, Font, bounds, dis.itemID, (DrawItemState)dis.itemState, ForeColor, BackColor));
                }
                finally {
                    g.Dispose();
                }
            }
            finally {
                if (oldPal != IntPtr.Zero) {
                    SafeNativeMethods.SelectPalette(new HandleRef(null, dc), new HandleRef(null, oldPal), 0);
                }
            }
            m.Result = (IntPtr)1;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.WmReflectMeasureItem"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        // This method is only called if in owner draw mode
        private void WmReflectMeasureItem(ref Message m) {
 
            NativeMethods.MEASUREITEMSTRUCT mis = (NativeMethods.MEASUREITEMSTRUCT)m.GetLParam(typeof(NativeMethods.MEASUREITEMSTRUCT));
 
            if (drawMode == DrawMode.OwnerDrawVariable && mis.itemID >= 0) {
                Graphics graphics = CreateGraphicsInternal();
                MeasureItemEventArgs mie = new MeasureItemEventArgs(graphics, mis.itemID, ItemHeight);
                try {
                    OnMeasureItem(mie);
                    mis.itemHeight = mie.ItemHeight;
                }
                finally {
                    graphics.Dispose();
                }
            }
            else {
                mis.itemHeight = ItemHeight;
            }
            Marshal.StructureToPtr(mis, m.LParam, false);
            m.Result = (IntPtr)1;
        }
 
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.WndProc"]/*' />
        /// <devdoc>
        ///     The list's window procedure.  Inheriting classes can override this
        ///     to add extra functionality, but should not forget to call
        ///     base.wndProc(m); to ensure the list continues to function properly.
        /// </devdoc>
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                case NativeMethods.WM_REFLECT + NativeMethods.WM_COMMAND:
                    WmReflectCommand(ref m);
                    break;
                case NativeMethods.WM_REFLECT + NativeMethods.WM_DRAWITEM:
                    WmReflectDrawItem(ref m);
                    break;
                case NativeMethods.WM_REFLECT + NativeMethods.WM_MEASUREITEM:
                    WmReflectMeasureItem(ref m);
                    break;
                case NativeMethods.WM_PRINT:
                    WmPrint(ref m);
                    break;
                case NativeMethods.WM_LBUTTONDOWN:
                    if (selectedItems != null) {
                        selectedItems.Dirty();
                    }
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_LBUTTONUP:
                    // Get the mouse location
                    //
                    int x = NativeMethods.Util.SignedLOWORD(m.LParam);
                    int y = NativeMethods.Util.SignedHIWORD(m.LParam);
                    Point pt = new Point(x,y);
                    pt = PointToScreen(pt);
                    bool captured = Capture;
                    if (captured && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) {
 
 
                        if (!doubleClickFired && !ValidationCancelled) {
                             OnClick(new MouseEventArgs(MouseButtons.Left, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                             OnMouseClick(new MouseEventArgs(MouseButtons.Left, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
 
                        }
                        else {
                            doubleClickFired = false;
                            // WM_COMMAND is only fired if the user double clicks an item,
                            // so we can't use that as a double-click substitute
                            if (!ValidationCancelled) {
                                OnDoubleClick(new MouseEventArgs(MouseButtons.Left, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                                OnMouseDoubleClick(new MouseEventArgs(MouseButtons.Left, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
 
                            }
                       }
                    }
 
                    //
                    // If this control has been disposed in the user's event handler, then we need to ignore the WM_LBUTTONUP
                    // message to avoid exceptions thrown as a result of handle re-creation (VSWhidbey#95150).
                    // We handle this situation here and not at the top of the window procedure since this is the only place
                    // where we can get disposed as an effect of external code (form.Close() for instance) and then pass the
                    // message to the base class.
                    //
                    if (GetState(STATE_DISPOSED))
                    {
                        base.DefWndProc(ref m);
                    }
                    else
                    {
                        base.WndProc(ref m);
                    }
 
                    doubleClickFired = false;
                    break;
 
                case NativeMethods.WM_RBUTTONUP:
                    // Get the mouse location
                    //
                    int rx = NativeMethods.Util.SignedLOWORD(m.LParam);
                    int ry = NativeMethods.Util.SignedHIWORD(m.LParam);
                    Point rpt = new Point(rx,ry);
                    rpt = PointToScreen(rpt);
                    bool rCaptured = Capture;
                    if (rCaptured && UnsafeNativeMethods.WindowFromPoint(rpt.X, rpt.Y) == Handle) {
                        if (selectedItems != null) {
                            selectedItems.Dirty();
                        }
                    }
                    base.WndProc(ref m);
                    break;
 
                case NativeMethods.WM_LBUTTONDBLCLK:
                    //the Listbox gets  WM_LBUTTONDOWN - WM_LBUTTONUP -WM_LBUTTONDBLCLK - WM_LBUTTONUP...
                    //sequence for doubleclick...
                    //the first WM_LBUTTONUP, resets the flag for Doubleclick
                    //So its necessary for us to set it again...
                    doubleClickFired = true;
                    base.WndProc(ref m);
                    break;
 
                case NativeMethods.WM_WINDOWPOSCHANGED:
                    base.WndProc(ref m);
                    if (integralHeight && fontIsChanged) {
                        Height = Math.Max(Height,ItemHeight);
                        fontIsChanged = false;
                    }
                    break;
 
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
 
        protected override AccessibleObject CreateAccessibilityInstance() {
            if (AccessibilityImprovements.Level3) {
                return new ListBoxAccessibleObject(this); 
            }
            else {
                return base.CreateAccessibilityInstance();
            }
        }
 
        /// <devdoc>
        ///     This is similar to ArrayList except that it also
        ///     mantains a bit-flag based state element for each item
        ///     in the array.
        ///
        ///     The methods to enumerate, count and get data support
        ///     virtualized indexes.  Indexes are virtualized according
        ///     to the state mask passed in.  This allows ItemArray
        ///     to be the backing store for one read-write "master"
        ///     collection and serveral read-only collections based
        ///     on masks.  ItemArray supports up to 31 masks.
        /// </devdoc>
        internal class ItemArray : IComparer {
 
            private static int lastMask = 1;
 
            private ListControl listControl;
            private Entry[]     entries;
            private int         count;
            private int         version;
 
            public ItemArray(ListControl listControl) {
                this.listControl = listControl;
            }
 
            /// <devdoc>
            ///     The version of this array.  This number changes with each
            ///     change to the item list.
            /// </devdoc>
            public int Version {
                get {
                    return version;
                }
            }
 
            /// <devdoc>
            ///     Adds the given item to the array.  The state is initially
            ///     zero.
            /// </devdoc>
            public object Add(object item) {
                EnsureSpace(1);
                version++;
                entries[count] = new Entry(item);
                return entries[count++];
            }
 
            /// <devdoc>
            ///     Adds the given collection of items to the array.
            /// </devdoc>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
            public void AddRange(ICollection items) {
                if (items == null) {
                    throw new ArgumentNullException("items");
                }
                EnsureSpace(items.Count);
                foreach(object i in items) {
                    entries[count++] = new Entry(i);
                }
                version++;
            }
 
            /// <devdoc>
            ///     Clears this array.
            /// </devdoc>
            public void Clear() {
                if (count > 0) {
                    Array.Clear(entries, 0, count);
                }
 
                count = 0;
                version++;
            }
 
            /// <devdoc>
            ///     Allocates a new bitmask for use.
            /// </devdoc>
            public static int CreateMask() {
                int mask = lastMask;
                lastMask = lastMask << 1;
                Debug.Assert(lastMask > mask, "We have overflowed our state mask.");
                return mask;
            }
 
            /// <devdoc>
            ///     Ensures that our internal array has space for
            ///     the requested # of elements.
            /// </devdoc>
            private void EnsureSpace(int elements) {
                if (entries == null) {
                    entries = new Entry[Math.Max(elements, 4)];
                }
                else if (count + elements >= entries.Length) {
                    int newLength = Math.Max(entries.Length * 2, entries.Length + elements);
                    Entry[] newEntries = new Entry[newLength];
                    entries.CopyTo(newEntries, 0);
                    entries = newEntries;
                }
            }
 
            /// <devdoc>
            ///     Turns a virtual index into an actual index.
            /// </devdoc>
            public int GetActualIndex(int virtualIndex, int stateMask) {
                if (stateMask == 0) {
                    return virtualIndex;
                }
 
                // More complex; we must compute this index.
                int calcIndex = -1;
                for(int i = 0; i < count; i++) {
                    if ((entries[i].state & stateMask) != 0) {
                        calcIndex++;
                        if (calcIndex == virtualIndex) {
                            return i;
                        }
                    }
                }
 
                return -1;
            }
 
            /// <devdoc>
            ///     Gets the count of items matching the given mask.
            /// </devdoc>
            public int GetCount(int stateMask) {
                // If mask is zero, then just give the main count
                if (stateMask == 0) {
                    return count;
                }
 
                // more complex:  must provide a count of items
                // based on a mask.
 
                int filteredCount = 0;
 
                for(int i = 0; i < count; i++) {
                    if ((entries[i].state & stateMask) != 0) {
                        filteredCount++;
                    }
                }
 
                return filteredCount;
            }
 
            /// <devdoc>
            ///     Retrieves an enumerator that will enumerate based on
            ///     the given mask.
            /// </devdoc>
            public IEnumerator GetEnumerator(int stateMask) {
                return GetEnumerator(stateMask, false);
            }
 
            /// <devdoc>
            ///     Retrieves an enumerator that will enumerate based on
            ///     the given mask.
            /// </devdoc>
            public IEnumerator GetEnumerator(int stateMask, bool anyBit) {
                return new EntryEnumerator(this, stateMask, anyBit);
            }
 
            /// <devdoc>
            ///     Gets the item at the given index.  The index is
            ///     virtualized against the given mask value.
            /// </devdoc>
            public object GetItem(int virtualIndex, int stateMask) {
                int actualIndex = GetActualIndex(virtualIndex, stateMask);
 
                if (actualIndex == -1) {
                    throw new IndexOutOfRangeException();
                }
 
                return entries[actualIndex].item;
            }
            /// <devdoc>
            ///     Gets the item at the given index.  The index is
            ///     virtualized against the given mask value.
            /// </devdoc>
            internal object GetEntryObject(int virtualIndex, int stateMask) {
                int actualIndex = GetActualIndex(virtualIndex, stateMask);
 
                if (actualIndex == -1) {
                    throw new IndexOutOfRangeException();
                }
 
                return entries[actualIndex];
            }
            /// <devdoc>
            ///     Returns true if the requested state mask is set.
            ///     The index is the actual index to the array.
            /// </devdoc>
            public bool GetState(int index, int stateMask) {
                return ((entries[index].state & stateMask) == stateMask);
            }
 
            /// <devdoc>
            ///     Returns the virtual index of the item based on the
            ///     state mask.
            /// </devdoc>
            public int IndexOf(object item, int stateMask) {
 
                int virtualIndex = -1;
 
                for(int i = 0; i < count; i++) {
                    if (stateMask == 0 || (entries[i].state & stateMask) != 0) {
                        virtualIndex++;
                        if (entries[i].item.Equals(item)) {
                            return virtualIndex;
                        }
                    }
                }
 
                return -1;
            }
 
            /// <devdoc>
            ///     Returns the virtual index of the item based on the
            ///     state mask. Uses reference equality to identify the
            ///     given object in the list.
            /// </devdoc>
            public int IndexOfIdentifier(object identifier, int stateMask) {
                int virtualIndex = -1;
 
                for(int i = 0; i < count; i++) {
                    if (stateMask == 0 || (entries[i].state & stateMask) != 0) {
                        virtualIndex++;
                        if (entries[i] == identifier) {
                            return virtualIndex;
                        }
                    }
                }
 
                return -1;
            }
 
            /// <devdoc>
            ///     Inserts item at the given index.  The index
            ///     is not virtualized.
            /// </devdoc>
            public void Insert(int index, object item) {
                EnsureSpace(1);
 
                if (index < count) {
                    System.Array.Copy(entries, index, entries, index + 1, count - index);
                }
 
                entries[index] = new Entry(item);
                count++;
                version++;
            }
 
            /// <devdoc>
            ///     Removes the given item from the array.  If
            ///     the item is not in the array, this does nothing.
            /// </devdoc>
            public void Remove(object item) {
                int index = IndexOf(item, 0);
 
                if (index != -1) {
                    RemoveAt(index);
                }
            }
 
            /// <devdoc>
            ///     Removes the item at the given index.
            /// </devdoc>
            public void RemoveAt(int index) {
                count--;
                for (int i = index; i < count; i++) {
                    entries[i] = entries[i+1];
                }
                entries[count] = null;
                version++;
            }
 
            /// <devdoc>
            ///     Sets the item at the given index to a new value.
            /// </devdoc>
            public void SetItem(int index, object item) {
                entries[index].item = item;
            }
 
            /// <devdoc>
            ///     Sets the state data for the given index.
            /// </devdoc>
            public void SetState(int index, int stateMask, bool value) {
                if (value) {
                    entries[index].state |= stateMask;
                }
                else {
                    entries[index].state &= ~stateMask;
                }
                version++;
            }
 
            /// <devdoc>
            ///     Find element in sorted array. If element is not found returns a binary complement of index for inserting
            /// </devdoc>
            public int BinarySearch(object element)
            {
                return Array.BinarySearch(entries, 0, count, element, this);
            }
 
 
            /// <devdoc>
            ///     Sorts our array.
            /// </devdoc>
            public void Sort() {
                Array.Sort(entries, 0, count, this);
            }
 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
            public void Sort(Array externalArray) {
                Array.Sort(externalArray, this);
            }
 
            int IComparer.Compare(object item1, object item2) {
                if (item1 == null) {
                    if (item2 == null)
                        return 0; //both null, then they are equal
 
                    return -1; //item1 is null, but item2 is valid (greater)
                }
                if (item2 == null)
                    return 1; //item2 is null, so item 1 is greater
 
                if (item1 is Entry) {
                    item1 = ((Entry)item1).item;
                }
 
                if (item2 is Entry) {
                    item2 = ((Entry)item2).item;
                }
 
                String itemName1 = listControl.GetItemText(item1);
                String itemName2 = listControl.GetItemText(item2);
 
                CompareInfo compInfo = (Application.CurrentCulture).CompareInfo;
                return compInfo.Compare(itemName1, itemName2, CompareOptions.StringSort);
            }
 
            /// <devdoc>
            ///     This is a single entry in our item array.
            /// </devdoc>
            private class Entry {
                public object item;
                public int state;
 
                public Entry(object item) {
                    this.item = item;
                    this.state = 0;
                }
            }
 
            /// <devdoc>
            ///     EntryEnumerator is an enumerator that will enumerate over
            ///     a given state mask.
            /// </devdoc>
            private class EntryEnumerator : IEnumerator {
                private ItemArray items;
                private bool anyBit;
                private int state;
                private int current;
                private int version;
 
                /// <devdoc>
                ///     Creates a new enumerator that will enumerate over the given state.
                /// </devdoc>
                public EntryEnumerator(ItemArray items, int state, bool anyBit) {
                    this.items = items;
                    this.state = state;
                    this.anyBit = anyBit;
                    this.version = items.version;
                    this.current = -1;
                }
 
                /// <devdoc>
                ///     Moves to the next element, or returns false if at the end.
                /// </devdoc>
                bool IEnumerator.MoveNext() {
                    if(version != items.version) throw new InvalidOperationException(SR.GetString(SR.ListEnumVersionMismatch));
 
                    while(true) {
                        if (current < items.count - 1) {
                                            current++;
                            if (anyBit) {
                                if ((items.entries[current].state & state) != 0) {
                                    return true;
                                }
                            }
                            else {
                                if ((items.entries[current].state & state) == state) {
                                    return true;
                                }
                            }
                        }
                        else {
                            current = items.count;
                            return false;
                        }
                    }
                }
 
                /// <devdoc>
                ///     Resets the enumeration back to the beginning.
                /// </devdoc>
                void IEnumerator.Reset() {
                    if(version != items.version) throw new InvalidOperationException(SR.GetString(SR.ListEnumVersionMismatch));
                    current = -1;
                }
 
                /// <devdoc>
                ///     Retrieves the current value in the enumerator.
                /// </devdoc>
                object IEnumerator.Current {
                    get {
                        if (current == -1 || current == items.count) {
                            throw new InvalidOperationException(SR.GetString(SR.ListEnumCurrentOutOfRange));
                        }
 
                        return items.entries[current].item;
                    }
                }
            }
        }
 
        // Items
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection"]/*' />
        /// <devdoc>
        ///     <para>
        ///       A collection that stores objects.
        ///    </para>
        /// </devdoc>
        [ListBindable(false)]
        public class ObjectCollection : IList {
 
            private ListBox owner;
            private ItemArray items;
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.ObjectCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public ObjectCollection(ListBox owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.ObjectCollection1"]/*' />
            /// <devdoc>
            ///     <para>
            ///       Initializes a new instance of ListBox.ObjectCollection based on another ListBox.ObjectCollection.
            ///    </para>
            /// </devdoc>
            public ObjectCollection(ListBox owner, ObjectCollection value) {
                this.owner = owner;
                this.AddRange(value);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.ObjectCollection2"]/*' />
            /// <devdoc>
            ///     <para>
            ///       Initializes a new instance of ListBox.ObjectCollection containing any array of objects.
            ///    </para>
            /// </devdoc>
            public ObjectCollection(ListBox owner, object[] value) {
                this.owner = owner;
                this.AddRange(value);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.Count"]/*' />
            /// <devdoc>
            ///     Retrieves the number of items.
            /// </devdoc>
            public int Count {
                get {
                    return InnerArray.GetCount(0);
                }
            }
 
            /// <devdoc>
            ///     Internal access to the actual data store.
            /// </devdoc>
            internal ItemArray InnerArray {
                get {
                    if (items == null) {
                        items = new ItemArray(owner);
                    }
                    return items;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ObjectCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ObjectCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ObjectCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.Add"]/*' />
            /// <devdoc>
            ///     Adds an item to the List box. For an unsorted List box, the item is
            ///     added to the end of the existing list of items. For a sorted List box,
            ///     the item is inserted into the list according to its sorted position.
            ///     The item's toString() method is called to obtain the string that is
            ///     displayed in the combo box.
            ///     A SystemException occurs if there is insufficient space available to
            ///     store the new item.
            /// </devdoc>
 
            public int Add(object item)
            {
                owner.CheckNoDataSource();
                int index = AddInternal(item);
                owner.UpdateHorizontalExtent();
                return index;
            }
 
 
            private int AddInternal(object item)
            {
                if (item == null)
                {
                    throw new ArgumentNullException("item");
                }
                int index = -1;
                if (!owner.sorted)
                {
                    InnerArray.Add(item);
                }
                else
                {
                    if (Count > 0)
                    {
                        index = InnerArray.BinarySearch(item);
                        if (index < 0)
                        {
                            index = ~index; // getting the index of the first element that is larger than the search value
                                            //this index will be used for insert
                        }
                    }
                    else
                        index = 0;
 
                    Debug.Assert(index >= 0 && index <= Count, "Wrong index for insert");
                    InnerArray.Insert(index, item);
                }
                bool successful = false;
 
                try
                {
                    if (owner.sorted)
                    {
                        if (owner.IsHandleCreated)
                        {
                            owner.NativeInsert(index, item);
                            owner.UpdateMaxItemWidth(item, false);
                            if (owner.selectedItems != null)
                            {
                                // VSWhidbey 95187: sorting may throw the LB contents and the selectedItem array out of synch.
                                owner.selectedItems.Dirty();
                            }
                        }
                    }
                    else
                    {
                        index = Count - 1;
                        if (owner.IsHandleCreated)
                        {
                            owner.NativeAdd(item);
                            owner.UpdateMaxItemWidth(item, false);
                        }
                    }
                    successful = true;
                }
                finally
                {
                    if (!successful)
                    {
                        InnerArray.Remove(item);
                    }
                }
              
                return index;
            }
 
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ObjectCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object item) {
                return Add(item);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.AddRange1"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void AddRange(ObjectCollection value) {
                owner.CheckNoDataSource();
                AddRangeInternal((ICollection)value);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.AddRange"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void AddRange(object[] items) {
                owner.CheckNoDataSource();
                AddRangeInternal((ICollection)items);
            }
           
            internal void AddRangeInternal(ICollection items) {
 
                if (items == null)
                {
                    throw new ArgumentNullException("items");
                }
                owner.BeginUpdate();
                try
                {
                    foreach (object item in items)
                    {
                        // adding items one-by-one for performance 
                        // not using sort because after the array is sorted index of each newly added item will need to be found
                        // AddInternal is based on BinarySearch and finds index without any additional cost
                        AddInternal(item);
                    }
                }
                finally
                {
                    owner.UpdateHorizontalExtent();
                    owner.EndUpdate();
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.this"]/*' />
            /// <devdoc>
            ///     Retrieves the item with the specified index.
            /// </devdoc>
            [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
            public virtual object this[int index] {
                get {
                    if (index < 0 || index >= InnerArray.GetCount(0)) {
                        throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                    }
 
                    return InnerArray.GetItem(index, 0);
                }
                set {
                    owner.CheckNoDataSource();
                    SetItemInternal(index, value);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.Clear"]/*' />
            /// <devdoc>
            ///     Removes all items from the ListBox.
            /// </devdoc>
            public virtual void Clear() {
                owner.CheckNoDataSource();
                ClearInternal();
            }
 
            /// <devdoc>
            ///     Removes all items from the ListBox.  Bypasses the data source check.
            /// </devdoc>
            internal void ClearInternal() {
 
                //update the width.. to reset Scrollbars..
                // Clear the selection state.
                //
                int cnt = owner.Items.Count;
                for (int i = 0; i < cnt; i++) {
                    owner.UpdateMaxItemWidth(InnerArray.GetItem(i, 0), true);
                }
 
 
                if (owner.IsHandleCreated) {
                    owner.NativeClear();
                }
                InnerArray.Clear();
                owner.maxWidth = -1;
                owner.UpdateHorizontalExtent();
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(object value) {
                return IndexOf(value) != -1;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.CopyTo"]/*' />
            /// <devdoc>
            ///     Copies the ListBox Items collection to a destination array.
            /// </devdoc>
            public void CopyTo(object[] destination, int arrayIndex) {
                int count = InnerArray.GetCount(0);
                for(int i = 0; i < count; i++) {
                    destination[i + arrayIndex] = InnerArray.GetItem(i, 0);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ObjectCollection.ICollection.CopyTo"]/*' />
            /// <internalonly/>
            void ICollection.CopyTo(Array destination, int index) {
                int count = InnerArray.GetCount(0);
                for(int i = 0; i < count; i++) {
                    destination.SetValue(InnerArray.GetItem(i, 0), i + index);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///     Returns an enumerator for the ListBox Items collection.
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                return InnerArray.GetEnumerator(0);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(object value) {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }
 
                return InnerArray.IndexOf(value,0);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.IndexOfIdentifier"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            /// <internalonly/>
            internal int IndexOfIdentifier(object value) {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }
 
                return InnerArray.IndexOfIdentifier(value,0);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.Insert"]/*' />
            /// <devdoc>
            ///     Adds an item to the combo box. For an unsorted combo box, the item is
            ///     added to the end of the existing list of items. For a sorted combo box,
            ///     the item is inserted into the list according to its sorted position.
            ///     The item's toString() method is called to obtain the string that is
            ///     displayed in the combo box.
            ///     A SystemException occurs if there is insufficient space available to
            ///     store the new item.
            /// </devdoc>
            public void Insert(int index, object item) {
                owner.CheckNoDataSource();
 
                if (index < 0 || index > InnerArray.GetCount(0)) {
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                }
 
                if (item == null) {
                    throw new ArgumentNullException("item");
                }
 
                // If the combo box is sorted, then nust treat this like an add
                // because we are going to twiddle the index anyway.
                //
                if (owner.sorted) {
                    Add(item);
                }
                else {
                    InnerArray.Insert(index, item);
                    if (owner.IsHandleCreated) {
 
                        bool successful = false;
 
                        try {
                            owner.NativeInsert(index, item);
                            owner.UpdateMaxItemWidth(item, false);
                            successful = true;
                        }
                        finally {
                            if (!successful) {
                                InnerArray.RemoveAt(index);
                            }
                        }
                    }
                }
                owner.UpdateHorizontalExtent();
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.Remove"]/*' />
            /// <devdoc>
            ///     Removes the given item from the ListBox, provided that it is
            ///     actually in the list.
            /// </devdoc>
            public void Remove(object value) {
 
                int index = InnerArray.IndexOf(value, 0);
 
                if (index != -1) {
                    RemoveAt(index);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.ObjectCollection.RemoveAt"]/*' />
            /// <devdoc>
            ///     Removes an item from the ListBox at the given index.
            /// </devdoc>
            public void RemoveAt(int index) {
                owner.CheckNoDataSource();
 
                if (index < 0 || index >= InnerArray.GetCount(0)) {
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                }
 
                owner.UpdateMaxItemWidth(InnerArray.GetItem(index, 0), true);
 
                // VSWhidbey 95181: Update InnerArray before calling NativeRemoveAt to ensure that when
                // SelectedIndexChanged is raised (by NativeRemoveAt), InnerArray's state matches wrapped LB state.
                InnerArray.RemoveAt(index);
 
                if (owner.IsHandleCreated) {
                    owner.NativeRemoveAt(index);
                }
 
                owner.UpdateHorizontalExtent();
            }
 
            internal void SetItemInternal(int index, object value) {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }
 
                if (index < 0 || index >= InnerArray.GetCount(0)) {
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                }
 
                owner.UpdateMaxItemWidth(InnerArray.GetItem(index, 0), true);
                InnerArray.SetItem(index, value);
 
                // If the native control has been created, and the display text of the new list item object
                // is different to the current text in the native list item, recreate the native list item...
                if (owner.IsHandleCreated) {
                    bool selected = (owner.SelectedIndex == index);
                    if (String.Compare(this.owner.GetItemText(value), this.owner.NativeGetItemText(index), true, CultureInfo.CurrentCulture) != 0) {
                        owner.NativeRemoveAt(index);
                        owner.SelectedItems.SetSelected(index, false);
                        owner.NativeInsert(index, value);
                        owner.UpdateMaxItemWidth(value, false);
                        if (selected) {
                            owner.SelectedIndex = index;
                        }
                    }
                    else {
                        // NEW - FOR COMPATIBILITY REASONS
                        // Minimum compatibility fix for VSWhidbey 377287
                        if (selected) {
                            owner.OnSelectedIndexChanged(EventArgs.Empty); //will fire selectedvaluechanged
                        }
                    }
                }
                owner.UpdateHorizontalExtent();
            }
        } // end ObjectCollection
 
        //******************************************************************************************
        // IntegerCollection
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public class IntegerCollection : IList {
            private ListBox owner;
            private int[] innerArray;
            private int count=0;
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.IntegerCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IntegerCollection(ListBox owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.Count"]/*' />
            /// <devdoc>
            ///    <para>Number of current selected items.</para>
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    return count;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            bool IList.IsReadOnly {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(int item) {
                return IndexOf(item) != -1;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.Contains"]/*' />
            /// <internalonly/>
            bool IList.Contains(object item) {
                if (item is Int32) {
                    return Contains((int)item);
                }
                else {
                    return false;
                }
            }
 
            public void Clear()
            {
                count = 0;
                innerArray = null;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(int item) {
                int index = -1;
 
                if (innerArray != null) {
                    index = Array.IndexOf(innerArray, item);
 
                    // We initialize innerArray with more elements than needed in the method EnsureSpace, 
                    // and we don't actually remove element from innerArray in the method RemoveAt,
                    // so there maybe some elements which are not actually in innerArray will be found
                    // and we need to filter them out
                    if (index >= count) {
                        index = -1;
                    }
                }
 
                return index;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.IndexOf"]/*' />
            /// <internalonly/>
            int IList.IndexOf(object item) {
                if (item is Int32) {
                    return IndexOf((int)item);
                }
                else {
                    return -1;
                }
            }
 
 
            /// <devdoc>
            ///     Add a unique integer to the collection in sorted order.
            ///     A SystemException occurs if there is insufficient space available to
            ///     store the new item.
            /// </devdoc>
            private int AddInternal(int item) {
 
                EnsureSpace(1);
 
                int index = IndexOf(item);
                if (index == -1) {
                    innerArray[count++] = item;
                    Array.Sort(innerArray,0,count);
                    index = IndexOf(item);
                }
               return index;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.Add"]/*' />
            /// <devdoc>
            ///     Adds a unique integer to the collection in sorted order.
            ///     A SystemException occurs if there is insufficient space available to
            ///     store the new item.
            /// </devdoc>
            public int Add(int item) {
                int index = AddInternal(item);
                owner.UpdateCustomTabOffsets();
 
                return index;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.Add"]/*' />
            /// <internalonly/>
            [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
            [
                SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // "item" is the name of the param passed in.
                                                                                                            // So we don't have to localize it.
            ]
            int IList.Add(object item) {
                if (!(item is int)) {
                    throw new ArgumentException("item");
                }
                return Add((int)item);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.AddRange2"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void AddRange(int[] items) {
                AddRangeInternal((ICollection)items);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.AddRange1"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void AddRange(IntegerCollection value) {
                AddRangeInternal((ICollection)value);
            }
 
            /// <devdoc>
            ///     Add range that bypasses the data source check.
            /// </devdoc>
            [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
            [
                SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // "item" is the name of the param passed in.
                                                                                                            // So we don't have to localize it.
            ]
            private void AddRangeInternal(ICollection items) {
                if (items == null) {
                    throw new ArgumentNullException("items");
                }
                owner.BeginUpdate();
                try
                {
                    EnsureSpace(items.Count);
                    foreach(object item in items) {
                        if (!(item is int)) {
                            throw new ArgumentException("item");
                        }
                        else {
                            AddInternal((int)item);
                        }
                    }
                    owner.UpdateCustomTabOffsets();
                }
                finally
                {
                    owner.EndUpdate();
                }
            }
 
 
            /// <devdoc>
            ///     Ensures that our internal array has space for
            ///     the requested # of elements.
            /// </devdoc>
            private void EnsureSpace(int elements) {
                if (innerArray == null) {
                    innerArray = new int[Math.Max(elements, 4)];
                }
                else if (count + elements >= innerArray.Length) {
                    int newLength = Math.Max(innerArray.Length * 2, innerArray.Length + elements);
                    int[] newEntries = new int[newLength];
                    innerArray.CopyTo(newEntries, 0);
                    innerArray = newEntries;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.Clear"]/*' />
            /// <internalonly/>
            void IList.Clear() {
                Clear();
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxCantInsertIntoIntegerCollection));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.Remove"]/*' />
            /// <internalonly/>            
            [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
            [
                SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // "value" is the name of the param passed in.
                                                                                                            // So we don't have to localize it.
            ]
            void IList.Remove(object value) {
                if (!(value is int)) {
                    throw new ArgumentException("value");
                }
                Remove((int)value);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                RemoveAt(index);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.Remove1"]/*' />
            /// <devdoc>
            ///     Removes the given item from the array.  If
            ///     the item is not in the array, this does nothing.
            /// </devdoc>
            public void Remove(int item) {
 
                int index = IndexOf(item);
 
                if (index != -1) {
                    RemoveAt(index);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.RemoveAt1"]/*' />
            /// <devdoc>
            ///     Removes the item at the given index.
            /// </devdoc>
            public void RemoveAt(int index) {
                if (index < 0 || index >= count) {
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                }
 
                count--;
                for (int i = index; i < count; i++) {
                    innerArray[i] = innerArray[i+1];
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.this"]/*' />
            /// <devdoc>
            ///     Retrieves the specified selected item.
            /// </devdoc>
            [
                SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // "index" is the name of the param passed in.
                                                                                                            // So we don't have to localize it.
            ]
            public int this[int index] {
                get {
                    return innerArray[index];
                }
                [
                    SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")     // This exception already shipped.
                                                                                                            // We can't change its text.
                ]
                set {
 
                    if (index < 0 || index >= count) {
                        throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                    }
                    innerArray[index] = (int)value;
                    owner.UpdateCustomTabOffsets();
 
 
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="IntegerCollection.IList.this"]/*' />
            /// <internalonly/>            
            [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
            object IList.this[int index] {
                get {
                    return this[index];
                }
                [
                    SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters"),    // "value" is the name of the param.
                                                                                                                    // So we don't have to localize it.
                    SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")             // This exception already shipped.
                                                                                                                    // We can't change its text.
                ]
                set {
                    if (!(value is int)) {
                        throw new ArgumentException("value");
                    }
                    else {
                        this[index] = (int)value;
                    }
 
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.CopyTo"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void CopyTo(Array destination, int index) {
                int cnt = Count;
                for (int i = 0; i < cnt; i++) {
                    destination.SetValue(this[i], i + index);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.IntegerCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            IEnumerator IEnumerable.GetEnumerator() {
                return new CustomTabOffsetsEnumerator(this);
            }
 
            /// <devdoc>
            ///     EntryEnumerator is an enumerator that will enumerate over
            ///     a given state mask.
            /// </devdoc>
            private class CustomTabOffsetsEnumerator : IEnumerator {
                private IntegerCollection items;
                private int current;
 
                /// <devdoc>
                ///     Creates a new enumerator that will enumerate over the given state.
                /// </devdoc>
                public CustomTabOffsetsEnumerator(IntegerCollection items) {
                    this.items = items;
                    this.current = -1;
                }
 
                /// <devdoc>
                ///     Moves to the next element, or returns false if at the end.
                /// </devdoc>
                bool IEnumerator.MoveNext() {
 
                    if (current < items.Count - 1) {
                        current++;
                        return true;
                    }
                    else {
                        current = items.Count;
                        return false;
                    }
                }
 
                /// <devdoc>
                ///     Resets the enumeration back to the beginning.
                /// </devdoc>
                void IEnumerator.Reset() {
                    current = -1;
                }
 
                /// <devdoc>
                ///     Retrieves the current value in the enumerator.
                /// </devdoc>
                object IEnumerator.Current {
                    get {
                        if (current == -1 || current == items.Count) {
                            throw new InvalidOperationException(SR.GetString(SR.ListEnumCurrentOutOfRange));
                        }
 
                        return items[current];
                    }
                }
            }
        }
 
        //******************************************************************************************
 
        // SelectedIndices
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public class SelectedIndexCollection : IList {
            private ListBox owner;
 
            /* C#r: protected */
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.SelectedIndexCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public SelectedIndexCollection(ListBox owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.Count"]/*' />
            /// <devdoc>
            ///    <para>Number of current selected items.</para>
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    return owner.SelectedItems.Count;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(int selectedIndex) {
                return IndexOf(selectedIndex) != -1;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Contains"]/*' />
            /// <internalonly/>
            bool IList.Contains(object selectedIndex) {
                if (selectedIndex is Int32) {
                    return Contains((int)selectedIndex);
                }
                else {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(int selectedIndex) {
 
                // Just what does this do?  The selectedIndex parameter above is the index into the
                // main object collection.  We look at the state of that item, and if the state indicates
                // that it is selected, we get back the virtualized index into this collection.  Indexes on
                // this collection match those on the SelectedObjectCollection.
                if (selectedIndex >= 0 &&
                    selectedIndex < InnerArray.GetCount(0) &&
                    InnerArray.GetState(selectedIndex, SelectedObjectCollection.SelectedObjectMask)) {
 
                    return InnerArray.IndexOf(InnerArray.GetItem(selectedIndex, 0), SelectedObjectCollection.SelectedObjectMask);
                }
 
                return -1;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.IndexOf"]/*' />
            /// <internalonly/>
            int IList.IndexOf(object selectedIndex) {
                if (selectedIndex is Int32) {
                    return IndexOf((int)selectedIndex);
                }
                else {
                    return -1;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedIndexCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Clear"]/*' />
            /// <internalonly/>
            void IList.Clear() {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedIndexCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedIndexCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Remove"]/*' />
            /// <internalonly/>
            void IList.Remove(object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedIndexCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedIndexCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.this"]/*' />
            /// <devdoc>
            ///     Retrieves the specified selected item.
            /// </devdoc>
            public int this[int index] {
                get {
                    object identifier = InnerArray.GetEntryObject(index, SelectedObjectCollection.SelectedObjectMask);
                    return InnerArray.IndexOfIdentifier(identifier, 0);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedIndexCollection.IList.this"]/*' />
            /// <internalonly/>
            object IList.this[int index] {
                get {
                    return this[index];
                }
                set {
                    throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedIndexCollectionIsReadOnly));
                }
            }
 
            /// <devdoc>
            ///     This is the item array that stores our data.  We share this backing store
            ///     with the main object collection.
            /// </devdoc>
            private ItemArray InnerArray {
                get {
                    owner.SelectedItems.EnsureUpToDate();
                    return ((ObjectCollection)owner.Items).InnerArray;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.CopyTo"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void CopyTo(Array destination, int index) {
                int cnt = Count;
                for (int i = 0; i < cnt; i++) {
                    destination.SetValue(this[i], i + index);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.ClearSelected"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void Clear() {
                if (owner != null) {
                    owner.ClearSelected();
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.Add"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void Add(int index) {
                if (owner != null) {
                    ObjectCollection items = owner.Items;
                    if (items != null) {
                        if (index != -1 && !Contains(index)) {
                            owner.SetSelected(index, true);
                        }
                    }
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.Remove"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void Remove(int index) {
                if (owner != null) {
                    ObjectCollection items = owner.Items;
                    if (items != null) {
                        if (index != -1 && Contains(index)) {
                            owner.SetSelected(index, false);
                        }
                    }
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedIndexCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                return new SelectedIndexEnumerator(this);
            }
 
            /// <devdoc>
            ///     EntryEnumerator is an enumerator that will enumerate over
            ///     a given state mask.
            /// </devdoc>
            private class SelectedIndexEnumerator : IEnumerator {
                private SelectedIndexCollection items;
                private int current;
 
                /// <devdoc>
                ///     Creates a new enumerator that will enumerate over the given state.
                /// </devdoc>
                public SelectedIndexEnumerator(SelectedIndexCollection items) {
                    this.items = items;
                    this.current = -1;
                }
 
                /// <devdoc>
                ///     Moves to the next element, or returns false if at the end.
                /// </devdoc>
                bool IEnumerator.MoveNext() {
 
                    if (current < items.Count - 1) {
                        current++;
                        return true;
                    }
                    else {
                        current = items.Count;
                        return false;
                    }
                }
 
                /// <devdoc>
                ///     Resets the enumeration back to the beginning.
                /// </devdoc>
                void IEnumerator.Reset() {
                    current = -1;
                }
 
                /// <devdoc>
                ///     Retrieves the current value in the enumerator.
                /// </devdoc>
                object IEnumerator.Current {
                    get {
                        if (current == -1 || current == items.Count) {
                            throw new InvalidOperationException(SR.GetString(SR.ListEnumCurrentOutOfRange));
                        }
 
                        return items[current];
                    }
                }
            }
        }
 
        // Should be "ObjectCollection", except we already have one of those.
        /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public class SelectedObjectCollection : IList {
 
            // This is the bitmask used within ItemArray to identify selected objects.
            internal static int SelectedObjectMask = ItemArray.CreateMask();
 
            private ListBox owner;
            private bool    stateDirty;
            private int     lastVersion;
            private int     count;
 
            /* C#r: protected */
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.SelectedObjectCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public SelectedObjectCollection(ListBox owner) {
                this.owner = owner;
                this.stateDirty = true;
                this.lastVersion = -1;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.Count"]/*' />
            /// <devdoc>
            ///     Number of current selected items.
            /// </devdoc>
            public int Count {
                get {
                    if (owner.IsHandleCreated) {
                        SelectionMode current = (owner.selectionModeChanging) ? owner.cachedSelectionMode : owner.selectionMode;
                        switch (current) {
 
                            case SelectionMode.None:
                                return 0;
 
                            case SelectionMode.One:
                                int index = owner.SelectedIndex;
                                if (index >= 0) {
                                    return 1;
                                }
                                return 0;
 
                            case SelectionMode.MultiSimple:
                            case SelectionMode.MultiExtended:
                                return unchecked( (int) (long)owner.SendMessage(NativeMethods.LB_GETSELCOUNT, 0, 0));
                        }
 
                        return 0;
                    }
 
                    // If the handle hasn't been created, we must do this the hard way.
                    // Getting the count when using a mask is expensive, so cache it.
                    //
                    if (lastVersion != InnerArray.Version) {
                        lastVersion = InnerArray.Version;
                        count = InnerArray.GetCount(SelectedObjectMask);
                    }
 
                    return count;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return true;
                }
            }
 
            /// <devdoc>
            ///     Called by the list box to dirty the selected item state.
            /// </devdoc>
            internal void Dirty() {
                stateDirty = true;
            }
 
            /// <devdoc>
            ///     This is the item array that stores our data.  We share this backing store
            ///     with the main object collection.
            /// </devdoc>
            private ItemArray InnerArray {
                get {
                    EnsureUpToDate();
                    return ((ObjectCollection)owner.Items).InnerArray;
                }
            }
 
 
            /// <devdoc>
            ///     This is the function that Ensures that the selections are uptodate with
            ///     current listbox handle selections.
            /// </devdoc>
            internal void EnsureUpToDate() {
                if (stateDirty) {
                     stateDirty = false;
                     if (owner.IsHandleCreated) {
                         owner.NativeUpdateSelection();
                     }
                }
            }
 
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(object selectedObject) {
                return IndexOf(selectedObject) != -1;
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(object selectedObject) {
                return InnerArray.IndexOf(selectedObject, SelectedObjectMask);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedObjectCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.Clear"]/*' />
            /// <internalonly/>
            void IList.Clear() {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedObjectCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedObjectCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.Remove"]/*' />
            /// <internalonly/>
            void IList.Remove(object value) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedObjectCollectionIsReadOnly));
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedObjectCollectionIsReadOnly));
            }
 
            // A new internal method used in SelectedIndex getter...
            // For a Multi select ListBox there can be two items with the same name ...
            // and hence a object comparison is required...
            // This method returns the "object" at the passed index rather than the "item" ...
            // this "object" is then compared in the IndexOf( ) method of the itemsCollection.
            //
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="SelectedObjectCollection.IList.GetObjectAt"]/*' />
            /// <internalonly/>
            internal object GetObjectAt(int index) {
               return InnerArray.GetEntryObject(index, SelectedObjectCollection.SelectedObjectMask);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.this"]/*' />
            /// <devdoc>
            ///     Retrieves the specified selected item.
            /// </devdoc>
            [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
            public object this[int index] {
                get {
                    return InnerArray.GetItem(index, SelectedObjectMask);
                }
                set {
                    throw new NotSupportedException(SR.GetString(SR.ListBoxSelectedObjectCollectionIsReadOnly));
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.CopyTo"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void CopyTo(Array destination, int index) {
                int cnt = InnerArray.GetCount(SelectedObjectMask);
                for (int i = 0; i < cnt; i++) {
                    destination.SetValue(InnerArray.GetItem(i, SelectedObjectMask), i + index);
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                return InnerArray.GetEnumerator(SelectedObjectMask);
            }
 
            /// <devdoc>
            ///     This method returns if the actual item index is selected.  The index is the index to the MAIN
            ///     collection, not this one.
            /// </devdoc>
            internal bool GetSelected(int index) {
                return InnerArray.GetState(index, SelectedObjectMask);
            }
 
            // when SelectedObjectsCollection::ItemArray is accessed we push the selection from Native ListBox into our .Net ListBox - see EnsureUpToDate()
            // when we create the handle we need to be able to do the opposite : push the selection from .Net ListBox into Native ListBox
            internal void PushSelectionIntoNativeListBox(int index) {
                // we can't use ItemArray accessor because this will wipe out our Selection collection
                bool selected = ((ObjectCollection)owner.Items).InnerArray.GetState(index, SelectedObjectMask);
                // push selection only if the item is actually selected
                // this also takes care of the case where owner.SelectionMode == SelectionMode.One
                if (selected) {
                    this.owner.NativeSetSelected(index, true /*we signal selection to the native listBox only if the item is actually selected*/);
                }
            }
 
            /// <devdoc>
            ///     Same thing for GetSelected.
            /// </devdoc>
            internal void SetSelected(int index, bool value) {
                InnerArray.SetState(index, SelectedObjectMask, value);
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.ClearSelected"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void Clear() {
                if (owner != null) {
                    owner.ClearSelected();
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.Add"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void Add(object value)  {
                if (owner != null) {
                    ObjectCollection items = owner.Items;
                    if (items != null && value != null) {
                        int index = items.IndexOf(value);
                        if (index != -1 && !GetSelected(index)) {
                            owner.SelectedIndex = index;
                        }
                    }
                }
            }
 
            /// <include file='doc\ListBox.uex' path='docs/doc[@for="ListBox.SelectedObjectCollection.Remove"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void Remove(object value) {
                if (owner != null) {
                    ObjectCollection items = owner.Items;
                    if (items != null & value != null) {
                        int index = items.IndexOf(value);
                        if (index != -1 && GetSelected(index)) {
                            owner.SetSelected(index, false);
                        }
                    }
                }
            }
        }
 
        private sealed class ListBoxAccessibleObject : ControlAccessibleObject {
            private readonly ListBox owner;
 
            public ListBoxAccessibleObject(ListBox control) : base(control) {
                this.owner = control;
            }
 
            #region IAccessibleEx related overrides
 
            internal override bool IsIAccessibleExSupported() {
                return true;
            }
 
            internal override object GetObjectForChild(int childId) {
                Accessibility.IAccessible systemIAccessible = this.GetSystemIAccessibleInternal();
                if (IsChildIdValid(childId, systemIAccessible)) {
                    if ((AccessibleRole)systemIAccessible.accRole[childId] == AccessibleRole.ListItem) {
                        return new ListBoxItemAccessibleObject(this.owner, childId);
                    }
                }
 
                return base.GetObjectForChild(childId);
            }
 
            #endregion
 
            private static bool IsChildIdValid(int childId, Accessibility.IAccessible systemIAccessible) {
                // 0 (i.e. CHILDID_SELF) references the control itself, so it is considered "invalid" in this scope
                return childId > 0 && childId <= systemIAccessible.accChildCount;
            }
 
            private sealed class ListBoxItemAccessibleObject : AccessibleObject {
                private readonly int childId;
                private readonly ListBox owner;
 
                public ListBoxItemAccessibleObject(ListBox owner, int childId) {
                    Debug.Assert(owner != null, $"{nameof(owner)} should not be null");
                    Debug.Assert(childId > 0, $"{nameof(childId)} has unexpected value");
 
                    this.owner = owner;
                    this.childId = childId;
                }
 
                #region IAccessibleEx related overrides
 
                internal override bool IsIAccessibleExSupported() {
                    return true;
                }
 
                internal override bool IsPatternSupported(int patternId) {
                    if (patternId == NativeMethods.UIA_ScrollItemPatternId) {
                        return true;
                    }
                    else {
                        return base.IsPatternSupported(patternId);
                    }
                }
 
                #endregion
 
                #region IScrollItemProvider related overrides
 
                internal override void ScrollIntoView() {
                    if (this.owner.IsHandleCreated && IsChildIdValid(this.childId, this.owner.AccessibilityObject.GetSystemIAccessibleInternal())) {
                        this.owner.TopIndex = this.childId - 1;
                    }
                }
 
                #endregion
            }
        }
    }
}