File: winforms\Managed\System\WinForms\ListView.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//-----------------------------------------------------------------------------
// <copyright file="ListView.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
/*
 */
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.ComponentModel;
    using System.Diagnostics;
    using System;
    using System.Drawing.Design;
    using System.Security.Permissions;
    using System.Security;
    using System.Drawing;
    using System.Windows.Forms.Internal;
    using System.ComponentModel.Design;
    using System.Collections;
    using Microsoft.Win32;
    using System.Globalization;
    using System.Windows.Forms.Layout;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Forms.VisualStyles;
 
    /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView"]/*' />
    /// <devdoc>
    ///    <para>
    ///       Displays a list of items in one of four
    ///       views. Each item displays a caption and optionally an image.
    ///
    ///    </para>
    /// </devdoc>
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    Docking(DockingBehavior.Ask),
    Designer("System.Windows.Forms.Design.ListViewDesigner, " + AssemblyRef.SystemDesign),
    DefaultProperty("Items"),
    DefaultEvent("SelectedIndexChanged"),
    SRDescription(SR.DescriptionListView)
    ]
    public class ListView : Control {
 
        //members
        private const int MASK_HITTESTFLAG = 0x00F7;
 
        private static readonly object EVENT_CACHEVIRTUALITEMS                 = new object();
        private static readonly object EVENT_COLUMNREORDERED                   = new object();
        private static readonly object EVENT_COLUMNWIDTHCHANGED                = new object();
        private static readonly object EVENT_COLUMNWIDTHCHANGING               = new object();
        private static readonly object EVENT_DRAWCOLUMNHEADER                  = new object();
        private static readonly object EVENT_DRAWITEM                          = new object();
        private static readonly object EVENT_DRAWSUBITEM                       = new object();
        private static readonly object EVENT_ITEMSELECTIONCHANGED              = new object();
        private static readonly object EVENT_RETRIEVEVIRTUALITEM               = new object();
        private static readonly object EVENT_SEARCHFORVIRTUALITEM              = new object();
        private static readonly object EVENT_SELECTEDINDEXCHANGED              = new object();
        private static readonly object EVENT_VIRTUALITEMSSELECTIONRANGECHANGED = new object();
        private static readonly object EVENT_RIGHTTOLEFTLAYOUTCHANGED           = new object();
 
 
        private ItemActivation activation     = ItemActivation.Standard;
        private ListViewAlignment alignStyle  = ListViewAlignment.Top;
        private BorderStyle borderStyle       = System.Windows.Forms.BorderStyle.Fixed3D;
        private ColumnHeaderStyle headerStyle = ColumnHeaderStyle.Clickable;
        private SortOrder sorting             = SortOrder.None;
        private View viewStyle                = System.Windows.Forms.View.LargeIcon;
        private string toolTipCaption = String.Empty;
 
 
        private const int   LISTVIEWSTATE_ownerDraw                           = 0x00000001;
        private const int   LISTVIEWSTATE_allowColumnReorder                  = 0x00000002;
        private const int   LISTVIEWSTATE_autoArrange                         = 0x00000004;
        private const int   LISTVIEWSTATE_checkBoxes                          = 0x00000008;
        private const int   LISTVIEWSTATE_fullRowSelect                       = 0x00000010;
        private const int   LISTVIEWSTATE_gridLines                           = 0x00000020;
        private const int   LISTVIEWSTATE_hideSelection                       = 0x00000040;
        private const int   LISTVIEWSTATE_hotTracking                         = 0x00000080;
        private const int   LISTVIEWSTATE_labelEdit                           = 0x00000100;
        private const int   LISTVIEWSTATE_labelWrap                           = 0x00000200;
        private const int   LISTVIEWSTATE_multiSelect                         = 0x00000400;
        private const int   LISTVIEWSTATE_scrollable                          = 0x00000800;
        private const int   LISTVIEWSTATE_hoverSelection                      = 0x00001000;
        private const int   LISTVIEWSTATE_nonclickHdr                         = 0x00002000;
        private const int   LISTVIEWSTATE_inLabelEdit                         = 0x00004000;
        private const int   LISTVIEWSTATE_showItemToolTips                    = 0x00008000;
        private const int   LISTVIEWSTATE_backgroundImageTiled                = 0x00010000;
        private const int   LISTVIEWSTATE_columnClicked                       = 0x00020000;
        private const int   LISTVIEWSTATE_doubleclickFired                    = 0x00040000;
        private const int   LISTVIEWSTATE_mouseUpFired                        = 0x00080000;
        private const int   LISTVIEWSTATE_expectingMouseUp                    = 0x00100000;
        private const int   LISTVIEWSTATE_comctlSupportsVisualStyles          = 0x00200000;
        private const int   LISTVIEWSTATE_comctlSupportsVisualStylesTested    = 0x00400000;
        private const int   LISTVIEWSTATE_showGroups                          = 0x00800000;
        private const int   LISTVIEWSTATE_handleDestroyed                     = 0x01000000; // while we are recreating the handle we want to know if we can still get data from the handle
        private const int   LISTVIEWSTATE_virtualMode                         = 0x02000000;
        private const int   LISTVIEWSTATE_headerControlTracking               = 0x04000000;
        private const int   LISTVIEWSTATE_itemCollectionChangedInMouseDown    = 0x08000000;
        private const int   LISTVIEWSTATE_flipViewToLargeIconAndSmallIcon     = 0x10000000;
        private const int   LISTVIEWSTATE_headerDividerDblClick               = 0x20000000;
        private const int   LISTVIEWSTATE_columnResizeCancelled               = 0x40000000;
 
        private const int   LISTVIEWSTATE1_insertingItemsNatively             = 0x00000001;
        private const int   LISTVIEWSTATE1_cancelledColumnWidthChanging       = 0x00000002;
        private const int   LISTVIEWSTATE1_disposingImageLists                = 0x00000004;
        private const int   LISTVIEWSTATE1_useCompatibleStateImageBehavior        = 0x00000008;
        private const int   LISTVIEWSTATE1_selectedIndexChangedSkipped        = 0x00000010;
 
        private const int   LVTOOLTIPTRACKING = 0x30;
        private const int   MAXTILECOLUMNS = 20;
 
        // PERF: take all the bools and put them into a state variable
        private System.Collections.Specialized.BitVector32      listViewState; // see LISTVIEWSTATE_ consts above
        private System.Collections.Specialized.BitVector32      listViewState1;// see LISTVIEWSTATE1_ consts above
 
 
 
        // Ownerdraw data caches...  Only valid inside WM_PAINT.
        // 
 
        private Color odCacheForeColor = SystemColors.WindowText;
        private Color odCacheBackColor = SystemColors.Window;
        private Font odCacheFont = null;
        private IntPtr odCacheFontHandle = IntPtr.Zero;
        private FontHandleWrapper odCacheFontHandleWrapper = null;
 
        private ImageList imageListLarge;
        private ImageList imageListSmall;
        private ImageList imageListState;
 
        private MouseButtons downButton;
        private int itemCount;
        private int columnIndex = 0;
        private int topIndex;           // Needed for the HACK ALERT below.
        private bool hoveredAlready  = false;
 
        private bool             rightToLeftLayout = false;
 
 
        // member variables which are used for VirtualMode
        private int virtualListSize = 0;
 
        private ListViewGroup defaultGroup = null;
 
        // Invariant: the table always contains all Items in the ListView, and maps IDs -> Items.
        // listItemsArray is null if the handle is created; otherwise, it contains all Items.
        // We do not try to sort listItemsArray as items are added, but during a handle recreate
        // we will make sure we get the items in the same order the ListView displays them.
        private Hashtable listItemsTable = new Hashtable(); // elements are ListViewItem's
        private ArrayList listItemsArray = new ArrayList(); // elements are ListViewItem's
 
        private Size tileSize = Size.Empty;
 
 
        // when we are in delayed update mode (that is when BeginUpdate has been called, we want to cache the items to
        // add until EndUpdate is called. To do that, we push in an array list into our PropertyStore
        // under this key.  When Endupdate is fired, we process the items all at once.
        //
        private static readonly int PropDelayedUpdateItems          = PropertyStore.CreateKey();
 
        private int  updateCounter = 0; // the counter we use to track how many BeginUpdate/EndUpdate calls there have been.
 
        private ColumnHeader[] columnHeaders;
        private ListViewItemCollection listItemCollection;
        private ColumnHeaderCollection columnHeaderCollection;
        private CheckedIndexCollection checkedIndexCollection;
        private CheckedListViewItemCollection checkedListViewItemCollection;
        private SelectedListViewItemCollection selectedListViewItemCollection;
        private SelectedIndexCollection selectedIndexCollection;
        private ListViewGroupCollection groups;
        private ListViewInsertionMark insertionMark;
        private LabelEditEventHandler onAfterLabelEdit;
        private LabelEditEventHandler onBeforeLabelEdit;
        private ColumnClickEventHandler onColumnClick;
        private EventHandler onItemActivate;
        private ItemCheckedEventHandler onItemChecked;
        private ItemDragEventHandler onItemDrag;
        private ItemCheckEventHandler onItemCheck;
        private ListViewItemMouseHoverEventHandler onItemMouseHover;
 
        // IDs for identifying ListViewItem's
        private int nextID = 0;
 
 
        // We save selected and checked items between handle creates.
        private List<ListViewItem> savedSelectedItems;
        private List<ListViewItem> savedCheckedItems;
 
        // Sorting
        private IComparer listItemSorter = null;
 
        private ListViewItem prevHoveredItem = null;
 
        // Background image stuff
        // Because we have to create a temporary file and the OS does not clean up the temporary files from the machine
        // we have to do that ourselves
        string backgroundImageFileName = string.Empty;
 
        // it *seems* that if the user changes the background image then the win32 listView will hang on to the previous
        // background image until it gets the first WM_PAINT message -  I use words like *seems* because nothing is guaranteed
        // when it comes to win32 listView.
        // so our wrapper has to hang on to the previousBackgroundImageFileNames and destroy them after it gets the first WM_PAINT message
        // vsWhidbey 243708
        int bkImgFileNamesCount = -1;
        string[] bkImgFileNames = null;
        private const int BKIMGARRAYSIZE = 8;
 
        // If the user clicked on the column divider, the native ListView fires HDN_ITEMCHANGED on each mouse up event.
        // This means that even if the user did not change the column width our wrapper will still think
        // that the column header width changed.
        // We need to make our ListView wrapper more robust in face of this limitation inside ComCtl ListView.
        // columnHeaderClicked will be set in HDN_BEGINTRACK and reset in HDN_ITEMCHANGED.
        ColumnHeader columnHeaderClicked;
        int columnHeaderClickedWidth;
 
        // The user cancelled the column width changing event.
        // We cache the NewWidth supplied by the user and use it on HDN_ENDTRACK to set the final column width.
        int newWidthForColumnWidthChangingCancelled = -1;
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ListView"]/*' />
        /// <devdoc>
        ///     Creates an empty ListView with default styles.
        /// </devdoc>
        public ListView() : base() {
 
            int listViewStateFlags = LISTVIEWSTATE_scrollable |
                                     LISTVIEWSTATE_multiSelect |
                                     LISTVIEWSTATE_labelWrap |
                                     LISTVIEWSTATE_autoArrange |
                                     LISTVIEWSTATE_showGroups;
            if (!AccessibilityImprovements.Level3) {
                // Show grey rectangle around the selected list item if the list view is out of focus.
                listViewStateFlags |= LISTVIEWSTATE_hideSelection;
            }
 
            listViewState = new System.Collections.Specialized.BitVector32(listViewStateFlags);
 
            listViewState1 = new System.Collections.Specialized.BitVector32(LISTVIEWSTATE1_useCompatibleStateImageBehavior);
            SetStyle(ControlStyles.UserPaint, false);
            SetStyle(ControlStyles.StandardClick, false);
            SetStyle(ControlStyles.UseTextForAccessibility, false);
 
            odCacheFont = Font;
            odCacheFontHandle = FontHandle;
            SetBounds(0,0,121,97);
 
            listItemCollection = new ListViewItemCollection(new ListViewNativeItemCollection(this));
            columnHeaderCollection = new ColumnHeaderCollection(this);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Activation"]/*' />
        /// <devdoc>
        ///     The activation style specifies what kind of user action is required to
        ///     activate an item.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(ItemActivation.Standard),
        SRDescription(SR.ListViewActivationDescr)
        ]
        public ItemActivation Activation {
            get {
                return activation;
            }
 
            set {
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)ItemActivation.Standard, (int)ItemActivation.TwoClick)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ItemActivation));
                }
 
                if (this.HotTracking && value != ItemActivation.OneClick) {
                    throw new ArgumentException(SR.GetString(SR.ListViewActivationMustBeOnWhenHotTrackingIsOn), "value");
                }
 
                if (activation != value) {
                    activation = value;
                    UpdateExtendedStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Alignment"]/*' />
        /// <devdoc>
        ///     The alignment style specifies which side of the window items are aligned
        ///     to by default
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(ListViewAlignment.Top),
        Localizable(true),
        SRDescription(SR.ListViewAlignmentDescr)
        ]
        public ListViewAlignment Alignment {
            get {
                return alignStyle;
            }
 
            set {
                // using this as ListViewAlignment has discontiguous values.
                if (!ClientUtils.IsEnumValid_NotSequential(value,
                                                (int)value,
                                                (int)ListViewAlignment.Default,
                                                (int)ListViewAlignment.Top,
                                                (int)ListViewAlignment.Left,
                                                (int)ListViewAlignment.SnapToGrid))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ListViewAlignment));
                }
                if (alignStyle != value) {
                    alignStyle = value;
                    RecreateHandleInternal();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.AllowColumnReorder"]/*' />
        /// <devdoc>
        ///     Specifies whether the user can drag column headers to
        ///     other column positions, thus changing the order of displayed columns.
        ///     This property is only meaningful in Details view.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListViewAllowColumnReorderDescr)
        ]
        public bool AllowColumnReorder {
            get {
                return listViewState[LISTVIEWSTATE_allowColumnReorder];
            }
 
            set {
                if (AllowColumnReorder != value) {
                    listViewState[LISTVIEWSTATE_allowColumnReorder] = value;
                    UpdateExtendedStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.AutoArrange"]/*' />
        /// <devdoc>
        ///     If AutoArrange is true items are automatically arranged according to
        ///     the alignment property.  Items are also kept snapped to grid.
        ///     This property is only meaningful in Large Icon or Small Icon views.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.ListViewAutoArrangeDescr)
        ]
        public bool AutoArrange {
            get {
                return listViewState[LISTVIEWSTATE_autoArrange];
            }
 
            set {
                if (AutoArrange != value) {
                    listViewState[LISTVIEWSTATE_autoArrange] = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.BackColor"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public override Color BackColor {
            get {
                if (ShouldSerializeBackColor()) {
                    return base.BackColor;
                }
                else {
                    return SystemColors.Window;
                }
            }
            set {
                base.BackColor = value;
                if (IsHandleCreated) {
                    SendMessage(NativeMethods.LVM_SETBKCOLOR, 0, ColorTranslator.ToWin32(BackColor));
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.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\ListView.uex' path='docs/doc[@for="ListView.BackgroundImageLayoutChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageLayoutChanged {
            add {
                base.BackgroundImageLayoutChanged += value;
            }
            remove {
                base.BackgroundImageLayoutChanged -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.BackgroundImageTiled"]/*' />
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(false),
        SRDescription(SR.ListViewBackgroundImageTiledDescr)
        ]
        public bool BackgroundImageTiled {
            get {
                return listViewState[LISTVIEWSTATE_backgroundImageTiled];
            }
            set {
                if (BackgroundImageTiled != value) {
                    listViewState[LISTVIEWSTATE_backgroundImageTiled] = value;
                    if (IsHandleCreated && BackgroundImage != null) {
                        // Don't call SetBackgroundImage because SetBackgroundImage deletes the existing image
                        // We don't need to delete it and this causes BAD problems w/ the Win32 list view control.
                        NativeMethods.LVBKIMAGE lvbkImage = new NativeMethods.LVBKIMAGE();
                        lvbkImage.xOffset = 0;
                        lvbkImage.yOffset = 0;
 
                        if (BackgroundImageTiled)
                            lvbkImage.ulFlags = NativeMethods.LVBKIF_STYLE_TILE;
                        else
                            lvbkImage.ulFlags = NativeMethods.LVBKIF_STYLE_NORMAL;
 
                        lvbkImage.ulFlags  |= NativeMethods.LVBKIF_SOURCE_URL;
                        lvbkImage.pszImage = this.backgroundImageFileName;
                        lvbkImage.cchImageMax = this.backgroundImageFileName.Length + 1;
 
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETBKIMAGE, 0, lvbkImage);
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.BorderStyle"]/*' />
        /// <devdoc>
        ///     Describes the border style of the window.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(BorderStyle.Fixed3D),
        DispId(NativeMethods.ActiveX.DISPID_BORDERSTYLE),
        SRDescription(SR.borderStyleDescr)
        ]
        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 (borderStyle != value) {
                    borderStyle = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckBoxes"]/*' />
        /// <devdoc>
        ///     If CheckBoxes is true, every item will display a checkbox next
        ///     to it.  The user can change the state of the item by clicking the checkbox.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(false),
        SRDescription(SR.ListViewCheckBoxesDescr)
        ]
        public bool CheckBoxes {
            get {
                return listViewState[LISTVIEWSTATE_checkBoxes];
            }
 
            set {
                if (this.UseCompatibleStateImageBehavior) {
                    if (CheckBoxes != value) {
                        
                        if (value && this.View == View.Tile) {
                            throw new NotSupportedException(SR.GetString(SR.ListViewCheckBoxesNotSupportedInTileView));
                        }
 
                        if (CheckBoxes) {
                            // Save away the checked items just in case we re-activate checkboxes
                            //
                            savedCheckedItems = new List<ListViewItem>(CheckedItems.Count);
                            ListViewItem[] items = new ListViewItem[CheckedItems.Count];
                            CheckedItems.CopyTo(items, 0);
                            for (int i = 0; i < items.Length; i ++) {
                                savedCheckedItems.Add(items[i]);
                            }
                        }
                    
                        listViewState[LISTVIEWSTATE_checkBoxes] = value;
                        UpdateExtendedStyles();
                        
                        if (CheckBoxes && savedCheckedItems != null) {
                            // Check the saved checked items.
                            //
                            if (savedCheckedItems.Count > 0) {
                                foreach(ListViewItem item in savedCheckedItems) {
                                    item.Checked = true;
                                }
                            }
                            savedCheckedItems = null;
                        }                                       
                                           
                        // Comctl should handle auto-arrange for us, but doesn't
                        if (AutoArrange)
                            ArrangeIcons(Alignment);
                    }
                } else {
                    if (CheckBoxes != value) {
 
                        if (value && this.View == View.Tile) {
                            throw new NotSupportedException(SR.GetString(SR.ListViewCheckBoxesNotSupportedInTileView));
                        }
 
                        if (CheckBoxes) {
                            // Save away the checked items just in case we re-activate checkboxes
                            //
                            savedCheckedItems = new List<ListViewItem>(CheckedItems.Count);
                            ListViewItem[] items = new ListViewItem[CheckedItems.Count];
                            CheckedItems.CopyTo(items, 0);
                            for (int i = 0; i < items.Length; i ++) {
                                savedCheckedItems.Add(items[i]);
                            }
                        }
 
                        listViewState[LISTVIEWSTATE_checkBoxes] = value;
 
                        if ((!value && this.StateImageList != null && this.IsHandleCreated) ||
                            (!value && this.Alignment == ListViewAlignment.Left && this.IsHandleCreated) ||
                            (value && this.View == View.List && this.IsHandleCreated) ||
                            (value && (this.View == View.SmallIcon || this.View == View.LargeIcon) && this.IsHandleCreated)) {
                            // we have to recreate the handle when we are going from CheckBoxes == true to CheckBoxes == false
                            // if we want to have the bitmaps from the StateImageList on the items.
 
                            /**
                            ***  there are a LOT of bugs w/ setting CheckBoxes to TRUE when in View.List, View.SmallIcon or View.LargeIcon:
                            ***  vsWhidbey 168958, 309997, 304288, 156370
                            ***
                            ***  these bugs are caused by the fact that the win32 ListView control does not resize its column width
                            ***  when CheckBoxes changes from FALSE to TRUE.
                            ***  we need to recreate the handle when we set CheckBoxes to TRUE
                            **/
                            RecreateHandleInternal();
                        } else {
                            UpdateExtendedStyles();
 
                        }
 
                        if (CheckBoxes && savedCheckedItems != null) {
                            // Check the saved checked items.
                            //
                            if (savedCheckedItems.Count > 0) {
                                foreach(ListViewItem item in savedCheckedItems) {
                                    item.Checked = true;
                                }
                            }
                            savedCheckedItems = null;
                        }
 
                        // Setting the LVS_CHECKBOXES window style also causes the ListView to display the default checkbox
                        // images rather than the user specified StateImageList.  We send a LVM_SETIMAGELIST to restore the
                        // user's images.
                        if (IsHandleCreated && imageListState != null) {
                            if (CheckBoxes) { // we want custom checkboxes
                                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, imageListState.Handle);
                            } else {
                                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, IntPtr.Zero);
                            }
                        }
 
                        // Comctl should handle auto-arrange for us, but doesn't
                        if (AutoArrange) {
                            ArrangeIcons(Alignment);
                        }
 
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndices"]/*' />
        /// <devdoc>
        ///     The indices of the currently checked list items.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ]
        public CheckedIndexCollection CheckedIndices {
            get {
                if (checkedIndexCollection == null) {
                    checkedIndexCollection = new CheckedIndexCollection(this);
                }
                return checkedIndexCollection;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedItems"]/*' />
        /// <devdoc>
        ///     The currently checked list items.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ]
        public CheckedListViewItemCollection CheckedItems {
            get {
                if (checkedListViewItemCollection == null) {
                    checkedListViewItemCollection = new CheckedListViewItemCollection(this);
                }
                return checkedListViewItemCollection;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Columns"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Editor("System.Windows.Forms.Design.ColumnHeaderCollectionEditor, " + AssemblyRef.SystemDesign,typeof(UITypeEditor)),
        SRDescription(SR.ListViewColumnsDescr),
        Localizable(true),
        MergableProperty(false)
        ]
        public ColumnHeaderCollection Columns {
            get {
                return columnHeaderCollection;
            }
        }
 
        /// <devdoc>
        ///     Actually we are using this to indicate whether ComCtl supports
        ///     the new listview features. This is true for ComCtl 6 and above, same as
        ///     the versions that support visual styles.
        /// </devdoc>
        private bool ComctlSupportsVisualStyles {
             get {
                  if(!listViewState[LISTVIEWSTATE_comctlSupportsVisualStylesTested])  {
                      listViewState[LISTVIEWSTATE_comctlSupportsVisualStylesTested] = true;
                      listViewState[LISTVIEWSTATE_comctlSupportsVisualStyles] = Application.ComCtlSupportsVisualStyles;
                  }
                  return listViewState[LISTVIEWSTATE_comctlSupportsVisualStyles];
              }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CreateParams"]/*' />
        /// <devdoc>
        ///     Computes the handle creation parameters for the ListView control.
        /// </devdoc>
        /// <internalonly/>
        protected override CreateParams CreateParams {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get {
                CreateParams cp = base.CreateParams;
 
                cp.ClassName = NativeMethods.WC_LISTVIEW;
 
                // Keep the scrollbar if we are just updating styles...
                //
                if (IsHandleCreated) {
                    int currentStyle = unchecked((int)((long)UnsafeNativeMethods.GetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE)));
                    cp.Style |= (currentStyle & (NativeMethods.WS_HSCROLL | NativeMethods.WS_VSCROLL));
                }
 
                cp.Style |= NativeMethods.LVS_SHAREIMAGELISTS;
 
                switch (alignStyle) {
                    case ListViewAlignment.Top:
                        cp.Style |= NativeMethods.LVS_ALIGNTOP;
                        break;
                    case ListViewAlignment.Left:
                        cp.Style |= NativeMethods.LVS_ALIGNLEFT;
                        break;
                }
 
                if (AutoArrange)
                    cp.Style |= NativeMethods.LVS_AUTOARRANGE;
 
                switch (borderStyle) {
                    case BorderStyle.Fixed3D:
                        cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
                        break;
                    case BorderStyle.FixedSingle:
                        cp.Style |= NativeMethods.WS_BORDER;
                        break;
                }
 
                switch (headerStyle) {
                    case ColumnHeaderStyle.None:
                        cp.Style |= NativeMethods.LVS_NOCOLUMNHEADER;
                        break;
                    case ColumnHeaderStyle.Nonclickable:
                        cp.Style |= NativeMethods.LVS_NOSORTHEADER;
                        break;
                }
 
                if (LabelEdit)
                    cp.Style |= NativeMethods.LVS_EDITLABELS;
 
                if (!LabelWrap)
                    cp.Style |= NativeMethods.LVS_NOLABELWRAP;
 
                if (!HideSelection)
                    cp.Style |= NativeMethods.LVS_SHOWSELALWAYS;
 
                if (!MultiSelect)
                    cp.Style |= NativeMethods.LVS_SINGLESEL;
 
                if (listItemSorter == null) {
                    switch (sorting) {
                        case SortOrder.Ascending:
                            cp.Style |= NativeMethods.LVS_SORTASCENDING;
                            break;
                        case SortOrder.Descending:
                            cp.Style |= NativeMethods.LVS_SORTDESCENDING;
                            break;
                    }
                }
 
                if (VirtualMode)
                    cp.Style |= NativeMethods.LVS_OWNERDATA;
 
                // We can do this 'cuz the viewStyle enums are the same values as the actual LVS styles
                // this new check since the value for LV_VIEW_TILE == LVS_SINGLESEL; so dont OR that value since
                // LV_VIEW_TILE is not a STYLE but should be Send via a SENDMESSAGE.
                if (viewStyle != View.Tile ) {
                    cp.Style |= (int)viewStyle;
                }
 
                if (RightToLeft == RightToLeft.Yes && RightToLeftLayout == true) {
                    //We want to turn on mirroring for Form explicitly.
                    cp.ExStyle |= NativeMethods.WS_EX_LAYOUTRTL;
                    //Don't need these styles when mirroring is turned on.
                    cp.ExStyle &= ~(NativeMethods.WS_EX_RTLREADING | NativeMethods.WS_EX_RIGHT | NativeMethods.WS_EX_LEFTSCROLLBAR);
                }
                return cp;
            }
        }
 
        internal ListViewGroup DefaultGroup {
            get
            {
                if (defaultGroup == null) {
                    defaultGroup = new ListViewGroup(SR.GetString(SR.ListViewGroupDefaultGroup, "1"));
                }
                return defaultGroup;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.DefaultSize"]/*' />
        /// <devdoc>
        ///     Deriving classes can override this to configure a default size for their control.
        ///     This is more efficient than setting the size in the control's constructor.
        /// </devdoc>
        protected override Size DefaultSize
        {
            get
            {
                return new Size(121, 97);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.DoubleBuffered"]/*' />
        protected override bool DoubleBuffered {
            get {
                return base.DoubleBuffered;
            }
            set {
                if (this.DoubleBuffered != value)
                {
                    base.DoubleBuffered = value;
                    UpdateExtendedStyles();
                }
            }
        }
 
        internal bool ExpectingMouseUp {
            get {
                return this.listViewState[LISTVIEWSTATE_expectingMouseUp];
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FocusedItem"]/*' />
        /// <devdoc>
        ///     Retreives the item which currently has the user focus.  This is the
        ///     item that's drawn with the dotted focus rectangle around it.
        ///     Returns null if no item is currently focused.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListViewFocusedItemDescr)
        ]
        public ListViewItem FocusedItem {
            get {
                if (IsHandleCreated) {
                    int displayIndex = unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETNEXTITEM, -1, NativeMethods.LVNI_FOCUSED));
                    if (displayIndex > -1)
                        return Items[displayIndex];
                }
                return null;
            }
            set {
                if (IsHandleCreated && value != null) {
                    value.Focused = true;
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ForeColor"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public override Color ForeColor
        {
            get {
                if (ShouldSerializeForeColor()) {
                    return base.ForeColor;
                }
                else {
                    return SystemColors.WindowText;
                }
            }
            set {
                base.ForeColor = value;
                if (IsHandleCreated) {
                    SendMessage(NativeMethods.LVM_SETTEXTCOLOR, 0, ColorTranslator.ToWin32(ForeColor));
                }
            }
        }
 
        private bool FlipViewToLargeIconAndSmallIcon {
            get {
                // it never hurts to check that our house is in order
                Debug.Assert(!this.listViewState[LISTVIEWSTATE_flipViewToLargeIconAndSmallIcon] || this.View == View.SmallIcon, "we need this bit only in SmallIcon view");
                Debug.Assert(!this.listViewState[LISTVIEWSTATE_flipViewToLargeIconAndSmallIcon] || this.ComctlSupportsVisualStyles, "we need this bit only when loading ComCtl 6.0");
 
                return this.listViewState[LISTVIEWSTATE_flipViewToLargeIconAndSmallIcon];
            }
            set {
                // it never hurts to check that our house is in order
                Debug.Assert(!value || this.View == View.SmallIcon, "we need this bit only in SmallIcon view");
                Debug.Assert(!value || this.ComctlSupportsVisualStyles, "we need this bit only when loading ComCtl 6.0");
 
                this.listViewState[LISTVIEWSTATE_flipViewToLargeIconAndSmallIcon] = value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FullRowSelect"]/*' />
        /// <devdoc>
        ///     Specifies whether a click on an item will select the entire row instead
        ///     of just the item itself.
        ///     This property is only meaningful in Details view
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(false),
        SRDescription(SR.ListViewFullRowSelectDescr)
        ]
        public bool FullRowSelect {
            get {
                return listViewState[LISTVIEWSTATE_fullRowSelect];
            }
            set {
                if (FullRowSelect != value) {
                    listViewState[LISTVIEWSTATE_fullRowSelect] = value;
                    UpdateExtendedStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GridLines"]/*' />
        /// <devdoc>
        ///     If true, draws grid lines between items and subItems.
        ///     This property is only meaningful in Details view
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(false),
        SRDescription(SR.ListViewGridLinesDescr)
        ]
        public bool GridLines {
            get {
                return listViewState[LISTVIEWSTATE_gridLines];
            }
 
            set {
                if (GridLines != value) {
                    listViewState[LISTVIEWSTATE_gridLines] = value;
                    UpdateExtendedStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Groups"]/*' />
        /// <devdoc>
        ///     The collection of groups belonging to this ListView
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Localizable(true),
        Editor("System.Windows.Forms.Design.ListViewGroupCollectionEditor, " + AssemblyRef.SystemDesign,typeof(UITypeEditor)),
        SRDescription(SR.ListViewGroupsDescr),
        MergableProperty(false)
        ]
        public ListViewGroupCollection Groups {
            get
            {
                if (groups == null) {
                    groups = new ListViewGroupCollection(this);
                }
                return groups;
            }
        }
 
        // this essentially means that the version of CommCtl supports list view grouping
        // and that the user wants to make use of list view groups
        internal bool GroupsEnabled
        {
            get {
                return this.ShowGroups && groups != null && groups.Count > 0 && ComctlSupportsVisualStyles && !VirtualMode;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HeaderStyle"]/*' />
        /// <devdoc>
        ///     Column headers can either be invisible, clickable, or non-clickable.
        ///     This property is only meaningful in Details view
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(ColumnHeaderStyle.Clickable),
        SRDescription(SR.ListViewHeaderStyleDescr)
        ]
        public ColumnHeaderStyle HeaderStyle {
            get { return headerStyle;}
            set {
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)ColumnHeaderStyle.None, (int)ColumnHeaderStyle.Clickable))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ColumnHeaderStyle));
                }
                if (headerStyle != value) {
                    // We can switch between NONE and either *one* of the other styles without
                    // recreating the handle, but if we change from CLICKABLE to NONCLICKABLE
                    // or vice versa, with or without an intervening setting of NONE, then
                    // the handle needs to be recreated.
                    headerStyle = value;
                    if ((listViewState[LISTVIEWSTATE_nonclickHdr] && value == ColumnHeaderStyle.Clickable) ||
                        (!listViewState[LISTVIEWSTATE_nonclickHdr] && value == ColumnHeaderStyle.Nonclickable)) {
                        listViewState[LISTVIEWSTATE_nonclickHdr] = !listViewState[LISTVIEWSTATE_nonclickHdr];
                        RecreateHandleInternal();
                    }
                    else
                        UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HideSelection"]/*' />
        /// <devdoc>
        ///     If false, selected items will still be highlighted (in a
        ///     different color) when focus is moved away from the ListView.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.ListViewHideSelectionDescr)
        ]
        public bool HideSelection {
            get {
                return listViewState[LISTVIEWSTATE_hideSelection];
            }
 
            set {
                if (HideSelection != value) {
                    listViewState[LISTVIEWSTATE_hideSelection] = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HotTracking"]/*' />
        /// <devdoc>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListViewHotTrackingDescr)
        ]
        public bool HotTracking {
            get {
                return listViewState[LISTVIEWSTATE_hotTracking];
            }
            set {
                if (HotTracking != value) {
 
                    listViewState[LISTVIEWSTATE_hotTracking] = value;
                    if (value) {
                        this.HoverSelection = true;
                        this.Activation = ItemActivation.OneClick;
                    }
                    UpdateExtendedStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HoverSelection"]/*' />
        /// <devdoc>
        ///     Determines whether items can be selected by hovering over them with the mouse.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListViewHoverSelectDescr)
        ]
        public bool HoverSelection {
            get {
                return listViewState[LISTVIEWSTATE_hoverSelection];
            }
 
            set {
                if (HoverSelection != value) {
                    if (HotTracking && !value) {
                        throw new ArgumentException(SR.GetString(SR.ListViewHoverMustBeOnWhenHotTrackingIsOn), "value");
                    }
 
                    listViewState[LISTVIEWSTATE_hoverSelection] = value;
                    UpdateExtendedStyles();
                }
            }
        }
 
        internal bool InsertingItemsNatively
        {
            get
            {
                return this.listViewState1[LISTVIEWSTATE1_insertingItemsNatively];
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.InsertionMark"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListViewInsertionMarkDescr)
        ]
        public ListViewInsertionMark InsertionMark {
            get
            {
                if(insertionMark == null) {
                    insertionMark = new ListViewInsertionMark(this);
                }
                return insertionMark;
            }
        }
 
        private bool ItemCollectionChangedInMouseDown {
            get {
                return this.listViewState[LISTVIEWSTATE_itemCollectionChangedInMouseDown];
            }
            set {
                this.listViewState[LISTVIEWSTATE_itemCollectionChangedInMouseDown] = value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Items"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Localizable(true),
        Editor("System.Windows.Forms.Design.ListViewItemCollectionEditor, " + AssemblyRef.SystemDesign,typeof(UITypeEditor)),
        SRDescription(SR.ListViewItemsDescr),
        MergableProperty(false)
        ]
        public ListViewItemCollection Items {
            get {
                return listItemCollection;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.LabelEdit"]/*' />
        /// <devdoc>
        ///     Tells whether the EditLabels style is currently set.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListViewLabelEditDescr)
        ]
        public bool LabelEdit {
            get {
                return listViewState[LISTVIEWSTATE_labelEdit];
            }
            set {
                if (LabelEdit != value) {
                    listViewState[LISTVIEWSTATE_labelEdit] = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.LabelWrap"]/*' />
        /// <devdoc>
        ///     Tells whether the LabelWrap style is currently set.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        Localizable(true),
        SRDescription(SR.ListViewLabelWrapDescr)
        ]
        public bool LabelWrap {
            get {
                return listViewState[LISTVIEWSTATE_labelWrap];
            }
            set {
                if (LabelWrap != value) {
                    listViewState[LISTVIEWSTATE_labelWrap] = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.LargeImageList"]/*' />
        /// <devdoc>
        ///     The Currently set ImageList for Large Icon mode.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(null),
        SRDescription(SR.ListViewLargeImageListDescr)
        ]
        public ImageList LargeImageList {
            get {
                return imageListLarge;
            }
            set {
                if (value != imageListLarge) {
 
                    EventHandler recreateHandler = new EventHandler(LargeImageListRecreateHandle);
                    EventHandler disposedHandler = new EventHandler(DetachImageList);
                    EventHandler changeHandler = new EventHandler(LargeImageListChangedHandle);
 
                    if (imageListLarge != null) {
                        imageListLarge.RecreateHandle -= recreateHandler;
                        imageListLarge.Disposed -= disposedHandler;
                        imageListLarge.ChangeHandle -= changeHandler;
                    }
 
                    imageListLarge = value;
 
                    if (value != null) {
                        value.RecreateHandle += recreateHandler;
                        value.Disposed += disposedHandler;
                        value.ChangeHandle += changeHandler;
                    }
 
                    if (IsHandleCreated) {
                        SendMessage(NativeMethods.LVM_SETIMAGELIST, (IntPtr)NativeMethods.LVSIL_NORMAL, value == null ? IntPtr.Zero: value.Handle);
                        if (AutoArrange && !listViewState1[LISTVIEWSTATE1_disposingImageLists]) {
                            UpdateListViewItemsLocations();
                        }
                    }
                }
            }
        }
 
        /// <devdoc>
        /// Returns the current LISTVIEWSTATE_handleDestroyed value so that this
        /// value can be accessed from child classes.
        /// </devdoc>
        internal bool ListViewHandleDestroyed {
            get {
                return listViewState[LISTVIEWSTATE_handleDestroyed];
            }
            set {
                listViewState[LISTVIEWSTATE_handleDestroyed] = value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ListViewItemSorter"]/*' />
        /// <devdoc>
        ///     The sorting comparer for this ListView.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListViewItemSorterDescr)
        ]
        public IComparer ListViewItemSorter {
            get {
                return listItemSorter;
            }
            set {
                if (listItemSorter != value) {
                    listItemSorter = value;
 
                    if (!this.VirtualMode) {
                        Sort();
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.MultiSelect"]/*' />
        /// <devdoc>
        ///     Tells whether the MultiSelect style is currently set.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.ListViewMultiSelectDescr)
        ]
        public bool MultiSelect {
            get {
                return listViewState[LISTVIEWSTATE_multiSelect];
            }
            set {
                if (MultiSelect != value) {
                    listViewState[LISTVIEWSTATE_multiSelect] = value;
                    UpdateStyles();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OwnerDraw"]/*' />
        /// <devdoc>
        ///     Indicates whether the list view items (and sub-items in the Details view) will be
        ///     drawn by the system or the user. This includes the column header when item index = -1.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListViewOwnerDrawDescr)
        ]
        public bool OwnerDraw {
            get {
                return listViewState[LISTVIEWSTATE_ownerDraw];
            }
 
            set {
                if (OwnerDraw != value)
                {
                   listViewState[LISTVIEWSTATE_ownerDraw] = value;
                   Invalidate(true);
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.RightToLeftLayout"]/*' />
        /// <devdoc>
        ///     This is used for international applications where the language
        ///     is written from RightToLeft. When this property is true,
        //      and the RightToLeft is true, mirroring will be turned on on the form, and
        ///     control placement and text will be from right to left.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        Localizable(true),
        DefaultValue(false),
        SRDescription(SR.ControlRightToLeftLayoutDescr)
        ]
        public virtual bool RightToLeftLayout {
            get {
 
                return rightToLeftLayout;
            }
 
            set {
                if (value != rightToLeftLayout) {
                    rightToLeftLayout = value;
                    using(new LayoutTransaction(this, this, PropertyNames.RightToLeftLayout)) {
                        OnRightToLeftLayoutChanged(EventArgs.Empty);
                    }
                }
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.RightToLeftLayoutChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)]
        public event EventHandler RightToLeftLayoutChanged {
            add {
                Events.AddHandler(EVENT_RIGHTTOLEFTLAYOUTCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_RIGHTTOLEFTLAYOUTCHANGED, value);
            }
        }
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Scrollable"]/*' />
        /// <devdoc>
        ///     Tells whether the ScrollBars are visible or not.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.ListViewScrollableDescr)
        ]
        public bool Scrollable {
            get {
                return listViewState[LISTVIEWSTATE_scrollable];
            }
            set {
                if (Scrollable != value) {
                    listViewState[LISTVIEWSTATE_scrollable] = value;
                    RecreateHandleInternal();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndices"]/*' />
        /// <devdoc>
        ///     The indices of the currently selected list items.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ]
        public SelectedIndexCollection SelectedIndices {
            get {
                if (selectedIndexCollection == null) {
                    selectedIndexCollection = new SelectedIndexCollection(this);
                }
                return selectedIndexCollection;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedItems"]/*' />
        /// <devdoc>
        ///     The currently selected list items.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListViewSelectedItemsDescr)
        ]
        public SelectedListViewItemCollection SelectedItems {
            get {
                if (selectedListViewItemCollection == null) {
                    selectedListViewItemCollection = new SelectedListViewItemCollection(this);
                }
                return selectedListViewItemCollection;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ShowGroups"]/*' />
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.ListViewShowGroupsDescr)
        ]
        public bool ShowGroups {
            get {
                return this.listViewState[LISTVIEWSTATE_showGroups];
            }
            set {
                if (value != this.ShowGroups) {
                    this.listViewState[LISTVIEWSTATE_showGroups] = value;
                    if (IsHandleCreated) {
                        UpdateGroupView();
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SmallImageList"]/*' />
        /// <devdoc>
        ///     The currently set SmallIcon image list.
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(null),
        SRDescription(SR.ListViewSmallImageListDescr)
        ]
        public ImageList SmallImageList {
            get {
                return imageListSmall;
            }
            set {
                if (imageListSmall != value) {
 
                    EventHandler recreateHandler = new EventHandler(SmallImageListRecreateHandle);
                    EventHandler disposedHandler = new EventHandler(DetachImageList);
 
                    if (imageListSmall != null) {
                        imageListSmall.RecreateHandle -= recreateHandler;
                        imageListSmall.Disposed -= disposedHandler;
                    }
                    imageListSmall = value;
                    if (value != null) {
                        value.RecreateHandle += recreateHandler;
                        value.Disposed += disposedHandler;
                    }
 
                    if (IsHandleCreated) {
 
                        SendMessage(NativeMethods.LVM_SETIMAGELIST, (IntPtr)NativeMethods.LVSIL_SMALL, value == null ? IntPtr.Zero: value.Handle);
 
                        if (this.View == View.SmallIcon) {
                            this.View = View.LargeIcon;
                            this.View = View.SmallIcon;
                        } else if (!listViewState1[LISTVIEWSTATE1_disposingImageLists]) {
                            UpdateListViewItemsLocations();
                        }
 
                        if (this.View == View.Details) {
                            this.Invalidate(true /*invalidateChildren*/);
                        }
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ShowItemToolTips"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ListViewShowItemToolTipsDescr)
        ]
        public bool ShowItemToolTips {
            get {
                return listViewState[LISTVIEWSTATE_showItemToolTips];
            }
            set {
                if (ShowItemToolTips != value) {
                    listViewState[LISTVIEWSTATE_showItemToolTips] = value;
                    RecreateHandleInternal();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Sorting"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(SortOrder.None),
        SRDescription(SR.ListViewSortingDescr)
        ]
        public SortOrder Sorting {
            get {
                return sorting;
            }
            set {
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)SortOrder.None, (int)SortOrder.Descending))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(SortOrder));
                }
                if (sorting != value) {
                    sorting = value;
                    if (this.View == View.LargeIcon || this.View == View.SmallIcon) {
                        if (listItemSorter == null) {
                            listItemSorter = new IconComparer(sorting);
                        }
                        else if (listItemSorter is IconComparer) {
                           ((IconComparer)listItemSorter).SortOrder = sorting;
                        }
 
                    } else if (value == SortOrder.None) {
                        listItemSorter = null;
                    }
 
                    // If we're changing to No Sorting, no need to recreate the handle
                    // because none of the existing items need to be rearranged.
                    if (value == SortOrder.None)
                        UpdateStyles();
                    else
                        RecreateHandleInternal();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.StateImageList"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(null),
        SRDescription(SR.ListViewStateImageListDescr)
        ]
        public ImageList StateImageList {
            get {
                return imageListState;
            }
            set {
                if (this.UseCompatibleStateImageBehavior) {
                    if (imageListState != value) {
                        
                        EventHandler recreateHandler = new EventHandler(StateImageListRecreateHandle);
                        EventHandler disposedHandler = new EventHandler(DetachImageList);
 
                        if (imageListState != null) {
                            imageListState.RecreateHandle -= recreateHandler;
                            imageListState.Disposed -= disposedHandler;
                        }
                        imageListState = value;
                        if (value != null) {
                            value.RecreateHandle += recreateHandler;
                            value.Disposed += disposedHandler;
                        }
                        
                        if (IsHandleCreated)
                            SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, value == null ? IntPtr.Zero: value.Handle);
                    }
                } else {
                    if (imageListState != value) {
 
                        EventHandler recreateHandler = new EventHandler(StateImageListRecreateHandle);
                        EventHandler disposedHandler = new EventHandler(DetachImageList);
 
                        if (imageListState != null) {
                            imageListState.RecreateHandle -= recreateHandler;
                            imageListState.Disposed -= disposedHandler;
                        }
 
                        if (this.IsHandleCreated && imageListState != null && this.CheckBoxes) {
                            // vsWhidbey 395361.
                            // If CheckBoxes are set to true, then we will have to recreate the handle.
                            // For some reason, if CheckBoxes are set to true and the list view has a state imageList, then the native listView destroys
                            // the state imageList.
                            // (Yes, it does exactly that even though our wrapper sets LVS_SHAREIMAGELISTS on the native listView.)
                            // So we make the native listView forget about its StateImageList just before we recreate the handle.
                            SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, IntPtr.Zero);
                        }
 
                        imageListState = value;
 
                        if (value != null) {
                            value.RecreateHandle += recreateHandler;
                            value.Disposed += disposedHandler;
                        }
 
                        if (IsHandleCreated) {
                            if (CheckBoxes) {
                                // need to recreate to get the new images pushed in.
                                RecreateHandleInternal();
                            } else {
                                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, (imageListState == null || imageListState.Images.Count == 0) ? IntPtr.Zero : imageListState.Handle);
                            }
 
                            // Comctl should handle auto-arrange for us, but doesn't
                            if (!listViewState1[LISTVIEWSTATE1_disposingImageLists]) {
                                UpdateListViewItemsLocations();
                            }
                        }
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Text"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false)]
        public override string Text {
            get {
                return base.Text;
            }
            set {
                base.Text = value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.TextChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TextChanged {
            add {
                base.TextChanged += value;
            }
            remove {
                base.TextChanged -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.TileSize"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
            SRCategory(SR.CatAppearance),
            Browsable(true),
            SRDescription(SR.ListViewTileSizeDescr),
        ]
        public Size TileSize {
            get {
                if (tileSize.IsEmpty) {
                    if (this.IsHandleCreated) {
                        // Get the default value from the ListView
                        //
                        NativeMethods.LVTILEVIEWINFO tileViewInfo = new NativeMethods.LVTILEVIEWINFO();
                        tileViewInfo.dwMask = NativeMethods.LVTVIM_TILESIZE;
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_GETTILEVIEWINFO, 0, tileViewInfo);
                        return new Size(tileViewInfo.sizeTile.cx, tileViewInfo.sizeTile.cy);
                    } else {
                        return Size.Empty;
                    }
                } else {
                    return tileSize;
                }
            }
            set {
                if (tileSize != value) {
                    if (value.IsEmpty || value.Height <= 0 || value.Width <= 0) {
                        throw new ArgumentOutOfRangeException("TileSize", SR.GetString(SR.ListViewTileSizeMustBePositive));
                    }
 
                    tileSize = value;
                    if (this.IsHandleCreated) {
                        NativeMethods.LVTILEVIEWINFO tileViewInfo = new NativeMethods.LVTILEVIEWINFO();
                        tileViewInfo.dwMask = NativeMethods.LVTVIM_TILESIZE;
                        tileViewInfo.dwFlags = NativeMethods.LVTVIF_FIXEDSIZE;
                        tileViewInfo.sizeTile = new NativeMethods.SIZE(tileSize.Width, tileSize.Height);
                        bool retval = UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETTILEVIEWINFO, 0, tileViewInfo);
                        Debug.Assert(retval, "LVM_SETTILEVIEWINFO failed");
                        if (this.AutoArrange) {
                            this.UpdateListViewItemsLocations();
                        }
                    }
                }
            }
        }
 
        private bool ShouldSerializeTileSize() {
            return !this.tileSize.Equals(Size.Empty);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.TopItem"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ListViewTopItemDescr)
        ]
        public ListViewItem TopItem {
            get {
                if (viewStyle == View.LargeIcon || viewStyle == View.SmallIcon || viewStyle == View.Tile)
                    throw new InvalidOperationException(SR.GetString(SR.ListViewGetTopItem));
 
                if (!IsHandleCreated) {
                    if (Items.Count > 0) {
                        return Items[0];
                    }
                    else {
                        return null;
                    }
                }
                topIndex = unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETTOPINDEX, 0, 0));
                if (topIndex >= 0 && topIndex < Items.Count)
                    return Items[topIndex];
 
                return null;
            }
            set {
                if (viewStyle == View.LargeIcon || viewStyle == View.SmallIcon || viewStyle == View.Tile)
                    throw new InvalidOperationException(SR.GetString(SR.ListViewSetTopItem));
 
                if (value == null)
                    return;
                if (value.ListView != this)
                    return;
                if (!IsHandleCreated) {
                    CreateHandle();
                }
                if (value == TopItem)
                    return;
                EnsureVisible(value.Index);
                ListViewItem topItem = TopItem;
 
                if ((topItem == null) && (topIndex == Items.Count)) // HACK ALERT! VSWhidbey bug 154094/Windows OS Bugs bug 872012
                {                                                   // There's a bug in the common controls when the listview window is too small to fully display
                    topItem = value;                                // a single item.  Result of the bug is that the return value from a LVM_GETTOPINDEX
                    if (Scrollable)                                 // message is the number of items in the list rather than an index of an item in the list.
                    {                                               // This causes TopItem to return null.  A side issue is that EnsureVisible doesn't do too well
                        EnsureVisible(0);                           // here either, because it causes the listview to go blank rather than displaying anything useful.
                        Scroll(0, value.Index);                     // To work around this, we force the listbox to display the first item, then scroll down to the item
                    }                                               // user is setting as the top item.
                    return;                                         //
                }                                                   // END HACK ALERT
 
                if (value.Index == topItem.Index)
                    return;
                if (Scrollable)
                    Scroll(topItem.Index, value.Index);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.UseCompatibleStateImageBehavior"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Advanced),
        DefaultValue(true)
        ]
        public bool UseCompatibleStateImageBehavior {
            get {
                return this.listViewState1[LISTVIEWSTATE1_useCompatibleStateImageBehavior];
            }
            set
            {
                this.listViewState1[LISTVIEWSTATE1_useCompatibleStateImageBehavior] = value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.View"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(View.LargeIcon),
        SRDescription(SR.ListViewViewDescr)
        ]
        public View View {
            get {
                return viewStyle;
            }
            set {
                if (value == View.Tile && this.CheckBoxes) {
                    throw new NotSupportedException(SR.GetString(SR.ListViewTileViewDoesNotSupportCheckBoxes));
                }
 
                this.FlipViewToLargeIconAndSmallIcon = false;
 
                //valid values are 0x0 to 0x4
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)View.LargeIcon, (int)View.Tile))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(View));
                }
 
                if (value == View.Tile && VirtualMode) {
                    throw new NotSupportedException(SR.GetString(SR.ListViewCantSetViewToTileViewInVirtualMode));
                }
 
                if (viewStyle != value) {
                    viewStyle = value;
                    if (IsHandleCreated && ComctlSupportsVisualStyles) {
                        SendMessage(NativeMethods.LVM_SETVIEW,(int)viewStyle,0);
                        UpdateGroupView();
 
                        // if we switched to Tile view we should update the win32 list view tile view info
                        if (viewStyle == View.Tile) {
                            UpdateTileView();
                        }
                    }
                    else {
                        UpdateStyles();
                    }
 
                    UpdateListViewItemsLocations();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.VirtualListSize"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(0),
        RefreshProperties(RefreshProperties.Repaint),
        SRDescription(SR.ListViewVirtualListSizeDescr)
        ]
        public int VirtualListSize {
            get {
                return this.virtualListSize;
            }
            set {
                if (value < 0)
                    throw new System.ArgumentException(SR.GetString(SR.ListViewVirtualListSizeInvalidArgument, "value", (value.ToString(CultureInfo.CurrentCulture))));
                if (value == virtualListSize)
                    return;
                bool keepTopItem = this.IsHandleCreated && VirtualMode && this.View == View.Details && !this.DesignMode;
                int topIndex = -1;
                if (keepTopItem) {
                    topIndex = unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETTOPINDEX, 0, 0));
                }
 
                virtualListSize = value;
 
                if (IsHandleCreated && VirtualMode && !DesignMode)
                    SendMessage(NativeMethods.LVM_SETITEMCOUNT, virtualListSize, 0);
 
                if (keepTopItem) {
                    topIndex = Math.Min(topIndex, this.VirtualListSize - 1);
                    // After setting the virtual list size ComCtl makes the first item the top item.
                    // So we set the top item only if it wasn't the first item to begin with.
                    if (topIndex > 0) {
                        ListViewItem lvItem = this.Items[topIndex];
                        this.TopItem = lvItem;
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.VirtualMode"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        RefreshProperties(RefreshProperties.Repaint),
        SRDescription(SR.ListViewVirtualModeDescr)
        ]
        public bool VirtualMode {
            get {
                return listViewState[LISTVIEWSTATE_virtualMode];
            }
            set {
                if (value == VirtualMode)
                    return;
 
                if (value && Items.Count > 0)
                    throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualListViewRequiresNoItems));
 
                if (value && CheckedItems.Count > 0) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualListViewRequiresNoCheckedItems));
                }
 
                if (value && SelectedItems.Count > 0) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualListViewRequiresNoSelectedItems));
                }
 
                // Tile view does not work w/ VirtualMode.
                if (value && View == View.Tile) {
                    throw new NotSupportedException(SR.GetString(SR.ListViewCantSetVirtualModeWhenInTileView));
                }
 
                listViewState[LISTVIEWSTATE_virtualMode] = value;
 
                RecreateHandleInternal();
            }
        }
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.AfterLabelEdit"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewAfterLabelEditDescr)]
        public event LabelEditEventHandler AfterLabelEdit {
            add {
                onAfterLabelEdit += value;
            }
            remove {
                onAfterLabelEdit -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.BeforeLabelEdit"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewBeforeLabelEditDescr)]
        public event LabelEditEventHandler BeforeLabelEdit {
            add {
                onBeforeLabelEdit += value;
            }
            remove {
                onBeforeLabelEdit -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CacheVirtualItems"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewCacheVirtualItemsEventDescr)]
        public event CacheVirtualItemsEventHandler CacheVirtualItems {
            add {
                Events.AddHandler(EVENT_CACHEVIRTUALITEMS, value);
            }
            remove {
                Events.RemoveHandler(EVENT_CACHEVIRTUALITEMS, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnClick"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewColumnClickDescr)]
        public event ColumnClickEventHandler ColumnClick {
            add {
                onColumnClick += value;
            }
            remove {
                onColumnClick -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnReordered"]/*' />
        /// <devdoc>
        ///     Tell the user that the column headers are being rearranged
        /// </devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ListViewColumnReorderedDscr)]
        public event ColumnReorderedEventHandler ColumnReordered {
            add {
                Events.AddHandler(EVENT_COLUMNREORDERED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_COLUMNREORDERED, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnWidthChanged"]/*' />
        /// <devdoc>
        ///     Tell the user that the column width changed
        /// </devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ListViewColumnWidthChangedDscr)]
        public event ColumnWidthChangedEventHandler ColumnWidthChanged {
            add {
                Events.AddHandler(EVENT_COLUMNWIDTHCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_COLUMNWIDTHCHANGED, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnWidthChanging"]/*' />
        /// <devdoc>
        ///     Tell the user that the column width is being changed
        /// </devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ListViewColumnWidthChangingDscr)]
        public event ColumnWidthChangingEventHandler ColumnWidthChanging {
            add {
                Events.AddHandler(EVENT_COLUMNWIDTHCHANGING, value);
            }
            remove {
                Events.RemoveHandler(EVENT_COLUMNWIDTHCHANGING, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.DrawColumnHeader"]/*' />
        /// <devdoc>
        ///    <para>Fires in owner draw + Details mode when a column header needs to be drawn.</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewDrawColumnHeaderEventDescr)]
        public event DrawListViewColumnHeaderEventHandler DrawColumnHeader {
            add {
                Events.AddHandler(EVENT_DRAWCOLUMNHEADER, value);
            }
            remove {
                Events.RemoveHandler(EVENT_DRAWCOLUMNHEADER, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.DrawItem"]/*' />
        /// <devdoc>
        ///    <para>Fires in owner draw mode when a ListView item needs to be drawn.</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewDrawItemEventDescr)]
        public event DrawListViewItemEventHandler DrawItem {
            add {
                Events.AddHandler(EVENT_DRAWITEM, value);
            }
            remove {
                Events.RemoveHandler(EVENT_DRAWITEM, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.DrawSubItem"]/*' />
        /// <devdoc>
        ///      <para>Fires in owner draw mode and Details view when a ListView sub-item needs to be drawn.</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewDrawSubItemEventDescr)]
        public event DrawListViewSubItemEventHandler DrawSubItem {
            add {
                Events.AddHandler(EVENT_DRAWSUBITEM, value);
            }
            remove {
                Events.RemoveHandler(EVENT_DRAWSUBITEM, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ItemActivate"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewItemClickDescr)]
        public event EventHandler ItemActivate {
            add {
                onItemActivate += value;
            }
            remove {
                onItemActivate -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ItemCheck"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.CheckedListBoxItemCheckDescr)]
        public event ItemCheckEventHandler ItemCheck {
            add {
                onItemCheck += value;
            }
            remove {
                onItemCheck -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ItemChecked"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewItemCheckedDescr)]
        public event ItemCheckedEventHandler ItemChecked {
            add {
                onItemChecked += value;
            }
            remove {
                onItemChecked -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ItemDrag"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewItemDragDescr)]
        public event ItemDragEventHandler ItemDrag {
            add {
                onItemDrag += value;
            }
            remove {
                onItemDrag -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.NodeMouseHover"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewItemMouseHoverDescr)]
        public event ListViewItemMouseHoverEventHandler ItemMouseHover {
            add {
                onItemMouseHover += value;
            }
            remove {
                onItemMouseHover -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexChanged"]/*' />
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewItemSelectionChangedDescr)]
        public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged {
            add {
                Events.AddHandler(EVENT_ITEMSELECTIONCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_ITEMSELECTIONCHANGED, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.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\ListView.uex' path='docs/doc[@for="ListView.OnPaint"]/*' />
        /// <devdoc>
        ///     ListView Onpaint.
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event PaintEventHandler Paint {
            add {
                base.Paint += value;
            }
            remove {
                base.Paint -= value;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.RetrieveVirtualItem"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewRetrieveVirtualItemEventDescr)]
        public event RetrieveVirtualItemEventHandler RetrieveVirtualItem {
            add {
                Events.AddHandler(EVENT_RETRIEVEVIRTUALITEM, value);
            }
            remove {
                Events.RemoveHandler(EVENT_RETRIEVEVIRTUALITEM, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SearchForVirtualItem"]/*' />
        /// <devdoc>
        /// </devdoc>
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewSearchForVirtualItemDescr)]
        public event SearchForVirtualItemEventHandler SearchForVirtualItem {
            add {
                Events.AddHandler(EVENT_SEARCHFORVIRTUALITEM, value);
            }
            remove {
                Events.RemoveHandler(EVENT_SEARCHFORVIRTUALITEM, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewSelectedIndexChangedDescr)]
        public event EventHandler SelectedIndexChanged {
            add {
                Events.AddHandler(EVENT_SELECTEDINDEXCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_SELECTEDINDEXCHANGED, value);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.VirtualItemsSelectionRangeChanged"]/*' />
        [SRCategory(SR.CatBehavior), SRDescription(SR.ListViewVirtualItemsSelectionRangeChangedDescr)]
        public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged {
            add {
                Events.AddHandler(EVENT_VIRTUALITEMSSELECTIONRANGECHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_VIRTUALITEMSSELECTIONRANGECHANGED, value);
            }
        }
 
 
        /// <devdoc>
        ///     Called to add any delayed update items we have to the list view.  We do this because
        ///     we have optimnized the case where a user is only adding items within a beginupdate/endupdate
        ///     block.  If they do any other operations (get the count, remove, insert, etc.), we push in the
        ///     cached up items first, then do the requested operation.  This keeps it simple so we don't have to
        ///     try to maintain parellel state of the cache during a begin update end update.
        /// </devdoc>
        private void ApplyUpdateCachedItems() {
            // first check if there is a delayed update array
            //
            ArrayList newItems = (ArrayList)Properties.GetObject(PropDelayedUpdateItems);
            if (newItems != null) {
                // if there is, clear it and push the items in.
                //
                Properties.SetObject(PropDelayedUpdateItems, null);
                ListViewItem[] items = (ListViewItem[])newItems.ToArray(typeof(ListViewItem));
                if (items.Length > 0) {
                    InsertItems(itemCount, items, false /*checkHosting*/);
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ArrangeIcons"]/*' />
        /// <devdoc>
        ///     In Large Icon or Small Icon view, arranges the items according to one
        ///     of the following behaviors:
        /// </devdoc>
        public void ArrangeIcons(ListViewAlignment value) {
            // LVM_ARRANGE only work in SmallIcon view
            if (viewStyle != View.SmallIcon) return;
 
            switch ((int)value) {
                case NativeMethods.LVA_DEFAULT:
                case NativeMethods.LVA_ALIGNLEFT:
                case NativeMethods.LVA_ALIGNTOP:
                case NativeMethods.LVA_SNAPTOGRID:
                    if (IsHandleCreated) {
                        UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_ARRANGE, (int) value, 0);
                    }
                    break;
 
                default:
                    throw new ArgumentException(SR.GetString(SR.InvalidArgument,
                                                              "value",
                                                              ((value).ToString())));
            }
 
            if (!VirtualMode && sorting != SortOrder.None) {
                Sort();
            }
 
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ArrangeIcons1"]/*' />
        /// <devdoc>
        ///     In Large Icon or Small Icon view, arranges items according to the ListView's
        ///     current alignment style.
        /// </devdoc>
        public void ArrangeIcons() {
            ArrangeIcons((ListViewAlignment)NativeMethods.LVA_DEFAULT);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.AutoResizeColumns"]/*' />
        public void AutoResizeColumns(ColumnHeaderAutoResizeStyle headerAutoResize) {
            if (!this.IsHandleCreated) {
                this.CreateHandle();
            }
            UpdateColumnWidths(headerAutoResize);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.AutoResizeColumn"]/*' />
        public void AutoResizeColumn(int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize) {
            if (!this.IsHandleCreated) {
                this.CreateHandle();
            }
            SetColumnWidth(columnIndex, headerAutoResize);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.BeginUpdate"]/*' />
        /// <devdoc>
        ///     Prevents the ListView from redrawing itself until EndUpdate is called.
        ///     Calling this method before individually adding or removing a large number of Items
        ///     will improve performance and reduce flicker on the ListView as items are
        ///     being updated.  Always call EndUpdate immediately after the last item is updated.
        /// </devdoc>
        public void BeginUpdate() {
            BeginUpdateInternal();
 
            // if this is the first BeginUpdate call, push an ArrayList into the PropertyStore so
            // we can cache up any items that have been added while this is active.
            //
            if (updateCounter++ == 0 && null == Properties.GetObject(PropDelayedUpdateItems)) {
                Properties.SetObject(PropDelayedUpdateItems, new ArrayList());
            }
        }
 
        internal void CacheSelectedStateForItem(ListViewItem lvi, bool selected) {
            if (selected) {
                if (this.savedSelectedItems == null) {
                    this.savedSelectedItems = new List<ListViewItem>();
                }
                if (!this.savedSelectedItems.Contains(lvi)) {
                    this.savedSelectedItems.Add(lvi);
                }
            } else {
                if (this.savedSelectedItems != null && this.savedSelectedItems.Contains(lvi)) {
                    this.savedSelectedItems.Remove(lvi);
                }
            }
        }
 
#if DEBUG
        private void CheckDisplayIndices() {
            // sanity check
            // all the column headers should have a displayIndex between 0 and this.Columns.Count - 1;
            // DisplayIndex should be different for different column headers
            int sumOfDisplayIndices = 0;
            for (int i = 0; i < this.Columns.Count; i ++) {
                sumOfDisplayIndices += this.Columns[i].DisplayIndex;
                Debug.Assert(this.Columns[i].DisplayIndex > -1 && this.Columns[i].DisplayIndex < this.Columns.Count, "display indices out of whack");
            }
            int colsCount = this.Columns.Count;
            Debug.Assert(sumOfDisplayIndices == (colsCount - 1) * colsCount / 2, "display indices out of whack");
        }
#endif
 
        private void CleanPreviousBackgroundImageFiles() {
            if (this.bkImgFileNames == null) {
                return;
            }
 
            // SECREVIEW : Safe to assert FileIO here since we are deleting files created by us.
            //
            FileIOPermission fiop = new FileIOPermission(PermissionState.Unrestricted);
            fiop.Assert();
            try {
                System.IO.FileInfo fi;
                for (int i = 0; i <= this.bkImgFileNamesCount; i ++) {
                    fi = new System.IO.FileInfo(this.bkImgFileNames[i]);
                    if (fi.Exists) {
                        // Microsoft: vsWhidbey 417804.
                        // ComCtl ListView uses COM objects to manipulate the bitmap we send it to them.
                        // I could not find any resources which explain in detail when the IImgCtx objects
                        // release the temporary file. So if we get a FileIO when we delete the temporary file
                        // we don't do anything about it ( because we don't know what is a good time to try to delete the file again ).
                        try {
                            fi.Delete();
                        } catch (System.IO.IOException){}
                    }
                }
            } finally {
                System.Security.PermissionSet.RevertAssert();
            }
 
            this.bkImgFileNames = null;
            this.bkImgFileNamesCount = -1;
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Clear"]/*' />
        /// <devdoc>
        ///     Removes all items and columns from the ListView.
        /// </devdoc>
        public void Clear() {
            Items.Clear();
            Columns.Clear();
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CompareFunc"]/*' />
        /// <devdoc>
        ///      This is the sorting callback function called by the system ListView control.
        /// </devdoc>
        /// <internalonly/>
        private int CompareFunc(IntPtr lparam1, IntPtr lparam2, IntPtr lparamSort) {
 
            Debug.Assert(listItemSorter != null, "null sorter!");
            if (listItemSorter != null) {
                return listItemSorter.Compare(listItemsTable[(int)lparam1], listItemsTable[(int)lparam2]);
            }
            else {
                return 0;
            }
        }
 
        private int CompensateColumnHeaderResize(Message m, bool columnResizeCancelled) {
            if (this.ComctlSupportsVisualStyles &&
                this.View == View.Details &&
                !columnResizeCancelled &&
                this.Items.Count > 0) {
                NativeMethods.NMHEADER header = (NativeMethods.NMHEADER) m.GetLParam(typeof(NativeMethods.NMHEADER));
 
                return CompensateColumnHeaderResize(header.iItem, columnResizeCancelled);
            } else {
                return 0;
            }
        }
 
        private int CompensateColumnHeaderResize(int columnIndex, bool columnResizeCancelled) {
            // We need to compensate padding only when ComCtl60 is loaded.
            // We need to compensate padding only if the list view is in Details mode.
            // We need to compensate padding only if the user did not cancel ColumnWidthChanging event.
            // We need to compensate padding only if the list view contains items.
            // We need to compensate padding if the user resizes the first column.
            // If the list view has a small image list then:
            //  1. if there is a list view item w/ ImageIndex > -1 then we don't have to resize the first column.
            //  2. Otherwise, we need to add 18 pixels.
            // If the list view does not have a small image list then we need to add 2 pixels.
 
            if (this.ComctlSupportsVisualStyles &&
                this.View == View.Details &&
                !columnResizeCancelled &&
                this.Items.Count > 0) {
                // The user resized the first column.
                if (columnIndex == 0) {
                    ColumnHeader col = (this.columnHeaders != null && this.columnHeaders.Length > 0) ? this.columnHeaders[0] : null;
                    if (col != null) {
                        if (this.SmallImageList == null) {
                            return 2;
                        } else {
                            // If the list view contains an item w/ a non-negative ImageIndex then we don't need to
                            // add extra padding.
                            bool addPadding = true;
                            for (int i = 0; i < this.Items.Count; i ++) {
                                if (this.Items[i].ImageIndexer.ActualIndex > -1) {
                                    addPadding = false;
                                    break;
                                }
                            }
 
                            if (addPadding) {
                                // 18 = 16 + 2.
                                // 16 = size of small image list.
                                // 2 is the padding we add when there is no small image list.
                                return 18;
                            }
                        }
                    }
                }
            }
 
            return 0;
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CreateHandle"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        protected override void CreateHandle() {
            if (!RecreatingHandle) {
                IntPtr userCookie = UnsafeNativeMethods.ThemingScope.Activate();
                        
                try {
                    NativeMethods.INITCOMMONCONTROLSEX icc = new NativeMethods.INITCOMMONCONTROLSEX();
                    icc.dwICC = NativeMethods.ICC_LISTVIEW_CLASSES;
                    SafeNativeMethods.InitCommonControlsEx(icc);
                }
                finally {
                    UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
                }
            }
            base.CreateHandle();
 
            // image location
            if (this.BackgroundImage != null)
                SetBackgroundImage();
        }
 
        //
 
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CustomDraw"]/*' />
        /// <devdoc>
        ///     Handles custom drawing of list items - for individual item font/color changes.
        ///
        ///        If OwnerDraw is true, we fire the OnDrawItem and OnDrawSubItem (in Details view)
        ///        events and let the user do the drawing.
        /// </devdoc>
        /// <internalonly/>
        unsafe void CustomDraw(ref Message m) {
 
            bool dontmess = false;
            bool itemDrawDefault = false;
 
            try
            {
                NativeMethods.NMLVCUSTOMDRAW* nmcd = (NativeMethods.NMLVCUSTOMDRAW*)m.LParam;
                // Find out which stage we're drawing
                switch (nmcd->nmcd.dwDrawStage)
                {
                    case NativeMethods.CDDS_PREPAINT:
                        if (OwnerDraw)
                        {
                            m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYITEMDRAW);
                            return;
                        }
                        // We want custom draw for this paint cycle
                        m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYSUBITEMDRAW | NativeMethods.CDRF_NEWFONT);
                        // refresh the cache of the current color & font settings for this paint cycle
                        odCacheBackColor = this.BackColor;
                        odCacheForeColor = this.ForeColor;
                        odCacheFont = this.Font;
                        odCacheFontHandle = this.FontHandle;
 
                        // If preparing to paint a group item, make sure its bolded.
                        if (nmcd->dwItemType == NativeMethods.LVCDI_GROUP)
                        {
                            if (odCacheFontHandleWrapper != null)
                            {
                                odCacheFontHandleWrapper.Dispose();
                            }
                            odCacheFont = new Font(odCacheFont, FontStyle.Bold);
                            odCacheFontHandleWrapper = new Control.FontHandleWrapper(odCacheFont);
                            odCacheFontHandle = odCacheFontHandleWrapper.Handle;
                            SafeNativeMethods.SelectObject(new HandleRef(nmcd->nmcd, nmcd->nmcd.hdc), new HandleRef(odCacheFontHandleWrapper, odCacheFontHandleWrapper.Handle));
                            m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT;
                        }
                        return;
 
                    //We have to return a NOTIFYSUBITEMDRAW (called NOTIFYSUBITEMREDRAW in the docs) here to
                    //get it to enter "change all subitems instead of whole rows" mode.
 
                    //HOWEVER... we only want to do this for report styles...
 
                    case NativeMethods.CDDS_ITEMPREPAINT:
 
                        int itemIndex = (int)nmcd->nmcd.dwItemSpec;
                        //VSWhidbey #163674 - the following call silently returns Rectangle.Empty if no corresponding
                        // item was found. We do this because the native listview, under some circumstances, seems
                        // to send spurious custom draw notifications. The check below does the rest.
                        Rectangle itemBounds = GetItemRectOrEmpty(itemIndex);
 
                        if (!ClientRectangle.IntersectsWith(itemBounds))
                        {
                            // we don't need to bother painting this one.
                            return;
                        }
 
                        // If OwnerDraw is true, fire the onDrawItem event.
                        if (OwnerDraw)
                        {
 
                            Graphics g = Graphics.FromHdcInternal(nmcd->nmcd.hdc);
 
#if DEBUGGING
                            Rectangle r = itemBounds;
                            Rectangle r2 = Rectangle.FromLTRB(nmcd->nmcd.rc.left, nmcd->nmcd.rc.top, nmcd->nmcd.rc.right, nmcd->nmcd.rc.bottom);
                            Debug.WriteLine("ClipBounds      : l {0} t {1} r {2} b {3}", g.ClipBounds.Left, g.ClipBounds.Top, g.ClipBounds.Right, g.ClipBounds.Bottom);
                            Debug.WriteLine("Rect (Send Msg) : l {0} t {1} r {2} b {3}", r.Left, r.Top, r.Right, r.Bottom);
                            Debug.WriteLine("Rect (NM)       : l {0} t {1} r {2} b {3}", r2.Left, r2.Top, r2.Right, r2.Bottom);
#endif
                            DrawListViewItemEventArgs e = null;
                            try
                            {
                                e = new DrawListViewItemEventArgs(g,
                                       Items[(int)nmcd->nmcd.dwItemSpec],
                                       itemBounds,
                                       (int)nmcd->nmcd.dwItemSpec,
                                       (ListViewItemStates)(nmcd->nmcd.uItemState));
 
                                OnDrawItem(e);
                            }
                            finally
                            {
                                g.Dispose();
                            }
 
                            itemDrawDefault = e.DrawDefault;
 
                            // For the Details view, we send a SKIPDEFAULT when we get a sub-item drawing notification.
                            // For other view styles, we do it here.
                            if (viewStyle == View.Details)
                            {
                                m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYSUBITEMDRAW);
                            }
                            else
                            {
                                if (!e.DrawDefault)
                                {
                                    m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT);
                                }
                            }
 
                            if (!e.DrawDefault)
                            {
                                return;   // skip our regular drawing code
                            }
                        }
 
                        if (viewStyle == View.Details || viewStyle == View.Tile)
                        {
                            m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYSUBITEMDRAW | NativeMethods.CDRF_NEWFONT);
                            dontmess = true; // don't mess with our return value!
 
                            //ITEMPREPAINT is used to work out the rect for the first column!!! GAH!!!
                            //(which means we can't just do our color/font work on SUBITEM|ITEM_PREPAINT)
                            //so fall through... and tell the end of SUBITEM|ITEM_PREPAINT not to mess
                            //with our return value...
 
                        }
 
                        //If it's not a report, we fall through and change the main item's styles
 
                        goto case (NativeMethods.CDDS_SUBITEM | NativeMethods.CDDS_ITEMPREPAINT);
 
                    case (NativeMethods.CDDS_SUBITEM | NativeMethods.CDDS_ITEMPREPAINT):
 
                        itemIndex = (int)nmcd->nmcd.dwItemSpec;
                        //VSWhidbey #163674 - the following call silently returns Rectangle.Empty if no corresponding
                        // item was found. We do this because the native listview, under some circumstances, seems
                        // to send spurious custom draw notifications. The check below does the rest.
                        itemBounds = GetItemRectOrEmpty(itemIndex);
 
                        if (!ClientRectangle.IntersectsWith(itemBounds))
                        {
                            // we don't need to bother painting this one.
                            return;
                        }
 
                        // If OwnerDraw is true, fire the onDrawSubItem event.
                        if (OwnerDraw && !itemDrawDefault)
                        {
 
                            Graphics g = Graphics.FromHdcInternal(nmcd->nmcd.hdc);
                            DrawListViewSubItemEventArgs e = null;
 
                            // by default, we want to skip the customDrawCode
                            bool skipCustomDrawCode = true;
                            try
                            {
 
                                //The ListView will send notifications for every column, even if no
                                //corresponding subitem exists for a particular item. We shouldn't
                                //fire events in such cases.
                                if (nmcd->iSubItem < Items[itemIndex].SubItems.Count)
                                {
                                    Rectangle subItemBounds = GetSubItemRect(itemIndex, nmcd->iSubItem);
 
                                    // For the first sub-item, the rectangle corresponds to the whole item.
                                    // We need to handle this case separately.
                                    if (nmcd->iSubItem == 0 && Items[itemIndex].SubItems.Count > 1)
                                    {
                                        // Use the width for the first column header.
                                        subItemBounds.Width = this.columnHeaders[0].Width;
                                    }
 
                                    if (this.ClientRectangle.IntersectsWith(subItemBounds))
                                    {
                                        e = new DrawListViewSubItemEventArgs(g,
                                                  subItemBounds,
                                                  Items[itemIndex],
                                                  Items[itemIndex].SubItems[nmcd->iSubItem],
                                                  itemIndex,
                                                  nmcd->iSubItem,
                                                  columnHeaders[nmcd->iSubItem],
                                                  (ListViewItemStates)(nmcd->nmcd.uItemState));
                                        OnDrawSubItem(e);
 
                                        // the customer still wants to draw the default.
                                        // Don't skip the custom draw code then
                                        skipCustomDrawCode = !e.DrawDefault;
                                    }
                                }
                            }
                            finally
                            {
                                g.Dispose();
                            }
 
                            if (skipCustomDrawCode)
                            {
                                m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT);
                                return; // skip our custom draw code
                            }
                        }
 
                        // get the node
                        ListViewItem item = Items[(int)(nmcd->nmcd.dwItemSpec)];
                        // if we're doing the whole row in one style, change our result!
                        if (dontmess && item.UseItemStyleForSubItems)
                        {
                            m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT;
                        }
                        Debug.Assert(item != null, "Item was null in ITEMPREPAINT");
 
                        int state = nmcd->nmcd.uItemState;
                        // There is a known and documented problem in the ListView winctl control -
                        // if the LVS_SHOWSELALWAYS style is set, then the item state will have
                        // the CDIS_SELECTED bit set for all items. So we need to verify with the
                        // real item state to be sure.
                        if (!HideSelection)
                        {
                            int realState = GetItemState((int)(nmcd->nmcd.dwItemSpec));
                            if ((realState & NativeMethods.LVIS_SELECTED) == 0)
                            {
                                state &= ~NativeMethods.CDIS_SELECTED;
                            }
                        }
 
                        // subitem is invalid if the flag isn't set -- and we also use this code in
                        // cases where subitems aren't visible (ie. non-Details modes), so if subitem
                        // is invalid, point it at the main item's render info
 
                        int subitem = ((nmcd->nmcd.dwDrawStage & NativeMethods.CDDS_SUBITEM) != 0) ? nmcd->iSubItem : 0;
 
                        // Work out the style in which to render this item
                        //
                        Font subItemFont = null;
                        Color subItemForeColor = Color.Empty;
                        Color subItemBackColor = Color.Empty;
                        bool haveRenderInfo = false;
                        bool disposeSubItemFont = false;
                        if (item != null && subitem < item.SubItems.Count)
                        {
                            haveRenderInfo = true;
                            if (subitem == 0 && (state & NativeMethods.CDIS_HOT) != 0 && HotTracking)
                            {
                                disposeSubItemFont = true;
                                subItemFont = new Font(item.SubItems[0].Font, FontStyle.Underline);
                            }
                            else
                            {
                                subItemFont = item.SubItems[subitem].Font;
                            }
 
                            if (subitem > 0 || (state & (NativeMethods.CDIS_SELECTED | NativeMethods.CDIS_GRAYED | NativeMethods.CDIS_HOT | NativeMethods.CDIS_DISABLED)) == 0)
                            {
                                // we only propogate colors if we're displaying things normally
                                // the user can override this method to do all kinds of other crazy things if they
                                // want to though - but we don't support that.
                                subItemForeColor = item.SubItems[subitem].ForeColor;
                                subItemBackColor = item.SubItems[subitem].BackColor;
                            }
                        }
 
                        // We always have to set font and color data, because of comctl design
 
                        //
 
 
 
 
                        Color riFore = Color.Empty;
                        Color riBack = Color.Empty;
 
                        if (haveRenderInfo)
                        {
                            riFore = subItemForeColor;
                            riBack = subItemBackColor;
                        }
 
                        bool changeColor = true;
                        if (!Enabled)
                        {
                            changeColor = false;
                        }
                        else if ((activation == ItemActivation.OneClick)
                              || (activation == ItemActivation.TwoClick))
                        {
                            if ((state & (NativeMethods.CDIS_SELECTED
                                        | NativeMethods.CDIS_GRAYED
                                        | NativeMethods.CDIS_HOT
                                        | NativeMethods.CDIS_DISABLED)) != 0)
                            {
                                changeColor = false;
                            }
                        }
 
                        if (changeColor)
                        {
                            if (!haveRenderInfo || riFore.IsEmpty)
                            {
                                nmcd->clrText = ColorTranslator.ToWin32(odCacheForeColor);
                            }
                            else
                            {
                                nmcd->clrText = ColorTranslator.ToWin32(riFore);
                            }
 
                            // Work-around for a comctl quirk where,
                            // if clrText is the same as SystemColors.HotTrack,
                            // the subitem's color is not changed to nmcd->clrText.
                            //
                            // Try to tweak the blue component of clrText first, then green, then red.
                            // Basically, if the color component is 0xFF, subtract 1 from it
                            // (adding 1 will overflow), else add 1 to it. If the color component is 0,
                            // skip it and go to the next color (unless it is our last option).
                            if (nmcd->clrText == ColorTranslator.ToWin32(SystemColors.HotTrack))
                            {
                                int totalshift = 0;
                                bool clrAdjusted = false;
                                int mask = 0xFF0000;
                                do
                                {
                                    int C = nmcd->clrText & mask;
                                    if (C != 0 || (mask == 0x0000FF)) // The color is not 0
                                    // or this is the last option
                                    {
                                        int n = 16 - totalshift;
                                        // Make sure the value doesn't overflow
                                        if (C == mask)
                                        {
                                            C = ((C >> n) - 1) << n;
                                        }
                                        else
                                        {
                                            C = ((C >> n) + 1) << n;
                                        }
                                        // Copy the adjustment into nmcd->clrText
                                        nmcd->clrText = (nmcd->clrText & (~mask)) | C;
                                        clrAdjusted = true;
                                    }
                                    else
                                    {
                                        mask >>= 8; // Try the next color.
                                        // We try adjusting Blue, Green, Red in that order,
                                        // since 0x0000FF is the most likely value of
                                        // SystemColors.HotTrack
                                        totalshift += 8;
                                    }
                                } while (!clrAdjusted);
                            }
 
                            if (!haveRenderInfo || riBack.IsEmpty)
                            {
                                nmcd->clrTextBk = ColorTranslator.ToWin32(odCacheBackColor);
                            }
                            else
                            {
                                nmcd->clrTextBk = ColorTranslator.ToWin32(riBack);
                            }
                        }
 
                        if (!haveRenderInfo || subItemFont == null)
                        {
                            // safety net code just in case
                            if (odCacheFont != null)
                            {
                                SafeNativeMethods.SelectObject(new HandleRef(nmcd->nmcd, nmcd->nmcd.hdc), new HandleRef(null, odCacheFontHandle));
                            }
                        }
                        else
                        {
                            if (odCacheFontHandleWrapper != null)
                            {
                                odCacheFontHandleWrapper.Dispose();
                            }
                            odCacheFontHandleWrapper = new Control.FontHandleWrapper(subItemFont);
                            SafeNativeMethods.SelectObject(new HandleRef(nmcd->nmcd, nmcd->nmcd.hdc), new HandleRef(odCacheFontHandleWrapper, odCacheFontHandleWrapper.Handle));
                        }
 
                        if (!dontmess)
                        {
                            m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT;
                        }
                        if (disposeSubItemFont)
                        {
                            subItemFont.Dispose();
                        }
                        return;
 
                    default:
                        m.Result = (IntPtr)NativeMethods.CDRF_DODEFAULT;
                        return;
                }
            }
            catch (Exception e)
            {
                Debug.Fail("Exception occurred attempting to setup custom draw. Disabling custom draw for this control", e.ToString());
                m.Result = (IntPtr)NativeMethods.CDRF_DODEFAULT;
            }
        }
 
        private void DeleteFileName(string fileName) {
            if (!String.IsNullOrEmpty(fileName)) {
                // the list view needs the FileIOPermission when the app runs on an UNC share
                // and the list view creates / destroys temporary files for its background image
                
                // SECREVIEW : Safe to assert FileIO here since we are deleting files created by us.
                //
                FileIOPermission fiop = new FileIOPermission(PermissionState.Unrestricted);
                fiop.Assert();
                try {
                    System.IO.FileInfo fi = new System.IO.FileInfo(fileName);
                    if (fi.Exists) {
                        // Microsoft: vsWhidbey 417804.
                        // ComCtl ListView uses COM objects to manipulate the bitmap we send it to them.
                        // I could not find any resources which explain in detail when the IImgCtx objects
                        // release the temporary file. So if we get a FileIO when we delete the temporary file
                        // we don't do anything about it ( because we don't know what is a good time to try to delete the file again ).
                        try {
                            fi.Delete();
                        } catch (System.IO.IOException){}
                    }
                } finally {
                    System.Security.PermissionSet.RevertAssert();
                }
            }
        }
 
        private void DestroyLVGROUP(NativeMethods.LVGROUP lvgroup) {
            if(lvgroup.pszHeader != IntPtr.Zero) {
                Marshal.FreeHGlobal(lvgroup.pszHeader);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.DetachImageList"]/*' />
        /// <devdoc>
        ///     Resets the imageList to null.  We wire this method up to the imageList's
        ///     Dispose event, so that we don't hang onto an imageList that's gone away.
        /// </devdoc>
        private void DetachImageList(object sender, EventArgs e) {
            listViewState1[LISTVIEWSTATE1_disposingImageLists] = true;
            try {
                #if DEBUG
                if (sender != imageListSmall && sender != imageListState && sender != imageListLarge)
                {
                    Debug.Fail("ListView sunk dispose event from unknown component");
                }
                #endif // DEBUG
                if (sender == imageListSmall)
                    SmallImageList = null;
                if (sender == imageListLarge)
                    LargeImageList = null;
                if (sender == imageListState)
                    StateImageList = null;
            }
            finally {
                listViewState1[LISTVIEWSTATE1_disposingImageLists] = false;
            }
 
            UpdateListViewItemsLocations();
 
            
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Dispose"]/*' />
        /// <devdoc>
        ///     Disposes of the component.  Call dispose when the component is no longer needed.
        ///     This method removes the component from its container (if the component has a site)
        ///     and triggers the dispose event.
        /// </devdoc>
        protected override void Dispose(bool disposing) {
            if (disposing) {
                // Remove any event sinks we have hooked up to imageLists
                if (imageListSmall != null) {
                    imageListSmall.Disposed -= new EventHandler(this.DetachImageList);
                    imageListSmall = null;
                }
                if (imageListLarge != null) {
                    imageListLarge.Disposed -= new EventHandler(this.DetachImageList);
                    imageListLarge = null;
                }
                if (imageListState != null) {
                    imageListState.Disposed -= new EventHandler(this.DetachImageList);
                    imageListState = null;
                }
 
                // Remove any ColumnHeaders contained in this control
                if (columnHeaders != null) {
                    for (int colIdx = columnHeaders.Length-1; colIdx >= 0; colIdx--) {
                        columnHeaders[colIdx].OwnerListview = null;
                        columnHeaders[colIdx].Dispose();
                    }
                    columnHeaders = null;
                }
 
                // Remove any items we have
                Items.Clear();
 
                if (odCacheFontHandleWrapper != null)
                {
                    odCacheFontHandleWrapper.Dispose();
                    odCacheFontHandleWrapper = null;
                }
 
                if (!String.IsNullOrEmpty(this.backgroundImageFileName) || this.bkImgFileNames != null) {
                    // we need the fileIoPermission when the app runs on an UNC share and
                    // the list view creates/deletes temporary files for its background image
                    
                    // SECREVIEW : Safe to assert FileIO here since we are deleting files created by us.
                    //
                    FileIOPermission fiop = new FileIOPermission(PermissionState.Unrestricted);
                    fiop.Assert();
 
                    try {
                        System.IO.FileInfo fi;
                        if (!String.IsNullOrEmpty(this.backgroundImageFileName)) {
                            fi = new System.IO.FileInfo(this.backgroundImageFileName);
                            Debug.Assert(fi.Exists, "who deleted our temp file?");
                            // Microsoft: vsWhidbey 417804.
                            // ComCtl ListView uses COM objects to manipulate the bitmap we send it to them.
                            // I could not find any resources which explain in detail when the IImgCtx objects
                            // release the temporary file. So if we get a FileIO when we delete the temporary file
                            // we don't do anything about it ( because we don't know what is a good time to try to delete the file again ).
                            try {
                                fi.Delete();
                            } catch (System.IO.IOException){}
                            this.backgroundImageFileName = String.Empty;
                        }
                        for (int i = 0; i <= this.bkImgFileNamesCount; i++) {
                            fi = new System.IO.FileInfo(this.bkImgFileNames[i]);
                            Debug.Assert(fi.Exists, "who deleted our temp file?");
                            // Microsoft: vsWhidbey 417804.
                            // ComCtl ListView uses COM objects to manipulate the bitmap we send it to them.
                            // I could not find any resources which explain in detail when the IImgCtx objects
                            // release the temporary file. So if we get a FileIO when we delete the temporary file
                            // we don't do anything about it ( because we don't know what is a good time to try to delete the file again ).
                            try {
                                fi.Delete();
                            } catch (System.IO.IOException){}
                        }
 
                        this.bkImgFileNames = null;
                        this.bkImgFileNamesCount = -1;
                    } finally {
                        System.Security.PermissionSet.RevertAssert();
                    }
                }
 
            }
 
            base.Dispose(disposing);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.EndUpdate"]/*' />
        /// <devdoc>
        ///     Cancels the effect of BeginUpdate.
        /// </devdoc>
        public void EndUpdate() {
 
            // On the final EndUpdate, check to see if we've got any cached items.
            // If we do, insert them as normal, then turn off the painting freeze.
            //
            if (--updateCounter == 0 && null != Properties.GetObject(PropDelayedUpdateItems)) {
                ApplyUpdateCachedItems();
            }
            EndUpdateInternal();
        }
 
        private void EnsureDefaultGroup() {
            if (IsHandleCreated && ComctlSupportsVisualStyles && GroupsEnabled) {
                if (SendMessage(NativeMethods.LVM_HASGROUP, DefaultGroup.ID, 0) == IntPtr.Zero) {
                    UpdateGroupView();
                    InsertGroupNative(0, DefaultGroup);
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.EnsureVisible"]/*' />
        /// <devdoc>
        ///     Ensure that the item is visible, scrolling the view as necessary.
        ///     @index  Index of item to scroll into view
        /// </devdoc>
        public void EnsureVisible(int index) {
            if (index < 0 || index >= Items.Count) {
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
            }
            if (IsHandleCreated)
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_ENSUREVISIBLE, index, 0);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FindItemWithText1"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewItem FindItemWithText(string text) {
            // if the user does not use the FindItemWithText overloads that specify a StartIndex and the listView is empty then return null
            if (this.Items.Count == 0) {
                return null;
            }
 
            return FindItemWithText(text, true, 0, true);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FindItemWithText2"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewItem FindItemWithText(string text, bool includeSubItemsInSearch, int startIndex) {
            return FindItemWithText(text, includeSubItemsInSearch, startIndex, true);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FindItemWithText3"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewItem FindItemWithText(string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch) {
            if (startIndex < 0 || startIndex >= this.Items.Count)
            {
                throw new ArgumentOutOfRangeException("startIndex", SR.GetString(SR.InvalidArgument, "startIndex", (startIndex).ToString(CultureInfo.CurrentCulture)));
            }
            return FindItem(true, text, isPrefixSearch, new Point(0,0), SearchDirectionHint.Down, startIndex, includeSubItemsInSearch);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FindNearestItem"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewItem FindNearestItem(SearchDirectionHint dir, Point point) {
            return FindNearestItem(dir, point.X, point.Y);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.FindNearestItem2"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewItem FindNearestItem(SearchDirectionHint searchDirection, int x, int y)
        {
            if (this.View != View.SmallIcon && this.View != View.LargeIcon) {
                throw new InvalidOperationException(SR.GetString(SR.ListViewFindNearestItemWorksOnlyInIconView));
            }
 
            if ( searchDirection < SearchDirectionHint.Left || searchDirection > SearchDirectionHint.Down) {
                throw new ArgumentOutOfRangeException("searchDirection", SR.GetString(SR.InvalidArgument, "searchDirection", (searchDirection).ToString()));
            }
 
            // the win32 ListView::FindNearestItem does some pretty weird things to determine the nearest item.
            // simply passing the (x,y) coordinates will cause problems when we call FindNearestItem for a point inside an item.
            // so we have to do some special processing when (x,y) falls inside an item;
            // take a look at VSWHIDBEY bug 178646 and the attached ListView_IFindNearestItem.c file for a complete story.
            ListViewItem lvi = this.GetItemAt(x,y);
 
            if (lvi != null) {
                Rectangle itemBounds = lvi.Bounds;
                // LVM_FINDITEM is a nightmare
                // LVM_FINDITEM will use the top left corner of icon rectangle to determine the closest item
                // What happens if there is no icon for this item? then the top left corner of the icon rectangle falls INSIDE the item label (???)
                //
 
                Rectangle iconBounds = this.GetItemRect(lvi.Index, ItemBoundsPortion.Icon);
 
                switch (searchDirection) {
                    case SearchDirectionHint.Up:
                        y = Math.Max(itemBounds.Top, iconBounds.Top) - 1;
                        break;
                    case SearchDirectionHint.Down:
                        y = Math.Max(itemBounds.Top, iconBounds.Top) + 1;
                        break;
                    case SearchDirectionHint.Left:
                        x = Math.Max(itemBounds.Left, iconBounds.Left) - 1;
                        break;
                    case SearchDirectionHint.Right:
                        x = Math.Max(itemBounds.Left, iconBounds.Left) + 1;
                        break;
                    default:
                        Debug.Assert(false, "these are all the search directions");
                        break;
                 }
            }
 
            return FindItem(false, String.Empty, false, new Point(x, y), searchDirection, -1, false);
        }
 
        private ListViewItem FindItem(bool isTextSearch, string text, bool isPrefixSearch, Point pt, SearchDirectionHint dir, int startIndex, bool includeSubItemsInSearch) {
            if (this.Items.Count == 0) {
                return null;
            }
 
            if (!IsHandleCreated)
                CreateHandle();
            if (VirtualMode) {
                SearchForVirtualItemEventArgs sviEvent = new SearchForVirtualItemEventArgs(isTextSearch, isPrefixSearch, includeSubItemsInSearch, text, pt, dir, startIndex);
 
                OnSearchForVirtualItem(sviEvent);
                // NOTE: this will cause a RetrieveVirtualItem event w/o a corresponding cache hint event.
                if (sviEvent.Index != -1) {
                    return this.Items[sviEvent.Index];
                } else {
                    return null;
                }
            } else {
                NativeMethods.LVFINDINFO lvFindInfo = new NativeMethods.LVFINDINFO();
                if (isTextSearch) {
                    lvFindInfo.flags = NativeMethods.LVFI_STRING;
                    lvFindInfo.flags |= (isPrefixSearch ? NativeMethods.LVFI_PARTIAL : 0);
                    lvFindInfo.psz = text;
                } else {
                    lvFindInfo.flags = NativeMethods.LVFI_NEARESTXY;
                    lvFindInfo.ptX = pt.X;
                    lvFindInfo.ptY = pt.Y;
                    // we can do this because SearchDirectionHint is set to the VK_*
                    lvFindInfo.vkDirection = (int)dir;
                }
                lvFindInfo.lParam = IntPtr.Zero;
                int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle),
                                                                 NativeMethods.LVM_FINDITEM,
                                                                 startIndex-1,                      // decrement startIndex so that the search is 0-based
                                                                 ref lvFindInfo);
                if (index >= 0) {
                    return Items[index];
                } else if (isTextSearch && includeSubItemsInSearch) {
                    // win32 listView control can't search inside sub items
                    for (int i = startIndex; i < this.Items.Count; i ++) {
                        ListViewItem lvi = this.Items[i];
                        for (int j = 0; j < lvi.SubItems.Count; j ++) {
                            ListViewItem.ListViewSubItem lvsi = lvi.SubItems[j];
                            // the win32 list view search for items w/ text is case insensitive
                            // do the same for sub items
                            // because we are comparing user defined strings we have to do the slower String search
                            // ie, use String.Compare(string, string, case sensitive, CultureInfo)
                            // instead of new Whidbey String.Equals overload
                            // String.Equals(string, string, StringComparison.OrdinalIgnoreCase
                            if (String.Equals(text,lvsi.Text, StringComparison.OrdinalIgnoreCase)) {
                                return lvi;
                            } else if (isPrefixSearch && CultureInfo.CurrentCulture.CompareInfo.IsPrefix(lvsi.Text, text, CompareOptions.IgnoreCase)) {
                                return lvi;
                            }
                        }
                    }
                    return null;
                } else {
                    return null;
                }
            }
        }
 
        private void ForceCheckBoxUpdate() {
            // Force ListView to update its checkbox bitmaps.
            //
            if (CheckBoxes && IsHandleCreated) {
                SendMessage(NativeMethods.LVM_SETEXTENDEDLISTVIEWSTYLE, NativeMethods.LVS_EX_CHECKBOXES, 0);
                SendMessage(NativeMethods.LVM_SETEXTENDEDLISTVIEWSTYLE, NativeMethods.LVS_EX_CHECKBOXES, NativeMethods.LVS_EX_CHECKBOXES);
 
                // Comctl should handle auto-arrange for us, but doesn't
                if (AutoArrange) {
                    ArrangeIcons(Alignment);
                }
            }
        }
 
        private string GenerateRandomName() {
            Debug.Assert(this.BackgroundImage != null, "we need to generate random numbers only when saving the background image to disk");
            Bitmap bm = new Bitmap(this.BackgroundImage);
            int handle = 0;
 
            try {
                handle = unchecked ((int) (long) bm.GetHicon());
            } catch {
                bm.Dispose();
            }
 
            Random rnd;
            if (handle == 0) {
                // there was a problem when we got the icon handle
                // use DateTime.Now to seed the randomizer
                rnd = new Random((int)System.DateTime.Now.Ticks);
            } else {
                rnd = new Random(handle);
            }
            return rnd.Next().ToString(CultureInfo.InvariantCulture);
        }
 
        // IDs for identifying ListViewItem's
        private int GenerateUniqueID() {
            // Okay, if someone adds several billion items to the list and doesn't remove all of them,
            // we can reuse the same ID, but I'm willing to take that risk.  We are even tracking IDs
            // on a per-list view basis to reduce the problem.
            int result = nextID++;
            if (result == -1) {// leave -1 as a "no such value" ID
                result = 0;
                nextID = 1;
            }
            return result;
        }
 
        /// <devdoc>
        ///     Gets the real index for the given item.  lastIndex is the last return
        ///     value from GetDisplayIndex, or -1 if you don't know.  If provided,
        ///     the search for the index can be greatly improved.
        /// </devdoc>
        internal int GetDisplayIndex(ListViewItem item, int lastIndex) {
 
            Debug.Assert(item.listView == this, "Can't GetDisplayIndex if the list item doesn't belong to us");
            Debug.Assert(item.ID != -1, "ListViewItem has no ID yet");
 
            ApplyUpdateCachedItems();
            if (IsHandleCreated && !ListViewHandleDestroyed) {
                Debug.Assert(listItemsArray == null, "listItemsArray not null, even though handle created");
 
                NativeMethods.LVFINDINFO info = new NativeMethods.LVFINDINFO();
                info.lParam = (IntPtr) item.ID;
                info.flags = NativeMethods.LVFI_PARAM;
 
                int displayIndex = -1;
 
                if (lastIndex != -1) {
                    displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_FINDITEM, lastIndex - 1, ref info);
                }
 
                if (displayIndex == -1) {
                    displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_FINDITEM, -1 /* beginning */, ref info);
                }
                Debug.Assert(displayIndex != -1, "This item is in the list view -- why can't we find a display index for it?");
                return displayIndex;
            }
            else {
                // PERF: The only reason we should ever call this before the handle is created
                // is if the user calls ListViewItem.Index.
                Debug.Assert(listItemsArray != null, "listItemsArray is null, but the handle isn't created");
 
                int index = 0;
                foreach (object o in listItemsArray) {
                    if (o == item)
                        return index;
                    index++;
                }
                return -1;
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetColumnIndex"]/*' />
        /// <devdoc>
        ///     Called by ColumnHeader objects to determine their position
        ///     in the ListView
        /// </devdoc>
        /// <internalonly/>
        internal int GetColumnIndex(ColumnHeader ch) {
            if (columnHeaders == null)
                return -1;
 
            for (int i = 0; i < columnHeaders.Length; i++) {
                if (columnHeaders[i] == ch)
                    return i;
            }
 
            return -1;
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetItemAt"]/*' />
        /// <devdoc>
        ///     Returns the current ListViewItem corresponding to the specific
        ///     x,y co-ordinate.
        /// </devdoc>
        public ListViewItem GetItemAt(int x, int y) {
            NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO();
 
            lvhi.pt_x = x;
            lvhi.pt_y = y;
 
            int displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi);
 
            ListViewItem li = null;
            if (displayIndex >= 0 && ((lvhi.flags & NativeMethods.LVHT_ONITEM) != 0))
                li = Items[displayIndex];
 
            return li;
        }
 
        internal int GetNativeGroupId(ListViewItem item) {
            item.UpdateGroupFromName();
 
            if (item.Group != null && Groups.Contains(item.Group)) {
                return item.Group.ID;
            }
            else {
                EnsureDefaultGroup();
                return DefaultGroup.ID;
            }
        }
 
        internal void GetSubItemAt(int x, int y, out int iItem, out int iSubItem) {
            NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO();
 
            lvhi.pt_x = x;
            lvhi.pt_y = y;
 
            int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SUBITEMHITTEST, 0, lvhi);
 
            if (index > -1) {
                iItem = lvhi.iItem;
                iSubItem = lvhi.iSubItem;
            } else {
                iItem = -1;
                iSubItem = -1;
            }
        }
 
        internal Point GetItemPosition(int index) {
            NativeMethods.POINT pt = new NativeMethods.POINT();
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_GETITEMPOSITION, index, pt);
 
            return new Point(pt.x, pt.y);
        }
 
        internal int GetItemState(int index) {
            return GetItemState(index, NativeMethods.LVIS_FOCUSED | NativeMethods.LVIS_SELECTED | NativeMethods.LVIS_CUT |
                                NativeMethods.LVIS_DROPHILITED | NativeMethods.LVIS_OVERLAYMASK |
                                NativeMethods.LVIS_STATEIMAGEMASK);
        }
 
        internal int GetItemState(int index, int mask) {
            if (index < 0 || ((this.VirtualMode && index >= this.VirtualListSize) || (!this.VirtualMode && index >= itemCount))) {
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
            }
            Debug.Assert(IsHandleCreated, "How did we add items without a handle?");
 
            return unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETITEMSTATE, index, mask));
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetItemRect"]/*' />
        /// <devdoc>
        ///     Returns a list item's bounding rectangle, including subitems.
        /// </devdoc>
        public Rectangle GetItemRect(int index) {
            return GetItemRect(index, 0);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetItemRect1"]/*' />
        /// <devdoc>
        ///     Returns a specific portion of a list item's bounding rectangle.
        /// </devdoc>
        public Rectangle GetItemRect(int index, ItemBoundsPortion portion) {
            if (index < 0 || index >= this.Items.Count) {
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
            }
            //valid values are 0x0 to 0x3
            if (!ClientUtils.IsEnumValid(portion, (int)portion, (int)ItemBoundsPortion.Entire, (int)ItemBoundsPortion.ItemOnly)){
                throw new InvalidEnumArgumentException("portion", (int)portion, typeof(ItemBoundsPortion));
            }
 
            if (this.View == View.Details && this.Columns.Count == 0) {
                return Rectangle.Empty;
            }
 
 
            NativeMethods.RECT itemrect = new NativeMethods.RECT();
            itemrect.left = (int)portion;
            if (unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETITEMRECT, index, ref itemrect)) == 0)
                throw new ArgumentException(SR.GetString(SR.InvalidArgument,
                                                          "index",
                                                          (index).ToString(CultureInfo.CurrentCulture)));
 
            return Rectangle.FromLTRB(itemrect.left, itemrect.top, itemrect.right, itemrect.bottom);
        }
 
        /// <devdoc>
        ///     Private version of GetItemRect that fails silently. We use this instead of catching
        ///     exceptions thrown by GetItemRect, to avoid first chance exceptions confusing the user.
        /// </devdoc>
        private Rectangle GetItemRectOrEmpty(int index) {
            if (index < 0 || index >= this.Items.Count)
                return Rectangle.Empty;
 
            if (this.View == View.Details && this.Columns.Count == 0) {
                return Rectangle.Empty;
            }
 
 
            NativeMethods.RECT itemrect = new NativeMethods.RECT();
            itemrect.left = 0;
            if (unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETITEMRECT, index, ref itemrect)) == 0)
                return Rectangle.Empty;
 
            return Rectangle.FromLTRB(itemrect.left, itemrect.top, itemrect.right, itemrect.bottom);
        }
 
        private NativeMethods.LVGROUP GetLVGROUP(ListViewGroup group)
        {
            NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP();
            lvgroup.mask = NativeMethods.LVGF_HEADER | NativeMethods.LVGF_GROUPID | NativeMethods.LVGF_ALIGN;
 
            // Header
            //
            String header = group.Header;
            lvgroup.pszHeader = Marshal.StringToHGlobalAuto(header);
            lvgroup.cchHeader = header.Length;
 
            // Group ID
            //
            lvgroup.iGroupId = group.ID;
 
            // Alignment
            //
            switch(group.HeaderAlignment) {
                case HorizontalAlignment.Left:
                    lvgroup.uAlign = NativeMethods.LVGA_HEADER_LEFT;
                    break;
                case HorizontalAlignment.Right:
                    lvgroup.uAlign = NativeMethods.LVGA_HEADER_RIGHT;
                    break;
                case HorizontalAlignment.Center:
                    lvgroup.uAlign = NativeMethods.LVGA_HEADER_CENTER;
                    break;
            }
            return lvgroup;
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetSubItemRect"]/*' />
        /// <devdoc>
        ///     Returns a listview sub-item's bounding rectangle.
        /// </devdoc>
        internal Rectangle GetSubItemRect(int itemIndex, int subItemIndex) {
            return GetSubItemRect(itemIndex, subItemIndex, 0);
        }
 
        internal Rectangle GetSubItemRect(int itemIndex, int subItemIndex, ItemBoundsPortion portion) {
            // it seems that getting the rectangle for a sub item only works for list view which are in Details view
            if (this.View != View.Details) {
                return Rectangle.Empty;
            }
            if (itemIndex < 0 || itemIndex >= this.Items.Count) {
                throw new ArgumentOutOfRangeException("itemIndex", SR.GetString(SR.InvalidArgument, "itemIndex", (itemIndex).ToString(CultureInfo.CurrentCulture)));
            }
            int subItemCount = Items[itemIndex].SubItems.Count;
 
            if (subItemIndex < 0 || subItemIndex >= subItemCount) {
                throw new ArgumentOutOfRangeException("subItemIndex", SR.GetString(SR.InvalidArgument, "subItemIndex", (subItemIndex).ToString(CultureInfo.CurrentCulture)));
            }
            //valid values are 0x0 to 0x3
            if (!ClientUtils.IsEnumValid(portion, (int)portion, (int)ItemBoundsPortion.Entire, (int)ItemBoundsPortion.ItemOnly))
            {
                throw new InvalidEnumArgumentException("portion", (int)portion, typeof(ItemBoundsPortion));
            }
 
            if (this.Columns.Count == 0) {
                return Rectangle.Empty;
            }
 
            NativeMethods.RECT itemrect = new NativeMethods.RECT();
            itemrect.left = (int)portion;
            itemrect.top = subItemIndex;
            if (unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETSUBITEMRECT, itemIndex, ref itemrect)) == 0)
                throw new ArgumentException(SR.GetString(SR.InvalidArgument,
                                                          "itemIndex",
                                                          (itemIndex).ToString(CultureInfo.CurrentCulture)));
 
            Rectangle result = Rectangle.FromLTRB(itemrect.left, itemrect.top, itemrect.right, itemrect.bottom);
 
            return result;
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HitTest"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewHitTestInfo HitTest(Point point) {
            return HitTest(point.X, point.Y);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HitTest1"]/*' />
        /// <devdoc>
        /// </devdoc>
        public ListViewHitTestInfo HitTest(int x, int y) {
            if (!this.ClientRectangle.Contains(x, y)) {
                return new ListViewHitTestInfo(null /*hitItem*/, null /*hitSubItem*/, ListViewHitTestLocations.None /*hitLocation*/);
            }
 
            NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO();
            lvhi.pt_x = x;
            lvhi.pt_y = y;
 
            int iItem;
 
            if (this.View == View.Details) {
                iItem = unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SUBITEMHITTEST, 0, lvhi));
            } else {
                iItem = unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_HITTEST, 0, lvhi));
            }
 
            ListViewItem item = (iItem == -1) ? null : Items[iItem];
            ListViewHitTestLocations location = ListViewHitTestLocations.None;
 
            if (item == null && (NativeMethods.LVHT_ABOVE & lvhi.flags) == NativeMethods.LVHT_ABOVE) {
                location = (ListViewHitTestLocations)((MASK_HITTESTFLAG & lvhi.flags) | (int)ListViewHitTestLocations.AboveClientArea);
            }
            else if (item != null && (NativeMethods.LVHT_ONITEMSTATEICON & lvhi.flags) == NativeMethods.LVHT_ONITEMSTATEICON) {
                location = (ListViewHitTestLocations)((MASK_HITTESTFLAG & lvhi.flags) | (int)ListViewHitTestLocations.StateImage);
            }
            else {
                location = (ListViewHitTestLocations)lvhi.flags;
            }
 
            if (this.View == View.Details && item != null) {
                if (lvhi.iSubItem < item.SubItems.Count) {
                    return new ListViewHitTestInfo(item, item.SubItems[lvhi.iSubItem], location);
                } else {
                    return new ListViewHitTestInfo(item, null, location);
                }
            } else {
                return (new ListViewHitTestInfo(item, null, location));
            }
        }
 
        private void InvalidateColumnHeaders() {
            if (viewStyle == View.Details && IsHandleCreated) {
                // 
 
                IntPtr hwndHdr = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_GETHEADER, 0, 0);
                if (hwndHdr != IntPtr.Zero)
                    SafeNativeMethods.InvalidateRect(new HandleRef(this, hwndHdr), null, true);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.InsertColumn"]/*' />
        /// <devdoc>
        ///     Inserts a new Column into the ListView
        /// </devdoc>
        internal ColumnHeader InsertColumn(int index, ColumnHeader ch) {
            return InsertColumn(index, ch, true);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.InsertColumn1"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        internal ColumnHeader InsertColumn(int index, ColumnHeader ch, bool refreshSubItems) {
            if (ch == null)
                throw new ArgumentNullException("ch");
            if (ch.OwnerListview != null)
                throw new ArgumentException(SR.GetString(SR.OnlyOneControl, ch.Text), "ch");
 
 
            int idx;
            // in Tile view the ColumnHeaders collection is used for the Tile Information
            // recreate the handle in that case
            if (IsHandleCreated && this.View != View.Tile) {
                idx = InsertColumnNative(index, ch);
            }
            else {
                idx = index;
            }
 
            // First column must be left aligned
 
            if (-1 == idx)
                throw new InvalidOperationException(SR.GetString(SR.ListViewAddColumnFailed));
 
            // Add the column to our internal array
            int columnCount = (columnHeaders == null ? 0 : columnHeaders.Length);
            if (columnCount > 0) {
                ColumnHeader[] newHeaders = new ColumnHeader[columnCount + 1];
                if (columnCount > 0)
                    System.Array.Copy(columnHeaders, 0, newHeaders, 0, columnCount);
                columnHeaders = newHeaders;
            }
            else
                columnHeaders = new ColumnHeader[1];
 
            if (idx < columnCount) {
                System.Array.Copy(columnHeaders, idx, columnHeaders, idx + 1, columnCount - idx);
            }
            columnHeaders[idx] = ch;
            ch.OwnerListview = this;
 
            // in Tile view the ColumnHeaders collection is used for the Tile Information
            // recreate the handle in that case
            if (ch.ActualImageIndex_Internal != -1 && this.IsHandleCreated && this.View != View.Tile) {
                SetColumnInfo(NativeMethods.LVCF_IMAGE, ch);
            }
 
 
            // update the DisplayIndex for each column
            // we are only setting an integer in the ColumnHeader, this is not expensive
            int[] indices = new int[this.Columns.Count];
            for (int i = 0; i < this.Columns.Count; i ++) {
                ColumnHeader hdr = this.Columns[i];
                if (hdr == ch) {
                    // the newly added column
                    hdr.DisplayIndexInternal = index;
                } else if (hdr.DisplayIndex >= index) {
                    hdr.DisplayIndexInternal ++;
                }
                indices[i] = hdr.DisplayIndexInternal;
            }
 
            SetDisplayIndices( indices );
             
#if DEBUG
            CheckDisplayIndices();
#endif
            // in Tile view the ColumnHeaders collection is used for the Tile Information
            // recreate the handle in that case
            if (this.IsHandleCreated && this.View == View.Tile) {
                this.RecreateHandleInternal();
            } else if (IsHandleCreated && refreshSubItems)
                RealizeAllSubItems();
 
            return ch;
        }
 
        private int InsertColumnNative(int index, ColumnHeader ch) {
            NativeMethods.LVCOLUMN_T lvColumn = new NativeMethods.LVCOLUMN_T();
            lvColumn.mask = NativeMethods.LVCF_FMT | NativeMethods.LVCF_TEXT | NativeMethods.LVCF_WIDTH;// | NativeMethods.LVCF_ORDER | NativeMethods.LVCF_IMAGE;
 
            if (ch.OwnerListview != null && ch.ActualImageIndex_Internal != -1) {
                lvColumn.mask |= NativeMethods.LVCF_IMAGE;
                lvColumn.iImage = ch.ActualImageIndex_Internal;
            }
 
            lvColumn.fmt        = (int)ch.TextAlign;
            lvColumn.cx         = ch.Width;
            lvColumn.pszText    = ch.Text;
 
            return (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_INSERTCOLUMN, index, lvColumn);
        }
 
        // when the user adds a group, this helper method makes sure that all the items
        // in the list view are parented by a group - be it the DefaultGroup or some other group
        internal void InsertGroupInListView(int index, ListViewGroup group) {
            Debug.Assert(this.groups != null && this.groups.Count > 0, "this method should be used only when the user adds a group, not when we add our own DefaultGroup");
            Debug.Assert(group != this.DefaultGroup, "this method should be used only when the user adds a group, not when we add our own DefaultGroup");
 
            // the first time we add a group we have to group the items in the Default Group
            bool groupItems = (this.groups.Count == 1) && this.GroupsEnabled;
 
            UpdateGroupView();
            EnsureDefaultGroup();
            InsertGroupNative(index, group);
 
            // take all the list view items which don't belong to any group and put them in the default group
            //
            if (groupItems) {
                for (int i = 0; i < this.Items.Count; i ++) {
                    ListViewItem item = this.Items[i];
                    if (item.Group == null) {
                        item.UpdateStateToListView(item.Index);
                    }
                }
            }
 
#if DEBUG
            // sanity check: all the items in the list view should have a group ID
            if (this.GroupsEnabled) {
                for (int i = 0; i < this.Items.Count; i ++) {
                    ListViewItem item = this.Items[i];
                    NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
                    lvItem.iItem = item.Index;
                    lvItem.mask = NativeMethods.LVIF_GROUPID;
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_GETITEM, 0, ref lvItem);
                    Debug.Assert(lvItem.iGroupId != -1, "there is a list view item which is not parented");
                }
            }
#endif
        }
 
        // does the Win32 part of the job of inserting the group
        private void InsertGroupNative(int index, ListViewGroup group) {
            Debug.Assert(IsHandleCreated,"InsertGroupNative precondition: list-view handle must be created");
            Debug.Assert(group == DefaultGroup || this.Groups.Contains(group),"Make sure ListView.Groups contains this group before adding the native LVGROUP. Otherwise, custom-drawing may break.");
 
            NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP();
            try
            {
                 lvgroup = GetLVGROUP(group);
                 int retval = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this,this.Handle),NativeMethods.LVM_INSERTGROUP,index,lvgroup);
                 Debug.Assert(retval != -1,"Failed to insert group");
            }
            finally
            {
                 DestroyLVGROUP(lvgroup);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.InsertItem"]/*' />
        /// <devdoc>
        ///     Inserts a new ListViewItem into the ListView.  The item will be inserted
        ///     either in the correct sorted position, or, if no sorting is set, at the
        ///     position indicated by the index parameter.
        /// </devdoc>
        private void InsertItems(int displayIndex, ListViewItem[] items, bool checkHosting) {
 
            if (items == null || items.Length == 0) {
                return;
            }
 
            if (this.IsHandleCreated && this.Items.Count == 0 && this.View == View.SmallIcon && this.ComctlSupportsVisualStyles)
            {
                this.FlipViewToLargeIconAndSmallIcon = true;
            }
 
            // if we're in the middle of a Begin/EndUpdate, just push the items into our array list
            // as they'll get processed on EndUpdate.
            //
            if (updateCounter > 0 && Properties.GetObject(PropDelayedUpdateItems) != null) {
                // CheckHosting.
                if (checkHosting) {
                    for (int i = 0; i < items.Length; i ++) {
                        if (items[i].listView != null) {
                            throw new ArgumentException(SR.GetString(SR.OnlyOneControl, items[i].Text), "item");
                        }
                    }
                }
 
                ArrayList itemList = (ArrayList)Properties.GetObject(PropDelayedUpdateItems);
                Debug.Assert(itemList != null, "In Begin/EndUpdate with no delayed array!");
                if (itemList != null) {
                    itemList.AddRange(items);
                }
 
                // vsw 518637: add the list view item to the list view
                // this way we can retrieve the item's index inside BeginUpdate/EndUpdate
                for (int i = 0; i < items.Length; i ++) {
                    items[i].Host(this, GenerateUniqueID(), -1);
                }
 
                this.FlipViewToLargeIconAndSmallIcon = false;
 
                return;
            }
 
            // loop through the items and give them id's so we can identify them later.
            //
            for (int i = 0; i < items.Length; i++) {
                ListViewItem item = items[i];
 
                if (checkHosting && item.listView != null) {
                    throw new ArgumentException(SR.GetString(SR.OnlyOneControl, item.Text), "item");
                }
 
                // create an ID..
                //
                int itemID = GenerateUniqueID();
                Debug.Assert(!listItemsTable.ContainsKey(itemID), "internal hash table inconsistent -- inserting item, but it's already in the hash table");
                listItemsTable.Add(itemID, item);
 
                itemCount++;
                item.Host(this,itemID, -1);
 
                // if there's no handle created, just ad them to our list items array.
                //
                if (!IsHandleCreated) {
                    Debug.Assert(listItemsArray != null, "listItemsArray is null, but the handle isn't created");
                    listItemsArray.Insert(displayIndex + i, item);
                }
            }
 
            // finally if the handle is created, do the actual add into the real list view
            //
            if (IsHandleCreated) {
                Debug.Assert(listItemsArray == null, "listItemsArray not null, even though handle created");
                InsertItemsNative(displayIndex, items);
            }
 
            Invalidate();
            ArrangeIcons(alignStyle);
 
            // Microsoft:  this is bad for perf...I don't think we need this here.
            // Any newly added items shoul dhave the correct location.
            // UpdateListViewItemsLocations();
 
 
            // Update sorted order
            if (!VirtualMode) {
                Sort();
            }
 
            Debug.Assert(!this.FlipViewToLargeIconAndSmallIcon, "if we added even 1 item then we should have been done w/ FlipViewToLargeIconAndSmallIcon");
        }
 
 
        /// <devdoc>
        ///     Inserts a new ListViewItem into the list view itself.
        ///     This only will be called when the Handle has been created for the list view.
        ///     This method loops through the items, sets up their state then adds them.
        /// </devdoc>
        private int InsertItemsNative(int index, ListViewItem[] items) {
            if (items == null || items.Length == 0) {
                return 0;
            }
            Debug.Assert(IsHandleCreated, "InsertItemsNative precondition: list-view handle must be created");
 
            // Much more efficient to call the native insert with max + 1, than with max.  The + 1
            // for the display index accounts for itemCount++ above.
            //
            if (index == itemCount - 1) {
                index++;
            }
 
            // Create and add the LVITEM
            NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
            int actualIndex = -1;
            IntPtr hGlobalColumns = IntPtr.Zero;
            int maxColumns = 0;
            this.listViewState1[LISTVIEWSTATE1_insertingItemsNatively] = true;
 
            try {
                // Set the count of items first.
                //
                SendMessage(NativeMethods.LVM_SETITEMCOUNT, itemCount, 0);
 
                // Now add the items.
                //
                for (int i = 0; i < items.Length; i++) {
                    ListViewItem li = items[i];
 
                    Debug.Assert(this.Items.Contains(li), "Make sure ListView.Items contains this item before adding the native LVITEM. Otherwise, custom-drawing may break.");
 
                    lvItem.Reset();
                    lvItem.mask = NativeMethods.LVIF_TEXT | NativeMethods.LVIF_IMAGE | NativeMethods.LVIF_PARAM | NativeMethods.LVIF_INDENT;
                    lvItem.iItem    = index + i;
                    lvItem.pszText  = li.Text;
                    lvItem.iImage   = li.ImageIndexer.ActualIndex;
                    lvItem.iIndent  = li.IndentCount;
                    lvItem.lParam   = (IntPtr)li.ID;
 
                    if (GroupsEnabled) {
                        lvItem.mask |= NativeMethods.LVIF_GROUPID;
                        lvItem.iGroupId = GetNativeGroupId(li);
 
                        #if DEBUG
                            Debug.Assert(SendMessage(NativeMethods.LVM_ISGROUPVIEWENABLED, 0, 0) != IntPtr.Zero, "Groups not enabled");
                            Debug.Assert(SendMessage(NativeMethods.LVM_HASGROUP, lvItem.iGroupId, 0) != IntPtr.Zero, "Doesn't contain group id: " + lvItem.iGroupId.ToString(CultureInfo.InvariantCulture));
                        #endif
                    }
 
                    lvItem.mask |= NativeMethods.LVIF_COLUMNS;
                    lvItem.cColumns = this.columnHeaders != null ? Math.Min(MAXTILECOLUMNS, this.columnHeaders.Length) : 0;
 
                    // make sure that our columns memory is big enough.
                    // if not, then realloc it.
                    //
                    if (lvItem.cColumns > maxColumns || hGlobalColumns == IntPtr.Zero) {
                        if (hGlobalColumns != IntPtr.Zero) {
                            Marshal.FreeHGlobal(hGlobalColumns);
                        }
                        hGlobalColumns = Marshal.AllocHGlobal(lvItem.cColumns * Marshal.SizeOf(typeof(int)));
                        maxColumns = lvItem.cColumns;
                    }
 
                    // now build and copy in the column indexes.
                    //
                    lvItem.puColumns = hGlobalColumns;
                    int[] columns = new int[lvItem.cColumns];
                    for(int c = 0; c < lvItem.cColumns; c++) {
                        columns[c] = c + 1;
                    }
                    Marshal.Copy(columns, 0, lvItem.puColumns, lvItem.cColumns);
 
                    // Inserting an item into a ListView with checkboxes causes one or more
                    // item check events to be fired for the newly added item.
                    // Therefore, we disable the item check event handler temporarily.
                    //
                    ItemCheckEventHandler oldOnItemCheck = onItemCheck;
                    onItemCheck = null;
 
                    int insertIndex;
 
                    try {
 
                        li.UpdateStateToListView(lvItem.iItem, ref lvItem, false);
 
                        insertIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_INSERTITEM, 0, ref lvItem);
                        if (actualIndex == -1) {
                            actualIndex = insertIndex;
 
                            // and update our starting index. so we're going from the same point.
                            //
                            index = actualIndex;
                        }
                    } finally {
 
                        // Restore the item check event handler.
                        //
                        onItemCheck = oldOnItemCheck;
                    }
 
                    if (-1 == insertIndex) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewAddItemFailed));
                    }
 
                    // add all sub items
                    for (int nItem = 1; nItem < li.SubItems.Count; ++nItem) {
                        SetItemText(insertIndex, nItem, li.SubItems[nItem].Text, ref lvItem);
                    }
 
                    // PERF.
                    // Use StateSelected in order to avoid a call into the native list view.
                    if (li.StateImageSet || li.StateSelected) {
                        // lvItem.state and lvItem.stateMask are set when the lvItem is updated in UpdateStateToListView call.
                        SetItemState(insertIndex, lvItem.state, lvItem.stateMask);
                    }
                }
            }
            finally {
                if (hGlobalColumns != IntPtr.Zero) {
                    Marshal.FreeHGlobal(hGlobalColumns);
                }
                this.listViewState1[LISTVIEWSTATE1_insertingItemsNatively] = false;
            }
 
            if (this.listViewState1[LISTVIEWSTATE1_selectedIndexChangedSkipped])
            {
                // VSWhidbey 549967 - SelectedIndexChanged event was delayed
                this.listViewState1[LISTVIEWSTATE1_selectedIndexChangedSkipped] = false;
                OnSelectedIndexChanged(EventArgs.Empty);
            }
 
            if (this.FlipViewToLargeIconAndSmallIcon) {
                this.FlipViewToLargeIconAndSmallIcon = false;
 
                this.View = View.LargeIcon;
                this.View = View.SmallIcon;
            }
 
            return actualIndex;
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.IsInputKey"]/*' />
        /// <devdoc>
        ///      Handling special input keys, such as pgup, pgdown, home, end, etc...
        /// </devdoc>
        protected override bool IsInputKey(Keys keyData) {
            if ((keyData & Keys.Alt) == Keys.Alt) return false;
            switch (keyData & Keys.KeyCode) {
                case Keys.PageUp:
                case Keys.PageDown:
                case Keys.Home:
                case Keys.End:
                    return true;
            }
 
            bool isInputKey = base.IsInputKey(keyData);
            if (isInputKey)
                return true;
 
            if (listViewState[LISTVIEWSTATE_inLabelEdit]) {
                switch (keyData & Keys.KeyCode) {
                    case Keys.Return:
                    case Keys.Escape:
                        return true;
                }
            }
 
            return false;
        }
 
        private void LargeImageListRecreateHandle(object sender, EventArgs e) {
            if (IsHandleCreated) {
                IntPtr handle = (LargeImageList == null) ? IntPtr.Zero : LargeImageList.Handle;
                SendMessage(NativeMethods.LVM_SETIMAGELIST, (IntPtr) NativeMethods.LVSIL_NORMAL, handle);
 
                ForceCheckBoxUpdate();
            }
        }
 
        private void LargeImageListChangedHandle(object sender, EventArgs e) {
            if (!this.VirtualMode && (null != sender) && (sender == imageListLarge) && IsHandleCreated) {
                foreach (ListViewItem item in Items) {
                    if (item.ImageIndexer.ActualIndex != -1 && item.ImageIndexer.ActualIndex >= imageListLarge.Images.Count) {
                        SetItemImage(item.Index,imageListLarge.Images.Count - 1);
                    }
                    else {
                        SetItemImage(item.Index,item.ImageIndexer.ActualIndex);
                    }
                }
            }
        }
 
        internal void ListViewItemToolTipChanged(ListViewItem item) {
            if (this.IsHandleCreated) {
                // If we reset the item text then we also reset the tool tip text
                //
                SetItemText(item.Index, 0 /*subItemIndex*/, item.Text);
            }
        }
 
        private void LvnBeginDrag(MouseButtons buttons, NativeMethods.NMLISTVIEW nmlv) {
            ListViewItem item = Items[nmlv.iItem];
            OnItemDrag(new ItemDragEventArgs(buttons, item));
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnAfterLabelEdit"]/*' />
        /// <devdoc>
        ///     Fires the afterLabelEdit event.
        /// </devdoc>
        protected virtual void OnAfterLabelEdit(LabelEditEventArgs e) {
            if (onAfterLabelEdit != null) onAfterLabelEdit(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnBackgroundImageChanged"]/*' />
        protected override void OnBackgroundImageChanged(EventArgs e) {
            if (IsHandleCreated) {
                SetBackgroundImage();
            }
            base.OnBackgroundImageChanged(e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnMouseLeave"]/*' />
        /// <devdoc>
        ///  We keep track of if we've hovered already so we don't fire multiple hover events
        /// </devdoc>
        /// <internalonly>
        protected override void OnMouseLeave(EventArgs e) {
            hoveredAlready = false;
            base.OnMouseLeave(e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnMouseHover"]/*' />
        /// <devdoc>
        ///     In order for the MouseHover event to fire for each item in a ListView,
        ///     the item the mouse is hovering over is found. Each time a new item is hovered
        ///     over a new event is raised.
        /// </devdoc>
        protected override void OnMouseHover(EventArgs e)  {
 
            /// Hover events need to be caught for each node
            /// within the TreeView so the appropriate
            /// NodeHovered event can be raised.
 
            ListViewItem item = null;
 
            if (this.Items.Count > 0) {
                // APPCOMPAT
                // V1.* users implement virtualization by communicating directly to the native ListView and by passing our virtualization implementation.
                // In that case, the native list view may have an item under the mouse even if our wrapper thinks the item count is 0.
                // And that may cause GetItemAt to throw an out of bounds exception.
                // See VSW 418791.
 
                Point pos = Cursor.Position;
                pos = PointToClientInternal(pos);
                item = GetItemAt(pos.X, pos.Y);
            }
 
            if (item != prevHoveredItem && item != null) {
                OnItemMouseHover(new ListViewItemMouseHoverEventArgs(item));
                prevHoveredItem = item;
            }
 
            if (!hoveredAlready) {
                base.OnMouseHover(e);
                hoveredAlready = true;
            }
 
            ResetMouseEventArgs();
 
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnBeforeLabelEdit"]/*' />
        /// <devdoc>
        ///     Fires the beforeLabelEdit event.
        /// </devdoc>
        protected virtual void OnBeforeLabelEdit(LabelEditEventArgs e) {
            if (onBeforeLabelEdit != null) onBeforeLabelEdit(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListBox.OnCacheVirtualItems"]/*' />
        /// <devdoc>
        /// </devdoc>
        protected virtual void OnCacheVirtualItems(CacheVirtualItemsEventArgs e)
        {
            CacheVirtualItemsEventHandler handler = (CacheVirtualItemsEventHandler)Events[EVENT_CACHEVIRTUALITEMS];
            if (handler != null)
                handler(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnColumnClick"]/*' />
        /// <devdoc>
        ///     Fires the columnClick event.
        /// </devdoc>
        protected virtual void OnColumnClick(ColumnClickEventArgs e) {
            if (onColumnClick != null) onColumnClick(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnColumnReordered"]/*' />
        /// <devdoc>
        ///     Fires the column header rearranged event.
        /// </devdoc>
        protected virtual void OnColumnReordered(ColumnReorderedEventArgs e) {
            ColumnReorderedEventHandler handler = (ColumnReorderedEventHandler) Events[EVENT_COLUMNREORDERED];
            if (handler != null)
                handler(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnColumnWidthChanged"]/*' />
        /// <devdoc>
        ///     Fires the column width changing event.
        /// </devdoc>
        protected virtual void OnColumnWidthChanged(ColumnWidthChangedEventArgs e) {
            ColumnWidthChangedEventHandler handler = (ColumnWidthChangedEventHandler)Events[EVENT_COLUMNWIDTHCHANGED];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnColumnWidthChanging"]/*' />
        /// <devdoc>
        ///     Fires the column width changing event.
        /// </devdoc>
        protected virtual void OnColumnWidthChanging(ColumnWidthChangingEventArgs e) {
            ColumnWidthChangingEventHandler handler = (ColumnWidthChangingEventHandler)Events[EVENT_COLUMNWIDTHCHANGING];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnDrawColumnHeader"]/*' />
        /// <devdoc>
        ///     Fires the DrawColumnHeader event.
        /// </devdoc>
        protected virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) {
            DrawListViewColumnHeaderEventHandler handler = (DrawListViewColumnHeaderEventHandler)Events[EVENT_DRAWCOLUMNHEADER];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnDrawItem"]/*' />
        /// <devdoc>
        ///     Fires the DrawItem event.
        /// </devdoc>
        protected virtual void OnDrawItem(DrawListViewItemEventArgs e) {
            DrawListViewItemEventHandler handler = (DrawListViewItemEventHandler)Events[EVENT_DRAWITEM];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListBox.OnDrawSubItem"]/*' />
        /// <devdoc>
        ///     Fires the DrawSubItem event.
        /// </devdoc>
        protected virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e) {
            DrawListViewSubItemEventHandler handler = (DrawListViewSubItemEventHandler)Events[EVENT_DRAWSUBITEM];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnFontChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnFontChanged(EventArgs e) {
            base.OnFontChanged(e);
 
            // When the user sets the font on the Form, the layout engine will compute the bounds for the native list view
            // and AFTER that will set the window font on the native list view.
            // That means that when the list view computed its item's position it did so w/ the previous font.
            // The solution is to send LVM_UPDATE to the native list view EVEN if the list view is not in SmallIcon or LargeIcon.
            // vsw 463436.
            if (!VirtualMode && IsHandleCreated && AutoArrange) {
                BeginUpdate();
                try {
                    SendMessage(NativeMethods.LVM_UPDATE, -1, 0);
                } finally {
                    EndUpdate();
                }
            }
 
            // If font changes and we have headers, they need to be expicitly invalidated
            //
            InvalidateColumnHeaders();
        }
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnHandleCreated"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        protected override void OnHandleCreated(EventArgs e) {
            // uncache the "ComctlSupportsVisualStyles" property on a handle creation
            listViewState[LISTVIEWSTATE_comctlSupportsVisualStylesTested] = false;
 
            // don't persist flipViewToLargeIconAndSmallIcon accross handle recreations...
            this.FlipViewToLargeIconAndSmallIcon = false;
 
            base.OnHandleCreated(e);
            //ComCtl 5 has some bug fixes that, to enable, require us to send the control
            //a CCM_SETVERSION with 5 as the version. The one we want in particular is
            //the fix for the node clipping issue when a font is set by means of CDRF_NEWFONT.
            //The fix is not perfect, but the behavior is better than before.
            int version = unchecked((int)(long)SendMessage(NativeMethods.CCM_GETVERSION, 0, 0));
            if (version < 5) {
                SendMessage(NativeMethods.CCM_SETVERSION, 5, 0);
            }
            UpdateExtendedStyles();
            RealizeProperties();
            int color = ColorTranslator.ToWin32(BackColor);
            SendMessage(NativeMethods.LVM_SETBKCOLOR,0,color);
            SendMessage(NativeMethods.LVM_SETTEXTCOLOR,0,ColorTranslator.ToWin32(base.ForeColor));
 
            // vsw 496340.
            // The native list view will not invalidate the entire list view item area if the BkColor is not CLR_NONE.
            // This not noticeable if the customer paints the items w/ the same background color as the list view itself.
            // However, if the customer paints the items w/ a color different from the list view's back color
            // then when the user changes selection the native list view will not invalidate the entire list view item area.
            SendMessage(NativeMethods.LVM_SETTEXTBKCOLOR, 0,NativeMethods.CLR_NONE);
 
            // LVS_NOSCROLL does not work well when the list view is in View.Details or in View.List modes.
            // we have to set this style after the list view was created and before we position the native list view items.
            //
            if (!Scrollable) {
                int style = unchecked((int)((long)UnsafeNativeMethods.GetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE)));
                style |= NativeMethods.LVS_NOSCROLL;
                UnsafeNativeMethods.SetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE, new HandleRef(null, (IntPtr)style));
            }
 
            // in VirtualMode we have to tell the list view to ask for the list view item's state image index
            if (VirtualMode) {
                int callbackMask = unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_GETCALLBACKMASK, 0, 0));
                callbackMask |= NativeMethods.LVIS_STATEIMAGEMASK;
                UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETCALLBACKMASK, callbackMask, 0);
            }
 
            if (ComctlSupportsVisualStyles) {
                SendMessage(NativeMethods.LVM_SETVIEW,(int)viewStyle,0);
                UpdateGroupView();
 
                // Add groups
                //
                if (groups != null) {
                    for(int index = 0;index < groups.Count;index++) {
                        InsertGroupNative(index,groups[index]);
                    }
                }
 
                // Set tile view settings
                //
                if (viewStyle == View.Tile) {
                    UpdateTileView();
                }
            }
 
            ListViewHandleDestroyed = false;
 
            // Use a copy of the list items array so that we can maintain the (handle created || listItemsArray != null) invariant
            //
            ListViewItem[] listViewItemsToAdd = null;
            if(listItemsArray != null)     {
                listViewItemsToAdd = (ListViewItem[])listItemsArray.ToArray(typeof(ListViewItem));
                listItemsArray = null;
            }
 
            int columnCount = (columnHeaders == null ? 0 : columnHeaders.Length);
            if(columnCount > 0)     {
                int[] indices = new int [columnHeaders.Length];
                int index = 0;
                foreach(ColumnHeader column in columnHeaders) {
                    indices[index] = column.DisplayIndex;
                    InsertColumnNative(index++,column);
                }
                SetDisplayIndices( indices );
            }
 
            // make sure that we're not in a begin/end update call.
            //
            if (itemCount > 0 && listViewItemsToAdd != null) {
                InsertItemsNative(0, listViewItemsToAdd);
            }
 
            if (VirtualMode && VirtualListSize > -1 && !DesignMode) {
                SendMessage(NativeMethods.LVM_SETITEMCOUNT, VirtualListSize, 0);
            }
 
            if(columnCount > 0) {
               UpdateColumnWidths(ColumnHeaderAutoResizeStyle.None);
            }
 
            ArrangeIcons(alignStyle);
            UpdateListViewItemsLocations();
 
            if (!VirtualMode) {
                Sort();
            }
            if (ComctlSupportsVisualStyles && (InsertionMark.Index > 0)) {
                InsertionMark.UpdateListView();
            }
 
            //
            // When the handle is recreated, update the SavedCheckedItems.
            // It is possible some checked items were added to the list view while its handle was null.
            //
            this.savedCheckedItems = null;
            if (!this.CheckBoxes && !this.VirtualMode) {
                for (int i = 0; i < this.Items.Count; i ++) {
                    if (this.Items[i].Checked) {
                        this.UpdateSavedCheckedItems(this.Items[i], true /*addItem*/);
                    }
                }
            }
 
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnHandleDestroyed"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnHandleDestroyed(EventArgs e) {
            // don't save the list view items state when in virtual mode : it is the responsability of the
            // user to cache the list view items in virtual mode
            if (!Disposing && !VirtualMode) {
 
                int count = Items.Count;
                for (int i = 0; i < count; i++) {
                    Items[i].UpdateStateFromListView(i, true);
                }
 
                // Save away the selected and checked items
                //
                if (SelectedItems != null && !VirtualMode) {
                    // Create an array because the SelectedItems collection is tuned for CopyTo()
                    ListViewItem[] lviArr = new ListViewItem[SelectedItems.Count];
                    SelectedItems.CopyTo(lviArr, 0);
                    savedSelectedItems = new List<ListViewItem>(lviArr.Length);
                    for (int i = 0; i < lviArr.Length; i ++) {
                        savedSelectedItems.Add(lviArr[i]);
                    }
                }
                Debug.Assert(listItemsArray == null, "listItemsArray not null, even though handle created");
                ListViewItem[] items = null;
                ListViewItemCollection tempItems = Items;
 
                if (tempItems != null) {
                    items = new ListViewItem[tempItems.Count];
                    tempItems.CopyTo(items, 0);
                }
 
                if (items != null) {
                    listItemsArray = new ArrayList(items.Length);
                    listItemsArray.AddRange(items);
                }
 
                ListViewHandleDestroyed = true;
            }
 
            base.OnHandleDestroyed(e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnItemActivate"]/*' />
        /// <devdoc>
        ///     Fires the itemActivate event.
        /// </devdoc>
        protected virtual void OnItemActivate(EventArgs e) {
            if (onItemActivate != null) onItemActivate(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnItemCheck"]/*' />
        /// <devdoc>
        ///     This is the code that actually fires the KeyEventArgs.  Don't
        ///     forget to call base.onItemCheck() to ensure that itemCheck vents
        ///     are correctly fired for all other keys.
        /// </devdoc>
        protected virtual void OnItemCheck(ItemCheckEventArgs ice) {
            if (onItemCheck != null) {
                onItemCheck(this, ice);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnItemChecked"]/*' />
        protected virtual void OnItemChecked(ItemCheckedEventArgs e) {
            if (onItemChecked != null) {
                onItemChecked(this, e);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnItemDrag"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected virtual void OnItemDrag(ItemDragEventArgs e) {
            if (onItemDrag != null) onItemDrag(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnItemMouseHover"]/*' />
        /// <devdoc>
        ///     Fires the ItemMouseHover event.
        /// </devdoc>
        protected virtual void OnItemMouseHover(ListViewItemMouseHoverEventArgs e) {
            if (onItemMouseHover != null) onItemMouseHover(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnItemSelectionChanged"]/*' />
        /// <devdoc>
        ///     Fires the ItemSelectionChanged event.
        /// </devdoc>
        protected virtual void OnItemSelectionChanged(ListViewItemSelectionChangedEventArgs e) {
            ListViewItemSelectionChangedEventHandler eh = (ListViewItemSelectionChangedEventHandler)Events[EVENT_ITEMSELECTIONCHANGED];
            if (eh != null)
                eh(this, e);
        }
 
        protected override void OnParentChanged(EventArgs e) {
            base.OnParentChanged(e);
 
            // We must do this because the list view control caches the parent
            // handle and always sends notifications to the same handle.
            if (IsHandleCreated) {
                RecreateHandleInternal();
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListBox.OnResize"]/*' />
        /// <devdoc>
        /// </devdoc>
        protected override void OnResize(EventArgs e) {
            // KB 137520: if the list view is in Details mode and it is not Scrollable, we need to reposition the column header control.
            if (this.View == View.Details && !this.Scrollable && this.IsHandleCreated) {
                PositionHeader();
            }
 
            base.OnResize(e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListBox.OnRetrieveVirtualItem"]/*' />
        /// <devdoc>
        /// </devdoc>
        protected virtual void OnRetrieveVirtualItem(RetrieveVirtualItemEventArgs e) {
            RetrieveVirtualItemEventHandler handler = (RetrieveVirtualItemEventHandler) Events[EVENT_RETRIEVEVIRTUALITEM];
            if (handler != null)
                handler(this, e);
        }
 
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnRightToLeftLayoutChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnRightToLeftLayoutChanged(EventArgs e) {
            if (GetAnyDisposingInHierarchy()) {
                return;
            }
 
            if (RightToLeft == RightToLeft.Yes) {
                RecreateHandleInternal();
            }
 
            EventHandler eh = Events[EVENT_RIGHTTOLEFTLAYOUTCHANGED] as EventHandler;
            if (eh != null) {
                 eh(this, e);
            }
        }
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnSearchForVirtualItem"]/*' />
        /// <devdoc>
        ///     Fires the search for virtual item event.
        /// </devdoc>
        protected virtual void OnSearchForVirtualItem(SearchForVirtualItemEventArgs e) {
            SearchForVirtualItemEventHandler handler = (SearchForVirtualItemEventHandler) Events[EVENT_SEARCHFORVIRTUALITEM];
            if (handler != null)
                handler(this, e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.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 virtual void OnSelectedIndexChanged(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EVENT_SELECTEDINDEXCHANGED];
            if (handler != null) handler(this,e);
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnSystemColorsChanged"]/*' />
        protected override void OnSystemColorsChanged(EventArgs e) {
            base.OnSystemColorsChanged(e);
 
            if (IsHandleCreated) {
                int color = ColorTranslator.ToWin32(BackColor);
                SendMessage(NativeMethods.LVM_SETBKCOLOR, 0,color);
                // We should probably be OK if we don't set the TEXTBKCOLOR to CLR_NONE.
                // However, for the sake of being more robust, reset the TECTBKCOLOR to CLR_NONE when the system palette changes.
                SendMessage(NativeMethods.LVM_SETTEXTBKCOLOR, 0,NativeMethods.CLR_NONE);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.OnVirtualItemSelectionRangeChanged"]/*' />
        protected virtual void OnVirtualItemsSelectionRangeChanged(ListViewVirtualItemsSelectionRangeChangedEventArgs e) {
            ListViewVirtualItemsSelectionRangeChangedEventHandler eh = (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events[EVENT_VIRTUALITEMSSELECTIONRANGECHANGED];
            if (eh != null)
                eh(this, e);
        }
 
        private unsafe void PositionHeader() {
            IntPtr hdrHWND = UnsafeNativeMethods.GetWindow(new HandleRef(this, this.Handle), NativeMethods.GW_CHILD);
            if (hdrHWND != IntPtr.Zero) {
 
                IntPtr prc   = IntPtr.Zero;
                IntPtr pwpos = IntPtr.Zero;
 
                prc = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.RECT)));
                if (prc == IntPtr.Zero) {
                    return;
                }
 
                try {
                    pwpos = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.WINDOWPOS)));
 
                    if (prc == IntPtr.Zero) {
                        // we could not allocate memory.
                        // return
                        return;
                    }
 
                    UnsafeNativeMethods.GetClientRect(new HandleRef(this, this.Handle), prc);
 
                    NativeMethods.HDLAYOUT hd = new NativeMethods.HDLAYOUT();
                    hd.prc = prc;
                    hd.pwpos = pwpos;
 
                    // get the layout information
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, hdrHWND), NativeMethods.HDM_LAYOUT, 0, ref hd);
 
                    // now take the information from the native wpos struct and put it into a managed WINDOWPOS
                    NativeMethods.WINDOWPOS wpos = (NativeMethods.WINDOWPOS) Marshal.PtrToStructure(pwpos, typeof(NativeMethods.WINDOWPOS));
 
                    // position the header control
                    SafeNativeMethods.SetWindowPos(new HandleRef(this, hdrHWND),
                                                   new HandleRef(this, wpos.hwndInsertAfter),
                                                   wpos.x,
                                                   wpos.y,
                                                   wpos.cx,
                                                   wpos.cy,
                                                   wpos.flags | NativeMethods.SWP_SHOWWINDOW);
                } finally {
 
                    // clean up our memory
                    if (prc != IntPtr.Zero) {
                        Marshal.FreeHGlobal(prc);
                    }
                    if (pwpos != IntPtr.Zero) {
                        Marshal.FreeHGlobal(pwpos);
                    }
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.RealizeAllSubItems"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        private void RealizeAllSubItems() {
            NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
            for (int i = 0; i < itemCount; i++) {
                int subItemCount = Items[i].SubItems.Count;
                for (int j = 0; j < subItemCount; j++) {
                    SetItemText(i, j, Items[i].SubItems[j].Text, ref lvItem);
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.RealizeProperties"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        protected void RealizeProperties() {
            //Realize state information
            Color c;
 
            c = BackColor;
            if (c != SystemColors.Window) {
                SendMessage(NativeMethods.LVM_SETBKCOLOR, 0, ColorTranslator.ToWin32(c));
            }
            c = ForeColor;
            if (c != SystemColors.WindowText)
                SendMessage(NativeMethods.LVM_SETTEXTCOLOR, 0, ColorTranslator.ToWin32(c));
 
 
            if (null != imageListLarge)
                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_NORMAL, imageListLarge.Handle);
 
            if (null != imageListSmall)
                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_SMALL, imageListSmall.Handle);
 
            if (null != imageListState) {
                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, imageListState.Handle);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.RedrawItems"]/*' />
        /// <devdoc>
        ///     Forces the redraw of a range of listview items.
        /// </devdoc>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public void RedrawItems(int startIndex, int endIndex, bool invalidateOnly)
        {
            if (this.VirtualMode)
            {
                if (startIndex < 0 || startIndex >= this.VirtualListSize)
                {
                    throw new ArgumentOutOfRangeException("startIndex", SR.GetString(SR.InvalidArgument, "startIndex", (startIndex).ToString(CultureInfo.CurrentCulture)));
                }
                if (endIndex < 0 || endIndex >= this.VirtualListSize)
                {
                    throw new ArgumentOutOfRangeException("endIndex", SR.GetString(SR.InvalidArgument, "endIndex", (endIndex).ToString(CultureInfo.CurrentCulture)));
                }
            }
            else
            {
                if (startIndex < 0 || startIndex >= this.Items.Count)
                {
                    throw new ArgumentOutOfRangeException("startIndex", SR.GetString(SR.InvalidArgument, "startIndex", (startIndex).ToString(CultureInfo.CurrentCulture)));
                }
                if (endIndex < 0 || endIndex >= this.Items.Count)
                {
                    throw new ArgumentOutOfRangeException("endIndex", SR.GetString(SR.InvalidArgument, "endIndex", (endIndex).ToString(CultureInfo.CurrentCulture)));
                }
            }
            if (startIndex > endIndex)
            {
                throw new ArgumentException(SR.GetString(SR.ListViewStartIndexCannotBeLargerThanEndIndex));
            }
            if (this.IsHandleCreated)
            {
                int retval = (int) UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle),
                                                                   NativeMethods.LVM_REDRAWITEMS,
                                                                   startIndex, endIndex);
                Debug.Assert(retval != 0);
                // ListView control seems to be bogus. Items affected need to be invalidated in LargeIcon and SmallIcons views.
                if (this.View == View.LargeIcon || this.View == View.SmallIcon)
                {
                    Rectangle rectInvalid = this.Items[startIndex].Bounds;
                    for (int index = startIndex+1; index <= endIndex; index++)
                    {
                        rectInvalid = Rectangle.Union(rectInvalid, this.Items[index].Bounds);
                    }
                    if (startIndex > 0)
                    {
                        rectInvalid = Rectangle.Union(rectInvalid, this.Items[startIndex - 1].Bounds);
                    }
                    else
                    {
                        rectInvalid.Width += rectInvalid.X;
                        rectInvalid.Height += rectInvalid.Y;
                        rectInvalid.X = rectInvalid.Y = 0;
                    }
                    if (endIndex < this.Items.Count - 1)
                    {
                        rectInvalid = Rectangle.Union(rectInvalid, this.Items[endIndex + 1].Bounds);
                    }
                    else
                    {
                        rectInvalid.Height += this.ClientRectangle.Bottom - rectInvalid.Bottom;
                        rectInvalid.Width += this.ClientRectangle.Right - rectInvalid.Right;
                    }
                    if (this.View == View.LargeIcon)
                    {
                        rectInvalid.Inflate(1, this.Font.Height + 1);
                    }
                    Invalidate(rectInvalid);
                }
                if (!invalidateOnly)
                {
                    Update();
                }
            }
        }
 
        // makes sure that the list view items which are w/o a listView group are parented to the DefaultGroup - if necessary
        // and then tell win32 to remove this group
        internal void RemoveGroupFromListView(ListViewGroup group) {
               EnsureDefaultGroup();
 
               foreach(ListViewItem item in group.Items) {
                    if(item.ListView == this) {
                         item.UpdateStateToListView(item.Index);
                    }
               }
 
               RemoveGroupNative(group);
 
               UpdateGroupView();
        }
 
        // does the job of telling win32 listView to remove this group
        private void RemoveGroupNative(ListViewGroup group) {
               Debug.Assert(IsHandleCreated,"RemoveGroupNative precondition: list-view handle must be created");
               Debug.Assert(ComctlSupportsVisualStyles, "we should have checked this already");
               int retval = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_REMOVEGROUP, group.ID, IntPtr.Zero);
               Debug.Assert(retval != -1,"Failed to remove group");
 
               // it is the job of whoever deletes this group to also turn off grouping if this was the last
               // group deleted
               return;
          }
 
        private void Scroll(int fromLVItem, int toLVItem) {
            int scrollY = GetItemPosition(toLVItem).Y - GetItemPosition(fromLVItem).Y;
            UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SCROLL, 0, scrollY);
        }
 
        private void SetBackgroundImage() {
            // needed for OleInitialize
            Application.OleRequired();
 
            NativeMethods.LVBKIMAGE lvbkImage = new NativeMethods.LVBKIMAGE();
            lvbkImage.xOffset = 0;
            lvbkImage.yOffset = 0;
 
            // first, is there an existing temporary file to delete, remember its name
            // so that we can delete it if the list control doesn't...
            string fileNameToDelete = this.backgroundImageFileName;
 
            if (this.BackgroundImage != null) {
 
                // the list view needs these permissions when the app runs on an UNC share
                // and the list view creates / destroys temporary files for its background image
 
                // SECREVIEW : Safe to assert FileIO & Environment permissions here, just creating/deleting temp files.
                //
                EnvironmentPermission envPermission = new EnvironmentPermission(EnvironmentPermissionAccess.Read, "TEMP");
                FileIOPermission fiop = new FileIOPermission(PermissionState.Unrestricted);
                System.Security.PermissionSet permSet = new System.Security.PermissionSet(PermissionState.Unrestricted);
                permSet.AddPermission(envPermission);
                permSet.AddPermission(fiop);
                permSet.Assert();
 
                // save the image to a temporary file name
                try {
                    string tempDirName = System.IO.Path.GetTempPath();
                    System.Text.StringBuilder sb = new System.Text.StringBuilder(1024);
                    UnsafeNativeMethods.GetTempFileName(tempDirName, this.GenerateRandomName(), 0, sb);
 
                    this.backgroundImageFileName = sb.ToString();
 
                    this.BackgroundImage.Save(this.backgroundImageFileName, System.Drawing.Imaging.ImageFormat.Bmp);
                } finally {
                    System.Security.PermissionSet.RevertAssert();
                }
 
                lvbkImage.pszImage = this.backgroundImageFileName;
                lvbkImage.cchImageMax = this.backgroundImageFileName.Length + 1;
                lvbkImage.ulFlags = NativeMethods.LVBKIF_SOURCE_URL;
                if (BackgroundImageTiled)
                    lvbkImage.ulFlags |= NativeMethods.LVBKIF_STYLE_TILE;
                else
                    lvbkImage.ulFlags |= NativeMethods.LVBKIF_STYLE_NORMAL;
 
            } else {
                lvbkImage.ulFlags = NativeMethods.LVBKIF_SOURCE_NONE;
                this.backgroundImageFileName = String.Empty;
            }
 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETBKIMAGE, 0, lvbkImage);
 
            if (String.IsNullOrEmpty(fileNameToDelete)) {
                return;
            }
 
            // we need to cause a paint message on the win32 list view. This way the win 32 list view gives up
            // its reference to the previous image file it was hanging on to.
            // vsWhidbey 243708
 
            // 8 strings should be good enough for us
            if (this.bkImgFileNames == null) {
                this.bkImgFileNames = new string[BKIMGARRAYSIZE];
                this.bkImgFileNamesCount = -1;
            }
 
            if (this.bkImgFileNamesCount == BKIMGARRAYSIZE - 1) {
                // it should be fine to delete the file name that was added first.
                // if it's not fine, then increase BKIMGARRAYSIZE
                this.DeleteFileName(this.bkImgFileNames[0]);
                this.bkImgFileNames[0] = this.bkImgFileNames[1];
                this.bkImgFileNames[1] = this.bkImgFileNames[2];
                this.bkImgFileNames[2] = this.bkImgFileNames[3];
                this.bkImgFileNames[3] = this.bkImgFileNames[4];
                this.bkImgFileNames[4] = this.bkImgFileNames[5];
                this.bkImgFileNames[5] = this.bkImgFileNames[6];
                this.bkImgFileNames[6] = this.bkImgFileNames[7];
                this.bkImgFileNames[7] = null;
 
                this.bkImgFileNamesCount --;
            }
 
            this.bkImgFileNamesCount ++;
            this.bkImgFileNames[this.bkImgFileNamesCount] = fileNameToDelete;
 
            // now force the paint
            this.Refresh();
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SetColumnInfo"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        internal void SetColumnInfo(int mask, ColumnHeader ch) {
            if (IsHandleCreated) {
                Debug.Assert((mask & ~(NativeMethods.LVCF_FMT | NativeMethods.LVCF_TEXT | NativeMethods.LVCF_IMAGE)) == 0, "Unsupported mask in setColumnInfo");
                NativeMethods.LVCOLUMN lvColumn = new NativeMethods.LVCOLUMN();
                lvColumn.mask  = mask;
 
                if ((mask & NativeMethods.LVCF_IMAGE) != 0 || (mask & NativeMethods.LVCF_FMT) != 0) {
                    // When we set the ImageIndex we also have to alter the column format.
                    // This means that we have to include the TextAlign into the column format.
 
                    lvColumn.mask |= NativeMethods.LVCF_FMT;
 
                    if (ch.ActualImageIndex_Internal > -1) {
                        // you would think that setting iImage would be enough.
                        // actually we also have to set the format to include LVCFMT_IMAGE
                        lvColumn.iImage = ch.ActualImageIndex_Internal;
                        lvColumn.fmt |= NativeMethods.LVCFMT_IMAGE;
                    }
 
                    lvColumn.fmt |= (int) ch.TextAlign;
                }
 
                if ((mask & NativeMethods.LVCF_TEXT) != 0) {
                    lvColumn.pszText    = Marshal.StringToHGlobalAuto(ch.Text);
                }
 
                int retval = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SETCOLUMN, ch.Index, lvColumn);
                if ((mask & NativeMethods.LVCF_TEXT) != 0) {
                    Marshal.FreeHGlobal(lvColumn.pszText);
                }
 
                if (0 == retval)
                    throw new InvalidOperationException(SR.GetString(SR.ListViewColumnInfoSet));
                // vsw 383220: when running on AMD64 the list view does not invalidate the column header.
                // So we do it ourselves.
                InvalidateColumnHeaders();
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SetColumnWidth"]/*' />
        /// <devdoc>
        ///     Setting width is a special case 'cuz LVM_SETCOLUMNWIDTH accepts more values
        ///     for width than LVM_SETCOLUMN does.
        /// </devdoc>
        /// <internalonly/>
        internal void SetColumnWidth(int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize) {
            if ((columnIndex < 0) ||
                (columnIndex >= 0 && this.columnHeaders == null) ||
                (columnIndex >= this.columnHeaders.Length)) {
                throw new ArgumentOutOfRangeException("columnIndex", SR.GetString(SR.InvalidArgument, "columnIndex", (columnIndex).ToString(CultureInfo.CurrentCulture)));
            }
 
            //valid values are 0x0 to 0x2
            if (!ClientUtils.IsEnumValid(headerAutoResize, (int)headerAutoResize, (int)ColumnHeaderAutoResizeStyle.None, (int)ColumnHeaderAutoResizeStyle.ColumnContent))
            {
                throw new InvalidEnumArgumentException("headerAutoResize", (int)headerAutoResize, typeof(ColumnHeaderAutoResizeStyle));
            }
 
 
            int width = 0;
            int compensate = 0;
 
            if (headerAutoResize == ColumnHeaderAutoResizeStyle.None) {
                width = this.columnHeaders[columnIndex].WidthInternal;
 
                // If the width maps to a LVCSW_ const, then native control will autoresize.
                // We may need to compensate for that.
                if (width == NativeMethods.LVSCW_AUTOSIZE_USEHEADER) {
                    headerAutoResize = ColumnHeaderAutoResizeStyle.HeaderSize;
                } else if (width == NativeMethods.LVSCW_AUTOSIZE) {
                    headerAutoResize = ColumnHeaderAutoResizeStyle.ColumnContent;
                }
            }
 
            if (headerAutoResize == ColumnHeaderAutoResizeStyle.HeaderSize) {
                compensate = this.CompensateColumnHeaderResize(columnIndex, false /*columnHeaderResizeCancelled*/);
                width = NativeMethods.LVSCW_AUTOSIZE_USEHEADER;
            } else if (headerAutoResize == ColumnHeaderAutoResizeStyle.ColumnContent) {
                compensate = this.CompensateColumnHeaderResize(columnIndex, false /*columnHeaderResizeCancelled*/);
                width = NativeMethods.LVSCW_AUTOSIZE;
            }
 
            if (IsHandleCreated) {
                SendMessage(NativeMethods.LVM_SETCOLUMNWIDTH, columnIndex, NativeMethods.Util.MAKELPARAM(width, 0));
            }
 
            if (this.IsHandleCreated &&
               (headerAutoResize == ColumnHeaderAutoResizeStyle.ColumnContent ||
                headerAutoResize == ColumnHeaderAutoResizeStyle.HeaderSize)) {
                if (compensate != 0) {
                    int newWidth = this.columnHeaders[columnIndex].Width + compensate;
                    SendMessage(NativeMethods.LVM_SETCOLUMNWIDTH, columnIndex, NativeMethods.Util.MAKELPARAM(newWidth, 0));
                }
            }
        }
 
        private void SetColumnWidth(int index, int width) {
            if (IsHandleCreated) {
                SendMessage(NativeMethods.LVM_SETCOLUMNWIDTH, index, NativeMethods.Util.MAKELPARAM(width,0));
            }
        }
 
        // set the display indices of the listview columns
        private void SetDisplayIndices(int[] indices) {
 
            int[] orderedColumns = new int[ indices.Length ];
            for (int i=0; i<indices.Length; i++) {
                this.Columns[i].DisplayIndexInternal = indices[i];
                orderedColumns[indices[i]] = i;
            }
 
            if (this.IsHandleCreated && !this.Disposing) {
               UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETCOLUMNORDERARRAY, orderedColumns.Length, orderedColumns);
        }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.RemovefromSavedCheckedItems"]/*' />
        /// <devdoc>
        ///     This is a new internal method added which is used by ListView Item to set
        ///     the check state of the item in the savedCheckedItems collection
        ///     if the ListView Checkboxes is OFF.
        /// </devdoc>
        /// <internalonly/>
        internal void UpdateSavedCheckedItems(ListViewItem item, bool addItem)
        {
            if (addItem && this.savedCheckedItems == null) {
                this.savedCheckedItems = new List<ListViewItem>();
            }
 
            if (addItem) {
                this.savedCheckedItems.Add(item);
            } else if (this.savedCheckedItems != null) {
                Debug.Assert(this.savedCheckedItems.Contains(item), "somehow we lost track of one item");
                this.savedCheckedItems.Remove(item);
            }
            #if FALSE
            if (savedCheckedItems != null && savedCheckedItems.Length > 0) {
                ListViewItem[] newSavedCheckedItems;
                int index = 0;
                if (!addItem) {
                    int current = 0;
                    newSavedCheckedItems = new ListViewItem[savedCheckedItems.Length -1];
                    for(index = 0 ; index < savedCheckedItems.Length ; index++)
                    {
                        if (savedCheckedItems[index] == item) {
                            current = 1;
                            continue;
                        }
                        newSavedCheckedItems[index - current] = savedCheckedItems[index];
                    }
                }
                else {
                    newSavedCheckedItems = new ListViewItem[savedCheckedItems.Length +1];
                    for(index = 0 ; index < savedCheckedItems.Length ; index++)
                    {
                        newSavedCheckedItems[index] = savedCheckedItems[index];
                    }
                    newSavedCheckedItems[index] = item;
                }
                savedCheckedItems = newSavedCheckedItems;
            }
            else if (addItem) {
                savedCheckedItems = new ListViewItem[1];
                savedCheckedItems[0] = item;
            }
            #endif // FALSE
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SetToolTip"]/*' />
        /// <devdoc>
        ///     Called by ToolTip to poke in that Tooltip into this ComCtl so that the Native ChildToolTip is not exposed.
        /// </devdoc>
        /// <internalonly/>
        internal void SetToolTip(ToolTip toolTip, string toolTipCaption) {
            this.toolTipCaption = toolTipCaption;
            //native ListView expects tooltip HWND as a wParam and ignores lParam
            IntPtr oldHandle = UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETTOOLTIPS, new HandleRef(toolTip, toolTip.Handle), 0);
            UnsafeNativeMethods.DestroyWindow(new HandleRef(null, oldHandle));
        }
 
        internal void SetItemImage(int index, int image) {
            if (index < 0 || ((this.VirtualMode && index >= this.VirtualListSize) || (!this.VirtualMode && index >= itemCount))) {
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
            }
            if (this.IsHandleCreated) {
                NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
                lvItem.mask = NativeMethods.LVIF_IMAGE;
                lvItem.iItem = index;
                lvItem.iImage = image;
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SETITEM, 0, ref lvItem);
            }
        }
 
        internal void SetItemIndentCount(int index, int indentCount) {
            if (index < 0 || ((this.VirtualMode && index >= this.VirtualListSize) || (!this.VirtualMode && index >= itemCount))) {
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
            }
            if (this.IsHandleCreated) {
                NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
                lvItem.mask = NativeMethods.LVIF_INDENT;
                lvItem.iItem = index;
                lvItem.iIndent = indentCount;
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SETITEM, 0, ref lvItem);
            }
        }
 
        internal void SetItemPosition(int index, int x, int y) {
            if (VirtualMode)
                return;
            if (index < 0 || index >= itemCount)
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
 
            Debug.Assert(IsHandleCreated, "How did we add items without a handle?");
 
            NativeMethods.POINT pt = new NativeMethods.POINT();
            pt.x = x;
            pt.y = y;
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SETITEMPOSITION32, index, pt);
        }
 
        internal void SetItemState(int index, int state, int mask) {
            if (index < -1 || ((this.VirtualMode && index >= this.VirtualListSize) || (!this.VirtualMode && index >= itemCount))) {
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
            }
            Debug.Assert(index == -1 || this.IsHandleCreated, "How did we add items without a handle?");
 
            if (this.IsHandleCreated) {
                NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
                lvItem.mask = NativeMethods.LVIF_STATE;
                lvItem.state = state;
                lvItem.stateMask = mask;
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SETITEMSTATE, index, ref lvItem);
            }
        }
 
        internal void SetItemText(int itemIndex, int subItemIndex, string text) {
 
            NativeMethods.LVITEM lvItem =  new NativeMethods.LVITEM();
            SetItemText(itemIndex, subItemIndex, text, ref lvItem);
        }
 
        ///<devdoc>
        /// For perf, allow a LVITEM to be passed in so we can reuse in tight loops.
        ///</devdoc>
        private void SetItemText(int itemIndex, int subItemIndex, string text, ref NativeMethods.LVITEM lvItem) {
 
            Debug.Assert(IsHandleCreated, "SetItemText with no handle");
 
            // bug 185563 : a listView in list mode will not increase the item width if the length of the item's text increases
            // We have to make sure that the width of the "column" contains the string
            if (this.View == View.List && subItemIndex == 0) {
                int colWidth = unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_GETCOLUMNWIDTH, 0, 0));
 
                Graphics g = this.CreateGraphicsInternal();
                int textWidth = 0;
 
                try {
                    textWidth = Size.Ceiling(g.MeasureString(text, this.Font)).Width;
                }
                finally {
                    g.Dispose();
                }
 
                if (textWidth > colWidth) {
                    SetColumnWidth(0, textWidth);
                }
            }
 
            lvItem.mask = NativeMethods.LVIF_TEXT;
            lvItem.iItem    = itemIndex;
            lvItem.iSubItem = subItemIndex;
            lvItem.pszText  = text;
 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SETITEMTEXT, itemIndex, ref lvItem);
        }
 
        //
        // ComCtl32 list view uses a selection mark to keep track of selection state - iMark.
        // ComCtl32 list view updates iMark only when the user hovers over the item.
        // This means that if we programatically set the selection item, then the list view will not update
        // its selection mark.
        // So we explicitly set the selection mark.
        //
        internal void SetSelectionMark(int itemIndex) {
            if (itemIndex < 0 || itemIndex >= this.Items.Count) {
                return;
            }
            SendMessage(NativeMethods.LVM_SETSELECTIONMARK, 0, itemIndex);
        }
 
        private void SmallImageListRecreateHandle(object sender, EventArgs e) {
            if (IsHandleCreated) {
                IntPtr handle = (SmallImageList == null) ? IntPtr.Zero : SmallImageList.Handle;
                SendMessage(NativeMethods.LVM_SETIMAGELIST, (IntPtr) NativeMethods.LVSIL_SMALL, handle);
 
                ForceCheckBoxUpdate();
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Sort"]/*' />
        /// <devdoc>
        ///      Updated the sorted order
        /// </devdoc>
        public void Sort() {
            if (VirtualMode) {
                throw new InvalidOperationException(SR.GetString(SR.ListViewSortNotAllowedInVirtualListView));
            }
 
            ApplyUpdateCachedItems();
            if (IsHandleCreated && listItemSorter != null) {
                NativeMethods.ListViewCompareCallback callback = new NativeMethods.ListViewCompareCallback(this.CompareFunc);
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SORTITEMS, IntPtr.Zero, callback);
            }
        }
 
        private void StateImageListRecreateHandle(object sender, EventArgs e) {
            if (IsHandleCreated) {
                IntPtr handle = IntPtr.Zero;
                if (StateImageList != null) {
                    handle = imageListState.Handle;
                }
                SendMessage(NativeMethods.LVM_SETIMAGELIST, (IntPtr) NativeMethods.LVSIL_STATE, handle);
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ToString"]/*' />
        /// <devdoc>
        ///     Returns a string representation for this control.
        /// </devdoc>
        /// <internalonly/>
        public override string ToString() {
 
            string s = base.ToString();
 
            if (listItemsArray != null) {
                s += ", Items.Count: " + listItemsArray.Count.ToString(CultureInfo.CurrentCulture);
                if (listItemsArray.Count > 0) {
                    string z = listItemsArray[0].ToString();
                    string txt = (z.Length > 40) ? z.Substring(0, 40) : z;
                    s += ", Items[0]: " + txt;
                }
            }
            else if (Items != null) {
                s += ", Items.Count: " + Items.Count.ToString(CultureInfo.CurrentCulture);
                if (Items.Count > 0 && !VirtualMode) {
                    //Debug.Assert(Items[0] != null, "Why is there a null item in the list view item collection?");
                    string z = (Items[0] == null) ?  "null" : Items[0].ToString();
                    string txt = (z.Length > 40) ? z.Substring(0, 40) : z;
                    s += ", Items[0]: " + txt;
                }
 
            }
            return s;
        }
 
        internal void UpdateListViewItemsLocations() {
            if (!VirtualMode && IsHandleCreated && AutoArrange && (View == View.LargeIcon || View == View.SmallIcon)) {
 
                // this only has an affect for large icon and small icon views.
                //
                try {
                    BeginUpdate();
                    /*
                       Not sure this does anything that just calling the function doesn't...
 
                      for (int i = 0; i < this.itemCount; i ++) {
                        UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_UPDATE, this.Items[i].Index, 0);
                    } */
                    SendMessage(NativeMethods.LVM_UPDATE, -1, 0);
                }
                finally {
                    EndUpdate();
                }
            }
 
        }
 
        private void UpdateColumnWidths(ColumnHeaderAutoResizeStyle headerAutoResize) {
            if (columnHeaders != null) {
                for (int i = 0; i < this.columnHeaders.Length; i ++) {
                    SetColumnWidth(i, headerAutoResize);
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.UpdateExtendedStyles"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected void UpdateExtendedStyles() {
 
            if (IsHandleCreated) {
                int exStyle = 0;
                int exMask = NativeMethods.LVS_EX_ONECLICKACTIVATE | NativeMethods.LVS_EX_TWOCLICKACTIVATE |
                             NativeMethods.LVS_EX_TRACKSELECT | NativeMethods.LVS_EX_UNDERLINEHOT | NativeMethods.LVS_EX_ONECLICKACTIVATE |
                             NativeMethods.LVS_EX_HEADERDRAGDROP | NativeMethods.LVS_EX_CHECKBOXES |
                             NativeMethods.LVS_EX_FULLROWSELECT | NativeMethods.LVS_EX_GRIDLINES |
                             NativeMethods.LVS_EX_INFOTIP | NativeMethods.LVS_EX_DOUBLEBUFFER;
 
                switch (activation) {
                    case ItemActivation.OneClick:
                        exStyle |= NativeMethods.LVS_EX_ONECLICKACTIVATE;
                        break;
                    case ItemActivation.TwoClick:
                        exStyle |= NativeMethods.LVS_EX_TWOCLICKACTIVATE;
                        break;
                }
 
                if (AllowColumnReorder)
                    exStyle |= NativeMethods.LVS_EX_HEADERDRAGDROP;
 
                if (CheckBoxes)
                    exStyle |= NativeMethods.LVS_EX_CHECKBOXES;
 
                if (DoubleBuffered)
                    exStyle |= NativeMethods.LVS_EX_DOUBLEBUFFER;
 
                if (FullRowSelect)
                    exStyle |= NativeMethods.LVS_EX_FULLROWSELECT;
 
                if (GridLines)
                    exStyle |= NativeMethods.LVS_EX_GRIDLINES;
 
                if (HoverSelection)
                    exStyle |= NativeMethods.LVS_EX_TRACKSELECT;
 
                if (HotTracking)
                    exStyle |= NativeMethods.LVS_EX_UNDERLINEHOT;
 
                if (ShowItemToolTips)
                    exStyle |= NativeMethods.LVS_EX_INFOTIP;
 
                SendMessage(NativeMethods.LVM_SETEXTENDEDLISTVIEWSTYLE, exMask, exStyle);
                Invalidate();
            }
        }
 
        internal void UpdateGroupNative(ListViewGroup group) {
            Debug.Assert(IsHandleCreated,"UpdateGroupNative precondition: list-view handle must be created");
            Debug.Assert(ComctlSupportsVisualStyles, "we should have checked this already");
 
            NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP();
            try {
                lvgroup = GetLVGROUP(group);
                int retval = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle),
                                                                  NativeMethods.LVM_SETGROUPINFO,
                                                                  group.ID,
                                                                  lvgroup);
                Debug.Assert(retval != -1, "Failed to set group info");
            }
            finally
            {
                DestroyLVGROUP(lvgroup);
            }
 
            // The comctl32 ListView does not correctly invalidate itself, so we need to invalidate the entire ListView
            //
            Invalidate();
        }
 
        // ListViewGroupCollection::Clear needs to remove the items from the Default group
        //
        internal void UpdateGroupView() {
            if (IsHandleCreated && ComctlSupportsVisualStyles && !VirtualMode) {
                int retval = unchecked( (int) (long)SendMessage(NativeMethods.LVM_ENABLEGROUPVIEW, GroupsEnabled ? 1 : 0, 0));
                Debug.Assert(retval != -1, "Error enabling group view");
            }
        }
 
        // updates the win32 list view w/ our tile info - columns + tile size
        private void UpdateTileView() {
            Debug.Assert(ComctlSupportsVisualStyles, "this function works only when ComCtl 6.0 and higher is loaded");
            Debug.Assert(this.viewStyle == View.Tile, "this function should be called only in Tile view");
            NativeMethods.LVTILEVIEWINFO tileViewInfo = new NativeMethods.LVTILEVIEWINFO();
            // the tile view info line count
            tileViewInfo.dwMask = NativeMethods.LVTVIM_COLUMNS;
            tileViewInfo.cLines = this.columnHeaders != null ? this.columnHeaders.Length : 0;
 
            // the tile view info size
            tileViewInfo.dwMask |= NativeMethods.LVTVIM_TILESIZE;
            tileViewInfo.dwFlags = NativeMethods.LVTVIF_FIXEDSIZE;
            tileViewInfo.sizeTile = new NativeMethods.SIZE(this.TileSize.Width, this.TileSize.Height);
 
            bool retval = UnsafeNativeMethods.SendMessage(new HandleRef(this,Handle),NativeMethods.LVM_SETTILEVIEWINFO,0,tileViewInfo);
            Debug.Assert(retval,"LVM_SETTILEVIEWINFO failed");
        }
 
        private void WmNmClick(ref Message m) {
 
            // If we're checked, hittest to see if we're
            // on the check mark
 
            if (CheckBoxes) {
                Point pos = Cursor.Position;
                pos = PointToClientInternal(pos);
                NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO();
 
                lvhi.pt_x = pos.X;
                lvhi.pt_y = pos.Y;
 
                int displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi);
                if (displayIndex != -1 && (lvhi.flags & NativeMethods.LVHT_ONITEMSTATEICON) != 0) {
                    ListViewItem clickedItem = Items[displayIndex];
                    if (clickedItem.Selected) {
                        bool check = !clickedItem.Checked;
                        if (!VirtualMode) {
                            foreach(ListViewItem item in SelectedItems) {
                                if (item != clickedItem) {
                                    item.Checked = check;
                                }
                            }
                        }
                    }
                }
            }
        }
 
        private void WmNmDblClick(ref Message m) {
 
            // If we're checked, hittest to see if we're
            // on the item
 
            if (CheckBoxes) {
                Point pos = Cursor.Position;
                pos = PointToClientInternal(pos);
                NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO();
 
                lvhi.pt_x = pos.X;
                lvhi.pt_y = pos.Y;
 
                int displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi);
                if (displayIndex != -1 && (lvhi.flags & NativeMethods.LVHT_ONITEM) != 0) {
                    ListViewItem clickedItem = Items[displayIndex];
                    clickedItem.Checked = !clickedItem.Checked;
                }
            }
        }
 
        private void WmMouseDown(ref Message m, MouseButtons button, int clicks) {
 
            //Always Reset the MouseupFired....
            listViewState[LISTVIEWSTATE_mouseUpFired] = false;
            listViewState[LISTVIEWSTATE_expectingMouseUp] = true;
 
            //This is required to FORCE Validation before Windows ListView pushes its own message loop...
            FocusInternal();
 
            // Windows ListView pushes its own Windows ListView in WM_xBUTTONDOWN, so fire the
            // event before calling defWndProc or else it won't get fired until the button
            // comes back up.
            int x = NativeMethods.Util.SignedLOWORD(m.LParam);
            int y = NativeMethods.Util.SignedHIWORD(m.LParam);
            OnMouseDown(new MouseEventArgs(button, clicks, x, y, 0));
 
            //If Validation is cancelled dont fire any events through the Windows ListView's message loop...
            if (!ValidationCancelled) {
 
                if (CheckBoxes) {
                    ListViewHitTestInfo lvhti = this.HitTest(x, y);
                    if (imageListState != null && imageListState.Images.Count < 2) {
                        // vsw 156366: when the user clicks on the check box and the listView's state image list
                        // does not have 2 images, comctl will give us an AttemptToDivideByZero exception.
                        // So don't send the message to DefWndProc in this situation.
                        if (lvhti.Location != ListViewHitTestLocations.StateImage) {
                            DefWndProc(ref m);
                        }
                    }
                    else {
                        // When a user clicks on the state image, focus the item.
                        if (AccessibilityImprovements.Level2 && lvhti.Item != null && lvhti.Location == ListViewHitTestLocations.StateImage) {
                            lvhti.Item.Focused = true;
                        }
                        DefWndProc(ref m);
                    }
                }
                else
                {
                    DefWndProc(ref m);
                }
            }
 
        }
 
        private unsafe bool WmNotify(ref Message m) {
            NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam;
 
            // column header custom draw message handling
            if (nmhdr->code == NativeMethods.NM_CUSTOMDRAW && OwnerDraw)
            {
                try
                {
                    NativeMethods.NMCUSTOMDRAW* nmcd = (NativeMethods.NMCUSTOMDRAW*)m.LParam;
                    // Find out which stage we're drawing
                    switch (nmcd->dwDrawStage)
                    {
                        case NativeMethods.CDDS_PREPAINT:
                            {
                                m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYITEMDRAW);
                                return true; // we are done - don't do default handling
 
                            }
                        case NativeMethods.CDDS_ITEMPREPAINT:
                            {
                                Graphics g = Graphics.FromHdcInternal(nmcd->hdc);
                                Rectangle r = Rectangle.FromLTRB(nmcd->rc.left, nmcd->rc.top, nmcd->rc.right, nmcd->rc.bottom);
                                DrawListViewColumnHeaderEventArgs e = null;
 
                                try
                                {
                                    Color foreColor = ColorTranslator.FromWin32(SafeNativeMethods.GetTextColor(new HandleRef(this, nmcd->hdc)));
                                    Color backColor = ColorTranslator.FromWin32(SafeNativeMethods.GetBkColor(new HandleRef(this, nmcd->hdc)));
                                    Font font = GetListHeaderFont();
                                    e = new DrawListViewColumnHeaderEventArgs(g, r, (int)(nmcd->dwItemSpec),
                                                                        columnHeaders[(int)nmcd->dwItemSpec],
                                                                        (ListViewItemStates)(nmcd->uItemState),
                                                                        foreColor, backColor, font);
 
                                    OnDrawColumnHeader(e);
                                }
                                finally
                                {
                                    g.Dispose();
                                }
 
                                if (e.DrawDefault)
                                {
                                    m.Result = (IntPtr)(NativeMethods.CDRF_DODEFAULT);
                                    return false;
                                }
                                else
                                {
                                
                                    m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT);
                                    return true; // we are done - don't do default handling
                                }
                            }
 
                        default:
                            return false; //default handling
                    }
                }
                catch (Exception e)
                {
                    Debug.Fail("Exception occurred attempting to setup header custom draw. Disabling custom draw for the column header", e.ToString());
                    m.Result = (IntPtr)NativeMethods.CDRF_DODEFAULT;
                }
            }
 
 
            if (nmhdr->code == NativeMethods.NM_RELEASEDCAPTURE && listViewState[LISTVIEWSTATE_columnClicked]) {
                listViewState[LISTVIEWSTATE_columnClicked] = false;
                OnColumnClick(new ColumnClickEventArgs(columnIndex));
            }
 
            if (nmhdr->code == NativeMethods.HDN_BEGINTRACKA ||
                nmhdr->code == NativeMethods.HDN_BEGINTRACKW) {
               this.listViewState[LISTVIEWSTATE_headerControlTracking] = true;
 
               // Reset our tracking information for the new BEGINTRACK cycle.
               this.listViewState1[LISTVIEWSTATE1_cancelledColumnWidthChanging] = false;
               this.newWidthForColumnWidthChangingCancelled = -1;
               this.listViewState1[LISTVIEWSTATE1_cancelledColumnWidthChanging] = false;
 
               NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER) m.GetLParam(typeof(NativeMethods.NMHEADER));
               if (this.columnHeaders != null && this.columnHeaders.Length > nmheader.iItem) {
                   this.columnHeaderClicked = this.columnHeaders[nmheader.iItem];
                   this.columnHeaderClickedWidth = this.columnHeaderClicked.Width;
               } else {
                   this.columnHeaderClickedWidth = -1;
                   this.columnHeaderClicked = null;
               }
            }
 
            if (nmhdr->code == NativeMethods.HDN_ITEMCHANGINGA || 
                nmhdr->code == NativeMethods.HDN_ITEMCHANGINGW) {
                NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER) m.GetLParam(typeof(NativeMethods.NMHEADER));
 
                if (columnHeaders != null && nmheader.iItem < columnHeaders.Length &&
                    (this.listViewState[LISTVIEWSTATE_headerControlTracking] || this.listViewState[LISTVIEWSTATE_headerDividerDblClick])) {
                    // SECREVIEW:
                    // UnsafeNativeMethods.PtrToStructure asserts ReflectionPermission.
                    // We are fine asserting this permission because the HDITEM2 type is our type and we have control over it
                    // and over what it does in its constructor.
                    NativeMethods.HDITEM2 hdItem = (NativeMethods.HDITEM2) UnsafeNativeMethods.PtrToStructure((IntPtr) nmheader.pItem, typeof(NativeMethods.HDITEM2));
                    int newColumnWidth = ((hdItem.mask & NativeMethods.HDI_WIDTH) != 0) ? hdItem.cxy : -1;
                    ColumnWidthChangingEventArgs colWidthChanging = new ColumnWidthChangingEventArgs(nmheader.iItem, newColumnWidth);
                    OnColumnWidthChanging(colWidthChanging);
                    m.Result = (IntPtr) (colWidthChanging.Cancel ? 1 : 0);
                    if (colWidthChanging.Cancel) {
                        hdItem.cxy = colWidthChanging.NewWidth;
 
                        // We are called inside HDN_DIVIDERDBLCLICK.
                        // Turn off the compensation that our processing of HDN_DIVIDERDBLCLICK would otherwise add.
                        if (this.listViewState[LISTVIEWSTATE_headerDividerDblClick]) {
                            this.listViewState[LISTVIEWSTATE_columnResizeCancelled] = true;
                        }
 
                        this.listViewState1[LISTVIEWSTATE1_cancelledColumnWidthChanging] = true;
                        this.newWidthForColumnWidthChangingCancelled = colWidthChanging.NewWidth;
 
                        // skip default processing
                        return true;
                    } else {
                        return false;
                    }
                }
            }
 
            if ((nmhdr->code == NativeMethods.HDN_ITEMCHANGEDA ||
                nmhdr->code == NativeMethods.HDN_ITEMCHANGEDW) &&
                !this.listViewState[LISTVIEWSTATE_headerControlTracking]) {
                NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER)m.GetLParam(typeof(NativeMethods.NMHEADER));
                if (columnHeaders != null && nmheader.iItem < columnHeaders.Length) {
                    int w = columnHeaders[nmheader.iItem].Width;
 
                    if (this.columnHeaderClicked == null ||
                        (this.columnHeaderClicked == this.columnHeaders[nmheader.iItem] &&
                         this.columnHeaderClickedWidth != -1 &&
                         this.columnHeaderClickedWidth != w)) {
 
                        //
                        // If the user double clicked on the column header and we still need to compensate for the column resize
                        // then don't fire ColumnWidthChanged because at this point the column header does not have the final width.
                        //
                        if (this.listViewState[LISTVIEWSTATE_headerDividerDblClick]) {
                            if (this.CompensateColumnHeaderResize(m, this.listViewState[LISTVIEWSTATE_columnResizeCancelled]) == 0) {
                                OnColumnWidthChanged(new ColumnWidthChangedEventArgs(nmheader.iItem));
                            }
                        } else {
                            OnColumnWidthChanged(new ColumnWidthChangedEventArgs(nmheader.iItem));
                        }
 
                    }
                }
 
                this.columnHeaderClicked = null;
                this.columnHeaderClickedWidth = -1;
 
                ISite site = Site;
 
                // Microsoft, this seems like a really wierd place to annouce this change...
                if (site != null) {
                    IComponentChangeService cs = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
                    if (cs != null) {
                        try {
                            cs.OnComponentChanging(this, null);
                        }
                        catch (CheckoutException coEx) {
                            if (coEx == CheckoutException.Canceled) {
                                return false;
                            }
                            throw coEx;
                        }
                    }
                }
            }
 
            if (nmhdr->code == NativeMethods.HDN_ENDTRACKA || 
                nmhdr->code == NativeMethods.HDN_ENDTRACKW) {
                Debug.Assert(this.listViewState[LISTVIEWSTATE_headerControlTracking], "HDN_ENDTRACK and HDN_BEGINTRACK are out of sync...");
                this.listViewState[LISTVIEWSTATE_headerControlTracking] = false;
                if (this.listViewState1[LISTVIEWSTATE1_cancelledColumnWidthChanging]) {
                    m.Result = (IntPtr) 1;
                    if (this.newWidthForColumnWidthChangingCancelled != -1) {
                        NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER)m.GetLParam(typeof(NativeMethods.NMHEADER));
                        if (this.columnHeaders != null && this.columnHeaders.Length > nmheader.iItem) {
                            this.columnHeaders[nmheader.iItem].Width = this.newWidthForColumnWidthChangingCancelled;
                        }
                    }
 
                    this.listViewState1[LISTVIEWSTATE1_cancelledColumnWidthChanging] = false;
                    this.newWidthForColumnWidthChangingCancelled = -1;
 
                    // skip default processing
                    return true;
                } else {
                    return false;
                }
            }
 
            if (nmhdr->code == NativeMethods.HDN_ENDDRAG) {
                NativeMethods.NMHEADER header = (NativeMethods.NMHEADER) m.GetLParam(typeof(NativeMethods.NMHEADER));
                if (header.pItem != IntPtr.Zero) {
                    // SECREVIEW:
                    // UnsafeNativeMethods.PtrToStructure asserts ReflectionPermission.
                    // We are fine asserting this permission because the HDITEM type is our type and we have control over it
                    // and over what it does in its constructor.
                    NativeMethods.HDITEM2 hdItem = (NativeMethods.HDITEM2) UnsafeNativeMethods.PtrToStructure((IntPtr) header.pItem, typeof(NativeMethods.HDITEM2));
                    if ((hdItem.mask & NativeMethods.HDI_ORDER) == NativeMethods.HDI_ORDER) {
 
                        int from = this.Columns[header.iItem].DisplayIndex;
                        int to = hdItem.iOrder;
                        // check this
                        if (from == to) {
                            return false;
                        }
 
                        // sometimes ComCtl gives us bogus values for HDIItem.iOrder.
                        // vsw 541880.
                        if (to < 0) {
                            return false;
                        }
                        ColumnReorderedEventArgs chrevent = new ColumnReorderedEventArgs(from,
                                                                                         to,
                                                                                         this.Columns[header.iItem]);
                        OnColumnReordered(chrevent);
                        if (chrevent.Cancel) {
                            m.Result = new IntPtr(1);
                            return true;
                        } else {
                            // set the display indices. This is not an expensive operation because
                            // we only set an integer in the column header class
                            int lowDI = Math.Min(from, to);
                            int hiDI = Math.Max(from, to);
                            bool hdrMovedForward = to > from;
                            ColumnHeader movedHdr = null;
                            int[] indices = new int[this.Columns.Count];
                            for (int i = 0; i < this.Columns.Count; i ++) {
 
                                ColumnHeader hdr = this.Columns[i];
                                if (hdr.DisplayIndex == from) {
                                    movedHdr = hdr;
                                } else if (hdr.DisplayIndex >= lowDI && hdr.DisplayIndex <= hiDI) {
                                    hdr.DisplayIndexInternal -= hdrMovedForward ? 1 : -1;
                                }
                                indices[i] = hdr.DisplayIndexInternal;
                            }
 
                            movedHdr.DisplayIndexInternal = to;
                            indices[movedHdr.Index] = movedHdr.DisplayIndexInternal;
                            SetDisplayIndices( indices );
#if DEBUG
                            CheckDisplayIndices();
#endif
                        }
                    }
                }
            }
 
            if (nmhdr->code == NativeMethods.HDN_DIVIDERDBLCLICKA ||
                nmhdr->code == NativeMethods.HDN_DIVIDERDBLCLICKW) {
                // We need to keep track that the user double clicked the column header divider
                // so we know that the column header width is changing.
                this.listViewState[LISTVIEWSTATE_headerDividerDblClick] = true;
 
                // Reset ColumnResizeCancelled.
                // It will be set if the user cancels the ColumnWidthChanging event.
                this.listViewState[LISTVIEWSTATE_columnResizeCancelled] = false;
 
                bool columnResizeCancelled = false;
 
                // ComCtl32 does not add enough padding when resizing the first column via mouse double click.
                // See vsw 336709 for a complete explanation including listing of the comctl32 code.
                // Our wrapper will add 2 pixels. (1 pixel is not enough, 3 pixels is too much)
 
                // Send the message to ComCtl32 so that it resizes the column.
                try
                {
                    DefWndProc(ref m);
                }
                finally
                {
                    this.listViewState[LISTVIEWSTATE_headerDividerDblClick] = false;
                    columnResizeCancelled = this.listViewState[LISTVIEWSTATE_columnResizeCancelled];
                    this.listViewState[LISTVIEWSTATE_columnResizeCancelled] = false;
                }
 
 
                this.columnHeaderClicked = null;
                this.columnHeaderClickedWidth = -1;
 
                if (columnResizeCancelled) {
                    // If the column resize was cancelled then apply the NewWidth supplied by the user.
                    if (this.newWidthForColumnWidthChangingCancelled != -1) {
                        NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER) m.GetLParam(typeof(NativeMethods.NMHEADER));
                        if (this.columnHeaders != null && this.columnHeaders.Length > nmheader.iItem) {
                            this.columnHeaders[nmheader.iItem].Width = this.newWidthForColumnWidthChangingCancelled;
                        }
                    }
 
                    // Tell ComCtl that the HDN_DIVIDERDBLCLICK was cancelled.
                    m.Result = (IntPtr) 1;
                } else {
                    // Compensate for the column resize.
                    int compensateForColumnResize = this.CompensateColumnHeaderResize(m, columnResizeCancelled);
                    if (compensateForColumnResize != 0) {
                        #if DEBUG
                        NativeMethods.NMHEADER header = (NativeMethods.NMHEADER) m.GetLParam(typeof(NativeMethods.NMHEADER));
                        Debug.Assert(header.iItem == 0, "we only need to compensate for the first column resize");
                        Debug.Assert(this.columnHeaders.Length > 0, "there should be a column that we need to compensate for");
                        #endif
 
                        ColumnHeader col = this.columnHeaders[0];
                        col.Width += compensateForColumnResize;
                    }
                }
 
                // We called DefWndProc so we don't need default handling.
                return true;
            }
 
            return false; // still need default handling
        }
 
        private Font GetListHeaderFont(){
            IntPtr hwndHdr = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_GETHEADER, 0, 0);
            IntPtr hFont = UnsafeNativeMethods.SendMessage(new HandleRef(this, hwndHdr), NativeMethods.WM_GETFONT, 0, 0);
            IntSecurity.ObjectFromWin32Handle.Assert();
            return Font.FromHfont(hFont);
        }
 
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetIndexOfClickedItem"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        private int GetIndexOfClickedItem(NativeMethods.LVHITTESTINFO lvhi) {
            Point pos = Cursor.Position;
            pos = PointToClientInternal(pos);
            lvhi.pt_x = pos.X;
            lvhi.pt_y = pos.Y;
            return (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi);
 
        }
 
        internal void RecreateHandleInternal() {
            // vsWhidbey 395361.
            // For some reason, if CheckBoxes are set to true and the list view has a state imageList, then the native listView destroys
            // the state imageList.
            // (Yes, it does exactly that even though our wrapper sets LVS_SHAREIMAGELISTS on the native listView.)
            if (this.IsHandleCreated && this.StateImageList != null) {
                SendMessage(NativeMethods.LVM_SETIMAGELIST, NativeMethods.LVSIL_STATE, IntPtr.Zero);
            }
 
            RecreateHandle();
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.WmNotify"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
        private unsafe void WmReflectNotify(ref Message m) {
 
            NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam;
 
            switch (nmhdr->code) {
                case NativeMethods.NM_CUSTOMDRAW:
                    CustomDraw(ref m);
                    break;
 
                case NativeMethods.LVN_BEGINLABELEDITA:
                case NativeMethods.LVN_BEGINLABELEDITW: {
                        NativeMethods.NMLVDISPINFO_NOTEXT nmlvdp = (NativeMethods.NMLVDISPINFO_NOTEXT)m.GetLParam(typeof(NativeMethods.NMLVDISPINFO_NOTEXT));
                        LabelEditEventArgs e = new LabelEditEventArgs(nmlvdp.item.iItem);
                        OnBeforeLabelEdit(e);
                        m.Result = (IntPtr)(e.CancelEdit ? 1 : 0);
                        listViewState[LISTVIEWSTATE_inLabelEdit] = !e.CancelEdit;
                        break;
                    }
 
                case NativeMethods.LVN_COLUMNCLICK: {
                        NativeMethods.NMLISTVIEW nmlv = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW));
                        listViewState[LISTVIEWSTATE_columnClicked] = true;
                        columnIndex = nmlv.iSubItem;
                        break;
                    }
 
                case NativeMethods.LVN_ENDLABELEDITA:
                case NativeMethods.LVN_ENDLABELEDITW: {
                        listViewState[LISTVIEWSTATE_inLabelEdit] = false;
                        NativeMethods.NMLVDISPINFO nmlvdp = (NativeMethods.NMLVDISPINFO)m.GetLParam(typeof(NativeMethods.NMLVDISPINFO));
                        LabelEditEventArgs e = new LabelEditEventArgs(nmlvdp.item.iItem, nmlvdp.item.pszText);
                        OnAfterLabelEdit(e);
                        m.Result = (IntPtr)(e.CancelEdit ? 0 : 1);
                        // from msdn:
                        //   "If the user cancels editing, the pszText member of the LVITEM structure is NULL"
                        if (!e.CancelEdit && nmlvdp.item.pszText != null)
                            Items[nmlvdp.item.iItem].Text = nmlvdp.item.pszText;
                        break;
                    }
 
                case NativeMethods.LVN_ITEMACTIVATE:
                    OnItemActivate(EventArgs.Empty);
                    break;
 
                case NativeMethods.LVN_BEGINDRAG: {
                    // the items collection was modified while dragging
                    // that means that we can't reliably give the user the item on which the dragging started
                    // so don't tell the user about this operation...
                    // vsWhidbey 235027
                    if (!this.ItemCollectionChangedInMouseDown) {
                        NativeMethods.NMLISTVIEW nmlv = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW));
                        LvnBeginDrag(MouseButtons.Left, nmlv);
                    }
 
                    break;
                }
 
                case NativeMethods.LVN_BEGINRDRAG: {
                    // the items collection was modified while dragging
                    // that means that we can't reliably give the user the item on which the dragging started
                    // so don't tell the user about this operation...
                    // vsWhidbey 235027
                    if (!this.ItemCollectionChangedInMouseDown) {
                        NativeMethods.NMLISTVIEW nmlv = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW));
                        LvnBeginDrag(MouseButtons.Right, nmlv);
                    }
                    break;
                }
 
 
                case NativeMethods.LVN_ITEMCHANGING: {
                        NativeMethods.NMLISTVIEW* nmlv = (NativeMethods.NMLISTVIEW*)m.LParam;
                        if ((nmlv->uChanged & NativeMethods.LVIF_STATE) != 0) {
                            // Because the state image mask is 1-based, a value of 1 means unchecked,
                            // anything else means checked.  We convert this to the more standard 0 or 1
                            CheckState oldState = (CheckState)(((nmlv->uOldState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1);
                            CheckState newState = (CheckState)(((nmlv->uNewState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1);
 
                            if (oldState != newState) {
                                ItemCheckEventArgs e = new ItemCheckEventArgs(nmlv->iItem, newState, oldState);
                                OnItemCheck(e);
                                m.Result = (IntPtr)(((int)e.NewValue == 0 ? 0 : 1) == (int)oldState ? 1 : 0);
                            }
                        }
                        break;
                    }
 
                case NativeMethods.LVN_ITEMCHANGED: {
                        NativeMethods.NMLISTVIEW* nmlv = (NativeMethods.NMLISTVIEW*)m.LParam;
                        // Check for state changes to the selected state...
                        if ((nmlv->uChanged & NativeMethods.LVIF_STATE) != 0) {
                            // Because the state image mask is 1-based, a value of 1 means unchecked,
                            // anything else means checked.  We convert this to the more standard 0 or 1
                            CheckState oldValue = (CheckState)(((nmlv->uOldState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1);
                            CheckState newValue = (CheckState)(((nmlv->uNewState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1);
 
                            if (newValue != oldValue) {
                                ItemCheckedEventArgs e = new ItemCheckedEventArgs(Items[nmlv->iItem]);
                                OnItemChecked(e);
                                if (AccessibilityImprovements.Level1) {
                                    AccessibilityNotifyClients(AccessibleEvents.StateChange, nmlv->iItem);
                                    AccessibilityNotifyClients(AccessibleEvents.NameChange, nmlv->iItem);
                                }
                            }
 
                            int oldState = nmlv->uOldState & NativeMethods.LVIS_SELECTED;
                            int newState = nmlv->uNewState & NativeMethods.LVIS_SELECTED;
                            // Windows common control always fires
                            // this event twice, once with newState, oldState, and again with
                            // oldState, newState.
                            // Changing this affects the behaviour as the control never
                            // fires the event on a Deselct of an Items from multiple selections.
                            // So leave it as it is...
                            if (newState != oldState) {
                                if (this.VirtualMode && nmlv->iItem == -1)
                                {
                                    if (this.VirtualListSize > 0) {
                                        ListViewVirtualItemsSelectionRangeChangedEventArgs lvvisrce = new ListViewVirtualItemsSelectionRangeChangedEventArgs(0, this.VirtualListSize-1, newState != 0);
                                        OnVirtualItemsSelectionRangeChanged(lvvisrce);
                                    }
                                }
                                else
                                {
                                    // APPCOMPAT
                                    // V1.* users implement virtualization by communicating directly to the native ListView and
                                    // by passing our virtualization implementation.
                                    // In that case, the native list view may have an item under the mouse even if our wrapper thinks the item count is 0.
                                    // And that may cause GetItemAt to throw an out of bounds exception.
                                    // See VSW 418791.
 
                                    if (this.Items.Count > 0) {
                                        ListViewItemSelectionChangedEventArgs lvisce = new ListViewItemSelectionChangedEventArgs(this.Items[nmlv->iItem],
                                                                                                                                 nmlv->iItem,
                                                                                                                                 newState != 0);
                                        OnItemSelectionChanged(lvisce);
                                    }
                                }
                                // VSWhidbey 549967 - Delay SelectedIndexChanged event because the last item isn't present yet.
                                if (this.Items.Count == 0 || this.Items[this.Items.Count - 1] != null)
                                {
                                    this.listViewState1[LISTVIEWSTATE1_selectedIndexChangedSkipped] = false;
                                    OnSelectedIndexChanged(EventArgs.Empty);
                                }
                                else
                                {
                                    this.listViewState1[LISTVIEWSTATE1_selectedIndexChangedSkipped] = true;
                                }
                            }
                        }
                        break;
                    }
 
                case NativeMethods.NM_CLICK:
                    WmNmClick(ref m);
                    // FALL THROUGH //
                    goto case NativeMethods.NM_RCLICK;
 
                case NativeMethods.NM_RCLICK:
                    NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO();
                    int displayIndex = GetIndexOfClickedItem(lvhi);
 
                    MouseButtons button = nmhdr->code == NativeMethods.NM_CLICK ? MouseButtons.Left : MouseButtons.Right;
                    Point pos = Cursor.Position;
                    pos = PointToClientInternal(pos);
 
                    if (!ValidationCancelled && displayIndex != -1) {
                        OnClick(EventArgs.Empty);
                        OnMouseClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
                    }
                    if (!listViewState[LISTVIEWSTATE_mouseUpFired])
                    {
                        OnMouseUp(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
                        listViewState[LISTVIEWSTATE_mouseUpFired] = true;
                    }
                    break;
 
                case NativeMethods.NM_DBLCLK:
                    WmNmDblClick(ref m);
                    // FALL THROUGH //
                    goto case NativeMethods.NM_RDBLCLK;
 
                case NativeMethods.NM_RDBLCLK:
                    NativeMethods.LVHITTESTINFO lvhip = new NativeMethods.LVHITTESTINFO();
                    int index = GetIndexOfClickedItem(lvhip);
 
                    if (index != -1) {
                        //just maintain state and fire double click.. in final mouseUp...
                        listViewState[LISTVIEWSTATE_doubleclickFired] = true;
                    }
                    //fire Up in the Wndproc !!
                    listViewState[LISTVIEWSTATE_mouseUpFired] = false;
                    //problem getting the UP... outside the control...
                    //
                    CaptureInternal = true;
                    break;
 
                case NativeMethods.LVN_KEYDOWN:
                    if (CheckBoxes) {
                        NativeMethods.NMLVKEYDOWN lvkd = (NativeMethods.NMLVKEYDOWN)m.GetLParam(typeof(NativeMethods.NMLVKEYDOWN));
                        if (lvkd.wVKey == (short)Keys.Space) {
                            ListViewItem focusedItem = FocusedItem;
                            if (focusedItem != null) {
                                bool check = !focusedItem.Checked;
                                if (!VirtualMode) {
                                    foreach(ListViewItem item in SelectedItems) {
                                        if (item != focusedItem) {
                                            item.Checked = check;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    break;
 
                case NativeMethods.LVN_ODCACHEHINT:
                    // tell the user to prepare the cache:
                    NativeMethods.NMLVCACHEHINT cacheHint = (NativeMethods.NMLVCACHEHINT) m.GetLParam(typeof(NativeMethods.NMLVCACHEHINT));
                    OnCacheVirtualItems(new CacheVirtualItemsEventArgs(cacheHint.iFrom, cacheHint.iTo));
                    break;
 
                default:
                    if (nmhdr->code == NativeMethods.LVN_GETDISPINFO) {
                        // we use the LVN_GETDISPINFO message only in virtual mode
                        if (this.VirtualMode && m.LParam != IntPtr.Zero) {
                            // we HAVE to use unsafe code because of a bug in the CLR: WHIDBEY bug 20313
                            NativeMethods.NMLVDISPINFO_NOTEXT dispInfo= (NativeMethods.NMLVDISPINFO_NOTEXT) m.GetLParam(typeof(NativeMethods.NMLVDISPINFO_NOTEXT));
 
                            RetrieveVirtualItemEventArgs rVI = new RetrieveVirtualItemEventArgs(dispInfo.item.iItem);
                            OnRetrieveVirtualItem(rVI);
                            ListViewItem lvItem = rVI.Item;
                            if (lvItem == null)
                            {
                                throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualItemRequired));
                            }
 
                            lvItem.SetItemIndex(this, dispInfo.item.iItem);
                            if ((dispInfo.item.mask & NativeMethods.LVIF_TEXT) != 0) {
                                string text;
                                if (dispInfo.item.iSubItem == 0) {
                                    text = lvItem.Text;                                         // we want the item
                                }
                                else {
                                    if (lvItem.SubItems.Count <= dispInfo.item.iSubItem) {
                                        throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualModeCantAccessSubItem));
                                    }
                                    else {
                                        text = lvItem.SubItems[dispInfo.item.iSubItem].Text;            // we want the sub item
                                    }
                                }
 
                                // use the buffer provided by the ComCtrl list view.
                                if (dispInfo.item.cchTextMax <= text.Length) {
                                    text = text.Substring(0, dispInfo.item.cchTextMax - 1);
                                }
 
                                if (Marshal.SystemDefaultCharSize == 1) {
                                    // ANSI. Use byte
                                    byte[] buff = System.Text.Encoding.Default.GetBytes(text + "\0");
                                    Marshal.Copy(buff, 0, dispInfo.item.pszText, text.Length + 1);
                                } else {
                                    char[] buff = (text + "\0").ToCharArray();
                                    Marshal.Copy(buff, 0, dispInfo.item.pszText, text.Length + 1);
                                }
                            }
 
                            if ((dispInfo.item.mask & NativeMethods.LVIF_IMAGE) != 0 && lvItem.ImageIndex != -1) {
                                dispInfo.item.iImage = lvItem.ImageIndex;
                            }
 
                            if ((dispInfo.item.mask & NativeMethods.LVIF_INDENT) != 0) {
                                dispInfo.item.iIndent = lvItem.IndentCount;
                            }
 
                            /* Microsoft: Couldn't make this work. The dispInfo.item.iSubItem received for the subitems' text
                                       are invalid
                            if ((dispInfo.item.mask & NativeMethods.LVIF_COLUMNS) != 0) {
                                int cColumns = this.columnHeaders != null ? this.columnHeaders.Length : 0;
                                dispInfo.item.cColumns = cColumns;
                                if (cColumns > 0) {
                                    dispInfo.item.puColumns = Marshal.AllocHGlobal(cColumns * Marshal.SizeOf(typeof(int)));
                                    int[] columns = new int[cColumns];
                                    for (int c = 0; c < cColumns; c++) {
                                        columns[c] = c + 1;
                                    }
                                    Marshal.Copy(columns, 0, dispInfo.item.puColumns, cColumns);
                                }
                            }
                            */
 
                            /* Microsoft: VirtualMode and grouping seem to be incompatible.
                                       dispInfo.item.mask never includes NativeMethods.LVIF_GROUPID.
                                       Besides, trying to send LVM_ENABLEGROUPVIEW to the listview fails in virtual mode.
                            if (this.GroupsEnabled && (dispInfo.item.mask & NativeMethods.LVIF_GROUPID) != 0)
                            {
                                dispInfo.item.iGroupId = GetNativeGroupId(lvItem);
                                #if DEBUG
                                    Debug.Assert(SendMessage(NativeMethods.LVM_ISGROUPVIEWENABLED, 0, 0) != IntPtr.Zero, "Groups not enabled");
                                    Debug.Assert(SendMessage(NativeMethods.LVM_HASGROUP, dispInfo.item.iGroupId, 0) != IntPtr.Zero, "Doesn't contain group id: " + dispInfo.item.iGroupId.ToString(CultureInfo.InvariantCulture));
                                #endif
                            }
                            */
 
                            if ((dispInfo.item.stateMask & NativeMethods.LVIS_STATEIMAGEMASK) != 0) {
                                dispInfo.item.state |= lvItem.RawStateImageIndex;
                            }
                            Marshal.StructureToPtr(dispInfo, (IntPtr) m.LParam, false);
 
                        }
                    }
                    else if (nmhdr->code == NativeMethods.LVN_ODSTATECHANGED) {
                        if (VirtualMode && m.LParam != IntPtr.Zero) {
                            NativeMethods.NMLVODSTATECHANGE odStateChange = (NativeMethods.NMLVODSTATECHANGE) m.GetLParam(typeof(NativeMethods.NMLVODSTATECHANGE));
                            bool selectedChanged = (odStateChange.uNewState & NativeMethods.LVIS_SELECTED) != (odStateChange.uOldState & NativeMethods.LVIS_SELECTED);
                            if (selectedChanged) {
                                // we have to substract 1 from iTo due to an imbecility in the win32 ListView control
                                // see vsWhidbey 275717 - especially the ListView_CalcMinMaxIndex method.
                                // in Vista, 275717 is fixed in windows OS side, we have don't need to work around here any more.
                                int iTo = odStateChange.iTo;
                                if (!UnsafeNativeMethods.IsVista) {
                                    iTo--;
                                }
                                ListViewVirtualItemsSelectionRangeChangedEventArgs lvvisrce = new ListViewVirtualItemsSelectionRangeChangedEventArgs(odStateChange.iFrom, iTo, (odStateChange.uNewState & NativeMethods.LVIS_SELECTED) != 0);
                                OnVirtualItemsSelectionRangeChanged(lvvisrce);
                            }
                        }
                    }
                    else if (nmhdr->code == NativeMethods.LVN_GETINFOTIP) {
                        if (ShowItemToolTips && m.LParam != IntPtr.Zero) {
                            NativeMethods.NMLVGETINFOTIP infoTip = (NativeMethods.NMLVGETINFOTIP) m.GetLParam(typeof(NativeMethods.NMLVGETINFOTIP));
                            ListViewItem lvi = Items[infoTip.item];
                            if (lvi != null && !string.IsNullOrEmpty(lvi.ToolTipText)) {
 
                                // MSDN:
                                // Setting the max width has the added benefit of enabling multiline
                                // tool tips!
                                //
                                
                                UnsafeNativeMethods.SendMessage(new HandleRef(this, nmhdr->hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width);
 
                                if (Marshal.SystemDefaultCharSize == 1) {
                                    // ANSI. Use byte.
                                    // we need to copy the null terminator character ourselves
                                    byte[] byteBuf = System.Text.Encoding.Default.GetBytes(lvi.ToolTipText + "\0");
                                    Marshal.Copy(byteBuf, 0, infoTip.lpszText, Math.Min(byteBuf.Length, infoTip.cchTextMax));
                                } else {
                                    // UNICODE. Use char.
                                    // we need to copy the null terminator character ourselves
                                    char[] charBuf = (lvi.ToolTipText + "\0").ToCharArray();
                                    Marshal.Copy(charBuf, 0, infoTip.lpszText, Math.Min(charBuf.Length, infoTip.cchTextMax));
                                }
                                Marshal.StructureToPtr(infoTip, (IntPtr) m.LParam, false);
                            }
                        }
                    }
                    else if (nmhdr->code == NativeMethods.LVN_ODFINDITEM) {
                        if (VirtualMode) {
                            NativeMethods.NMLVFINDITEM nmlvif = (NativeMethods.NMLVFINDITEM) m.GetLParam(typeof(NativeMethods.NMLVFINDITEM));
 
                            if ((nmlvif.lvfi.flags & NativeMethods.LVFI_PARAM) != 0) {
                                m.Result = (IntPtr) (-1);
                                return;
                            }
 
                            bool isTextSearch = ((nmlvif.lvfi.flags & NativeMethods.LVFI_STRING) != 0) ||
                                                ((nmlvif.lvfi.flags & NativeMethods.LVFI_PARTIAL) != 0);
 
                            bool isPrefixSearch = (nmlvif.lvfi.flags & NativeMethods.LVFI_PARTIAL) != 0;
 
                            string text = String.Empty;
                            if (isTextSearch) {
                                text = nmlvif.lvfi.psz;
                            }
 
                            Point startingPoint = Point.Empty;
                            if ((nmlvif.lvfi.flags & NativeMethods.LVFI_NEARESTXY) != 0) {
                                startingPoint = new Point(nmlvif.lvfi.ptX, nmlvif.lvfi.ptY);
                            }
 
                            SearchDirectionHint dir = SearchDirectionHint.Down;
                            if ((nmlvif.lvfi.flags & NativeMethods.LVFI_NEARESTXY) != 0) {
                                // We can do this because SearchDirectionHint is set to the VK_*
                                dir = (SearchDirectionHint) nmlvif.lvfi.vkDirection;
                            }
 
                            int startIndex = nmlvif.iStart;
                            if (startIndex >= this.VirtualListSize) {
                                // we want to search starting from the last item. Wrap around the first item.
                                startIndex = 0;
                            }
 
 
                            SearchForVirtualItemEventArgs sviEvent = new SearchForVirtualItemEventArgs(
                                                                         isTextSearch,
                                                                         isPrefixSearch,
                                                                         false, /* includeSubItemsInSearch */
                                                                         text,
                                                                         startingPoint,
                                                                         dir,
                                                                         nmlvif.iStart);
 
                            OnSearchForVirtualItem(sviEvent);
                            if (sviEvent.Index != -1) {
                                m.Result = (IntPtr) sviEvent.Index;
                            } else {
                                m.Result = (IntPtr) (-1);
                            }
                        }
                    }
                break;
            }
        }
 
        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);
                        g.DrawRectangle(new Pen(VisualStyleInformation.TextControlBorder), rect);
                        rect.Inflate(-1, -1);
                        g.DrawRectangle(SystemPens.Window, rect);
                    }
                }
                finally {
                    CodeAccessPermission.RevertAssert();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.WndProc"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
 
            switch (m.Msg) {
                case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY:
                    WmReflectNotify(ref m);
                    break;
                case NativeMethods.WM_LBUTTONDBLCLK:
 
                    // Ensure that the itemCollectionChangedInMouseDown is not set
                    // before processing the mousedown event.  
                    this.ItemCollectionChangedInMouseDown = false;
                    CaptureInternal = true;
                    WmMouseDown(ref m, MouseButtons.Left, 2);
                    break;
 
                case NativeMethods.WM_LBUTTONDOWN:
 
                    // Ensure that the itemCollectionChangedInMouseDown is not set
                    // before processing the mousedown event.  
                    this.ItemCollectionChangedInMouseDown = false;
                    WmMouseDown(ref m, MouseButtons.Left, 1);
                    downButton = MouseButtons.Left;
                    break;
 
                case NativeMethods.WM_LBUTTONUP:
                case NativeMethods.WM_RBUTTONUP:
                case NativeMethods.WM_MBUTTONUP:
 
                    // see the mouse is on item
                    //
                    NativeMethods.LVHITTESTINFO lvhip = new NativeMethods.LVHITTESTINFO();
                    int index = GetIndexOfClickedItem(lvhip);
 
                    if (!ValidationCancelled && listViewState[LISTVIEWSTATE_doubleclickFired] && index != -1) {
                        listViewState[LISTVIEWSTATE_doubleclickFired] = false;
                        OnDoubleClick(EventArgs.Empty);
                        OnMouseDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                    }
                    if (!listViewState[LISTVIEWSTATE_mouseUpFired])
                    {
                        OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                        listViewState[LISTVIEWSTATE_expectingMouseUp] = false;
                    }
 
                    this.ItemCollectionChangedInMouseDown = false;
 
                    listViewState[LISTVIEWSTATE_mouseUpFired] = true;
                    CaptureInternal = false;
                    break;
                case NativeMethods.WM_MBUTTONDBLCLK:
                    WmMouseDown(ref m, MouseButtons.Middle, 2);
                    break;
                case NativeMethods.WM_MBUTTONDOWN:
                    WmMouseDown(ref m, MouseButtons.Middle, 1);
                    downButton = MouseButtons.Middle;
                    break;
                case NativeMethods.WM_RBUTTONDBLCLK:
                    WmMouseDown(ref m, MouseButtons.Right, 2);
                    break;
                case NativeMethods.WM_RBUTTONDOWN:
                    WmMouseDown(ref m, MouseButtons.Right, 1);
                    downButton = MouseButtons.Right;
                    break;
                case NativeMethods.WM_MOUSEMOVE:
                    if (listViewState[LISTVIEWSTATE_expectingMouseUp] && !listViewState[LISTVIEWSTATE_mouseUpFired] && MouseButtons == MouseButtons.None)
                    {
                        OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                        listViewState[LISTVIEWSTATE_mouseUpFired] = true;
                    }
                    CaptureInternal = false;
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_MOUSEHOVER:
                    if (HoverSelection) {
                        base.WndProc(ref m);
                    }
                    else
                        OnMouseHover(EventArgs.Empty);
                    break;
                case NativeMethods.WM_NOTIFY:
                    if(WmNotify(ref m))
                    {
                        break; // we are done - skip default handling
                    }
                    else
                    {
                        goto default;  //default handling needed
                    }
                case NativeMethods.WM_SETFOCUS:
                    base.WndProc(ref m);
 
                    if (!this.RecreatingHandle && !this.ListViewHandleDestroyed) {
                        // This means that we get a WM_SETFOCUS on the hWnd that was destroyed.
                        // Don't do anything because the information on the previous hWnd is most likely
                        // out of sync w/ the information in our ListView wrapper.
                        // See comment in vsw 451268.
 
                        // We should set focus to the first item,
                        // if none of the items are focused already.
                        if (FocusedItem == null && Items.Count > 0)
                        {
                            Items[0].Focused = true;
                        }
                    }
                    break;
                case NativeMethods.WM_MOUSELEAVE:
                    // if the mouse leaves and then re-enters the ListView
                    // ItemHovered events should be raised.
                    prevHoveredItem = null;
                    base.WndProc(ref m);
                    break;
 
                case NativeMethods.WM_PAINT:
                    base.WndProc(ref m);
 
                    // win32 ListView - look for comments about vsWhidbey 243708
                    BeginInvoke(new MethodInvoker(this.CleanPreviousBackgroundImageFiles));
                    break;
                case NativeMethods.WM_PRINT:
                    WmPrint(ref m);
                    break;
                case NativeMethods.WM_TIMER:
                    if (unchecked( (int) (long)m.WParam) != LVTOOLTIPTRACKING || !ComctlSupportsVisualStyles) {
                        base.WndProc(ref m);
                    }
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            };
        }
 
        ///new class for comparing and sorting Icons ....
        //subhag
        internal class IconComparer: IComparer {
            private SortOrder sortOrder;
 
            public IconComparer(SortOrder currentSortOrder) {
                   this.sortOrder = currentSortOrder;
            }
 
            public SortOrder SortOrder {
                set {
                    sortOrder = value;
                }
            }
 
            public int Compare(object obj1, object obj2) {
                //subhag
                ListViewItem currentItem =  (ListViewItem)obj1;
                ListViewItem nextItem =  (ListViewItem)obj2;
                if (sortOrder == SortOrder.Ascending) {
                    return (String.Compare(currentItem.Text,nextItem.Text, false, CultureInfo.CurrentCulture));
                }
                else {
                    return (String.Compare(nextItem.Text,currentItem.Text, false, CultureInfo.CurrentCulture));
                }
            }
        }
        //end subhag
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ListBindable(false)]
        public class CheckedIndexCollection : IList {
            private ListView owner;
 
            /* C#r: protected */
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.CheckedIndexCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public CheckedIndexCollection(ListView owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.Count"]/*' />
            /// <devdoc>
            ///     Number of currently selected items.
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    if (!owner.CheckBoxes) {
                        return 0;
                    }
 
                    // Count the number of checked items
                    //
                    int count = 0;
                    foreach(ListViewItem item in owner.Items) {
                        if (item != null && item.Checked) {
                            count++;
                        }
                    }
                    return count;
                }
            }
 
            private int[] IndicesArray {
                get {
                    int[] indices = new int[Count];
                    int index = 0;
                    for(int i=0; i < owner.Items.Count && index < indices.Length; ++i) {
                        if (owner.Items[i].Checked) {
                            indices[index++] = i;
                        }
                    }
                    return indices;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.this"]/*' />
            /// <devdoc>
            ///     Selected item in the list.
            /// </devdoc>
            public int this[int index] {
                get {
 
                    if (index < 0) {
                        throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                    }
 
                    // Loop through the main collection until we find the right index.
                    //
                    int cnt = owner.Items.Count;
                    int nChecked = 0;
                    for(int i = 0; i < cnt; i++) {
                        ListViewItem item = owner.Items[i];
 
                        if (item.Checked) {
                            if (nChecked == index) {
                                return i;
                            }
                            nChecked++;
                        }
                    }
 
                    // Should never get to this point.
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.this"]/*' />
            /// <internalonly/>
            object IList.this[int index] {
                get {
                    return this[index];
                }
                set {
                    throw new NotSupportedException();
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(int checkedIndex) {
                if (owner.Items[checkedIndex].Checked) {
                    return true;
                }
                else {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Contains"]/*' />
            /// <internalonly/>
            bool IList.Contains(object checkedIndex) {
                if (checkedIndex is Int32) {
                    return Contains((int)checkedIndex);
                }
                else {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(int checkedIndex) {
                int[] indices = IndicesArray;
                for(int index=0; index < indices.Length; ++index) {
                    if (indices[index] == checkedIndex) {
                        return index;
                    }
                }
                return -1;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.IndexOf"]/*' />
            /// <internalonly/>
            int IList.IndexOf(object checkedIndex) {
                if (checkedIndex is Int32) {
                    return IndexOf((int)checkedIndex);
                }
                else {
                    return -1;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Clear"]/*' />
            /// <internalonly/>
            void IList.Clear() {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Remove"]/*' />
            /// <internalonly/>
            void IList.Remove(object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedIndexCollection.ICollection.CopyTo"]/*' />
            /// <internalonly/>
            void ICollection.CopyTo(Array dest, int index) {
                if (Count > 0) {
                    System.Array.Copy(IndicesArray, 0, dest, index, Count);
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedIndexCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                int[] indices = IndicesArray;
                if (indices != null) {
                    return indices.GetEnumerator();
                }
                else {
                    return new int[0].GetEnumerator();
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ListBindable(false)]
        public class CheckedListViewItemCollection : IList {
            private ListView owner;
 
               /// A caching mechanism for key accessor
               /// We use an index here rather than control so that we don't have lifetime
               /// issues by holding on to extra references.
               private int lastAccessedIndex = -1;
 
            /* C#r: protected */
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.CheckedListViewItemCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public CheckedListViewItemCollection(ListView owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.Count"]/*' />
            /// <devdoc>
            ///     Number of currently selected items.
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                    }
 
                    return owner.CheckedIndices.Count;
                }
            }
 
            private ListViewItem[] ItemArray {
                get {
                    ListViewItem[] items = new ListViewItem[Count];
                    int index = 0;
                    for(int i=0; i < owner.Items.Count && index < items.Length; ++i) {
                        if (owner.Items[i].Checked) {
                            items[index++] = owner.Items[i];
                        }
                    }
                    return items;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.this"]/*' />
            /// <devdoc>
            ///     Selected item in the list.
            /// </devdoc>
            public ListViewItem this[int index] {
                get {
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                    }
 
                    int itemIndex = owner.CheckedIndices[index];
                    return owner.Items[itemIndex];
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.this"]/*' />
            /// <internalonly/>
            object IList.this[int index] {
                get {
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                    }
 
                    return this[index];
                }
                set {
                    throw new NotSupportedException();
                }
            }
 
               /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedItemCollection.this"]/*' />
               /// <devdoc>
               ///     <para>Retrieves the child control with the specified key.</para>
               /// </devdoc>
               public virtual ListViewItem this[string key] {
                    get {
                        if (owner.VirtualMode) {
                            throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                        }
 
                         // We do not support null and empty string as valid keys.
                         if(string.IsNullOrEmpty(key)) {
                              return null;
                         }
 
                         // Search for the key in our collection
                         int index = IndexOfKey(key);
                         if(IsValidIndex(index)) {
                              return this[index];
                         }
                         else {
                              return null;
                         }
 
                    }
               }
 
               /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return true;
                }
            }
 
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(ListViewItem item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                if (item != null && item.ListView == owner && item.Checked) {
                    return true;
                }
                else {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.Contains"]/*' />
            /// <internalonly/>
            bool IList.Contains(object item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                if (item is ListViewItem) {
                    return Contains((ListViewItem)item);
                }
                else {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedItemCollection.ContainsKey"]/* />
            /// <devdoc>
            ///     <para>Returns true if the collection contains an item with the specified key, false otherwise.</para>
            /// </devdoc>
            public virtual bool ContainsKey(string key) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                 return IsValidIndex(IndexOfKey(key));
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(ListViewItem item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                ListViewItem[] items = ItemArray;
                for(int index=0; index < items.Length; ++index) {
                    if (items[index] == item) {
                        return index;
                    }
                }
                return -1;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedItemCollection.this"]/*' />
            /// <devdoc>
            ///     <para>The zero-based index of the first occurrence of value within the entire CollectionBase, if found; otherwise, -1.</para>
            /// </devdoc>
            public virtual int IndexOfKey(String key) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                // Step 0 - Arg validation
                if (string.IsNullOrEmpty(key)) {
                      return -1; // we dont support empty or null keys.
                }
 
                // step 1 - check the last cached item
                if (IsValidIndex(lastAccessedIndex))
                {
                    if (WindowsFormsUtils.SafeCompareStrings(this[lastAccessedIndex].Name, key, /* ignoreCase = */ true)) {
                        return lastAccessedIndex;
                    }
                }
 
                // step 2 - search for the item
                for (int i = 0; i < this.Count; i ++) {
                    if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, /* ignoreCase = */ true)) {
                        lastAccessedIndex = i;
                        return i;
                    }
                }
 
                // step 3 - we didn't find it.  Invalidate the last accessed index and return -1.
                lastAccessedIndex = -1;
                return -1;
            }
 
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedItemCollection.IsValidIndex"]/*' />
            /// <devdoc>
            ///     <para>Determines if the index is valid for the collection.</para>
            /// </devdoc>
            /// <internalonly/>
            private bool IsValidIndex(int index) {
                return ((index >= 0) && (index < this.Count));
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.IndexOf"]/*' />
            /// <internalonly/>
            int IList.IndexOf(object item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                if (item is ListViewItem) {
                    return IndexOf((ListViewItem)item);
                }
                else {
                    return -1;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.Clear"]/*' />
            /// <internalonly/>
            void IList.Clear() {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.Remove"]/*' />
            /// <internalonly/>
            void IList.Remove(object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="CheckedListViewItemCollection.CopyTo"]/*' />
            public void CopyTo(Array dest, int index) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                if (Count > 0) {
                    System.Array.Copy(ItemArray, 0, dest, index, Count);
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CheckedListViewItemCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessCheckedItemsCollectionWhenInVirtualMode));
                }
 
                ListViewItem[] items = ItemArray;
                if (items != null) {
                    return items.GetEnumerator();
                }
                else {
                    return new ListViewItem[0].GetEnumerator();
                }
            }
 
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ListBindable(false)]
        public class SelectedIndexCollection : IList {
            private ListView owner;
 
            /* C#r: protected */
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.SelectedIndexCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public SelectedIndexCollection(ListView owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.Count"]/*' />
            /// <devdoc>
            ///     Number of currently selected items.
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    if (owner.IsHandleCreated) {
                        return unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETSELECTEDCOUNT, 0, 0));
                    }
                    else {
                        if (owner.savedSelectedItems != null) {
                            return owner.savedSelectedItems.Count;
                        }
                        return 0;
                    }
                }
            }
 
            private int[] IndicesArray {
                get {
                    int count = Count;
                    int[] indices = new int[count];
 
                    if (owner.IsHandleCreated) {
                        int displayIndex = -1;
                        for (int i = 0; i < count; i++) {
                            int fidx = unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETNEXTITEM, displayIndex, NativeMethods.LVNI_SELECTED));
 
                            if (fidx > -1) {
                                indices[i] = fidx;
                                displayIndex = fidx;
                            }
                            else
                                throw new InvalidOperationException(SR.GetString(SR.SelectedNotEqualActual));
                        }
                    }
                    else {
                        Debug.Assert(owner.savedSelectedItems != null || count == 0, "if the count of selectedItems is greater than 0 then the selectedItems should have been saved by now");
                        for (int i = 0; i < count; i++) {
                            indices[i] = owner.savedSelectedItems[i].Index;
                        }
                    }
 
                    return indices;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.this"]/*' />
            /// <devdoc>
            ///     Selected item in the list.
            /// </devdoc>
            public int this[int index] {
                get {
 
                    if (index < 0 || index >= Count) {
                        throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                    }
 
                    if (owner.IsHandleCreated) {
 
                        // Count through the selected items in the ListView, until
                        // we reach the 'index'th selected item.
                        //
                        int fidx = -1;
                        for(int count = 0; count <= index; count++) {
                            fidx = unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETNEXTITEM, fidx, NativeMethods.LVNI_SELECTED));
                            Debug.Assert(fidx != -1, "Invalid index returned from LVM_GETNEXTITEM");
                        }
 
                        return fidx;
                    }
                    else {
                        Debug.Assert(owner.savedSelectedItems != null, "Null selected items collection");
                        return owner.savedSelectedItems[index].Index;
                    }
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.this"]/*' />
            /// <internalonly/>
            object IList.this[int index] {
                get {
                    return this[index];
                }
                set {
                    throw new NotSupportedException();
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(int selectedIndex) {
                return owner.Items[selectedIndex].Selected;
            }
 
            /// <include file='doc\ListView.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\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(int selectedIndex) {
                int[] indices = IndicesArray;
                for(int index=0; index < indices.Length; ++index) {
                    if (indices[index] == selectedIndex) {
                        return index;
                    }
                }
                return -1;
            }
 
            /// <include file='doc\ListView.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\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object value)
            {
                if (value is int)
                {
                    return Add((int) value);
                }
                else
                {
                    throw new ArgumentException(SR.GetString(SR.InvalidArgument, "value", ((value).ToString())));
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Clear"]/*' />
            /// <internalonly/>
            void IList.Clear() {
                Clear();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.Remove"]/*' />
            /// <internalonly/>
            void IList.Remove(object value)
            {
                if (value is int)
                {
                    Remove((int) value);
                }
                else
                {
                    throw new ArgumentException(SR.GetString(SR.InvalidArgument, "value", ((value).ToString())));
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.Add"]/*' />
            public int Add(int itemIndex)
            {
                if (this.owner.VirtualMode)
                {
                    if (itemIndex < 0 || itemIndex >= this.owner.VirtualListSize)
                    {
                        throw new ArgumentOutOfRangeException("itemIndex", SR.GetString(SR.InvalidArgument, "itemIndex", (itemIndex).ToString(CultureInfo.CurrentCulture)));
                    }
                    if (this.owner.IsHandleCreated)
                    {
                        this.owner.SetItemState(itemIndex, NativeMethods.LVIS_SELECTED, NativeMethods.LVIS_SELECTED);
                        return this.Count;
                    }
                    else
                    {
                        return -1;
                    }
                }
                else
                {
                    if (itemIndex < 0 || itemIndex >= this.owner.Items.Count)
                    {
                        throw new ArgumentOutOfRangeException("itemIndex", SR.GetString(SR.InvalidArgument, "itemIndex", (itemIndex).ToString(CultureInfo.CurrentCulture)));
                    }
                    this.owner.Items[itemIndex].Selected = true;
                    return this.Count;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.Clear"]/*' />
            public void Clear()
            {
                if (!this.owner.VirtualMode)
                {
                    this.owner.savedSelectedItems = null;
                }
                if (this.owner.IsHandleCreated)
                {
                    this.owner.SetItemState(-1, 0, NativeMethods.LVIS_SELECTED);
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedIndexCollection.CopyTo"]/*' />
            public void CopyTo(Array dest, int index) {
                if (Count > 0) {
                    System.Array.Copy(IndicesArray, 0, dest, index, Count);
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                int[] indices = IndicesArray;
                if (indices != null) {
                    return indices.GetEnumerator();
                }
                else {
                    return new int[0].GetEnumerator();
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedIndexCollection.Remove"]/*' />
            public void Remove(int itemIndex)
            {
                if (this.owner.VirtualMode)
                {
                    if (itemIndex < 0 || itemIndex >= this.owner.VirtualListSize)
                    {
                        throw new ArgumentOutOfRangeException("itemIndex", SR.GetString(SR.InvalidArgument, "itemIndex", (itemIndex).ToString(CultureInfo.CurrentCulture)));
                    }
                    if (this.owner.IsHandleCreated)
                    {
                        this.owner.SetItemState(itemIndex, 0, NativeMethods.LVIS_SELECTED);
                    }
                }
                else
                {
                    if (itemIndex < 0 || itemIndex >= this.owner.Items.Count)
                    {
                        throw new ArgumentOutOfRangeException("itemIndex", SR.GetString(SR.InvalidArgument, "itemIndex", (itemIndex).ToString(CultureInfo.CurrentCulture)));
                    }
                    this.owner.Items[itemIndex].Selected = false;
                }
            }
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ListBindable(false)]
        public class SelectedListViewItemCollection : IList {
            private ListView owner;
 
            /// A caching mechanism for key accessor
            /// We use an index here rather than control so that we don't have lifetime
            /// issues by holding on to extra references.
            private int lastAccessedIndex = -1;
 
            /* C#r: protected */
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.SelectedListViewItemCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public SelectedListViewItemCollection(ListView owner) {
                this.owner = owner;
            }
 
            private ListViewItem[] SelectedItemArray {
                get {
                    if (owner.IsHandleCreated) {
                        int cnt = unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETSELECTEDCOUNT, 0, 0));
 
                        ListViewItem[] lvitems = new ListViewItem[cnt];
 
                        int displayIndex = -1;
 
                        for (int i = 0; i < cnt; i++) {
                            int fidx = unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETNEXTITEM, displayIndex, NativeMethods.LVNI_SELECTED));
 
                            if (fidx > -1) {
                                lvitems[i] = owner.Items[fidx];
                                displayIndex = fidx;
                            }
                            else
                                throw new InvalidOperationException(SR.GetString(SR.SelectedNotEqualActual));
                        }
 
                        return lvitems;
 
                    }
                    else {
                        if (owner.savedSelectedItems != null) {
                            ListViewItem[] cloned = new ListViewItem[owner.savedSelectedItems.Count];
                            for (int i = 0; i < owner.savedSelectedItems.Count; i ++) {
                                cloned[i] = owner.savedSelectedItems[i];
                            }
                            return cloned;
                        }
                        else {
                            return new ListViewItem[0];
                        }
                    }
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.Count"]/*' />
            /// <devdoc>
            ///     Number of currently selected items.
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                    }
 
                    if (owner.IsHandleCreated) {
                        return unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETSELECTEDCOUNT, 0, 0));
                    }
                    else {
                        if (owner.savedSelectedItems != null) {
                            return owner.savedSelectedItems.Count;
                        }
                        return 0;
                    }
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.this"]/*' />
            /// <devdoc>
            ///     Selected item in the list.
            /// </devdoc>
            public ListViewItem this[int index] {
                get {
 
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                    }
 
                    if (index < 0 || index >= Count) {
                        throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                    }
 
                    if (owner.IsHandleCreated) {
 
                        // Count through the selected items in the ListView, until
                        // we reach the 'index'th selected item.
                        //
                        int fidx = -1;
                        for(int count = 0; count <= index; count++) {
                            fidx = unchecked( (int) (long)owner.SendMessage(NativeMethods.LVM_GETNEXTITEM, fidx, NativeMethods.LVNI_SELECTED));
                            Debug.Assert(fidx != -1, "Invalid index returned from LVM_GETNEXTITEM");
                        }
 
                        return owner.Items[fidx];
                    }
                    else {
                        Debug.Assert(owner.savedSelectedItems != null, "Null selected items collection");
                        return owner.savedSelectedItems[index];
                    }
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedItemCollection.this"]/*' />
            /// <devdoc>
            ///     <para>Retrieves the child control with the specified key.</para>
            /// </devdoc>
            public virtual ListViewItem this[string key] {
                get {
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                    }
 
                    // We do not support null and empty string as valid keys.
                    if (string.IsNullOrEmpty(key)){
                        return null;
                    }
 
                    // Search for the key in our collection
                    int index = IndexOfKey(key);
                    if (IsValidIndex(index)) {
                        return this[index];
                    }
                    else {
                        return null;
                    }
 
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.this"]/*' />
            /// <internalonly/>
            object IList.this[int index] {
                get {
                    if (owner.VirtualMode) {
                        throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                    }
 
                    return this[index];
                }
                set {
                    // SelectedListViewItemCollection is read-only
                    throw new NotSupportedException();
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.Add"]/*' />
            /// <internalonly/>
            int IList.Add(object value) {
                // SelectedListViewItemCollection is read-only
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.Insert"]/*' />
            /// <internalonly/>
            void IList.Insert(int index, object value) {
                // SelectedListViewItemCollection is read-only
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedItemCollection.IsValidIndex"]/*' />
            /// <devdoc>
            ///     <para>Determines if the index is valid for the collection.</para>
            /// </devdoc>
            /// <internalonly/>
            private bool IsValidIndex(int index) {
                return ((index >= 0) && (index < this.Count));
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.Remove"]/*' />
            /// <internalonly/>
            void IList.Remove(object value) {
                // SelectedListViewItemCollection is read-only
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.RemoveAt"]/*' />
            /// <internalonly/>
            void IList.RemoveAt(int index) {
                // SelectedListViewItemCollection is read-only
                throw new NotSupportedException();
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.Clear"]/*' />
            /// <devdoc>
            ///     Unselects all items.
            /// </devdoc>
            public void Clear() {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                ListViewItem[] items = SelectedItemArray;
                for (int i=0; i < items.Length; i++) {
                    items[i].Selected = false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedItemCollection.ContainsKey"]/*' />
            /// <devdoc>
            ///     <para>Returns true if the collection contains an item with the specified key, false otherwise.</para>
            /// </devdoc>
            public virtual bool ContainsKey(string key) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                return IsValidIndex(IndexOfKey(key));
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.Contains"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool Contains(ListViewItem item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                return (IndexOf(item) != -1);
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.Contains"]/*' />
            /// <internalonly/>
            bool IList.Contains(object item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                if (item is ListViewItem) {
                    return Contains((ListViewItem)item);
                }
                else {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.CopyTo"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void CopyTo(Array dest, int index) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                if (Count > 0) {
                    System.Array.Copy(SelectedItemArray, 0, dest, index, Count);
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                ListViewItem[] items = SelectedItemArray;
                if (items != null) {
                    return items.GetEnumerator();
                }
                else {
                    return new ListViewItem[0].GetEnumerator();
                }
           }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedListViewItemCollection.IndexOf"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public int IndexOf(ListViewItem item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                ListViewItem[] items = SelectedItemArray;
                for(int index=0; index < items.Length; ++index) {
                    if (items[index] == item) {
                        return index;
                    }
                }
                return -1;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="SelectedListViewItemCollection.IList.IndexOf"]/*' />
            /// <internalonly/>
            int IList.IndexOf(object item) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                if (item is ListViewItem) {
                    return IndexOf((ListViewItem)item);
                }
                else {
                    return -1;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.SelectedItemCollection.this"]/*' />
            /// <devdoc>
            ///     <para>The zero-based index of the first occurrence of value within the entire CollectionBase, if found; otherwise, -1.</para>
            /// </devdoc>
            public virtual int  IndexOfKey(String key) {
                if (owner.VirtualMode) {
                    throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode));
                }
 
                // Step 0 - Arg validation
                if (string.IsNullOrEmpty(key)){
                      return -1; // we dont support empty or null keys.
                }
 
                // step 1 - check the last cached item
                if (IsValidIndex(lastAccessedIndex))
                {
                    if (WindowsFormsUtils.SafeCompareStrings(this[lastAccessedIndex].Name, key, /* ignoreCase = */ true)) {
                        return lastAccessedIndex;
                    }
                }
 
                // step 2 - search for the item
                for (int i = 0; i < this.Count; i ++) {
                    if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, /* ignoreCase = */ true)) {
                        lastAccessedIndex = i;
                        return i;
                    }
                }
 
                // step 3 - we didn't find it.  Invalidate the last accessed index and return -1.
                lastAccessedIndex = -1;
                return -1;
            }
 
        }
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ListBindable(false)]
        public class ColumnHeaderCollection : IList {
            private ListView owner;
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.ColumnHeaderCollection"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public ColumnHeaderCollection(ListView owner) {
                this.owner = owner;
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.this"]/*' />
            /// <devdoc>
            ///     Given a Zero based index, returns the ColumnHeader object
            ///     for the column at that index
            /// </devdoc>
            public virtual ColumnHeader this[int index] {
                get {
                    if (owner.columnHeaders == null || index < 0 || index >= owner.columnHeaders.Length)
                        throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
                    return owner.columnHeaders[index];
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ColumnHeaderCollection.IList.this"]/*' />
            /// <internalonly/>
            object IList.this[int index] {
                get {
                    return this[index];
                }
                set {
                    throw new NotSupportedException();
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.this"]/*' />
            /// <devdoc>
            ///     <para>Retrieves the child control with the specified key.</para>
            /// </devdoc>
            public virtual ColumnHeader this[string key] {
                get {
                    // We do not support null and empty string as valid keys.
                    if (string.IsNullOrEmpty(key)){
                        return null;
                    }
 
                    // Search for the key in our collection
                    int index = IndexOfKey(key);
                    if (IsValidIndex(index)) {
                        return this[index];
                    }
                    else {
                        return null;
                    }
 
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.Count"]/*' />
            /// <devdoc>
            ///     The number of columns the ListView currently has in Details view.
            /// </devdoc>
            [Browsable(false)]
            public int Count {
                get {
                    return owner.columnHeaders == null ? 0 : owner.columnHeaders.Length;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ColumnHeaderCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ColumnHeaderCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return true;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ColumnHeaderCollection.IList.IsFixedSize"]/*' />
            /// <internalonly/>
            bool IList.IsFixedSize {
                get {
                    return false;
                }
            }
 
            /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.IsReadOnly"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public bool IsReadOnly {
                get {
                    return false;
                }
            }
 
 
 
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.RemoveByKey"]/*' />
        /// <devdoc>
        ///     <para>Removes the child control with the specified key.</para>
        /// </devdoc>
        public virtual void RemoveByKey(string key) {
                int index = IndexOfKey(key);
                if (IsValidIndex(index)) {
                    RemoveAt(index);
                 }
           }
 
        /// A caching mechanism for key accessor
        /// We use an index here rather than control so that we don't have lifetime
        /// issues by holding on to extra references.
        /// Note this is not Thread Safe - but Microsoft has to be run in a STA anyways.
        private int lastAccessedIndex = -1;
 
 
        /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.ColumnHeaderCollection.this"]/*' />
        /// <devdoc>
        ///     <para>The zero-based index of the first occurrence of value within the entire CollectionBase, if found; otherwise, -1.</para>
        /// </devdoc>
          public virtual int  IndexOfKey(String key) {
                  // Step 0 - Arg validation
                  if (st