2006-11-09 Mike Kestner <mkestner@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListView.cs
index 9081c1af21dc29c2097f7af6be63b79905b0c66d..31888daa1bd97fb181e801b32f563299fb8cccbf 100644 (file)
 // Authors:
 //     Ravindra Kumar (rkumar@novell.com)
 //     Jordi Mas i Hernandez, jordi@ximian.com
+//     Mike Kestner (mkestner@novell.com)
 //
 // TODO:
-//   - Item text editing
-//   - Column resizing/reodering
 //   - Feedback for item activation, change in cursor types as mouse moves.
-//   - HideSelection
 //   - LabelEdit
-//   - Manual column resizing
 //   - Drag and drop
 
 
@@ -55,14 +52,9 @@ namespace System.Windows.Forms
                private bool allow_column_reorder = false;
                private bool auto_arrange = true;
                private bool check_boxes = false;
-               private CheckedIndexCollection checked_indices;
-               private CheckedListViewItemCollection checked_items;
-               private ColumnHeader clicked_column;
-               private ListViewItem clicked_item;
-               private ListViewItem last_clicked_item;
-               private ColumnHeaderCollection columns;
-               private bool ctrl_pressed;
-               private bool shift_pressed;
+               private readonly CheckedIndexCollection checked_indices;
+               private readonly CheckedListViewItemCollection checked_items;
+               private readonly ColumnHeaderCollection columns;
                internal ListViewItem focused_item;
                private bool full_row_select = false;
                private bool grid_lines = false;
@@ -70,13 +62,13 @@ namespace System.Windows.Forms
                private bool hide_selection = true;
                private bool hover_selection = false;
                private IComparer item_sorter;
-               private ListViewItemCollection items;
+               private readonly ListViewItemCollection items;
                private bool label_edit = false;
                private bool label_wrap = true;
                private bool multiselect = true;
                private bool scrollable = true;
-               private SelectedIndexCollection selected_indices;
-               private SelectedListViewItemCollection selected_items;
+               private readonly SelectedIndexCollection selected_indices;
+               private readonly SelectedListViewItemCollection selected_items;
                private SortOrder sort_order = SortOrder.None;
                private ImageList state_image_list;
                private bool updating = false;
@@ -84,14 +76,16 @@ namespace System.Windows.Forms
                private int layout_wd;    // We might draw more than our client area
                private int layout_ht;    // therefore we need to have these two.
                //private TextBox editor;   // Used for editing an item text
+               HeaderControl header_control;
+               internal ItemControl item_control;
                internal ScrollBar h_scroll; // used for scrolling horizontally
                internal ScrollBar v_scroll; // used for scrolling vertically
                internal int h_marker;          // Position markers for scrolling
                internal int v_marker;
-               internal Rectangle client_area; // ClientRectangle - scrollbars
                private int keysearch_tickcnt;
                private string keysearch_text;
                static private readonly int keysearch_keydelay = 1000;
+               private int[] reordered_column_indices;
 
                // internal variables
                internal ImageList large_image_list;
@@ -103,7 +97,10 @@ namespace System.Windows.Forms
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler BackgroundImageChanged;
+               public new event EventHandler BackgroundImageChanged {
+                       add { base.BackgroundImageChanged += value; }
+                       remove { base.BackgroundImageChanged -= value; }
+               }
 
                public event LabelEditEventHandler BeforeLabelEdit;
                public event ColumnClickEventHandler ColumnClick;
@@ -113,32 +110,49 @@ namespace System.Windows.Forms
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event PaintEventHandler Paint;
+               public new event PaintEventHandler Paint {
+                       add { base.Paint += value; }
+                       remove { base.Paint -= value; }
+               }
 
                public event EventHandler SelectedIndexChanged;
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler TextChanged;
+               public new event EventHandler TextChanged {
+                       add { base.TextChanged += value; }
+                       remove { base.TextChanged -= value; }
+               }
+
                #endregion // Events
 
                #region Public Constructors
                public ListView ()
                {
                        background_color = ThemeEngine.Current.ColorWindow;
+                       items = new ListViewItemCollection (this);
                        checked_indices = new CheckedIndexCollection (this);
                        checked_items = new CheckedListViewItemCollection (this);
                        columns = new ColumnHeaderCollection (this);
                        foreground_color = SystemColors.WindowText;
-                       items = new ListViewItemCollection (this);
                        selected_indices = new SelectedIndexCollection (this);
                        selected_items = new SelectedListViewItemCollection (this);
 
                        border_style = BorderStyle.Fixed3D;
 
-                       // we are mostly scrollable
-                       h_scroll = new HScrollBar ();
-                       v_scroll = new VScrollBar ();
+                       header_control = new HeaderControl (this);
+                       header_control.Visible = false;
+                       Controls.AddImplicit (header_control);
+
+                       item_control = new ItemControl (this);
+                       Controls.AddImplicit (item_control);
+
+                       h_scroll = new ImplicitHScrollBar ();
+                       Controls.AddImplicit (this.h_scroll);
+
+                       v_scroll = new ImplicitVScrollBar ();
+                       Controls.AddImplicit (this.v_scroll);
+
                        h_marker = v_marker = 0;
                        keysearch_tickcnt = 0;
 
@@ -149,15 +163,11 @@ namespace System.Windows.Forms
                        v_scroll.ValueChanged += new EventHandler(VerticalScroller);
 
                        // event handlers
-                       base.DoubleClick += new EventHandler(ListView_DoubleClick);
                        base.KeyDown += new KeyEventHandler(ListView_KeyDown);
-                       base.KeyUp += new KeyEventHandler(ListView_KeyUp);
-                       base.MouseDown += new MouseEventHandler(ListView_MouseDown);
-                       base.MouseHover += new EventHandler(ListView_MouseHover);
-                       base.MouseUp += new MouseEventHandler(ListView_MouseUp);
-                       base.MouseMove += new MouseEventHandler(ListView_MouseMove);
-                       base.Paint += new PaintEventHandler (ListView_Paint);
                        SizeChanged += new EventHandler (ListView_SizeChanged);
+                       GotFocus += new EventHandler (FocusChanged);
+                       LostFocus += new EventHandler (FocusChanged);
+                       MouseWheel += new MouseEventHandler(ListView_MouseWheel);
 
                        this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
                }
@@ -176,15 +186,6 @@ namespace System.Windows.Forms
                        }
                }
 
-               internal bool CanMultiselect {
-                       get {
-                               if (this.multiselect &&
-                                       (this.ctrl_pressed || this.shift_pressed))
-                                       return true;
-                               else
-                                       return false;
-                       }
-               }
                #endregion      // Private Internal Properties
 
                #region  Protected Properties
@@ -236,14 +237,7 @@ namespace System.Windows.Forms
                [DefaultValue (false)]
                public bool AllowColumnReorder {
                        get { return allow_column_reorder; }
-                       set {
-                               if (this.allow_column_reorder != value) {
-                                       allow_column_reorder = value;
-                                       // column reorder does not matter in Details view
-                                       if (this.view != View.Details)
-                                               this.Redraw (true);
-                               }
-                       }
+                       set { allow_column_reorder = value; }
                }
 
                [DefaultValue (true)]
@@ -278,8 +272,7 @@ namespace System.Windows.Forms
                                        return;
 
                                background_image = value;
-                               if (BackgroundImageChanged != null)
-                                       BackgroundImageChanged (this, new EventArgs ());
+                               OnBackgroundImageChanged (EventArgs.Empty);
                        }
                }
 
@@ -295,6 +288,13 @@ namespace System.Windows.Forms
                        get { return check_boxes; }
                        set {
                                if (check_boxes != value) {
+#if NET_2_0
+                                       if (value && View == View.Tile)
+                                               throw new NotSupportedException ("CheckBoxes are not"
+                                                       + " supported in Tile view. Choose a different"
+                                                       + " view or set CheckBoxes to false.");
+#endif
+
                                        check_boxes = value;
                                        this.Redraw (true);
                                }
@@ -323,7 +323,9 @@ namespace System.Windows.Forms
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public ListViewItem FocusedItem {
-                       get { return focused_item; }
+                       get {
+                               return focused_item;
+                       }
                }
 
                public override Color ForeColor {
@@ -357,18 +359,22 @@ namespace System.Windows.Forms
                public ColumnHeaderStyle HeaderStyle {
                        get { return header_style; }
                        set {
-                               if (value != ColumnHeaderStyle.Clickable && value != ColumnHeaderStyle.Nonclickable  && 
-                                       value != ColumnHeaderStyle.None) {
+                               if (header_style == value)
+                                       return;
+
+                               switch (value) {
+                               case ColumnHeaderStyle.Clickable:
+                               case ColumnHeaderStyle.Nonclickable:
+                               case ColumnHeaderStyle.None:
+                                       break;
+                               default:
                                        throw new InvalidEnumArgumentException (string.Format 
                                                ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
                                }
                                
-                               if (header_style != value) {
-                                       header_style = value;
-                                       // header style matters only in Details view
-                                       if (this.view == View.Details)
-                                               this.Redraw (false);
-                               }
+                               header_style = value;
+                               if (view == View.Details)
+                                       Redraw (true);
                        }
                }
 
@@ -426,8 +432,17 @@ namespace System.Windows.Forms
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public IComparer ListViewItemSorter {
-                       get { return item_sorter; }
-                       set { item_sorter = value; }
+                       get {
+                               if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
+                                       return null;
+                               return item_sorter;
+                       }
+                       set {
+                               if (item_sorter != value) {
+                                       item_sorter = value;
+                                       Sort ();
+                               }
+                       }
                }
 
                [DefaultValue (true)]
@@ -459,6 +474,18 @@ namespace System.Windows.Forms
                        get { return selected_items; }
                }
 
+#if NET_2_0
+               [MonoTODO("Implement")]
+               public bool ShowGroups {
+                       get {
+                               return false;
+                       }
+
+                       set {
+                       }
+               }
+#endif
+
                [DefaultValue (null)]
                public ImageList SmallImageList {
                        get { return small_image_list; }
@@ -472,15 +499,46 @@ namespace System.Windows.Forms
                public SortOrder Sorting {
                        get { return sort_order; }
                        set { 
-                               if (value != SortOrder.Ascending && value != SortOrder.Descending  && 
-                                       value != SortOrder.None) {
-                                       throw new InvalidEnumArgumentException (string.Format
-                                               ("Enum argument value '{0}' is not valid for Sorting", value));
+                               if (!Enum.IsDefined (typeof (SortOrder), value)) {
+                                       throw new InvalidEnumArgumentException ("value", (int) value,
+                                               typeof (SortOrder));
                                }
                                
-                               if (sort_order != value)  {                     
-                                       sort_order = value; 
+                               if (sort_order == value)
+                                       return;
+
+                               sort_order = value;
+
+                               if (value == SortOrder.None) {
+                                       if (item_sorter != null) {
+                                               // ListViewItemSorter should never be reset for SmallIcon
+                                               // and LargeIcon view
+                                               if (View != View.SmallIcon && View != View.LargeIcon)
+#if NET_2_0
+                                                       item_sorter = null;
+#else
+                                                       // in .NET 1.1, only internal IComparer would be
+                                                       // set to null
+                                                       if (item_sorter is ItemComparer)
+                                                               item_sorter = null;
+#endif
+                                       }
                                        this.Redraw (false);
+                               } else {
+                                       if (item_sorter == null)
+                                               item_sorter = new ItemComparer (value);
+                                       if (item_sorter is ItemComparer) {
+#if NET_2_0
+                                               item_sorter = new ItemComparer (value);
+#else
+                                               // in .NET 1.1, the sort order is not updated for
+                                               // SmallIcon and LargeIcon views if no custom IComparer
+                                               // is set
+                                               if (View != View.SmallIcon && View != View.LargeIcon)
+                                                       item_sorter = new ItemComparer (value);
+#endif
+                                       }
+                                       Sort ();
                                }
                        }
                }
@@ -506,8 +564,7 @@ namespace System.Windows.Forms
                                text = value;
                                this.Redraw (true);
 
-                               if (TextChanged != null)
-                                       TextChanged (this, new EventArgs ());
+                               OnTextChanged (EventArgs.Empty);
                        }
                }
 
@@ -525,7 +582,7 @@ namespace System.Windows.Forms
                                // do a hit test for the scrolled position
                                else {
                                        foreach (ListViewItem item in this.items) {
-                                               if (item.EntireRect.X >= h_marker && item.EntireRect.Y >= v_marker)
+                                               if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
                                                        return item;
                                        }
                                        return null;
@@ -533,17 +590,34 @@ namespace System.Windows.Forms
                        }
                }
 
+#if NET_2_0
+               [MonoTODO("Implement")]
+               public bool UseCompatibleStateImageBehavior {
+                       get {
+                               return false;
+                       }
+
+                       set {
+                       }
+               }
+#endif
+
                [DefaultValue (View.LargeIcon)]
                public View View {
                        get { return view; }
                        set { 
-                               if (value != View.Details && value != View.LargeIcon  && 
-                                       value != View.List  && value != View.SmallIcon  ) {
-                                       throw new InvalidEnumArgumentException (string.Format
-                                               ("Enum argument value '{0}' is not valid for View", value));
-                               }
-                               
+                               if (!Enum.IsDefined (typeof (View), value))
+                                       throw new InvalidEnumArgumentException ("value", (int) value,
+                                               typeof (View));
+
                                if (view != value) {
+#if NET_2_0
+                                       if (CheckBoxes && value == View.Tile)
+                                               throw new NotSupportedException ("CheckBoxes are not"
+                                                       + " supported in Tile view. Choose a different"
+                                                       + " view or set CheckBoxes to false.");
+#endif
+
                                        h_scroll.Value = v_scroll.Value = 0;
                                        view = value; 
                                        Redraw (true);
@@ -564,8 +638,7 @@ namespace System.Windows.Forms
                                        return 0;                                       
                                
                                foreach (ListViewItem item in this.items) {
-                                       if (item.EntireRect.X + item.EntireRect.Width >= h_marker 
-                                               && item.EntireRect.Y + item.EntireRect.Height >= v_marker)
+                                       if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
                                                return item.Index;
                                }
                                return 0;
@@ -574,17 +647,28 @@ namespace System.Windows.Forms
                }
 
                
-               internal int LastItemIndex {                    
+               internal int LastVisibleIndex {                 
                        get {                                                   
-                               for (int i = FirstVisibleIndex; i < Items.Count; i++) {                                         
-                                       if (Items[i].EntireRect.Y > v_marker + ClientRectangle.Bottom)                                          
-                                                       return i -1;                                    
+                               for (int i = FirstVisibleIndex; i < Items.Count; i++) {
+                                       if (View == View.List || Alignment == ListViewAlignment.Left) {
+                                               if (Items[i].Bounds.X > ClientRectangle.Right)
+                                                       return i - 1;                                   
+                                       } else {
+                                               if (Items[i].Bounds.Y > ClientRectangle.Bottom)
+                                                       return i - 1;                                   
+                                       }
                                }
                                
                                return Items.Count - 1;
                        }
                }
                
+               internal void OnSelectedIndexChanged ()
+               {
+                       if (IsHandleCreated)
+                               OnSelectedIndexChanged (EventArgs.Empty);
+               }
+
                internal int TotalWidth {
                        get { return Math.Max (this.Width, this.layout_wd); }
                }
@@ -665,6 +749,8 @@ namespace System.Windows.Forms
                        return ret_size;
                }
 
+               const int max_wrap_padding = 38;
+
                // Sets the size of the biggest item text as per the view
                private void CalcTextSize ()
                {                       
@@ -680,10 +766,8 @@ namespace System.Windows.Forms
                                Size temp = Size.Empty;
                                if (this.check_boxes)
                                        temp.Width += 2 * this.CheckBoxSize.Width;
-                               if (large_image_list != null)
-                                       temp.Width += large_image_list.ImageSize.Width;
-                               if (temp.Width == 0)
-                                       temp.Width = 43;
+                               int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
+                               temp.Width += icon_w + max_wrap_padding;
                                // wrapping is done for two lines only
                                if (text_size.Width > temp.Width) {
                                        text_size.Width = temp.Width;
@@ -712,40 +796,65 @@ namespace System.Windows.Forms
                        text_size.Height += 2;
                }
 
+               private void Scroll (ScrollBar scrollbar, int delta)
+               {
+                       if (delta == 0 || !scrollbar.Visible)
+                               return;
+
+                       int max;
+                       if (scrollbar == h_scroll)
+                               max = h_scroll.Maximum - item_control.Width;
+                       else
+                               max = v_scroll.Maximum - item_control.Height;
+
+                       int val = scrollbar.Value + delta;
+                       if (val > max)
+                               val = max;
+                       else if (val < scrollbar.Minimum)
+                               val = scrollbar.Minimum;
+                       scrollbar.Value = val;
+               }
+
                private void CalculateScrollBars ()
                {
-                       client_area = ClientRectangle;
+                       Rectangle client_area = ClientRectangle;
                        
                        if (!this.scrollable || this.items.Count <= 0) {
                                h_scroll.Visible = false;
                                v_scroll.Visible = false;
+                               item_control.Location = new Point (0, header_control.Height);
+                               item_control.Height = ClientRectangle.Width - header_control.Height;
+                               item_control.Width = ClientRectangle.Width;
+                               header_control.Width = ClientRectangle.Width;
                                return;
                        }
 
+                       // Don't calculate if the view is not displayable
+                       if (client_area.Height < 0 || client_area.Width < 0)
+                               return;
+
                        // making a scroll bar visible might make
                        // other scroll bar visible                     
                        if (layout_wd > client_area.Right) {
                                h_scroll.Visible = true;
-                               if ((layout_ht + h_scroll.Height) > client_area.Bottom) {
+                               if ((layout_ht + h_scroll.Height) > client_area.Bottom)
                                        v_scroll.Visible = true;                                        
-                               }
-                               else {
+                               else
                                        v_scroll.Visible = false;
-                               }
                        } else if (layout_ht > client_area.Bottom) {                            
                                v_scroll.Visible = true;
-                               if ((layout_wd + v_scroll.Width) > client_area.Right) {
+                               if ((layout_wd + v_scroll.Width) > client_area.Right)
                                        h_scroll.Visible = true;
-                               }
-                               else {
+                               else
                                        h_scroll.Visible = false;
-                               }
                        } else {
                                h_scroll.Visible = false;
                                v_scroll.Visible = false;
                        }                       
 
-                       if (h_scroll.Visible) {
+                       item_control.Height = ClientRectangle.Height - header_control.Height;
+
+                       if (h_scroll.is_visible) {
                                h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
                                h_scroll.Minimum = 0;
 
@@ -762,11 +871,14 @@ namespace System.Windows.Forms
    
                                h_scroll.LargeChange = client_area.Width;
                                h_scroll.SmallChange = Font.Height;
-                               client_area.Height -= h_scroll.Height;
+                               item_control.Height -= h_scroll.Height;
                        }
 
-                       // vertical scrollbar
-                       if (v_scroll.Visible) {
+                       if (header_control.is_visible)
+                               header_control.Width = ClientRectangle.Width;
+                       item_control.Width = ClientRectangle.Width;
+
+                       if (v_scroll.is_visible) {
                                v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
                                v_scroll.Minimum = 0;
 
@@ -782,188 +894,214 @@ namespace System.Windows.Forms
 
                                v_scroll.LargeChange = client_area.Height;
                                v_scroll.SmallChange = Font.Height;
-                               client_area.Width -= v_scroll.Width;
+                               if (header_control.Visible)
+                                       header_control.Width -= v_scroll.Width;
+                               item_control.Width -= v_scroll.Width;
                        }
                }
                
-               
-               // Sets the location of every item on
-               // the ListView as per the view
-               private void CalculateListView (ListViewAlignment align)
+               ColumnHeader GetReorderedColumn (int index)
                {
-                       int current_pos_x = 0; // our x-position marker
-                       int current_pos_y = 0; // our y-position marker
-                       int item_ht;
-                       int item_wd;
-                       int max;         // max x_pos or y_pos depending on the alignment
-                       int current = 0; // current row or column
-                       int vertical_spacing = ThemeEngine.Current.ListViewVerticalSpacing;
-                       int horizontal_spacing = ThemeEngine.Current.ListViewHorizontalSpacing;
+                       if (reordered_column_indices == null)
+                               return Columns [index];
+                       else
+                               return Columns [reordered_column_indices [index]];
+               }
 
-                       CalcTextSize ();
+               void ReorderColumn (ColumnHeader col, int index)
+               {
+                       if (reordered_column_indices == null) {
+                               reordered_column_indices = new int [Columns.Count];
+                               for (int i = 0; i < Columns.Count; i++)
+                                       reordered_column_indices [i] = i;
+                       }
 
-                       switch (view) {
+                       if (reordered_column_indices [index] == col.Index)
+                               return;
 
-                       case View.Details:
-                               // ColumnHeaders are not drawn if headerstyle is none
-                               int ht = (this.header_style == ColumnHeaderStyle.None) ? 
-                                       0 : this.Font.Height + 3;
-                               
-                               if (columns.Count > 0) {
-                                       foreach (ColumnHeader col in columns) {
-                                               col.X = current_pos_x;
-                                               col.Y = current_pos_y;
-                                               col.CalcColumnHeader ();
-                                               current_pos_x += col.Wd;
+                       int[] curr = reordered_column_indices;
+                       int[] result = new int [Columns.Count];
+                       int curr_idx = 0;
+                       for (int i = 0; i < Columns.Count; i++) {
+                               if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
+                                       curr_idx++;
+
+                               if (i == index)
+                                       result [i] = col.Index;
+                               else
+                                       result [i] = curr [curr_idx++];
+                       }
+
+                       reordered_column_indices = result;
+                       LayoutDetails ();
+                       header_control.Invalidate ();
+                       item_control.Invalidate ();
+               }
+
+               Size LargeIconItemSize {
+                       get {
+                               int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
+                               int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
+                               int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
+                               int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
+                               return new Size (w, h);
+                       }
+               }
+
+               Size SmallIconItemSize {
+                       get {
+                               int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
+                               int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
+                               int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
+                               int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
+                               return new Size (w, h);
+                       }
+               }
+
+               int rows;
+               int cols;
+               ListViewItem[,] item_matrix;
+
+               void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
+               {
+                       header_control.Visible = false;
+                       header_control.Size = Size.Empty;
+                       item_control.Visible = true;
+                       item_control.Location = Point.Empty;
+
+                       if (items.Count == 0)
+                               return;
+
+                       Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
+
+                       Rectangle area = ClientRectangle;
+
+                       if (left_aligned) {
+                               rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
+                               if (rows <= 0)
+                                       rows = 1;
+                               cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
+                       } else {
+                               cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
+                               if (cols <= 0)
+                                       cols = 1;
+                               rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
+                       }
+
+                       layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
+                       layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
+                       item_matrix = new ListViewItem [rows, cols];
+                       int row = 0;
+                       int col = 0;
+                       foreach (ListViewItem item in items) {
+                               int x = col * (sz.Width + x_spacing);
+                               int y = row * (sz.Height + y_spacing);
+                               item.Location = new Point (x, y);
+                               item.Layout ();
+                               item.row = row;
+                               item.col = col;
+                               item_matrix [row, col] = item;
+                               if (left_aligned) {
+                                       if (++row == rows) {
+                                               row = 0;
+                                               col++;
                                        }
-                                       this.layout_wd = current_pos_x;
-                               }
-                               // set the position marker for placing items
-                               // vertically down
-                               current_pos_y = ht;
-
-                               if (items.Count > 0) {
-                                       foreach (ListViewItem item in items) {
-                                               item.location.X = 0;
-                                               item.location.Y = current_pos_y;
-                                               item.CalcListViewItem ();
-                                               current_pos_y += item.EntireRect.Height;
+                               } else {
+                                       if (++col == cols) {
+                                               col = 0;
+                                               row++;
                                        }
-                                       this.layout_ht = current_pos_y;
+                               }
+                       }
+
+                       item_control.Size = new Size (layout_wd, layout_ht);
+               }
+
+               void LayoutHeader ()
+               {
+                       int x = 0;
+                       for (int i = 0; i < Columns.Count; i++) {
+                               ColumnHeader col = GetReorderedColumn (i);
+                               col.X = x;
+                               col.Y = 0;
+                               col.CalcColumnHeader ();
+                               x += col.Wd;
+                       }
+
+                       if (x < ClientRectangle.Width)
+                               x = ClientRectangle.Width;
+
+                       if (header_style == ColumnHeaderStyle.None) {
+                               header_control.Visible = false;
+                               header_control.Size = Size.Empty;
+                       } else {
+                               header_control.Width = x;
+                               header_control.Height = columns [0].Ht;
+                               header_control.Visible = true;
+                       }
+               }
+
+               void LayoutDetails ()
+               {
+                       if (columns.Count == 0) {
+                               header_control.Visible = false;
+                               item_control.Visible = false;
+                               return;
+                       }
+
+                       LayoutHeader ();
+
+                       item_control.Visible = true;
+                       item_control.Location = new Point (0, header_control.Height);
 
-                                       // some space for bottom gridline
-                                       if (this.grid_lines)
-                                               this.layout_ht += 2;
+                       int y = 0; 
+                       if (items.Count > 0) {
+                               foreach (ListViewItem item in items) {
+                                       item.Layout ();
+                                       item.Location = new Point (0, y);
+                                       y += item.Bounds.Height + 2;
                                }
+
+                               // some space for bottom gridline
+                               if (grid_lines)
+                                       y += 2;
+                       }
+
+                       layout_wd = Math.Max (header_control.Width, item_control.Width);
+                       layout_ht = y + header_control.Height;
+               }
+
+               private void CalculateListView (ListViewAlignment align)
+               {
+                       CalcTextSize ();
+
+                       switch (view) {
+                       case View.Details:
+                               LayoutDetails ();
                                break;
 
                        case View.SmallIcon:
-                               vertical_spacing = 0;
-                               horizontal_spacing = 0;
-                               goto case View.LargeIcon;
+                               LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
+                               break;
 
                        case View.LargeIcon:
-                               if (items.Count > 0) {
-                                       items [0].CalcListViewItem ();
-                                       item_ht = items [0].EntireRect.Height;
-                                       item_wd = items [0].EntireRect.Width;
-
-                                       // top (default) and snaptogrid alignments are handled same way
-                                       if (align == ListViewAlignment.Left) {
-                                               max = client_area.Height;
-                                               foreach (ListViewItem item in items) {
-                                                       item.location.X = current_pos_x +
-                                                               horizontal_spacing;
-                                                       item.location.Y = 0;
-                                                       item.CalcListViewItem ();
-                                                       current_pos_y += item_ht;
-
-                                                       current ++; // just to know about the last element
-                                                       // we just did the last item
-                                                       if (current == items.Count) {
-                                                               if (max < current_pos_y)
-                                                                       max = current_pos_y;
-                                                               current_pos_x = item.EntireRect.Right;
-                                                               break;
-                                                       }
-                                                       else {
-                                                               // is there enough space for another row ?
-                                                               if ((current_pos_y + vertical_spacing
-                                                                    + item_ht) <= client_area.Height)
-                                                                       current_pos_y += vertical_spacing;
-                                                               else {
-                                                                       // start another column
-                                                                       // make current_pos_y as the
-                                                                       // max value and reset
-                                                                       // current_pos_y value.
-                                                                       max = current_pos_y;
-                                                                       current_pos_x += item_wd;
-                                                                       current_pos_y = 0;
-                                                               }
-                                                       }
-                                               }
-                                               // adjust the layout dimensions
-                                               this.layout_ht = max;
-                                               this.layout_wd = current_pos_x;
-                                       }
-                                       else { // other default/top alignment
-                                               max = client_area.Width;
-                                               foreach (ListViewItem item in items) {
-                                                       item.location.X = current_pos_x +
-                                                               horizontal_spacing;
-
-                                                       item.location.Y = current_pos_y;
-                                                       item.CalcListViewItem ();
-                                                       current_pos_x += item_wd;
-
-                                                       current ++; // just to know about the last element
-                                                       // we just did the last item
-                                                       if (current == items.Count) {
-                                                               if (max < current_pos_x)
-                                                                       max = current_pos_x;
-                                                               current_pos_y = item.EntireRect.Bottom;
-                                                               break;
-                                                       }
-                                                       else {
-                                                               // is there enough space for another column?
-                                                               if ((current_pos_x + horizontal_spacing
-                                                                    + item_wd) <= client_area.Width)
-                                                                       continue;
-                                                               else {
-                                                                       // start another row
-                                                                       // make current_pos_x as the
-                                                                       // max value and reset
-                                                                       // current_pos_x value.
-                                                                       max = current_pos_x;
-                                                                       current_pos_y += (item_ht +
-                                                                                         vertical_spacing);
-                                                                       current_pos_x = 0;
-                                                               }
-                                                       }
-                                               }
-                                               // adjust the layout dimensions
-                                               this.layout_wd = max;
-                                               this.layout_ht = current_pos_y;
-                                       }
-                               }
+                               LayoutIcons (true, alignment == ListViewAlignment.Left,
+                                            ThemeEngine.Current.ListViewHorizontalSpacing,
+                                            ThemeEngine.Current.ListViewVerticalSpacing);
                                break;
 
                        case View.List:
-                               if (items.Count > 0) {
-                                       items [0].CalcListViewItem ();
-                                       item_ht = items [0].EntireRect.Height;
-                                       item_wd = items [0].EntireRect.Width;
-
-                                       max = client_area.Height / item_ht;
-                                       if (max == 0)
-                                               max = 1; // we draw at least one row
-
-                                       foreach (ListViewItem item in items) {
-                                               item.location.X = current_pos_x;
-                                               item.location.Y = current_pos_y;
-                                               item.CalcListViewItem ();
-                                               current ++;
-                                               if (current == max) {
-                                                       current_pos_x += item_wd;
-                                                       current_pos_y = 0;
-                                                       current = 0;
-                                               }
-                                               else
-                                                       current_pos_y += item_ht;
-                                       }
-
-                                       // adjust the layout dimensions
-                                       this.layout_ht = max * item_ht;
-                                       if (current == 0) // we have fully filled layout
-                                               this.layout_wd = current_pos_x;
-                                       else
-                                               this.layout_wd = current_pos_x + item_wd;
-                               }
+                               LayoutIcons (false, true, 4, 2);
                                break;
                        }
 
                         CalculateScrollBars ();
-                        
+               }
+
+               bool HaveModKeys {
+                       get {
+                               return (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0;
+                       }
                }
 
                private bool KeySearchString (KeyEventArgs ke)
@@ -976,7 +1114,8 @@ namespace System.Windows.Forms
                        keysearch_text += (char) ke.KeyData;
                        keysearch_tickcnt = current_tickcnt;
 
-                       int i = FocusedItem.Index;
+                       int start = FocusedItem == null ? 0 : FocusedItem.Index;
+                       int i = start;
                        while (true) {
                                if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
                                        CompareOptions.IgnoreCase)) {
@@ -987,319 +1126,772 @@ namespace System.Windows.Forms
                                }
                                i = (i + 1  < Items.Count) ? i+1 : 0;
 
-                               if (i == FocusedItem.Index)
+                               if (i == start)
                                        break;
                        }
                        return true;
                }
 
-                               
-               // Event Handlers
-               private void ListView_DoubleClick (object sender, EventArgs e)
+               int GetAdjustedIndex (Keys key)
                {
-                       if (this.activation == ItemActivation.Standard
-                           && this.ItemActivate != null)
-                               this.ItemActivate (this, e);
-               }
+                       int result = -1;
+
+                       if (View == View.Details) {
+                               if (key == Keys.Up)
+                                       result = FocusedItem.Index - 1;
+                               else if (key == Keys.Down) {
+                                       result = FocusedItem.Index + 1;
+                                       if (result == items.Count)
+                                               result = -1;
+                               }
+                               return result;
+                       }
 
-               private void ListView_KeyDown (object sender, KeyEventArgs ke)
-               {                       
-                       int index = -1;
-                       if (ke.Handled || Items.Count == 0)
-                               return;
+                       int row = FocusedItem.row;
+                       int col = FocusedItem.col;
 
-                       ke.Handled = true;
+                       switch (key) {
+                       case Keys.Left:
+                               if (col == 0)
+                                       return -1;
+                               return item_matrix [row, col - 1].Index;
 
-                       switch (ke.KeyCode) {
+                       case Keys.Right:
+                               if (col == (cols - 1))
+                                       return -1;
+                               while (item_matrix [row, col + 1] == null)
+                                      row--;   
+                               return item_matrix [row, col + 1].Index;
 
-                       case Keys.ControlKey:
-                               ctrl_pressed = true;
-                               break;
+                       case Keys.Up:
+                               if (row == 0)
+                                       return -1;
+                               return item_matrix [row - 1, col].Index;
 
                        case Keys.Down:
-                               if (focused_item != null && focused_item.Index + 1 < Items.Count) {
-                                       index = focused_item.Index + 1;
-                               }
-                               break;
+                               if (row == (rows - 1) || row == Items.Count - 1)
+                                       return -1;
+                               while (item_matrix [row + 1, col] == null)
+                                      col--;   
+                               return item_matrix [row + 1, col].Index;
 
-                       case Keys.End:
-                               index = Items.Count - 1;
-                               break;
+                       default:
+                               return -1;
+                       }
+               }
 
-                       case Keys.Home:                 
-                               index = 0;
-                               break;
+               ListViewItem selection_start;
 
-                       case Keys.Left:
-                               index = -1;
-                               if (focused_item != null)
-                                       index = focused_item.Index;
-                               else
-                                       break;
+               private bool SelectItems (ArrayList sel_items)
+               {
+                       bool changed = false;
+                       ArrayList curr_items = SelectedItems.List;
+                       foreach (ListViewItem item in curr_items)
+                               if (!sel_items.Contains (item)) {
+                                       item.Selected = false;
+                                       changed = true;
+                               }
+                       foreach (ListViewItem item in sel_items)
+                               if (!item.Selected) {
+                                       item.Selected = true;
+                                       changed = true;
+                               }
+                       return changed;
+               }
 
-                               if (index > 0)
-                                       index -= 1;
-                                                                       
-                               break;
+               private void UpdateMultiSelection (int index)
+               {
+                       bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
+                       bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
+                       ListViewItem item = items [index];
+
+                       if (shift_pressed && selection_start != null) {
+                               ArrayList list = new ArrayList ();
+                               int start = Math.Min (selection_start.Index, index);
+                               int end = Math.Max (selection_start.Index, index);
+                               if (View == View.Details) {
+                                       for (int i = start; i <= end; i++)
+                                               list.Add (items [i]);
+                               } else {
+                                       int left = Math.Min (items [start].col, items [end].col);
+                                       int right = Math.Max (items [start].col, items [end].col);
+                                       int top = Math.Min (items [start].row, items [end].row);
+                                       int bottom = Math.Max (items [start].row, items [end].row);
+                                       foreach (ListViewItem curr in items)
+                                               if (curr.row >= top && curr.row <= bottom && 
+                                                   curr.col >= left && curr.col <= right)
+                                                       list.Add (curr);
+                               }
+                               if (SelectItems (list))
+                                       OnSelectedIndexChanged (EventArgs.Empty);
+                       } else  if (ctrl_pressed) {
+                               item.Selected = !item.Selected;
+                               selection_start = item;
+                               OnSelectedIndexChanged (EventArgs.Empty);
+                       } else {
+                               SelectedItems.Clear ();
+                               item.Selected = true;
+                               selection_start = item;
+                               OnSelectedIndexChanged (EventArgs.Empty);
+                       }
+               }
 
-                       case Keys.Right:
-                               if (focused_item != null)
-                                       index = focused_item.Index + 1;
-                               else
-                                       index = 1;
+               internal override bool InternalPreProcessMessage (ref Message msg)
+               {
+                       if (msg.Msg == (int)Msg.WM_KEYDOWN) {
+                               Keys key_data = (Keys)msg.WParam.ToInt32();
+                               if (HandleNavKeys (key_data))
+                                       return true;
+                       } 
+                       return base.InternalPreProcessMessage (ref msg);
+               }
+
+               bool HandleNavKeys (Keys key_data)
+               {
+                       if (Items.Count == 0 || !item_control.Visible)
+                               return false;
 
-                               if (index == items.Count)
-                                       index = -1;
+                       if (FocusedItem == null)
+                               SetFocusedItem (Items [0]);
 
+                       switch (key_data) {
+                       case Keys.End:
+                               SelectIndex (Items.Count - 1);
                                break;
 
-                       case Keys.ShiftKey:
-                               shift_pressed = true;
+                       case Keys.Home:                 
+                               SelectIndex (0);
                                break;
 
+                       case Keys.Left:
+                       case Keys.Right:
                        case Keys.Up:                           
-                               if (focused_item != null)
-                                       index = focused_item.Index;
-                               else
-                                       break;
-
-                               if (index > 0)
-                                       index--;
-
-                               if (index < 0) {
-                                       index = -1;
-                               }
+                       case Keys.Down:
+                               SelectIndex (GetAdjustedIndex (key_data));
                                break;
 
                        default:
-                               if (KeySearchString (ke)) {
-                                       ke.Handled = true;
-                               } else {
-                                       ke.Handled = false;
-                               }
-                               return;
-                       }
-                       
-                       if (index != -1) {
-                               items [index].Selected = true;
-                               SetFocusedItem (items [index]);                         
-                               EnsureVisible (index);
+                               return false;
                        }
+
+                       return true;
                }
 
-               private void ListView_KeyUp (object sender, KeyEventArgs ke)
+               void SelectIndex (int index)
                {
-                       if (!ke.Handled) {
-                               if (ke.KeyCode == Keys.ControlKey)
-                                       this.ctrl_pressed = false;
+                       if (index == -1)
+                               return;
 
-                               if (ke.KeyCode == Keys.ShiftKey)
-                                       this.shift_pressed = false;
-                               ke.Handled = true;
+                       if (MultiSelect)
+                               UpdateMultiSelection (index);
+                       else if (!items [index].Selected) {
+                               items [index].Selected = true;
+                               OnSelectedIndexChanged (EventArgs.Empty);
                        }
+
+                       SetFocusedItem (items [index]);                         
+                       EnsureVisible (index);
                }
 
-               private void ListView_MouseDown (object sender, MouseEventArgs me)
-               {
-                       if (items.Count == 0)
+               private void ListView_KeyDown (object sender, KeyEventArgs ke)
+               {                       
+                       if (ke.Handled || Items.Count == 0 || !item_control.Visible)
                                return;
 
-                       Point hit = Point.Empty;
-                       if (this.HeaderStyle != ColumnHeaderStyle.None) {
-                               // take horizontal scrolling into account
-                               hit = new Point (me.X + h_marker, me.Y);
-
-                               // hit test on columns
-                               if (this.view == View.Details && this.columns.Count > 0) {
-                                       foreach (ColumnHeader col in this.columns) {
-                                               if (col.Rect.Contains (hit)) {
-                                                       this.clicked_column = col;
-                                                       this.Capture = true;
-                                                       break;
-                                               }
-                                       }
+                       ke.Handled = KeySearchString (ke);
+               }
+
+               internal class ItemControl : Control {
+
+                       ListView owner;
+                       ListViewItem clicked_item;
+                       ListViewItem last_clicked_item;
+                       bool hover_processed = false;
+                       bool checking = false;
+                       
+                       ListViewLabelEditTextBox edit_text_box;
+                       internal ListViewItem edit_item;
+                       LabelEditEventArgs edit_args;
 
-                                       if (this.clicked_column != null) {
-                                               this.clicked_column.pressed = true;
-                                               this.Redraw (false);
+                       public ItemControl (ListView owner)
+                       {
+                               this.owner = owner;
+                               DoubleClick += new EventHandler(ItemsDoubleClick);
+                               MouseDown += new MouseEventHandler(ItemsMouseDown);
+                               MouseMove += new MouseEventHandler(ItemsMouseMove);
+                               MouseHover += new EventHandler(ItemsMouseHover);
+                               MouseUp += new MouseEventHandler(ItemsMouseUp);
+                       }
+
+                       void ItemsDoubleClick (object sender, EventArgs e)
+                       {
+                               if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
+                                       owner.ItemActivate (this, e);
+                       }
+
+                       enum BoxSelect {
+                               None,
+                               Normal,
+                               Shift,
+                               Control
+                       }
+
+                       BoxSelect box_select_mode = BoxSelect.None;
+                       ArrayList prev_selection;
+                       Point box_select_start;
+
+                       Rectangle box_select_rect;
+                       internal Rectangle BoxSelectRectangle {
+                               get { return box_select_rect; }
+                               set {
+                                       if (box_select_rect == value)
                                                return;
+
+                                       InvalidateBoxSelectRect ();
+                                       box_select_rect = value;
+                                       InvalidateBoxSelectRect ();
+                               }
+                       }
+
+                       void InvalidateBoxSelectRect ()
+                       {
+                               if (BoxSelectRectangle.Size.IsEmpty)
+                                       return;
+
+                               Rectangle edge = BoxSelectRectangle;
+                               edge.X -= 1;
+                               edge.Y -= 1;
+                               edge.Width += 2;
+                               edge.Height = 2;
+                               Invalidate (edge);
+                               edge.Y = BoxSelectRectangle.Bottom - 1;
+                               Invalidate (edge);
+                               edge.Y = BoxSelectRectangle.Y - 1;
+                               edge.Width = 2;
+                               edge.Height = BoxSelectRectangle.Height + 2;
+                               Invalidate (edge);
+                               edge.X = BoxSelectRectangle.Right - 1;
+                               Invalidate (edge);
+                       }
+
+                       private Rectangle CalculateBoxSelectRectangle (Point pt)
+                       {
+                               int left = Math.Min (box_select_start.X, pt.X);
+                               int right = Math.Max (box_select_start.X, pt.X);
+                               int top = Math.Min (box_select_start.Y, pt.Y);
+                               int bottom = Math.Max (box_select_start.Y, pt.Y);
+                               return Rectangle.FromLTRB (left, top, right, bottom);
+                       }
+
+                       ArrayList BoxSelectedItems {
+                               get {
+                                       ArrayList result = new ArrayList ();
+                                       foreach (ListViewItem item in owner.Items) {
+                                               Rectangle r = item.Bounds;
+                                               r.X += r.Width / 4;
+                                               r.Y += r.Height / 4;
+                                               r.Width /= 2;
+                                               r.Height /= 2;
+                                               if (BoxSelectRectangle.IntersectsWith (r))
+                                                       result.Add (item);
                                        }
+                                       return result;
                                }
                        }
 
-                       // hit test on items
-                       // we need to take scrolling into account
-                       hit = new Point (me.X + h_marker, me.Y + v_marker);
-                       foreach (ListViewItem item in this.items) {
-                               if (item.CheckRect.Contains (hit)) {
-                                       CheckState curr_state = item.Checked ?
-                                               CheckState.Checked : CheckState.Unchecked;
-                                       if (item.Checked)
-                                               item.Checked = false;
-                                       else
-                                               item.Checked = true;
+                       private bool PerformBoxSelection (Point pt)
+                       {
+                               if (box_select_mode == BoxSelect.None)
+                                       return false;
 
-                                       CheckState new_state = item.Checked ?
-                                               CheckState.Checked : CheckState.Unchecked;
-                                       this.Redraw (false);
+                               BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
+                               
+                               ArrayList box_items = BoxSelectedItems;
+
+                               ArrayList items;
+
+                               switch (box_select_mode) {
 
-                                       // Raise the ItemCheck event
-                                       ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index,
-                                                                                        curr_state,
-                                                                                        new_state);
-                                       this.OnItemCheck (ice);
+                               case BoxSelect.Normal:
+                                       items = box_items;
                                        break;
+
+                               case BoxSelect.Control:
+                                       items = new ArrayList ();
+                                       foreach (ListViewItem item in prev_selection)
+                                               if (!box_items.Contains (item))
+                                                       items.Add (item);
+                                       foreach (ListViewItem item in box_items)
+                                               if (!prev_selection.Contains (item))
+                                                       items.Add (item);
+                                       break;
+
+                               case BoxSelect.Shift:
+                                       items = box_items;
+                                       foreach (ListViewItem item in box_items)
+                                               prev_selection.Remove (item);
+                                       foreach (ListViewItem item in prev_selection)
+                                               items.Add (item);
+                                       break;
+
+                               default:
+                                       throw new Exception ("Unexpected Selection mode: " + box_select_mode);
                                }
 
-                               if (this.view == View.Details &&
-                                   this.FullRowSelect == false) {
-                                       if (item.LabelRect.Contains (hit)) {
-                                               this.clicked_item = item;
-                                               break;
+                               SuspendLayout ();
+                               owner.SelectItems (items);
+                               ResumeLayout ();
+
+                               return true;
+                       }
+
+                       private void ToggleCheckState (ListViewItem item)
+                       {
+                               CheckState curr_state = item.Checked ?  CheckState.Checked : CheckState.Unchecked;
+                               item.Checked = !item.Checked;
+                               CheckState new_state = item.Checked ?  CheckState.Checked : CheckState.Unchecked;
+
+                               ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
+                               owner.OnItemCheck (ice);
+                       }
+
+                       private void ItemsMouseDown (object sender, MouseEventArgs me)
+                       {
+                               if (owner.items.Count == 0)
+                                       return;
+
+                               Point pt = new Point (me.X, me.Y);
+                               foreach (ListViewItem item in owner.items) {
+                                       if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
+                                               checking = true;
+                                               if (me.Clicks > 1)
+                                                       return;
+                                               ToggleCheckState (item);
+                                               return;
+                                       }
+
+                                       if (owner.View == View.Details && !owner.FullRowSelect) {
+                                               if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
+                                                       clicked_item = item;
+                                                       break;
+                                               }
+                                       } else {
+                                               if (item.Bounds.Contains (pt)) {
+                                                       clicked_item = item;
+                                                       break;
+                                               }
                                        }
                                }
-                               else {
-                                       if (item.EntireRect.Contains (hit)) {
-                                               this.clicked_item = item;
-                                               break;
+
+
+                               if (clicked_item != null) {
+                                       owner.SetFocusedItem (clicked_item);
+                                       bool changed = !clicked_item.Selected;
+                                       if (owner.MultiSelect)
+                                               owner.UpdateMultiSelection (clicked_item.Index);
+                                       else
+                                               clicked_item.Selected = true;
+                               
+                                       if (changed)
+                                               owner.OnSelectedIndexChanged (EventArgs.Empty);
+
+                                       // Raise double click if the item was clicked. On MS the
+                                       // double click is only raised if you double click an item
+                                       if (me.Clicks > 1) {
+                                               owner.OnDoubleClick (EventArgs.Empty);
+                                               if (owner.CheckBoxes)
+                                                       ToggleCheckState (clicked_item);
+                                       } else if (me.Clicks == 1) {
+                                               owner.OnClick (EventArgs.Empty);
+                                               if (owner.LabelEdit && !changed)
+                                                       BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
+                                       }
+                               } else {
+                                       if (owner.MultiSelect) {
+                                               Keys mods = XplatUI.State.ModifierKeys;
+                                               if ((mods & Keys.Shift) != 0)
+                                                       box_select_mode = BoxSelect.Shift;
+                                               else if ((mods & Keys.Control) != 0)
+                                                       box_select_mode = BoxSelect.Control;
+                                               else
+                                                       box_select_mode = BoxSelect.Normal;
+                                               box_select_start = pt; 
+                                               prev_selection = owner.SelectedItems.List;
+                                       } else if (owner.SelectedItems.Count > 0) {
+                                               owner.SelectedItems.Clear ();
+                                               owner.OnSelectedIndexChanged (EventArgs.Empty);
                                        }
                                }
                        }
 
-                       // set the FocusedItem to be the current clicked_item
-                       SetFocusedItem (clicked_item);
+                       private void ItemsMouseMove (object sender, MouseEventArgs me)
+                       {
+                               if (PerformBoxSelection (new Point (me.X, me.Y)))
+                                       return;
 
-                       if (clicked_item != null) {
-                               bool changed = !clicked_item.Selected;
-                               clicked_item.Selected = true;
-                               
-                               // Only Raise the event if the selected item has changed
-                               if (changed)
-                                       OnSelectedIndexChanged (EventArgs.Empty);
+                               if (owner.HoverSelection && hover_processed) {
 
-                               // Raise double click if the item was clicked. On MS the
-                               // double click is only raised if you double click an item
-                               if (me.Clicks > 1 && this.clicked_item != null)
-                                       OnDoubleClick (EventArgs.Empty);
+                                       Point pt = PointToClient (Control.MousePosition);
+                                       ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
+                                       if (item == null || item.Selected)
+                                               return;
 
-                               this.Redraw (false);
-                       } else if (selected_indices.Count > 0) {
-                               // NOTE: selected_indices isn't computed properly so
-                               // this doesn't actually work
-                               
-                               // Raise the event if there was at least one item
-                               // selected and the user click on a dead area (unselecting all)
-                               OnSelectedIndexChanged (EventArgs.Empty);
-                               Redraw (false);
+                                       hover_processed = false;
+                                       XplatUI.ResetMouseHover (Handle);
+                               }
                        }
-               }
 
-               private void ListView_MouseHover (object sender, EventArgs e)
-               {
-                       // handle the hover events only when the mouse
-                       // is not captured.
-                       if (this.hover_selection == false || this.Capture)
-                               return;
 
-                       // hit test for the items
-                       Point hit = this.PointToClient (Control.MousePosition);
-                       ListViewItem item = this.GetItemAt (hit.X, hit.Y);
+                       private void ItemsMouseHover (object sender, EventArgs e)
+                       {
+                               if (Capture || !owner.HoverSelection)
+                                       return;
+
+                               hover_processed = true;
+                               Point pt = PointToClient (Control.MousePosition);
+                               ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
+
+                               if (item == null)
+                                       return;
 
-                       if (item != null) {
                                item.Selected = true;
-                               // Raise the event
-                               this.OnSelectedIndexChanged (new EventArgs ());
+                               owner.OnSelectedIndexChanged (new EventArgs ());
+                       }
 
-                               this.Redraw (false);
+                       private void ItemsMouseUp (object sender, MouseEventArgs me)
+                       {
+                               Capture = false;
+                               if (owner.Items.Count == 0)
+                                       return;
+
+                               Point pt = new Point (me.X, me.Y);
+
+                               Rectangle rect = Rectangle.Empty;
+                               if (clicked_item != null) {
+                                       if (owner.view == View.Details && !owner.full_row_select)
+                                               rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
+                                       else
+                                               rect = clicked_item.Bounds;
+
+                                       if (rect.Contains (pt)) {
+                                               switch (owner.activation) {
+                                               case ItemActivation.OneClick:
+                                                       owner.OnItemActivate (EventArgs.Empty);
+                                                       break;
+
+                                               case ItemActivation.TwoClick:
+                                                       if (last_clicked_item == clicked_item) {
+                                                               owner.OnItemActivate (EventArgs.Empty);
+                                                               last_clicked_item = null;
+                                                       } else
+                                                               last_clicked_item = clicked_item;
+                                                       break;
+                                               default:
+                                                       // DoubleClick activation is handled in another handler
+                                                       break;
+                                               }
+                                       }
+                               } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
+                                       // Need this to clean up background clicks
+                                       owner.SelectedItems.Clear ();
+                                       owner.OnSelectedIndexChanged (EventArgs.Empty);
+                               }
+
+                               clicked_item = null;
+                               box_select_start = Point.Empty;
+                               BoxSelectRectangle = Rectangle.Empty;
+                               prev_selection = null;
+                               box_select_mode = BoxSelect.None;
+                               checking = false;
+                       }
+                       
+                       internal void LabelEditFinished (object sender, EventArgs e)
+                       {
+                               EndEdit (edit_item);
+                       }
+                       
+                       internal void BeginEdit (ListViewItem item)
+                       {
+                               if (edit_item != null)
+                                       EndEdit (edit_item);
+                               
+                               if (edit_text_box == null) {
+                                       edit_text_box = new ListViewLabelEditTextBox ();
+                                       edit_text_box.BorderStyle = BorderStyle.FixedSingle;
+                                       edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
+                                       edit_text_box.Visible = false;
+                                       Controls.Add (edit_text_box);
+                               }
+                               
+                               item.EnsureVisible();
+                               
+                               edit_text_box.Reset ();
+                               
+                               switch (owner.view) {
+                                       case View.List:
+                                       case View.SmallIcon:
+                                       case View.Details:
+                                               edit_text_box.TextAlign = HorizontalAlignment.Left;
+                                               edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
+                                               SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
+                                               edit_text_box.Width = (int)sizef.Width + 4;
+                                               edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
+                                               edit_text_box.WordWrap = false;
+                                               edit_text_box.Multiline = false;
+                                               break;
+                                       case View.LargeIcon:
+                                               edit_text_box.TextAlign = HorizontalAlignment.Center;
+                                               edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
+                                               sizef = DeviceContext.MeasureString (item.Text, item.Font);
+                                               edit_text_box.Width = (int)sizef.Width + 4;
+                                               edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
+                                               edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
+                                               edit_text_box.WordWrap = true;
+                                               edit_text_box.Multiline = true;
+                                               break;
+                               }
+                               
+                               edit_text_box.Text = item.Text;
+                               edit_text_box.Font = item.Font;
+                               edit_text_box.Visible = true;
+                               edit_text_box.Focus ();
+                               edit_text_box.SelectAll ();
+                               
+                               edit_args = new LabelEditEventArgs (owner.Items.IndexOf(edit_item));
+                               owner.OnBeforeLabelEdit (edit_args);
+                               
+                               if (edit_args.CancelEdit)
+                                       EndEdit (item);
+                               
+                               edit_item = item;
+                       }
+                       
+                       internal void EndEdit (ListViewItem item)
+                       {
+                               if (edit_text_box != null && edit_text_box.Visible) {
+                                       edit_text_box.Visible = false;
+                               }
+                               
+                               if (edit_item != null && edit_item == item) {
+                                       owner.OnAfterLabelEdit (edit_args);
+                                       
+                                       if (!edit_args.CancelEdit) {
+                                               if (edit_args.Label != null)
+                                                       edit_item.Text = edit_args.Label;
+                                               else
+                                                       edit_item.Text = edit_text_box.Text;
+                                       }
+                                       
+                               }
+                               
+                               
+                               edit_item = null;
+                       }
+
+                       internal override void OnPaintInternal (PaintEventArgs pe)
+                       {
+                               ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
+                       }
+
+                       internal override void OnGotFocusInternal (EventArgs e)
+                       {
+                               owner.Focus ();
+                       }
+               }
+               
+               internal class ListViewLabelEditTextBox : TextBox
+               {
+                       int max_width = -1;
+                       int min_width = -1;
+                       
+                       int max_height = -1;
+                       int min_height = -1;
+                       
+                       int old_number_lines = 1;
+                       
+                       SizeF text_size_one_char;
+                       
+                       public ListViewLabelEditTextBox ()
+                       {
+                               min_height = DefaultSize.Height;
+                               text_size_one_char = DeviceContext.MeasureString ("B", Font);
+                       }
+                       
+                       public int MaxWidth {
+                               set {
+                                       if (value < min_width)
+                                               max_width = min_width;
+                                       else
+                                               max_width = value;
+                               }
+                       }
+                       
+                       public int MaxHeight {
+                               set {
+                                       if (value < min_height)
+                                               max_height = min_height;
+                                       else
+                                               max_height = value;
+                               }
+                       }
+                       
+                       public new int Width {
+                               get {
+                                       return base.Width;
+                               }
+                               set {
+                                       min_width = value;
+                                       base.Width = value;
+                               }
+                       }
+                       
+                       public override Font Font {
+                               get {
+                                       return base.Font;
+                               }
+                               set {
+                                       base.Font = value;
+                                       text_size_one_char = DeviceContext.MeasureString ("B", Font);
+                               }
+                       }
+                       
+                       protected override void OnTextChanged (EventArgs e)
+                       {
+                               SizeF text_size = DeviceContext.MeasureString (Text, Font);
+                               
+                               int new_width = (int)text_size.Width + 8;
+                               
+                               if (!Multiline)
+                                       ResizeTextBoxWidth (new_width);
+                               else {
+                                       if (Width != max_width)
+                                               ResizeTextBoxWidth (new_width);
+                                       
+                                       int number_lines = Lines.Length;
+                                       
+                                       if (number_lines != old_number_lines) {
+                                               int new_height = number_lines * (int)text_size_one_char.Height + 4;
+                                               old_number_lines = number_lines;
+                                               
+                                               ResizeTextBoxHeight (new_height);
+                                       }
+                               }
+                               
+                               base.OnTextChanged (e);
+                       }
+                       
+                       protected override bool IsInputKey (Keys key_data)
+                       {
+                               if ((key_data & Keys.Alt) == 0) {
+                                       switch (key_data & Keys.KeyCode) {
+                                               case Keys.Enter:
+                                                       return true;
+                                       }
+                               }
+                               return base.IsInputKey (key_data);
+                       }
+                       
+                       protected override void OnKeyDown (KeyEventArgs e)
+                       {
+                               if (e.KeyCode == Keys.Return && Visible) {
+                                       this.Visible = false;
+                                       OnEditingFinished (e);
+                               }
+                       }
+                       
+                       protected override void OnLostFocus (EventArgs e)
+                       {
+                               if (Visible) {
+                                       OnEditingFinished (e);
+                               }
+                       }
+                       
+                       protected void OnEditingFinished (EventArgs e)
+                       {
+                               if (EditingFinished != null)
+                                       EditingFinished (this, EventArgs.Empty);
+                       }
+                       
+                       private void ResizeTextBoxWidth (int new_width)
+                       {
+                               if (new_width > max_width)
+                                       base.Width = max_width;
+                               else 
+                               if (new_width >= min_width)
+                                       base.Width = new_width;
+                               else
+                                       base.Width = min_width;
+                       }
+                       
+                       private void ResizeTextBoxHeight (int new_height)
+                       {
+                               if (new_height > max_height)
+                                       base.Height = max_height;
+                               else 
+                               if (new_height >= min_height)
+                                       base.Height = new_height;
+                               else
+                                       base.Height = min_height;
+                       }
+                       
+                       public void Reset ()
+                       {
+                               max_width = -1;
+                               min_width = -1;
+                               
+                               max_height = -1;
+                               
+                               old_number_lines = 1;
+                               
+                               Text = String.Empty;
+                               
+                               Size = DefaultSize;
                        }
+                       
+                       public event EventHandler EditingFinished;
                }
 
-               private void ListView_MouseMove (object sender, MouseEventArgs me)
+               internal override void OnPaintInternal (PaintEventArgs pe)
                {
-                       // Column header is always at the top. It can
-                       // scroll only horizontally. So, we have to take
-                       // only horizontal scrolling into account
-                       Point hit = new Point (me.X + h_marker, me.Y);
-
-                       // non-null clicked_col means mouse down has happened
-                       // on a column
-                       if (this.clicked_column != null) {
-                               if (this.clicked_column.pressed == false &&
-                                   this.clicked_column.Rect.Contains (hit)) {
-                                       this.clicked_column.pressed = true;
-                                       this.Redraw (false);
-                               }
-                               else if (this.clicked_column.pressed && 
-                                        ! this.clicked_column.Rect.Contains (hit)) {
-                                       this.clicked_column.pressed = false;
-                                       this.Redraw (false);
-                               }
-                       }
+                       if (updating)
+                               return; 
+                               
+                       CalculateScrollBars ();
                }
 
-               private void ListView_MouseUp (object sender, MouseEventArgs me)
+               void FocusChanged (object o, EventArgs args)
                {
-                       this.Capture = false;
-                       if (items.Count == 0)
+                       if (Items.Count == 0)
                                return;
 
-                       Point hit = new Point (me.X, me.Y);
-
-                       if (this.clicked_column != null) {
-                               if (this.clicked_column.pressed) {
-                                       this.clicked_column.pressed = false;
-                                       this.Redraw (false);
-
-                                       // Raise the ColumnClick event
-                                       this.OnColumnClick (new ColumnClickEventArgs
-                                                           (this.clicked_column.Index));
-                               }
-                       }
-
-                       // Raise the ItemActivate event
-                       Rectangle rect = Rectangle.Empty;
-                       if (this.clicked_item != null) {
-                               if (this.view == View.Details && !this.full_row_select)
-                                       rect = this.clicked_item.LabelRect;
-                               else
-                                       rect = this.clicked_item.EntireRect;
-
-                               // We handle double click in a separate handler
-                               if (this.activation != ItemActivation.Standard &&
-                                   rect.Contains (hit)) {
-                                       if (this.activation == ItemActivation.OneClick)
-                                               this.ItemActivate (this, EventArgs.Empty);
-
-                                       // ItemActivate is raised on the second click on the same item
-                                       else if (this.activation == ItemActivation.TwoClick) {
-                                               if (this.last_clicked_item == this.clicked_item) {
-                                                       this.ItemActivate (this, EventArgs.Empty);
-                                                       this.last_clicked_item = null;
-                                               }
-                                               else
-                                                       this.last_clicked_item = this.clicked_item;
-                                       }
-                               }
-                       }
+                       if (FocusedItem == null)
+                               SetFocusedItem (Items [0]);
 
-                       this.clicked_column = null;
-                       this.clicked_item = null;
+                       item_control.Invalidate (FocusedItem.Bounds);
                }
 
-               private void ListView_Paint (object sender, PaintEventArgs pe)
+               private void ListView_MouseWheel (object sender, MouseEventArgs me)
                {
-                       if (this.Width <= 0 || this.Height <=  0 ||
-                           this.Visible == false || this.updating == true)
-                               return; 
-                               
-                       CalculateScrollBars ();
+                       if (Items.Count == 0)
+                               return;
 
-                       ThemeEngine.Current.DrawListView (pe.Graphics,
-                                       pe.ClipRectangle, this);
-                                       
-                       // Raise the Paint event
-                       if (Paint != null)
-                               Paint (this, pe);
+                       int lines = me.Delta / 120;
+
+                       if (lines == 0)
+                               return;
+
+                       switch (View) {
+                       case View.Details:
+                       case View.SmallIcon:
+                               Scroll (v_scroll, -Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
+                               break;
+                       case View.LargeIcon:
+                               Scroll (v_scroll, -(Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing)  * lines);
+                               break;
+                       case View.List:
+                               Scroll (h_scroll, -Items [0].Bounds.Width * lines);
+                               break;
+                       }
                }
 
                private void ListView_SizeChanged (object sender, EventArgs e)
@@ -1320,38 +1912,33 @@ namespace System.Windows.Forms
 
                private void HorizontalScroller (object sender, EventArgs e)
                {
+                       item_control.EndEdit (item_control.edit_item);
+                       
                        // Avoid unnecessary flickering, when button is
                        // kept pressed at the end
                        if (h_marker != h_scroll.Value) {
                                
                                int pixels =  h_marker - h_scroll.Value;
-                               Rectangle area = client_area;
-                               
-                               if (View == View.Details && Columns.Count > 0) {
-                                       area.Y += Columns[0].Ht;
-                                       area.Height -= Columns[0].Ht;
-                               }
                                
                                h_marker = h_scroll.Value;
-                               XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
+                               if (header_control.Visible)
+                                       XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
+
+                               XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
                        }
                }
 
                private void VerticalScroller (object sender, EventArgs e)
                {
+                       item_control.EndEdit (item_control.edit_item);
+                       
                        // Avoid unnecessary flickering, when button is
                        // kept pressed at the end
                        if (v_marker != v_scroll.Value) {
                                int pixels =  v_marker - v_scroll.Value;
-                               Rectangle area = client_area;
-                               
-                               if (View == View.Details && Columns.Count > 0) {
-                                       area.Y += Columns[0].Ht;
-                                       area.Height -= Columns[0].Ht;
-                               }
-                               
+                               Rectangle area = item_control.ClientRectangle;
                                v_marker = v_scroll.Value;
-                               XplatUI.ScrollWindow (Handle, area, 0, pixels, false);
+                               XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
                        }
                }
                #endregion      // Internal Methods Properties
@@ -1360,6 +1947,8 @@ namespace System.Windows.Forms
                protected override void CreateHandle ()
                {
                        base.CreateHandle ();
+                       for (int i = 0; i < SelectedItems.Count; i++)
+                               OnSelectedIndexChanged (EventArgs.Empty);
                }
 
                protected override void Dispose (bool disposing)
@@ -1428,10 +2017,7 @@ namespace System.Windows.Forms
                protected override void OnHandleCreated (EventArgs e)
                {
                        base.OnHandleCreated (e);
-                       SuspendLayout ();
-                       Controls.AddImplicit (this.v_scroll);
-                       Controls.AddImplicit (this.h_scroll);
-                       ResumeLayout ();
+                       Sort ();
                }
 
                protected override void OnHandleDestroyed (EventArgs e)
@@ -1523,37 +2109,24 @@ namespace System.Windows.Forms
 
                public void EnsureVisible (int index)
                {
-                       if (index < 0 || index >= this.items.Count || this.scrollable == false)
+                       if (index < 0 || index >= items.Count || scrollable == false)
                                return;
 
-                       // dimensions of visible area
-                       int view_wd = client_area.Width;
-                       int view_ht = client_area.Height;
-                       // visible area is decided by the h_marker and v_marker
-                       Rectangle view_rect = new Rectangle (h_marker, v_marker, view_wd, view_ht);
-                       
-                       // an item's bounding rect
-                       Rectangle rect = this.items [index].EntireRect;
+                       Rectangle view_rect = item_control.ClientRectangle;
+                       Rectangle bounds = items [index].Bounds;
 
-                       // we don't need to do anything if item is visible.
-                       // visible area is represented by (0,0,view_wd,view_ht)
-                       if (view_rect.Contains (rect))
+                       if (view_rect.Contains (bounds))
                                return;
 
-                       // Scroll Left or Up
-                       if ((rect.Left < view_rect.Left) || (rect.Top < view_rect.Top)) {
-                               if (rect.Left < view_rect.Left)
-                                       this.h_scroll.Value -= (view_rect.Left - rect.Left);
-                               if (rect.Top < view_rect.Top)
-                                       this.v_scroll.Value -= (view_rect.Top - rect.Top);
-                       }
-                       // Scroll Right or Down
-                       else {
-                               if (rect.Right > view_rect.Right)
-                                       this.h_scroll.Value += (rect.Right - view_rect.Right);
-                               if (rect.Bottom > view_rect.Bottom)
-                                       this.v_scroll.Value += (rect.Bottom - view_rect.Bottom);
-                       }
+                       if (bounds.Left < 0)
+                               h_scroll.Value += bounds.Left;
+                       else if (bounds.Right > view_rect.Right)
+                               h_scroll.Value += (bounds.Right - view_rect.Right);
+
+                       if (bounds.Top < 0)
+                               v_scroll.Value += bounds.Top;
+                       else if (bounds.Bottom > view_rect.Bottom)
+                               v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
                }
                
                public ListViewItem GetItemAt (int x, int y)
@@ -1573,20 +2146,34 @@ namespace System.Windows.Forms
                public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
                {
                        if (index < 0 || index >= items.Count)
-                               throw new IndexOutOfRangeException ("Invalid Index");
+                               throw new IndexOutOfRangeException ("index");
 
                        return items [index].GetBounds (portion);
                }
 
                public void Sort ()
                {
-                       if (sort_order != SortOrder.None)
-                               items.list.Sort (item_sorter);
-
-                       if (sort_order == SortOrder.Descending)
-                               items.list.Reverse ();
-
-                       this.Redraw (true);
+                       Sort (true);
+               }
+
+               // we need this overload to reuse the logic for sorting, while allowing
+               // redrawing to be done by caller or have it done by this method when
+               // sorting is really performed
+               //
+               // ListViewItemCollection's Add and AddRange methods call this overload
+               // with redraw set to false, as they take care of redrawing themselves
+               // (they even want to redraw the listview if no sort is performed, as 
+               // an item was added), while ListView.Sort () only wants to redraw if 
+               // sorting was actually performed
+               private void Sort (bool redraw)
+               {
+                       if (!IsHandleCreated || item_sorter == null) {
+                               return;
+                       }
+                       
+                       items.Sort (item_sorter);
+                       if (redraw)
+                               this.Redraw (true);
                }
 
                public override string ToString ()
@@ -1602,34 +2189,246 @@ namespace System.Windows.Forms
 
 
                #region Subclasses
+
+               class HeaderControl : Control {
+
+                       ListView owner;
+                       bool column_resize_active = false;
+                       ColumnHeader resize_column;
+                       ColumnHeader clicked_column;
+                       ColumnHeader drag_column;
+                       int drag_x;
+                       int drag_to_index = -1;
+
+                       public HeaderControl (ListView owner)
+                       {
+                               this.owner = owner;
+                               MouseDown += new MouseEventHandler (HeaderMouseDown);
+                               MouseMove += new MouseEventHandler (HeaderMouseMove);
+                               MouseUp += new MouseEventHandler (HeaderMouseUp);
+                       }
+
+                       private ColumnHeader ColumnAtX (int x)
+                       {
+                               Point pt = new Point (x, 0);
+                               ColumnHeader result = null;
+                               foreach (ColumnHeader col in owner.Columns) {
+                                       if (col.Rect.Contains (pt)) {
+                                               result = col;
+                                               break;
+                                       }
+                               }
+                               return result;
+                       }
+
+                       private int GetReorderedIndex (ColumnHeader col)
+                       {
+                               if (owner.reordered_column_indices == null)
+                                       return col.Index;
+                               else
+                                       for (int i = 0; i < owner.Columns.Count; i++)
+                                               if (owner.reordered_column_indices [i] == col.Index)
+                                                       return i;
+                               throw new Exception ("Column index missing from reordered array");
+                       }
+
+                       private void HeaderMouseDown (object sender, MouseEventArgs me)
+                       {
+                               if (resize_column != null) {
+                                       column_resize_active = true;
+                                       Capture = true;
+                                       return;
+                               }
+
+                               clicked_column = ColumnAtX (me.X + owner.h_marker);
+
+                               if (clicked_column != null) {
+                                       Capture = true;
+                                       if (owner.AllowColumnReorder) {
+                                               drag_x = me.X;
+                                               drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
+                                               drag_column.column_rect = clicked_column.Rect;
+                                               drag_to_index = GetReorderedIndex (clicked_column);
+                                       }
+                                       clicked_column.pressed = true;
+                                       Rectangle bounds = clicked_column.Rect;
+                                       bounds.X -= owner.h_marker;
+                                       Invalidate (bounds);
+                                       return;
+                               }
+                       }
+
+                       private void HeaderMouseMove (object sender, MouseEventArgs me)
+                       {
+                               Point pt = new Point (me.X + owner.h_marker, me.Y);
+
+                               if (column_resize_active)  {
+                                       resize_column.Width = pt.X - resize_column.X;
+                                       if (resize_column.Width < 0)
+                                               resize_column.Width = 0;
+                                       return;
+                               }
+
+                               resize_column = null;
+
+                               if (clicked_column != null) {
+                                       if (owner.AllowColumnReorder) {
+                                               Rectangle r;
+
+                                               r = drag_column.column_rect;
+                                               r.X = clicked_column.Rect.X + me.X - drag_x;
+                                               drag_column.column_rect = r;
+
+                                               int x = me.X + owner.h_marker;
+                                               ColumnHeader over = ColumnAtX (x);
+                                               if (over == null)
+                                                       drag_to_index = owner.Columns.Count;
+                                               else if (x < over.X + over.Width / 2)
+                                                       drag_to_index = GetReorderedIndex (over);
+                                               else
+                                                       drag_to_index = GetReorderedIndex (over) + 1;
+                                               Invalidate ();
+                                       } else {
+                                               ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
+                                               bool pressed = clicked_column.pressed;
+                                               clicked_column.pressed = over == clicked_column;
+                                               if (clicked_column.pressed ^ pressed) {
+                                                       Rectangle bounds = clicked_column.Rect;
+                                                       bounds.X -= owner.h_marker;
+                                                       Invalidate (bounds);
+                                               }
+                                       }
+                                       return;
+                               }
+
+                               for (int i = 0; i < owner.Columns.Count; i++) {
+                                       Rectangle zone = owner.Columns [i].Rect;
+                                       zone.X = zone.Right - 5;
+                                       zone.Width = 10;
+                                       if (zone.Contains (pt)) {
+                                               if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
+                                                       i++;
+                                               resize_column = owner.Columns [i];
+                                               break;
+                                       }
+                               }
+
+                               if (resize_column == null)
+                                       Cursor = Cursors.Default;
+                               else
+                                       Cursor = Cursors.VSplit;
+                       }
+
+                       void HeaderMouseUp (object sender, MouseEventArgs me)
+                       {
+                               Capture = false;
+
+                               if (column_resize_active) {
+                                       column_resize_active = false;
+                                       resize_column = null;
+                                       Cursor = Cursors.Default;
+                                       return;
+                               }
+
+                               if (clicked_column != null && clicked_column.pressed) {
+                                       clicked_column.pressed = false;
+                                       Rectangle bounds = clicked_column.Rect;
+                                       bounds.X -= owner.h_marker;
+                                       Invalidate (bounds);
+                                       owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
+                               }
+
+                               if (drag_column != null && owner.AllowColumnReorder) {
+                                       drag_column = null;
+                                       if (drag_to_index > GetReorderedIndex (clicked_column))
+                                               drag_to_index--;
+                                       if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
+                                               owner.ReorderColumn (clicked_column, drag_to_index);
+                                       drag_to_index = -1;
+                                       Invalidate ();
+                               }
+
+                               clicked_column = null;
+                       }
+
+                       internal override void OnPaintInternal (PaintEventArgs pe)
+                       {
+                               if (owner.updating)
+                                       return; 
+                               
+                               Theme theme = ThemeEngine.Current;
+                               theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
+
+                               if (drag_column == null)
+                                       return;
+
+                               int target_x;
+                               if (drag_to_index == owner.Columns.Count)
+                                       target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
+                               else
+                                       target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
+                               theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
+                       }
+
+                       protected override void WndProc (ref Message m)
+                       {
+                               switch ((Msg)m.Msg) {
+                               case Msg.WM_SETFOCUS:
+                                       owner.Focus ();
+                                       break;
+                               default:
+                                       base.WndProc (ref m);
+                                       break;
+                               }
+                       }
+               }
+
+               private class ItemComparer : IComparer {
+                       readonly SortOrder sort_order;
+
+                       public ItemComparer (SortOrder sortOrder)
+                       {
+                               sort_order = sortOrder;
+                       }
+
+                       public int Compare (object x, object y)
+                       {
+                               ListViewItem item_x = x as ListViewItem;
+                               ListViewItem item_y = y as ListViewItem;
+                               if (sort_order == SortOrder.Ascending)
+                                       return String.Compare (item_x.Text, item_y.Text);
+                               else
+                                       return String.Compare (item_y.Text, item_x.Text);
+                       }
+               }
+
                public class CheckedIndexCollection : IList, ICollection, IEnumerable
                {
-                       internal ArrayList list;
-                       private ListView owner;
+                       private readonly ListView owner;
 
                        #region Public Constructor
                        public CheckedIndexCollection (ListView owner)
                        {
-                               list = new ArrayList ();
                                this.owner = owner;
                        }
                        #endregion      // Public Constructor
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
-                               get { return list.Count; }
+                       public int Count {
+                               get { return owner.CheckedItems.Count; }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return true; }
                        }
 
                        public int this [int index] {
                                get {
-                                       if (index < 0 || index >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
-                                       return (int) list [index];
+                                       int [] indices = GetIndices ();
+                                       if (index < 0 || index >= indices.Length)
+                                               throw new ArgumentOutOfRangeException ("index");
+                                       return indices [index];
                                }
                        }
 
@@ -1654,17 +2453,24 @@ namespace System.Windows.Forms
                        #region Public Methods
                        public bool Contains (int checkedIndex)
                        {
-                               return list.Contains (checkedIndex);
+                               int [] indices = GetIndices ();
+                               for (int i = 0; i < indices.Length; i++) {
+                                       if (indices [i] == checkedIndex)
+                                               return true;
+                               }
+                               return false;
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
-                               return list.GetEnumerator ();
+                               int [] indices = GetIndices ();
+                               return indices.GetEnumerator ();
                        }
 
                        void ICollection.CopyTo (Array dest, int index)
                        {
-                               list.CopyTo (dest, index);
+                               int [] indices = GetIndices ();
+                               Array.Copy (indices, 0, dest, index, indices.Length);
                        }
 
                        int IList.Add (object value)
@@ -1679,12 +2485,16 @@ namespace System.Windows.Forms
 
                        bool IList.Contains (object checkedIndex)
                        {
-                               return list.Contains (checkedIndex);
+                               if (!(checkedIndex is int))
+                                       return false;
+                               return Contains ((int) checkedIndex);
                        }
 
                        int IList.IndexOf (object checkedIndex)
                        {
-                               return list.IndexOf (checkedIndex);
+                               if (!(checkedIndex is int))
+                                       return -1;
+                               return IndexOf ((int) checkedIndex);
                        }
 
                        void IList.Insert (int index, object value)
@@ -1704,45 +2514,66 @@ namespace System.Windows.Forms
 
                        public int IndexOf (int checkedIndex)
                        {
-                               return list.IndexOf (checkedIndex);
+                               int [] indices = GetIndices ();
+                               for (int i = 0; i < indices.Length; i++) {
+                                       if (indices [i] == checkedIndex)
+                                               return i;
+                               }
+                               return -1;
                        }
                        #endregion      // Public Methods
 
+                       private int [] GetIndices ()
+                       {
+                               ArrayList checked_items = owner.CheckedItems.List;
+                               int [] indices = new int [checked_items.Count];
+                               for (int i = 0; i < checked_items.Count; i++) {
+                                       ListViewItem item = (ListViewItem) checked_items [i];
+                                       indices [i] = item.Index;
+                               }
+                               return indices;
+                       }
                }       // CheckedIndexCollection
 
                public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
                {
-                       internal ArrayList list;
-                       private ListView owner;
+                       private readonly ListView owner;
+                       private ArrayList list;
 
                        #region Public Constructor
                        public CheckedListViewItemCollection (ListView owner)
                        {
-                               list = new ArrayList ();
                                this.owner = owner;
+                               this.owner.Items.Changed += new CollectionChangedHandler (
+                                       ItemsCollection_Changed);
                        }
                        #endregion      // Public Constructor
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
-                               get { return list.Count; }
+                       public int Count {
+                               get {
+                                       if (!owner.CheckBoxes)
+                                               return 0;
+                                       return List.Count;
+                               }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return true; }
                        }
 
                        public ListViewItem this [int index] {
                                get {
-                                       if (index < 0 || index >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
-                                       return (ListViewItem) list [index];
+                                       ArrayList checked_items = List;
+                                       if (index < 0 || index >= checked_items.Count)
+                                               throw new ArgumentOutOfRangeException ("index");
+                                       return (ListViewItem) checked_items [index];
                                }
                        }
 
                        bool ICollection.IsSynchronized {
-                               get { return list.IsSynchronized; }
+                               get { return false; }
                        }
 
                        object ICollection.SyncRoot {
@@ -1762,17 +2593,23 @@ namespace System.Windows.Forms
                        #region Public Methods
                        public bool Contains (ListViewItem item)
                        {
-                               return list.Contains (item);
+                               if (!owner.CheckBoxes)
+                                       return false;
+                               return List.Contains (item);
                        }
 
-                       public virtual void CopyTo (Array dest, int index)
+                       public void CopyTo (Array dest, int index)
                        {
-                               list.CopyTo (dest, index);
+                               if (!owner.CheckBoxes)
+                                       return;
+                               List.CopyTo (dest, index);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
-                               return list.GetEnumerator ();
+                               if (!owner.CheckBoxes)
+                                       return (new ListViewItem [0]).GetEnumerator ();
+                               return List.GetEnumerator ();
                        }
 
                        int IList.Add (object value)
@@ -1787,12 +2624,16 @@ namespace System.Windows.Forms
 
                        bool IList.Contains (object item)
                        {
-                               return list.Contains (item);
+                               if (!(item is ListViewItem))
+                                       return false;
+                               return Contains ((ListViewItem) item);
                        }
 
                        int IList.IndexOf (object item)
                        {
-                               return list.IndexOf (item);
+                               if (!(item is ListViewItem))
+                                       return -1;
+                               return IndexOf ((ListViewItem) item);
                        }
 
                        void IList.Insert (int index, object value)
@@ -1812,10 +2653,35 @@ namespace System.Windows.Forms
 
                        public int IndexOf (ListViewItem item)
                        {
-                               return list.IndexOf (item);
+                               if (!owner.CheckBoxes)
+                                       return -1;
+                               return List.IndexOf (item);
                        }
                        #endregion      // Public Methods
 
+                       internal ArrayList List {
+                               get {
+                                       if (list == null) {
+                                               list = new ArrayList ();
+                                               foreach (ListViewItem item in owner.Items) {
+                                                       if (item.Checked)
+                                                               list.Add (item);
+                                               }
+                                       }
+                                       return list;
+                               }
+                       }
+
+                       internal void Reset ()
+                       {
+                               // force re-population of list
+                               list = null;
+                       }
+
+                       private void ItemsCollection_Changed ()
+                       {
+                               Reset ();
+                       }
                }       // CheckedListViewItemCollection
 
                public class ColumnHeaderCollection : IList, ICollection, IEnumerable
@@ -1833,18 +2699,18 @@ namespace System.Windows.Forms
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
+                       public int Count {
                                get { return list.Count; }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return false; }
                        }
 
                        public virtual ColumnHeader this [int index] {
                                get {
                                        if (index < 0 || index >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
+                                               throw new ArgumentOutOfRangeException ("index");
                                        return (ColumnHeader) list [index];
                                }
                        }
@@ -1873,7 +2739,9 @@ namespace System.Windows.Forms
                                int idx;
                                value.owner = this.owner;
                                idx = list.Add (value);
-                               owner.Redraw (true); 
+                               if (owner.IsHandleCreated) {
+                                       owner.Redraw (true); 
+                               }
                                return idx;
                        }
 
@@ -1905,7 +2773,7 @@ namespace System.Windows.Forms
                                return list.Contains (value);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
                                return list.GetEnumerator ();
                        }
@@ -1970,7 +2838,7 @@ namespace System.Windows.Forms
                                // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
                                // but it's really only greater.
                                if (index < 0 || index > list.Count)
-                                       throw new ArgumentOutOfRangeException ("Index out of range.");
+                                       throw new ArgumentOutOfRangeException ("index");
 
                                value.owner = this.owner;
                                list.Insert (index, value);
@@ -1993,7 +2861,7 @@ namespace System.Windows.Forms
                        public virtual void RemoveAt (int index)
                        {
                                if (index < 0 || index >= list.Count)
-                                       throw new ArgumentOutOfRangeException ("Index out of range.");
+                                       throw new ArgumentOutOfRangeException ("index");
 
                                // TODO: Update Column internal index ?
                                list.RemoveAt (index);
@@ -2006,8 +2874,8 @@ namespace System.Windows.Forms
 
                public class ListViewItemCollection : IList, ICollection, IEnumerable
                {
-                       internal ArrayList list;
-                       private ListView owner;
+                       private readonly ArrayList list;
+                       private readonly ListView owner;
 
                        #region Public Constructor
                        public ListViewItemCollection (ListView owner)
@@ -2019,30 +2887,31 @@ namespace System.Windows.Forms
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
+                       public int Count {
                                get { return list.Count; }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return false; }
                        }
 
                        public virtual ListViewItem this [int displayIndex] {
                                get {
                                        if (displayIndex < 0 || displayIndex >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
+                                               throw new ArgumentOutOfRangeException ("displayIndex");
                                        return (ListViewItem) list [displayIndex];
                                }
 
                                set {
                                        if (displayIndex < 0 || displayIndex >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
+                                               throw new ArgumentOutOfRangeException ("displayIndex");
 
                                        if (list.Contains (value))
                                                throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
 
-                                       value.owner = this.owner;
+                                       value.Owner = owner;
                                        list [displayIndex] = value;
+                                       OnChange ();
 
                                        owner.Redraw (true);
                                }
@@ -2067,6 +2936,7 @@ namespace System.Windows.Forms
                                                this [index] = (ListViewItem) value;
                                        else
                                                this [index] = new ListViewItem (value.ToString ());
+                                       OnChange ();
                                }
                        }
                        #endregion      // Public Properties
@@ -2077,14 +2947,12 @@ namespace System.Windows.Forms
                                if (list.Contains (value))
                                        throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
 
-                               value.owner = this.owner;
+                               value.Owner = owner;
                                list.Add (value);
 
-                               if (owner.Sorting != SortOrder.None)
-                                       owner.Sort ();
-
+                               owner.Sort (false);
+                               OnChange ();
                                owner.Redraw (true);
-
                                return value;
                        }
 
@@ -2103,19 +2971,14 @@ namespace System.Windows.Forms
                        public void AddRange (ListViewItem [] values)
                        {
                                list.Clear ();
-                               owner.SelectedItems.list.Clear ();
-                               owner.SelectedIndices.list.Clear ();
-                               owner.CheckedItems.list.Clear ();
-                               owner.CheckedIndices.list.Clear ();
 
                                foreach (ListViewItem item in values) {
-                                       item.owner = this.owner;
+                                       item.Owner = owner;
                                        list.Add (item);
                                }
 
-                               if (owner.Sorting != SortOrder.None)
-                                       owner.Sort ();
-
+                               owner.Sort (false);
+                               OnChange ();
                                owner.Redraw (true);
                        }
 
@@ -2124,10 +2987,7 @@ namespace System.Windows.Forms
                                owner.SetFocusedItem (null);
                                owner.h_scroll.Value = owner.v_scroll.Value = 0;
                                list.Clear ();
-                               owner.SelectedItems.list.Clear ();
-                               owner.SelectedIndices.list.Clear ();
-                               owner.CheckedItems.list.Clear ();
-                               owner.CheckedIndices.list.Clear ();
+                               OnChange ();
                                owner.Redraw (true);
                        }
 
@@ -2136,12 +2996,12 @@ namespace System.Windows.Forms
                                return list.Contains (item);
                        }
 
-                       public virtual void CopyTo (Array dest, int index)
+                       public void CopyTo (Array dest, int index)
                        {
                                list.CopyTo (dest, index);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
                                return list.GetEnumerator ();
                        }
@@ -2159,8 +3019,9 @@ namespace System.Windows.Forms
                                else
                                        li = new ListViewItem (item.ToString ());
 
-                               li.owner = this.owner;
+                               li.Owner = owner;
                                result = list.Add (li);
+                               OnChange ();
                                owner.Redraw (true);
 
                                return result;
@@ -2196,16 +3057,15 @@ namespace System.Windows.Forms
 
                        public ListViewItem Insert (int index, ListViewItem item)
                        {
-                               // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
-                               // but it's really only greater.
                                if (index < 0 || index > list.Count)
-                                       throw new ArgumentOutOfRangeException ("Index out of range.");
+                                       throw new ArgumentOutOfRangeException ("index");
 
                                if (list.Contains (item))
                                        throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
 
-                               item.owner = this.owner;
+                               item.Owner = owner;
                                list.Insert (index, item);
+                               OnChange ();
                                owner.Redraw (true);
                                return item;
                        }
@@ -2225,63 +3085,76 @@ namespace System.Windows.Forms
                                if (!list.Contains (item))
                                        return;
                                        
-                               owner.SelectedItems.list.Remove (item);
-                               owner.SelectedIndices.list.Remove (item.Index);
-                               owner.CheckedItems.list.Remove (item);
-                               owner.CheckedIndices.list.Remove (item.Index);
+                               bool selection_changed = owner.SelectedItems.Contains (item);
                                list.Remove (item);
+                               OnChange ();
                                owner.Redraw (true);                            
+                               if (selection_changed)
+                                       owner.OnSelectedIndexChanged (EventArgs.Empty);
                        }
 
                        public virtual void RemoveAt (int index)
                        {
-                               if (index < 0 || index >= list.Count)
-                                       throw new ArgumentOutOfRangeException ("Index out of range.");
-
+                               if (index < 0 || index >= Count)
+                                       throw new ArgumentOutOfRangeException ("index");
+                               bool selection_changed = owner.SelectedIndices.Contains (index);
                                list.RemoveAt (index);
-                               owner.SelectedItems.list.RemoveAt (index);
-                               owner.SelectedIndices.list.RemoveAt (index);
-                               owner.CheckedItems.list.RemoveAt (index);
-                               owner.CheckedIndices.list.RemoveAt (index);
+                               OnChange ();
                                owner.Redraw (false);
+                               if (selection_changed)
+                                       owner.OnSelectedIndexChanged (EventArgs.Empty);
                        }
                        #endregion      // Public Methods
 
+                       internal event CollectionChangedHandler Changed;
+
+                       internal void Sort (IComparer comparer)
+                       {
+                               list.Sort (comparer);
+                               OnChange ();
+                       }
+
+                       internal void OnChange ()
+                       {
+                               if (Changed != null)
+                                       Changed ();
+                       }
                }       // ListViewItemCollection
 
                public class SelectedIndexCollection : IList, ICollection, IEnumerable
                {
-                       internal ArrayList list;
-                       private ListView owner;
+                       private readonly ListView owner;
 
                        #region Public Constructor
                        public SelectedIndexCollection (ListView owner)
                        {
-                               list = new ArrayList ();
                                this.owner = owner;
                        }
                        #endregion      // Public Constructor
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
-                               get { return list.Count; }
+                       public int Count {
+                               get {
+                                       return owner.SelectedItems.Count;
+                               }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return true; }
                        }
 
                        public int this [int index] {
                                get {
-                                       if (index < 0 || index >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
-                                       return (int) list [index];
+                                       int [] indices = GetIndices ();
+                                       if (index < 0 || index >= indices.Length)
+                                               throw new ArgumentOutOfRangeException ("index");
+                                       return indices [index];
                                }
                        }
 
                        bool ICollection.IsSynchronized {
-                               get { return list.IsSynchronized; }
+                               get { return false; }
                        }
 
                        object ICollection.SyncRoot {
@@ -2301,17 +3174,24 @@ namespace System.Windows.Forms
                        #region Public Methods
                        public bool Contains (int selectedIndex)
                        {
-                               return list.Contains (selectedIndex);
+                               int [] indices = GetIndices ();
+                               for (int i = 0; i < indices.Length; i++) {
+                                       if (indices [i] == selectedIndex)
+                                               return true;
+                               }
+                               return false;
                        }
 
-                       public virtual void CopyTo (Array dest, int index)
+                       public void CopyTo (Array dest, int index)
                        {
-                               list.CopyTo (dest, index);
+                               int [] indices = GetIndices ();
+                               Array.Copy (indices, 0, dest, index, indices.Length);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
-                               return list.GetEnumerator ();
+                               int [] indices = GetIndices ();
+                               return indices.GetEnumerator ();
                        }
 
                        int IList.Add (object value)
@@ -2326,12 +3206,16 @@ namespace System.Windows.Forms
 
                        bool IList.Contains (object selectedIndex)
                        {
-                               return list.Contains (selectedIndex);
+                               if (!(selectedIndex is int))
+                                       return false;
+                               return Contains ((int) selectedIndex);
                        }
 
                        int IList.IndexOf (object selectedIndex)
                        {
-                               return list.IndexOf (selectedIndex);
+                               if (!(selectedIndex is int))
+                                       return -1;
+                               return IndexOf ((int) selectedIndex);
                        }
 
                        void IList.Insert (int index, object value)
@@ -2351,45 +3235,66 @@ namespace System.Windows.Forms
 
                        public int IndexOf (int selectedIndex)
                        {
-                               return list.IndexOf (selectedIndex);
+                               int [] indices = GetIndices ();
+                               for (int i = 0; i < indices.Length; i++) {
+                                       if (indices [i] == selectedIndex)
+                                               return i;
+                               }
+                               return -1;
                        }
                        #endregion      // Public Methods
 
+                       private int [] GetIndices ()
+                       {
+                               ArrayList selected_items = owner.SelectedItems.List;
+                               int [] indices = new int [selected_items.Count];
+                               for (int i = 0; i < selected_items.Count; i++) {
+                                       ListViewItem item = (ListViewItem) selected_items [i];
+                                       indices [i] = item.Index;
+                               }
+                               return indices;
+                       }
                }       // SelectedIndexCollection
 
                public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
                {
-                       internal ArrayList list;
-                       private ListView owner;
+                       private readonly ListView owner;
+                       private ArrayList list;
 
                        #region Public Constructor
                        public SelectedListViewItemCollection (ListView owner)
                        {
-                               list = new ArrayList ();
                                this.owner = owner;
+                               this.owner.Items.Changed += new CollectionChangedHandler (
+                                       ItemsCollection_Changed);
                        }
                        #endregion      // Public Constructor
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
-                               get { return list.Count; }
+                       public int Count {
+                               get {
+                                       if (!owner.IsHandleCreated)
+                                               return 0;
+                                       return List.Count;
+                               }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return true; }
                        }
 
                        public ListViewItem this [int index] {
                                get {
-                                       if (index < 0 || index >= list.Count)
-                                               throw new ArgumentOutOfRangeException ("Index out of range.");
-                                       return (ListViewItem) list [index];
+                                       ArrayList selected_items = List;
+                                       if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
+                                               throw new ArgumentOutOfRangeException ("index");
+                                       return (ListViewItem) selected_items [index];
                                }
                        }
 
                        bool ICollection.IsSynchronized {
-                               get { return list.IsSynchronized; }
+                               get { return false; }
                        }
 
                        object ICollection.SyncRoot {
@@ -2407,31 +3312,34 @@ namespace System.Windows.Forms
                        #endregion      // Public Properties
 
                        #region Public Methods
-                       public virtual void Clear ()
+                       public void Clear ()
                        {
-                               // mark the items as unselected before clearing the list
-                               for (int i = 0; i < list.Count; i++)
-                                       ((ListViewItem) list [i]).selected = false;
+                               if (!owner.IsHandleCreated)
+                                       return;
 
-                               list.Clear ();
-                               
-                               if (owner != null)
-                                       owner.Invalidate ();
+                               foreach (ListViewItem item in List)
+                                       item.Selected = false;
                        }
 
                        public bool Contains (ListViewItem item)
                        {
-                               return list.Contains (item);
+                               if (!owner.IsHandleCreated)
+                                       return false;
+                               return List.Contains (item);
                        }
 
-                       public virtual void CopyTo (Array dest, int index)
+                       public void CopyTo (Array dest, int index)
                        {
-                               list.CopyTo (dest, index);
+                               if (!owner.IsHandleCreated)
+                                       return;
+                               List.CopyTo (dest, index);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
-                               return list.GetEnumerator ();
+                               if (!owner.IsHandleCreated)
+                                       return (new ListViewItem [0]).GetEnumerator ();
+                               return List.GetEnumerator ();
                        }
 
                        int IList.Add (object value)
@@ -2441,12 +3349,16 @@ namespace System.Windows.Forms
 
                        bool IList.Contains (object item)
                        {
-                               return list.Contains (item);
+                               if (!(item is ListViewItem))
+                                       return false;
+                               return Contains ((ListViewItem) item);
                        }
 
                        int IList.IndexOf (object item)
                        {
-                               return list.IndexOf (item);
+                               if (!(item is ListViewItem))
+                                       return -1;
+                               return IndexOf ((ListViewItem) item);
                        }
 
                        void IList.Insert (int index, object value)
@@ -2466,12 +3378,39 @@ namespace System.Windows.Forms
 
                        public int IndexOf (ListViewItem item)
                        {
-                               return list.IndexOf (item);
+                               if (!owner.IsHandleCreated)
+                                       return -1;
+                               return List.IndexOf (item);
                        }
                        #endregion      // Public Methods
 
+                       internal ArrayList List {
+                               get {
+                                       if (list == null) {
+                                               list = new ArrayList ();
+                                               foreach (ListViewItem item in owner.Items) {
+                                                       if (item.Selected)
+                                                               list.Add (item);
+                                               }
+                                       }
+                                       return list;
+                               }
+                       }
+
+                       internal void Reset ()
+                       {
+                               // force re-population of list
+                               list = null;
+                       }
+
+                       private void ItemsCollection_Changed ()
+                       {
+                               Reset ();
+                       }
                }       // SelectedListViewItemCollection
 
+               internal delegate void CollectionChangedHandler ();
+
                #endregion // Subclasses
        }
 }