2006-11-09 Mike Kestner <mkestner@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListView.cs
index 6702dad150c14797a7a5026b92fc7796a39f1c5b..31888daa1bd97fb181e801b32f563299fb8cccbf 100644 (file)
@@ -52,9 +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 ColumnHeaderCollection columns;
+               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;
@@ -62,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;
@@ -130,11 +130,11 @@ namespace System.Windows.Forms
                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);
 
@@ -147,10 +147,10 @@ namespace System.Windows.Forms
                        item_control = new ItemControl (this);
                        Controls.AddImplicit (item_control);
 
-                       h_scroll = new HScrollBar ();
+                       h_scroll = new ImplicitHScrollBar ();
                        Controls.AddImplicit (this.h_scroll);
 
-                       v_scroll = new VScrollBar ();
+                       v_scroll = new ImplicitVScrollBar ();
                        Controls.AddImplicit (this.v_scroll);
 
                        h_marker = v_marker = 0;
@@ -186,19 +186,6 @@ namespace System.Windows.Forms
                        }
                }
 
-               bool multiselecting;
-
-               bool CanMultiselect {
-                       get {
-                               if (multiselecting)
-                                       return true;
-                               else if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
-                                       return true;
-                               else
-                                       return false;
-                       }
-               }
-
                #endregion      // Private Internal Properties
 
                #region  Protected Properties
@@ -676,6 +663,12 @@ namespace System.Windows.Forms
                        }
                }
                
+               internal void OnSelectedIndexChanged ()
+               {
+                       if (IsHandleCreated)
+                               OnSelectedIndexChanged (EventArgs.Empty);
+               }
+
                internal int TotalWidth {
                        get { return Math.Max (this.Width, this.layout_wd); }
                }
@@ -756,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 ()
                {                       
@@ -771,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;
@@ -861,7 +854,7 @@ namespace System.Windows.Forms
 
                        item_control.Height = ClientRectangle.Height - header_control.Height;
 
-                       if (h_scroll.Visible) {
+                       if (h_scroll.is_visible) {
                                h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
                                h_scroll.Minimum = 0;
 
@@ -881,11 +874,11 @@ namespace System.Windows.Forms
                                item_control.Height -= h_scroll.Height;
                        }
 
-                       if (header_control.Visible)
+                       if (header_control.is_visible)
                                header_control.Width = ClientRectangle.Width;
                        item_control.Width = ClientRectangle.Width;
 
-                       if (v_scroll.Visible) {
+                       if (v_scroll.is_visible) {
                                v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
                                v_scroll.Minimum = 0;
 
@@ -1105,19 +1098,9 @@ namespace System.Windows.Forms
                         CalculateScrollBars ();
                }
 
-               internal void UpdateSelection (ListViewItem item)
-               {
-                       if (item.Selected) {
-
-                               if (!CanMultiselect && SelectedItems.Count > 0) {
-                                       SelectedItems.Clear ();
-                               }
-
-                               if (!SelectedItems.list.Contains (item)) {
-                                       SelectedItems.list.Add (item);
-                               }
-                       } else {
-                               SelectedItems.list.Remove (item);
+               bool HaveModKeys {
+                       get {
+                               return (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0;
                        }
                }
 
@@ -1202,8 +1185,7 @@ namespace System.Windows.Forms
                private bool SelectItems (ArrayList sel_items)
                {
                        bool changed = false;
-                       multiselecting = true;
-                       ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
+                       ArrayList curr_items = SelectedItems.List;
                        foreach (ListViewItem item in curr_items)
                                if (!sel_items.Contains (item)) {
                                        item.Selected = false;
@@ -1214,7 +1196,6 @@ namespace System.Windows.Forms
                                        item.Selected = true;
                                        changed = true;
                                }
-                       multiselecting = false;
                        return changed;
                }
 
@@ -1243,7 +1224,11 @@ namespace System.Windows.Forms
                                }
                                if (SelectItems (list))
                                        OnSelectedIndexChanged (EventArgs.Empty);
-                       } else if (!ctrl_pressed) {
+                       } else  if (ctrl_pressed) {
+                               item.Selected = !item.Selected;
+                               selection_start = item;
+                               OnSelectedIndexChanged (EventArgs.Empty);
+                       } else {
                                SelectedItems.Clear ();
                                item.Selected = true;
                                selection_start = item;
@@ -1251,39 +1236,49 @@ namespace System.Windows.Forms
                        }
                }
 
-               private void ListView_KeyDown (object sender, KeyEventArgs ke)
-               {                       
-                       if (ke.Handled || Items.Count == 0 || !item_control.Visible)
-                               return;
+               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);
+               }
 
-                       int index = -1;
-                       ke.Handled = true;
+               bool HandleNavKeys (Keys key_data)
+               {
+                       if (Items.Count == 0 || !item_control.Visible)
+                               return false;
 
                        if (FocusedItem == null)
                                SetFocusedItem (Items [0]);
 
-                       switch (ke.KeyCode) {
-
+                       switch (key_data) {
                        case Keys.End:
-                               index = Items.Count - 1;
+                               SelectIndex (Items.Count - 1);
                                break;
 
                        case Keys.Home:                 
-                               index = 0;
+                               SelectIndex (0);
                                break;
 
                        case Keys.Left:
                        case Keys.Right:
                        case Keys.Up:                           
                        case Keys.Down:
-                               index = GetAdjustedIndex (ke.KeyCode);
+                               SelectIndex (GetAdjustedIndex (key_data));
                                break;
 
                        default:
-                               ke.Handled = KeySearchString (ke);
-                               return;
+                               return false;
                        }
-                       
+
+                       return true;
+               }
+
+               void SelectIndex (int index)
+               {
                        if (index == -1)
                                return;
 
@@ -1298,7 +1293,14 @@ namespace System.Windows.Forms
                        EnsureVisible (index);
                }
 
-                               
+               private void ListView_KeyDown (object sender, KeyEventArgs ke)
+               {                       
+                       if (ke.Handled || Items.Count == 0 || !item_control.Visible)
+                               return;
+
+                       ke.Handled = KeySearchString (ke);
+               }
+
                internal class ItemControl : Control {
 
                        ListView owner;
@@ -1306,6 +1308,10 @@ namespace System.Windows.Forms
                        ListViewItem last_clicked_item;
                        bool hover_processed = false;
                        bool checking = false;
+                       
+                       ListViewLabelEditTextBox edit_text_box;
+                       internal ListViewItem edit_item;
+                       LabelEditEventArgs edit_args;
 
                        public ItemControl (ListView owner)
                        {
@@ -1481,7 +1487,7 @@ namespace System.Windows.Forms
                                if (clicked_item != null) {
                                        owner.SetFocusedItem (clicked_item);
                                        bool changed = !clicked_item.Selected;
-                                       if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
+                                       if (owner.MultiSelect)
                                                owner.UpdateMultiSelection (clicked_item.Index);
                                        else
                                                clicked_item.Selected = true;
@@ -1495,8 +1501,11 @@ namespace System.Windows.Forms
                                                owner.OnDoubleClick (EventArgs.Empty);
                                                if (owner.CheckBoxes)
                                                        ToggleCheckState (clicked_item);
-                                       } else if (me.Clicks == 1)
+                                       } 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;
@@ -1507,8 +1516,8 @@ namespace System.Windows.Forms
                                                else
                                                        box_select_mode = BoxSelect.Normal;
                                                box_select_start = pt; 
-                                               prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
-                                       } else if (owner.selected_indices.Count > 0) {
+                                               prev_selection = owner.SelectedItems.List;
+                                       } else if (owner.SelectedItems.Count > 0) {
                                                owner.SelectedItems.Clear ();
                                                owner.OnSelectedIndexChanged (EventArgs.Empty);
                                        }
@@ -1595,6 +1604,89 @@ namespace System.Windows.Forms
                                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)
                        {
@@ -1606,6 +1698,158 @@ namespace System.Windows.Forms
                                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;
+               }
 
                internal override void OnPaintInternal (PaintEventArgs pe)
                {
@@ -1668,6 +1912,8 @@ 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) {
@@ -1684,6 +1930,8 @@ namespace System.Windows.Forms
 
                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) {
@@ -1699,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)
@@ -1921,7 +2171,7 @@ namespace System.Windows.Forms
                                return;
                        }
                        
-                       items.list.Sort (item_sorter);
+                       items.Sort (item_sorter);
                        if (redraw)
                                this.Redraw (true);
                }
@@ -2275,9 +2525,10 @@ namespace System.Windows.Forms
 
                        private int [] GetIndices ()
                        {
-                               int [] indices = new int [Count];
-                               for (int i = 0; i < owner.CheckedItems.Count; i++) {
-                                       ListViewItem item = owner.CheckedItems [i];
+                               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;
@@ -2286,14 +2537,15 @@ namespace System.Windows.Forms
 
                public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
                {
-                       internal readonly ArrayList list;
                        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
 
@@ -2303,7 +2555,7 @@ namespace System.Windows.Forms
                                get {
                                        if (!owner.CheckBoxes)
                                                return 0;
-                                       return list.Count;
+                                       return List.Count;
                                }
                        }
 
@@ -2313,14 +2565,15 @@ namespace System.Windows.Forms
 
                        public ListViewItem this [int index] {
                                get {
-                                       if (index < 0 || index >= Count)
+                                       ArrayList checked_items = List;
+                                       if (index < 0 || index >= checked_items.Count)
                                                throw new ArgumentOutOfRangeException ("index");
-                                       return (ListViewItem) list [index];
+                                       return (ListViewItem) checked_items [index];
                                }
                        }
 
                        bool ICollection.IsSynchronized {
-                               get { return list.IsSynchronized; }
+                               get { return false; }
                        }
 
                        object ICollection.SyncRoot {
@@ -2342,21 +2595,21 @@ namespace System.Windows.Forms
                        {
                                if (!owner.CheckBoxes)
                                        return false;
-                               return list.Contains (item);
+                               return List.Contains (item);
                        }
 
                        public void CopyTo (Array dest, int index)
                        {
                                if (!owner.CheckBoxes)
                                        return;
-                               list.CopyTo (dest, index);
+                               List.CopyTo (dest, index);
                        }
 
                        public IEnumerator GetEnumerator ()
                        {
                                if (!owner.CheckBoxes)
                                        return (new ListViewItem [0]).GetEnumerator ();
-                               return list.GetEnumerator ();
+                               return List.GetEnumerator ();
                        }
 
                        int IList.Add (object value)
@@ -2402,9 +2655,33 @@ namespace System.Windows.Forms
                        {
                                if (!owner.CheckBoxes)
                                        return -1;
-                               return list.IndexOf (item);
+                               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
@@ -2597,7 +2874,7 @@ namespace System.Windows.Forms
 
                public class ListViewItemCollection : IList, ICollection, IEnumerable
                {
-                       internal ArrayList list;
+                       private readonly ArrayList list;
                        private readonly ListView owner;
 
                        #region Public Constructor
@@ -2634,6 +2911,7 @@ namespace System.Windows.Forms
 
                                        value.Owner = owner;
                                        list [displayIndex] = value;
+                                       OnChange ();
 
                                        owner.Redraw (true);
                                }
@@ -2658,6 +2936,7 @@ namespace System.Windows.Forms
                                                this [index] = (ListViewItem) value;
                                        else
                                                this [index] = new ListViewItem (value.ToString ());
+                                       OnChange ();
                                }
                        }
                        #endregion      // Public Properties
@@ -2672,6 +2951,7 @@ namespace System.Windows.Forms
                                list.Add (value);
 
                                owner.Sort (false);
+                               OnChange ();
                                owner.Redraw (true);
                                return value;
                        }
@@ -2691,8 +2971,6 @@ namespace System.Windows.Forms
                        public void AddRange (ListViewItem [] values)
                        {
                                list.Clear ();
-                               owner.SelectedItems.list.Clear ();
-                               owner.CheckedItems.list.Clear ();
 
                                foreach (ListViewItem item in values) {
                                        item.Owner = owner;
@@ -2700,6 +2978,7 @@ namespace System.Windows.Forms
                                }
 
                                owner.Sort (false);
+                               OnChange ();
                                owner.Redraw (true);
                        }
 
@@ -2708,8 +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.CheckedItems.list.Clear ();
+                               OnChange ();
                                owner.Redraw (true);
                        }
 
@@ -2743,6 +3021,7 @@ namespace System.Windows.Forms
 
                                li.Owner = owner;
                                result = list.Add (li);
+                               OnChange ();
                                owner.Redraw (true);
 
                                return result;
@@ -2786,6 +3065,7 @@ namespace System.Windows.Forms
 
                                item.Owner = owner;
                                list.Insert (index, item);
+                               OnChange ();
                                owner.Redraw (true);
                                return item;
                        }
@@ -2805,22 +3085,40 @@ namespace System.Windows.Forms
                                if (!list.Contains (item))
                                        return;
                                        
-                               owner.SelectedItems.list.Remove (item);
-                               owner.CheckedItems.list.Remove (item);
+                               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)
                        {
-                               ListViewItem item = this [index];
+                               if (index < 0 || index >= Count)
+                                       throw new ArgumentOutOfRangeException ("index");
+                               bool selection_changed = owner.SelectedIndices.Contains (index);
                                list.RemoveAt (index);
-                               owner.SelectedItems.list.Remove (item);
-                               owner.CheckedItems.list.Remove (item);
+                               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
@@ -2948,26 +3246,27 @@ namespace System.Windows.Forms
 
                        private int [] GetIndices ()
                        {
-                               int [] indices = new int [Count];
-                               for (int i = 0; i < owner.SelectedItems.Count; i++) {
-                                       ListViewItem item = owner.SelectedItems [i];
+                               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 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
 
@@ -2977,7 +3276,7 @@ namespace System.Windows.Forms
                                get {
                                        if (!owner.IsHandleCreated)
                                                return 0;
-                                       return list.Count;
+                                       return List.Count;
                                }
                        }
 
@@ -2987,14 +3286,15 @@ namespace System.Windows.Forms
 
                        public ListViewItem this [int index] {
                                get {
-                                       if (index < 0 || index >= Count)
+                                       ArrayList selected_items = List;
+                                       if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
                                                throw new ArgumentOutOfRangeException ("index");
-                                       return (ListViewItem) list [index];
+                                       return (ListViewItem) selected_items [index];
                                }
                        }
 
                        bool ICollection.IsSynchronized {
-                               get { return list.IsSynchronized; }
+                               get { return false; }
                        }
 
                        object ICollection.SyncRoot {
@@ -3017,32 +3317,29 @@ namespace System.Windows.Forms
                                if (!owner.IsHandleCreated)
                                        return;
 
-                               ArrayList copy = (ArrayList) list.Clone ();
-                               for (int i = 0; i < copy.Count; i++)
-                                       ((ListViewItem) copy [i]).Selected = false;
-
-                               list.Clear ();
+                               foreach (ListViewItem item in List)
+                                       item.Selected = false;
                        }
 
                        public bool Contains (ListViewItem item)
                        {
                                if (!owner.IsHandleCreated)
                                        return false;
-                               return list.Contains (item);
+                               return List.Contains (item);
                        }
 
                        public void CopyTo (Array dest, int index)
                        {
                                if (!owner.IsHandleCreated)
                                        return;
-                               list.CopyTo (dest, index);
+                               List.CopyTo (dest, index);
                        }
 
                        public IEnumerator GetEnumerator ()
                        {
                                if (!owner.IsHandleCreated)
                                        return (new ListViewItem [0]).GetEnumerator ();
-                               return list.GetEnumerator ();
+                               return List.GetEnumerator ();
                        }
 
                        int IList.Add (object value)
@@ -3083,12 +3380,37 @@ namespace System.Windows.Forms
                        {
                                if (!owner.IsHandleCreated)
                                        return -1;
-                               return list.IndexOf (item);
+                               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
        }
 }