1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
23 // Ravindra Kumar (rkumar@novell.com)
24 // Jordi Mas i Hernandez, jordi@ximian.com
25 // Mike Kestner (mkestner@novell.com)
28 // - Feedback for item activation, change in cursor types as mouse moves.
36 using System.Collections;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
40 using System.Runtime.InteropServices;
41 using System.Globalization;
43 namespace System.Windows.Forms
45 [DefaultEvent ("SelectedIndexChanged")]
46 [DefaultProperty ("Items")]
47 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
48 public class ListView : Control
50 private ItemActivation activation = ItemActivation.Standard;
51 private ListViewAlignment alignment = ListViewAlignment.Top;
52 private bool allow_column_reorder = false;
53 private bool auto_arrange = true;
54 private bool check_boxes = false;
55 private readonly CheckedIndexCollection checked_indices;
56 private readonly CheckedListViewItemCollection checked_items;
57 private readonly ColumnHeaderCollection columns;
58 internal ListViewItem focused_item;
59 private bool full_row_select = false;
60 private bool grid_lines = false;
61 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
62 private bool hide_selection = true;
63 private bool hover_selection = false;
64 private IComparer item_sorter;
65 private readonly ListViewItemCollection items;
66 private bool label_edit = false;
67 private bool label_wrap = true;
68 private bool multiselect = true;
69 private bool scrollable = true;
70 private readonly SelectedIndexCollection selected_indices;
71 private readonly SelectedListViewItemCollection selected_items;
72 private SortOrder sort_order = SortOrder.None;
73 private ImageList state_image_list;
74 private bool updating = false;
75 private View view = View.LargeIcon;
76 private int layout_wd; // We might draw more than our client area
77 private int layout_ht; // therefore we need to have these two.
78 //private TextBox editor; // Used for editing an item text
79 HeaderControl header_control;
80 internal ItemControl item_control;
81 internal ScrollBar h_scroll; // used for scrolling horizontally
82 internal ScrollBar v_scroll; // used for scrolling vertically
83 internal int h_marker; // Position markers for scrolling
84 internal int v_marker;
85 private int keysearch_tickcnt;
86 private string keysearch_text;
87 static private readonly int keysearch_keydelay = 1000;
88 private int[] reordered_column_indices;
91 internal ImageList large_image_list;
92 internal ImageList small_image_list;
93 internal Size text_size = Size.Empty;
96 public event LabelEditEventHandler AfterLabelEdit;
99 [EditorBrowsable (EditorBrowsableState.Never)]
100 public new event EventHandler BackgroundImageChanged {
101 add { base.BackgroundImageChanged += value; }
102 remove { base.BackgroundImageChanged -= value; }
105 public event LabelEditEventHandler BeforeLabelEdit;
106 public event ColumnClickEventHandler ColumnClick;
107 public event EventHandler ItemActivate;
108 public event ItemCheckEventHandler ItemCheck;
109 public event ItemDragEventHandler ItemDrag;
112 [EditorBrowsable (EditorBrowsableState.Never)]
113 public new event PaintEventHandler Paint {
114 add { base.Paint += value; }
115 remove { base.Paint -= value; }
118 public event EventHandler SelectedIndexChanged;
121 [EditorBrowsable (EditorBrowsableState.Never)]
122 public new event EventHandler TextChanged {
123 add { base.TextChanged += value; }
124 remove { base.TextChanged -= value; }
129 #region Public Constructors
132 background_color = ThemeEngine.Current.ColorWindow;
133 items = new ListViewItemCollection (this);
134 checked_indices = new CheckedIndexCollection (this);
135 checked_items = new CheckedListViewItemCollection (this);
136 columns = new ColumnHeaderCollection (this);
137 foreground_color = SystemColors.WindowText;
138 selected_indices = new SelectedIndexCollection (this);
139 selected_items = new SelectedListViewItemCollection (this);
141 border_style = BorderStyle.Fixed3D;
143 header_control = new HeaderControl (this);
144 header_control.Visible = false;
145 Controls.AddImplicit (header_control);
147 item_control = new ItemControl (this);
148 Controls.AddImplicit (item_control);
150 h_scroll = new HScrollBar ();
151 Controls.AddImplicit (this.h_scroll);
153 v_scroll = new VScrollBar ();
154 Controls.AddImplicit (this.v_scroll);
156 h_marker = v_marker = 0;
157 keysearch_tickcnt = 0;
159 // scroll bars are disabled initially
160 h_scroll.Visible = false;
161 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
162 v_scroll.Visible = false;
163 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
166 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
167 SizeChanged += new EventHandler (ListView_SizeChanged);
168 GotFocus += new EventHandler (FocusChanged);
169 LostFocus += new EventHandler (FocusChanged);
170 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
172 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
174 #endregion // Public Constructors
176 #region Private Internal Properties
177 internal Size CheckBoxSize {
179 if (this.check_boxes) {
180 if (this.state_image_list != null)
181 return this.state_image_list.ImageSize;
183 return ThemeEngine.Current.ListViewCheckBoxSize;
189 #endregion // Private Internal Properties
191 #region Protected Properties
192 protected override CreateParams CreateParams {
193 get { return base.CreateParams; }
196 protected override Size DefaultSize {
197 get { return ThemeEngine.Current.ListViewDefaultSize; }
199 #endregion // Protected Properties
201 #region Public Instance Properties
202 [DefaultValue (ItemActivation.Standard)]
203 public ItemActivation Activation {
204 get { return activation; }
206 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
207 value != ItemActivation.TwoClick) {
208 throw new InvalidEnumArgumentException (string.Format
209 ("Enum argument value '{0}' is not valid for Activation", value));
216 [DefaultValue (ListViewAlignment.Top)]
218 public ListViewAlignment Alignment {
219 get { return alignment; }
221 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
222 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
223 throw new InvalidEnumArgumentException (string.Format
224 ("Enum argument value '{0}' is not valid for Alignment", value));
227 if (this.alignment != value) {
229 // alignment does not matter in Details/List views
230 if (this.view == View.LargeIcon ||
231 this.View == View.SmallIcon)
237 [DefaultValue (false)]
238 public bool AllowColumnReorder {
239 get { return allow_column_reorder; }
240 set { allow_column_reorder = value; }
243 [DefaultValue (true)]
244 public bool AutoArrange {
245 get { return auto_arrange; }
247 if (auto_arrange != value) {
248 auto_arrange = value;
249 // autoarrange does not matter in Details/List views
250 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
256 public override Color BackColor {
258 if (background_color.IsEmpty)
259 return ThemeEngine.Current.ColorWindow;
261 return background_color;
263 set { background_color = value; }
267 [EditorBrowsable (EditorBrowsableState.Never)]
268 public override Image BackgroundImage {
269 get { return background_image; }
271 if (value == background_image)
274 background_image = value;
275 OnBackgroundImageChanged (EventArgs.Empty);
279 [DefaultValue (BorderStyle.Fixed3D)]
281 public BorderStyle BorderStyle {
282 get { return InternalBorderStyle; }
283 set { InternalBorderStyle = value; }
286 [DefaultValue (false)]
287 public bool CheckBoxes {
288 get { return check_boxes; }
290 if (check_boxes != value) {
292 if (value && View == View.Tile)
293 throw new NotSupportedException ("CheckBoxes are not"
294 + " supported in Tile view. Choose a different"
295 + " view or set CheckBoxes to false.");
305 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
306 public CheckedIndexCollection CheckedIndices {
307 get { return checked_indices; }
311 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
312 public CheckedListViewItemCollection CheckedItems {
313 get { return checked_items; }
316 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
318 [MergableProperty (false)]
319 public ColumnHeaderCollection Columns {
320 get { return columns; }
324 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
325 public ListViewItem FocusedItem {
331 public override Color ForeColor {
333 if (foreground_color.IsEmpty)
334 return ThemeEngine.Current.ColorWindowText;
336 return foreground_color;
338 set { foreground_color = value; }
341 [DefaultValue (false)]
342 public bool FullRowSelect {
343 get { return full_row_select; }
344 set { full_row_select = value; }
347 [DefaultValue (false)]
348 public bool GridLines {
349 get { return grid_lines; }
351 if (grid_lines != value) {
358 [DefaultValue (ColumnHeaderStyle.Clickable)]
359 public ColumnHeaderStyle HeaderStyle {
360 get { return header_style; }
362 if (header_style == value)
366 case ColumnHeaderStyle.Clickable:
367 case ColumnHeaderStyle.Nonclickable:
368 case ColumnHeaderStyle.None:
371 throw new InvalidEnumArgumentException (string.Format
372 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
375 header_style = value;
376 if (view == View.Details)
381 [DefaultValue (true)]
382 public bool HideSelection {
383 get { return hide_selection; }
385 if (hide_selection != value) {
386 hide_selection = value;
392 [DefaultValue (false)]
393 public bool HoverSelection {
394 get { return hover_selection; }
395 set { hover_selection = value; }
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
400 [MergableProperty (false)]
401 public ListViewItemCollection Items {
402 get { return items; }
405 [DefaultValue (false)]
406 public bool LabelEdit {
407 get { return label_edit; }
408 set { label_edit = value; }
411 [DefaultValue (true)]
413 public bool LabelWrap {
414 get { return label_wrap; }
416 if (label_wrap != value) {
423 [DefaultValue (null)]
424 public ImageList LargeImageList {
425 get { return large_image_list; }
427 large_image_list = value;
433 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
434 public IComparer ListViewItemSorter {
436 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
441 if (item_sorter != value) {
448 [DefaultValue (true)]
449 public bool MultiSelect {
450 get { return multiselect; }
451 set { multiselect = value; }
454 [DefaultValue (true)]
455 public bool Scrollable {
456 get { return scrollable; }
458 if (scrollable != value) {
466 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
467 public SelectedIndexCollection SelectedIndices {
468 get { return selected_indices; }
472 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
473 public SelectedListViewItemCollection SelectedItems {
474 get { return selected_items; }
478 [MonoTODO("Implement")]
479 public bool ShowGroups {
489 [DefaultValue (null)]
490 public ImageList SmallImageList {
491 get { return small_image_list; }
493 small_image_list = value;
498 [DefaultValue (SortOrder.None)]
499 public SortOrder Sorting {
500 get { return sort_order; }
502 if (!Enum.IsDefined (typeof (SortOrder), value)) {
503 throw new InvalidEnumArgumentException ("value", (int) value,
507 if (sort_order == value)
512 if (value == SortOrder.None) {
513 if (item_sorter != null) {
514 // ListViewItemSorter should never be reset for SmallIcon
515 // and LargeIcon view
516 if (View != View.SmallIcon && View != View.LargeIcon)
520 // in .NET 1.1, only internal IComparer would be
522 if (item_sorter is ItemComparer)
528 if (item_sorter == null)
529 item_sorter = new ItemComparer (value);
530 if (item_sorter is ItemComparer) {
532 item_sorter = new ItemComparer (value);
534 // in .NET 1.1, the sort order is not updated for
535 // SmallIcon and LargeIcon views if no custom IComparer
537 if (View != View.SmallIcon && View != View.LargeIcon)
538 item_sorter = new ItemComparer (value);
546 [DefaultValue (null)]
547 public ImageList StateImageList {
548 get { return state_image_list; }
550 state_image_list = value;
557 [EditorBrowsable (EditorBrowsableState.Never)]
558 public override string Text {
567 OnTextChanged (EventArgs.Empty);
572 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
573 public ListViewItem TopItem {
576 if (this.items.Count == 0)
578 // if contents are not scrolled
579 // it is the first item
580 else if (h_marker == 0 && v_marker == 0)
581 return this.items [0];
582 // do a hit test for the scrolled position
584 foreach (ListViewItem item in this.items) {
585 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
594 [MonoTODO("Implement")]
595 public bool UseCompatibleStateImageBehavior {
605 [DefaultValue (View.LargeIcon)]
609 if (!Enum.IsDefined (typeof (View), value))
610 throw new InvalidEnumArgumentException ("value", (int) value,
615 if (CheckBoxes && value == View.Tile)
616 throw new NotSupportedException ("CheckBoxes are not"
617 + " supported in Tile view. Choose a different"
618 + " view or set CheckBoxes to false.");
621 h_scroll.Value = v_scroll.Value = 0;
627 #endregion // Public Instance Properties
629 #region Internal Methods Properties
631 internal int FirstVisibleIndex {
634 if (this.items.Count == 0)
637 if (h_marker == 0 && v_marker == 0)
640 foreach (ListViewItem item in this.items) {
641 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
650 internal int LastVisibleIndex {
652 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
653 if (View == View.List || Alignment == ListViewAlignment.Left) {
654 if (Items[i].Bounds.X > ClientRectangle.Right)
657 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
662 return Items.Count - 1;
666 internal int TotalWidth {
667 get { return Math.Max (this.Width, this.layout_wd); }
670 internal int TotalHeight {
671 get { return Math.Max (this.Height, this.layout_ht); }
674 internal void Redraw (bool recalculate)
676 // Avoid calculations when control is being updated
681 CalculateListView (this.alignment);
686 internal Size GetChildColumnSize (int index)
688 Size ret_size = Size.Empty;
689 ColumnHeader col = this.columns [index];
691 if (col.Width == -2) { // autosize = max(items, columnheader)
692 Size size = Size.Ceiling (this.DeviceContext.MeasureString
693 (col.Text, this.Font));
694 ret_size = BiggestItem (index);
695 if (size.Width > ret_size.Width)
698 else { // -1 and all the values < -2 are put under one category
699 ret_size = BiggestItem (index);
700 // fall back to empty columns' width if no subitem is available for a column
701 if (ret_size.IsEmpty) {
702 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
703 if (col.Text.Length > 0)
704 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
705 (col.Text, this.Font)).Height;
707 ret_size.Height = this.Font.Height;
711 // adjust the size for icon and checkbox for 0th column
713 ret_size.Width += (this.CheckBoxSize.Width + 4);
714 if (this.small_image_list != null)
715 ret_size.Width += this.small_image_list.ImageSize.Width;
720 // Returns the size of biggest item text in a column.
721 private Size BiggestItem (int col)
723 Size temp = Size.Empty;
724 Size ret_size = Size.Empty;
726 // 0th column holds the item text, we check the size of
727 // the various subitems falling in that column and get
728 // the biggest one's size.
729 foreach (ListViewItem item in items) {
730 if (col >= item.SubItems.Count)
733 temp = Size.Ceiling (this.DeviceContext.MeasureString
734 (item.SubItems [col].Text, this.Font));
735 if (temp.Width > ret_size.Width)
739 // adjustment for space
740 if (!ret_size.IsEmpty)
746 const int max_wrap_padding = 38;
748 // Sets the size of the biggest item text as per the view
749 private void CalcTextSize ()
751 // clear the old value
752 text_size = Size.Empty;
754 if (items.Count == 0)
757 text_size = BiggestItem (0);
759 if (view == View.LargeIcon && this.label_wrap) {
760 Size temp = Size.Empty;
761 if (this.check_boxes)
762 temp.Width += 2 * this.CheckBoxSize.Width;
763 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
764 temp.Width += icon_w + max_wrap_padding;
765 // wrapping is done for two lines only
766 if (text_size.Width > temp.Width) {
767 text_size.Width = temp.Width;
768 text_size.Height *= 2;
771 else if (view == View.List) {
772 // in list view max text shown in determined by the
773 // control width, even if scolling is enabled.
774 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
775 if (this.small_image_list != null)
776 max_wd -= this.small_image_list.ImageSize.Width;
778 if (text_size.Width > max_wd)
779 text_size.Width = max_wd;
782 // we do the default settings, if we have got 0's
783 if (text_size.Height <= 0)
784 text_size.Height = this.Font.Height;
785 if (text_size.Width <= 0)
786 text_size.Width = this.Width;
789 text_size.Width += 4;
790 text_size.Height += 2;
793 private void Scroll (ScrollBar scrollbar, int delta)
795 if (delta == 0 || !scrollbar.Visible)
799 if (scrollbar == h_scroll)
800 max = h_scroll.Maximum - item_control.Width;
802 max = v_scroll.Maximum - item_control.Height;
804 int val = scrollbar.Value + delta;
807 else if (val < scrollbar.Minimum)
808 val = scrollbar.Minimum;
809 scrollbar.Value = val;
812 private void CalculateScrollBars ()
814 Rectangle client_area = ClientRectangle;
816 if (!this.scrollable || this.items.Count <= 0) {
817 h_scroll.Visible = false;
818 v_scroll.Visible = false;
819 item_control.Location = new Point (0, header_control.Height);
820 item_control.Height = ClientRectangle.Width - header_control.Height;
821 item_control.Width = ClientRectangle.Width;
822 header_control.Width = ClientRectangle.Width;
826 // Don't calculate if the view is not displayable
827 if (client_area.Height < 0 || client_area.Width < 0)
830 // making a scroll bar visible might make
831 // other scroll bar visible
832 if (layout_wd > client_area.Right) {
833 h_scroll.Visible = true;
834 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
835 v_scroll.Visible = true;
837 v_scroll.Visible = false;
838 } else if (layout_ht > client_area.Bottom) {
839 v_scroll.Visible = true;
840 if ((layout_wd + v_scroll.Width) > client_area.Right)
841 h_scroll.Visible = true;
843 h_scroll.Visible = false;
845 h_scroll.Visible = false;
846 v_scroll.Visible = false;
849 item_control.Height = ClientRectangle.Height - header_control.Height;
851 if (h_scroll.is_visible) {
852 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
853 h_scroll.Minimum = 0;
855 // if v_scroll is visible, adjust the maximum of the
856 // h_scroll to account for the width of v_scroll
857 if (v_scroll.Visible) {
858 h_scroll.Maximum = layout_wd + v_scroll.Width;
859 h_scroll.Width = client_area.Width - v_scroll.Width;
862 h_scroll.Maximum = layout_wd;
863 h_scroll.Width = client_area.Width;
866 h_scroll.LargeChange = client_area.Width;
867 h_scroll.SmallChange = Font.Height;
868 item_control.Height -= h_scroll.Height;
871 if (header_control.is_visible)
872 header_control.Width = ClientRectangle.Width;
873 item_control.Width = ClientRectangle.Width;
875 if (v_scroll.is_visible) {
876 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
877 v_scroll.Minimum = 0;
879 // if h_scroll is visible, adjust the maximum of the
880 // v_scroll to account for the height of h_scroll
881 if (h_scroll.Visible) {
882 v_scroll.Maximum = layout_ht + h_scroll.Height;
883 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
885 v_scroll.Maximum = layout_ht;
886 v_scroll.Height = client_area.Height;
889 v_scroll.LargeChange = client_area.Height;
890 v_scroll.SmallChange = Font.Height;
891 if (header_control.Visible)
892 header_control.Width -= v_scroll.Width;
893 item_control.Width -= v_scroll.Width;
897 ColumnHeader GetReorderedColumn (int index)
899 if (reordered_column_indices == null)
900 return Columns [index];
902 return Columns [reordered_column_indices [index]];
905 void ReorderColumn (ColumnHeader col, int index)
907 if (reordered_column_indices == null) {
908 reordered_column_indices = new int [Columns.Count];
909 for (int i = 0; i < Columns.Count; i++)
910 reordered_column_indices [i] = i;
913 if (reordered_column_indices [index] == col.Index)
916 int[] curr = reordered_column_indices;
917 int[] result = new int [Columns.Count];
919 for (int i = 0; i < Columns.Count; i++) {
920 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
924 result [i] = col.Index;
926 result [i] = curr [curr_idx++];
929 reordered_column_indices = result;
931 header_control.Invalidate ();
932 item_control.Invalidate ();
935 Size LargeIconItemSize {
937 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
938 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
939 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
940 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
941 return new Size (w, h);
945 Size SmallIconItemSize {
947 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
948 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
949 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
950 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
951 return new Size (w, h);
957 ListViewItem[,] item_matrix;
959 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
961 header_control.Visible = false;
962 header_control.Size = Size.Empty;
963 item_control.Visible = true;
964 item_control.Location = Point.Empty;
966 if (items.Count == 0)
969 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
971 Rectangle area = ClientRectangle;
974 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
977 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
979 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
982 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
985 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
986 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
987 item_matrix = new ListViewItem [rows, cols];
990 foreach (ListViewItem item in items) {
991 int x = col * (sz.Width + x_spacing);
992 int y = row * (sz.Height + y_spacing);
993 item.Location = new Point (x, y);
997 item_matrix [row, col] = item;
1004 if (++col == cols) {
1011 item_control.Size = new Size (layout_wd, layout_ht);
1014 void LayoutHeader ()
1017 for (int i = 0; i < Columns.Count; i++) {
1018 ColumnHeader col = GetReorderedColumn (i);
1021 col.CalcColumnHeader ();
1025 if (x < ClientRectangle.Width)
1026 x = ClientRectangle.Width;
1028 if (header_style == ColumnHeaderStyle.None) {
1029 header_control.Visible = false;
1030 header_control.Size = Size.Empty;
1032 header_control.Width = x;
1033 header_control.Height = columns [0].Ht;
1034 header_control.Visible = true;
1038 void LayoutDetails ()
1040 if (columns.Count == 0) {
1041 header_control.Visible = false;
1042 item_control.Visible = false;
1048 item_control.Visible = true;
1049 item_control.Location = new Point (0, header_control.Height);
1052 if (items.Count > 0) {
1053 foreach (ListViewItem item in items) {
1055 item.Location = new Point (0, y);
1056 y += item.Bounds.Height + 2;
1059 // some space for bottom gridline
1064 layout_wd = Math.Max (header_control.Width, item_control.Width);
1065 layout_ht = y + header_control.Height;
1068 private void CalculateListView (ListViewAlignment align)
1077 case View.SmallIcon:
1078 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1081 case View.LargeIcon:
1082 LayoutIcons (true, alignment == ListViewAlignment.Left,
1083 ThemeEngine.Current.ListViewHorizontalSpacing,
1084 ThemeEngine.Current.ListViewVerticalSpacing);
1088 LayoutIcons (false, true, 4, 2);
1092 CalculateScrollBars ();
1097 return (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0;
1101 private bool KeySearchString (KeyEventArgs ke)
1103 int current_tickcnt = Environment.TickCount;
1104 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1105 keysearch_text = string.Empty;
1108 keysearch_text += (char) ke.KeyData;
1109 keysearch_tickcnt = current_tickcnt;
1111 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1114 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1115 CompareOptions.IgnoreCase)) {
1116 SetFocusedItem (Items [i]);
1117 items [i].Selected = true;
1121 i = (i + 1 < Items.Count) ? i+1 : 0;
1129 int GetAdjustedIndex (Keys key)
1133 if (View == View.Details) {
1135 result = FocusedItem.Index - 1;
1136 else if (key == Keys.Down) {
1137 result = FocusedItem.Index + 1;
1138 if (result == items.Count)
1144 int row = FocusedItem.row;
1145 int col = FocusedItem.col;
1151 return item_matrix [row, col - 1].Index;
1154 if (col == (cols - 1))
1156 while (item_matrix [row, col + 1] == null)
1158 return item_matrix [row, col + 1].Index;
1163 return item_matrix [row - 1, col].Index;
1166 if (row == (rows - 1) || row == Items.Count - 1)
1168 while (item_matrix [row + 1, col] == null)
1170 return item_matrix [row + 1, col].Index;
1177 ListViewItem selection_start;
1179 private bool SelectItems (ArrayList sel_items)
1181 bool changed = false;
1182 ArrayList curr_items = SelectedItems.List;
1183 foreach (ListViewItem item in curr_items)
1184 if (!sel_items.Contains (item)) {
1185 item.Selected = false;
1188 foreach (ListViewItem item in sel_items)
1189 if (!item.Selected) {
1190 item.Selected = true;
1196 private void UpdateMultiSelection (int index)
1198 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1199 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1200 ListViewItem item = items [index];
1202 if (shift_pressed && selection_start != null) {
1203 ArrayList list = new ArrayList ();
1204 int start = Math.Min (selection_start.Index, index);
1205 int end = Math.Max (selection_start.Index, index);
1206 if (View == View.Details) {
1207 for (int i = start; i <= end; i++)
1208 list.Add (items [i]);
1210 int left = Math.Min (items [start].col, items [end].col);
1211 int right = Math.Max (items [start].col, items [end].col);
1212 int top = Math.Min (items [start].row, items [end].row);
1213 int bottom = Math.Max (items [start].row, items [end].row);
1214 foreach (ListViewItem curr in items)
1215 if (curr.row >= top && curr.row <= bottom &&
1216 curr.col >= left && curr.col <= right)
1219 if (SelectItems (list))
1220 OnSelectedIndexChanged (EventArgs.Empty);
1221 } else if (ctrl_pressed) {
1222 item.Selected = !item.Selected;
1223 selection_start = item;
1224 OnSelectedIndexChanged (EventArgs.Empty);
1226 SelectedItems.Clear ();
1227 item.Selected = true;
1228 selection_start = item;
1229 OnSelectedIndexChanged (EventArgs.Empty);
1233 internal override bool InternalPreProcessMessage (ref Message msg)
1235 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
1236 Keys key_data = (Keys)msg.WParam.ToInt32();
1237 if (HandleNavKeys (key_data))
1240 return base.InternalPreProcessMessage (ref msg);
1243 bool HandleNavKeys (Keys key_data)
1245 if (Items.Count == 0 || !item_control.Visible)
1248 if (FocusedItem == null)
1249 SetFocusedItem (Items [0]);
1253 SelectIndex (Items.Count - 1);
1264 SelectIndex (GetAdjustedIndex (key_data));
1274 void SelectIndex (int index)
1280 UpdateMultiSelection (index);
1281 else if (!items [index].Selected) {
1282 items [index].Selected = true;
1283 OnSelectedIndexChanged (EventArgs.Empty);
1286 SetFocusedItem (items [index]);
1287 EnsureVisible (index);
1290 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1292 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1295 ke.Handled = KeySearchString (ke);
1298 internal class ItemControl : Control {
1301 ListViewItem clicked_item;
1302 ListViewItem last_clicked_item;
1303 bool hover_processed = false;
1304 bool checking = false;
1306 ListViewLabelEditTextBox edit_text_box;
1307 internal ListViewItem edit_item;
1308 LabelEditEventArgs edit_args;
1310 public ItemControl (ListView owner)
1313 DoubleClick += new EventHandler(ItemsDoubleClick);
1314 MouseDown += new MouseEventHandler(ItemsMouseDown);
1315 MouseMove += new MouseEventHandler(ItemsMouseMove);
1316 MouseHover += new EventHandler(ItemsMouseHover);
1317 MouseUp += new MouseEventHandler(ItemsMouseUp);
1320 void ItemsDoubleClick (object sender, EventArgs e)
1322 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1323 owner.ItemActivate (this, e);
1333 BoxSelect box_select_mode = BoxSelect.None;
1334 ArrayList prev_selection;
1335 Point box_select_start;
1337 Rectangle box_select_rect;
1338 internal Rectangle BoxSelectRectangle {
1339 get { return box_select_rect; }
1341 if (box_select_rect == value)
1344 InvalidateBoxSelectRect ();
1345 box_select_rect = value;
1346 InvalidateBoxSelectRect ();
1350 void InvalidateBoxSelectRect ()
1352 if (BoxSelectRectangle.Size.IsEmpty)
1355 Rectangle edge = BoxSelectRectangle;
1361 edge.Y = BoxSelectRectangle.Bottom - 1;
1363 edge.Y = BoxSelectRectangle.Y - 1;
1365 edge.Height = BoxSelectRectangle.Height + 2;
1367 edge.X = BoxSelectRectangle.Right - 1;
1371 private Rectangle CalculateBoxSelectRectangle (Point pt)
1373 int left = Math.Min (box_select_start.X, pt.X);
1374 int right = Math.Max (box_select_start.X, pt.X);
1375 int top = Math.Min (box_select_start.Y, pt.Y);
1376 int bottom = Math.Max (box_select_start.Y, pt.Y);
1377 return Rectangle.FromLTRB (left, top, right, bottom);
1380 ArrayList BoxSelectedItems {
1382 ArrayList result = new ArrayList ();
1383 foreach (ListViewItem item in owner.Items) {
1384 Rectangle r = item.Bounds;
1386 r.Y += r.Height / 4;
1389 if (BoxSelectRectangle.IntersectsWith (r))
1396 private bool PerformBoxSelection (Point pt)
1398 if (box_select_mode == BoxSelect.None)
1401 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1403 ArrayList box_items = BoxSelectedItems;
1407 switch (box_select_mode) {
1409 case BoxSelect.Normal:
1413 case BoxSelect.Control:
1414 items = new ArrayList ();
1415 foreach (ListViewItem item in prev_selection)
1416 if (!box_items.Contains (item))
1418 foreach (ListViewItem item in box_items)
1419 if (!prev_selection.Contains (item))
1423 case BoxSelect.Shift:
1425 foreach (ListViewItem item in box_items)
1426 prev_selection.Remove (item);
1427 foreach (ListViewItem item in prev_selection)
1432 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1436 owner.SelectItems (items);
1442 private void ToggleCheckState (ListViewItem item)
1444 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1445 item.Checked = !item.Checked;
1446 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1448 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1449 owner.OnItemCheck (ice);
1452 private void ItemsMouseDown (object sender, MouseEventArgs me)
1454 if (owner.items.Count == 0)
1457 Point pt = new Point (me.X, me.Y);
1458 foreach (ListViewItem item in owner.items) {
1459 if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
1463 ToggleCheckState (item);
1467 if (owner.View == View.Details && !owner.FullRowSelect) {
1468 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1469 clicked_item = item;
1473 if (item.Bounds.Contains (pt)) {
1474 clicked_item = item;
1481 if (clicked_item != null) {
1482 owner.SetFocusedItem (clicked_item);
1483 bool changed = !clicked_item.Selected;
1484 if (owner.MultiSelect)
1485 owner.UpdateMultiSelection (clicked_item.Index);
1487 clicked_item.Selected = true;
1490 owner.OnSelectedIndexChanged (EventArgs.Empty);
1492 // Raise double click if the item was clicked. On MS the
1493 // double click is only raised if you double click an item
1494 if (me.Clicks > 1) {
1495 owner.OnDoubleClick (EventArgs.Empty);
1496 if (owner.CheckBoxes)
1497 ToggleCheckState (clicked_item);
1498 } else if (me.Clicks == 1) {
1499 owner.OnClick (EventArgs.Empty);
1500 if (owner.LabelEdit && !changed)
1501 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
1504 if (owner.MultiSelect) {
1505 Keys mods = XplatUI.State.ModifierKeys;
1506 if ((mods & Keys.Shift) != 0)
1507 box_select_mode = BoxSelect.Shift;
1508 else if ((mods & Keys.Control) != 0)
1509 box_select_mode = BoxSelect.Control;
1511 box_select_mode = BoxSelect.Normal;
1512 box_select_start = pt;
1513 prev_selection = owner.SelectedItems.List;
1514 } else if (owner.SelectedItems.Count > 0) {
1515 owner.SelectedItems.Clear ();
1516 owner.OnSelectedIndexChanged (EventArgs.Empty);
1521 private void ItemsMouseMove (object sender, MouseEventArgs me)
1523 if (PerformBoxSelection (new Point (me.X, me.Y)))
1526 if (owner.HoverSelection && hover_processed) {
1528 Point pt = PointToClient (Control.MousePosition);
1529 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1530 if (item == null || item.Selected)
1533 hover_processed = false;
1534 XplatUI.ResetMouseHover (Handle);
1539 private void ItemsMouseHover (object sender, EventArgs e)
1541 if (Capture || !owner.HoverSelection)
1544 hover_processed = true;
1545 Point pt = PointToClient (Control.MousePosition);
1546 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1551 item.Selected = true;
1552 owner.OnSelectedIndexChanged (new EventArgs ());
1555 private void ItemsMouseUp (object sender, MouseEventArgs me)
1558 if (owner.Items.Count == 0)
1561 Point pt = new Point (me.X, me.Y);
1563 Rectangle rect = Rectangle.Empty;
1564 if (clicked_item != null) {
1565 if (owner.view == View.Details && !owner.full_row_select)
1566 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1568 rect = clicked_item.Bounds;
1570 if (rect.Contains (pt)) {
1571 switch (owner.activation) {
1572 case ItemActivation.OneClick:
1573 owner.OnItemActivate (EventArgs.Empty);
1576 case ItemActivation.TwoClick:
1577 if (last_clicked_item == clicked_item) {
1578 owner.OnItemActivate (EventArgs.Empty);
1579 last_clicked_item = null;
1581 last_clicked_item = clicked_item;
1584 // DoubleClick activation is handled in another handler
1588 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1589 // Need this to clean up background clicks
1590 owner.SelectedItems.Clear ();
1591 owner.OnSelectedIndexChanged (EventArgs.Empty);
1594 clicked_item = null;
1595 box_select_start = Point.Empty;
1596 BoxSelectRectangle = Rectangle.Empty;
1597 prev_selection = null;
1598 box_select_mode = BoxSelect.None;
1602 internal void LabelEditFinished (object sender, EventArgs e)
1604 EndEdit (edit_item);
1607 internal void BeginEdit (ListViewItem item)
1609 if (edit_item != null)
1610 EndEdit (edit_item);
1612 if (edit_text_box == null) {
1613 edit_text_box = new ListViewLabelEditTextBox ();
1614 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1615 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1616 edit_text_box.Visible = false;
1617 Controls.Add (edit_text_box);
1620 item.EnsureVisible();
1622 edit_text_box.Reset ();
1624 switch (owner.view) {
1626 case View.SmallIcon:
1628 edit_text_box.TextAlign = HorizontalAlignment.Left;
1629 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1630 SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
1631 edit_text_box.Width = (int)sizef.Width + 4;
1632 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
1633 edit_text_box.WordWrap = false;
1634 edit_text_box.Multiline = false;
1636 case View.LargeIcon:
1637 edit_text_box.TextAlign = HorizontalAlignment.Center;
1638 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1639 sizef = DeviceContext.MeasureString (item.Text, item.Font);
1640 edit_text_box.Width = (int)sizef.Width + 4;
1641 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
1642 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
1643 edit_text_box.WordWrap = true;
1644 edit_text_box.Multiline = true;
1648 edit_text_box.Text = item.Text;
1649 edit_text_box.Font = item.Font;
1650 edit_text_box.Visible = true;
1651 edit_text_box.Focus ();
1652 edit_text_box.SelectAll ();
1654 edit_args = new LabelEditEventArgs (owner.Items.IndexOf(edit_item));
1655 owner.OnBeforeLabelEdit (edit_args);
1657 if (edit_args.CancelEdit)
1663 internal void EndEdit (ListViewItem item)
1665 if (edit_text_box != null && edit_text_box.Visible) {
1666 edit_text_box.Visible = false;
1669 if (edit_item != null && edit_item == item) {
1670 owner.OnAfterLabelEdit (edit_args);
1672 if (!edit_args.CancelEdit) {
1673 if (edit_args.Label != null)
1674 edit_item.Text = edit_args.Label;
1676 edit_item.Text = edit_text_box.Text;
1685 internal override void OnPaintInternal (PaintEventArgs pe)
1687 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1690 internal override void OnGotFocusInternal (EventArgs e)
1696 internal class ListViewLabelEditTextBox : TextBox
1701 int max_height = -1;
1702 int min_height = -1;
1704 int old_number_lines = 1;
1706 SizeF text_size_one_char;
1708 public ListViewLabelEditTextBox ()
1710 min_height = DefaultSize.Height;
1711 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1714 public int MaxWidth {
1716 if (value < min_width)
1717 max_width = min_width;
1723 public int MaxHeight {
1725 if (value < min_height)
1726 max_height = min_height;
1732 public new int Width {
1742 public override Font Font {
1748 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1752 protected override void OnTextChanged (EventArgs e)
1754 SizeF text_size = DeviceContext.MeasureString (Text, Font);
1756 int new_width = (int)text_size.Width + 8;
1759 ResizeTextBoxWidth (new_width);
1761 if (Width != max_width)
1762 ResizeTextBoxWidth (new_width);
1764 int number_lines = Lines.Length;
1766 if (number_lines != old_number_lines) {
1767 int new_height = number_lines * (int)text_size_one_char.Height + 4;
1768 old_number_lines = number_lines;
1770 ResizeTextBoxHeight (new_height);
1774 base.OnTextChanged (e);
1777 protected override bool IsInputKey (Keys key_data)
1779 if ((key_data & Keys.Alt) == 0) {
1780 switch (key_data & Keys.KeyCode) {
1785 return base.IsInputKey (key_data);
1788 protected override void OnKeyDown (KeyEventArgs e)
1790 if (e.KeyCode == Keys.Return && Visible) {
1791 this.Visible = false;
1792 OnEditingFinished (e);
1796 protected override void OnLostFocus (EventArgs e)
1799 OnEditingFinished (e);
1803 protected void OnEditingFinished (EventArgs e)
1805 if (EditingFinished != null)
1806 EditingFinished (this, EventArgs.Empty);
1809 private void ResizeTextBoxWidth (int new_width)
1811 if (new_width > max_width)
1812 base.Width = max_width;
1814 if (new_width >= min_width)
1815 base.Width = new_width;
1817 base.Width = min_width;
1820 private void ResizeTextBoxHeight (int new_height)
1822 if (new_height > max_height)
1823 base.Height = max_height;
1825 if (new_height >= min_height)
1826 base.Height = new_height;
1828 base.Height = min_height;
1831 public void Reset ()
1838 old_number_lines = 1;
1840 Text = String.Empty;
1845 public event EventHandler EditingFinished;
1848 internal override void OnPaintInternal (PaintEventArgs pe)
1853 CalculateScrollBars ();
1856 void FocusChanged (object o, EventArgs args)
1858 if (Items.Count == 0)
1861 if (FocusedItem == null)
1862 SetFocusedItem (Items [0]);
1864 item_control.Invalidate (FocusedItem.Bounds);
1867 private void ListView_MouseWheel (object sender, MouseEventArgs me)
1869 if (Items.Count == 0)
1872 int lines = me.Delta / 120;
1879 case View.SmallIcon:
1880 Scroll (v_scroll, -Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1882 case View.LargeIcon:
1883 Scroll (v_scroll, -(Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1886 Scroll (h_scroll, -Items [0].Bounds.Width * lines);
1891 private void ListView_SizeChanged (object sender, EventArgs e)
1893 CalculateListView (alignment);
1896 private void SetFocusedItem (ListViewItem item)
1898 if (focused_item != null)
1899 focused_item.Focused = false;
1902 item.Focused = true;
1904 focused_item = item;
1907 private void HorizontalScroller (object sender, EventArgs e)
1909 item_control.EndEdit (item_control.edit_item);
1911 // Avoid unnecessary flickering, when button is
1912 // kept pressed at the end
1913 if (h_marker != h_scroll.Value) {
1915 int pixels = h_marker - h_scroll.Value;
1917 h_marker = h_scroll.Value;
1918 if (header_control.Visible)
1919 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1921 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1925 private void VerticalScroller (object sender, EventArgs e)
1927 item_control.EndEdit (item_control.edit_item);
1929 // Avoid unnecessary flickering, when button is
1930 // kept pressed at the end
1931 if (v_marker != v_scroll.Value) {
1932 int pixels = v_marker - v_scroll.Value;
1933 Rectangle area = item_control.ClientRectangle;
1934 v_marker = v_scroll.Value;
1935 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1938 #endregion // Internal Methods Properties
1940 #region Protected Methods
1941 protected override void CreateHandle ()
1943 base.CreateHandle ();
1946 protected override void Dispose (bool disposing)
1949 h_scroll.Dispose ();
1950 v_scroll.Dispose ();
1952 large_image_list = null;
1953 small_image_list = null;
1954 state_image_list = null;
1957 base.Dispose (disposing);
1960 protected override bool IsInputKey (Keys keyData)
1977 return base.IsInputKey (keyData);
1980 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1982 if (AfterLabelEdit != null)
1983 AfterLabelEdit (this, e);
1986 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1988 if (BeforeLabelEdit != null)
1989 BeforeLabelEdit (this, e);
1992 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1994 if (ColumnClick != null)
1995 ColumnClick (this, e);
1998 protected override void OnEnabledChanged (EventArgs e)
2000 base.OnEnabledChanged (e);
2003 protected override void OnFontChanged (EventArgs e)
2005 base.OnFontChanged (e);
2009 protected override void OnHandleCreated (EventArgs e)
2011 base.OnHandleCreated (e);
2015 protected override void OnHandleDestroyed (EventArgs e)
2017 base.OnHandleDestroyed (e);
2020 protected virtual void OnItemActivate (EventArgs e)
2022 if (ItemActivate != null)
2023 ItemActivate (this, e);
2026 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
2028 if (ItemCheck != null)
2029 ItemCheck (this, ice);
2032 protected virtual void OnItemDrag (ItemDragEventArgs e)
2034 if (ItemDrag != null)
2038 protected virtual void OnSelectedIndexChanged (EventArgs e)
2040 if (SelectedIndexChanged != null)
2041 SelectedIndexChanged (this, e);
2044 protected override void OnSystemColorsChanged (EventArgs e)
2046 base.OnSystemColorsChanged (e);
2049 protected void RealizeProperties ()
2054 protected void UpdateExtendedStyles ()
2059 protected override void WndProc (ref Message m)
2061 base.WndProc (ref m);
2063 #endregion // Protected Methods
2065 #region Public Instance Methods
2066 public void ArrangeIcons ()
2068 ArrangeIcons (this.alignment);
2071 public void ArrangeIcons (ListViewAlignment alignment)
2073 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2074 if (view == View.LargeIcon || view == View.SmallIcon) {
2075 this.CalculateListView (alignment);
2076 // we have done the calculations already
2077 this.Redraw (false);
2081 public void BeginUpdate ()
2083 // flag to avoid painting
2087 public void Clear ()
2090 items.Clear (); // Redraw (true) called here
2093 public void EndUpdate ()
2095 // flag to avoid painting
2098 // probably, now we need a redraw with recalculations
2102 public void EnsureVisible (int index)
2104 if (index < 0 || index >= items.Count || scrollable == false)
2107 Rectangle view_rect = item_control.ClientRectangle;
2108 Rectangle bounds = items [index].Bounds;
2110 if (view_rect.Contains (bounds))
2113 if (bounds.Left < 0)
2114 h_scroll.Value += bounds.Left;
2115 else if (bounds.Right > view_rect.Right)
2116 h_scroll.Value += (bounds.Right - view_rect.Right);
2119 v_scroll.Value += bounds.Top;
2120 else if (bounds.Bottom > view_rect.Bottom)
2121 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
2124 public ListViewItem GetItemAt (int x, int y)
2126 foreach (ListViewItem item in items) {
2127 if (item.Bounds.Contains (x, y))
2133 public Rectangle GetItemRect (int index)
2135 return GetItemRect (index, ItemBoundsPortion.Entire);
2138 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
2140 if (index < 0 || index >= items.Count)
2141 throw new IndexOutOfRangeException ("index");
2143 return items [index].GetBounds (portion);
2151 // we need this overload to reuse the logic for sorting, while allowing
2152 // redrawing to be done by caller or have it done by this method when
2153 // sorting is really performed
2155 // ListViewItemCollection's Add and AddRange methods call this overload
2156 // with redraw set to false, as they take care of redrawing themselves
2157 // (they even want to redraw the listview if no sort is performed, as
2158 // an item was added), while ListView.Sort () only wants to redraw if
2159 // sorting was actually performed
2160 private void Sort (bool redraw)
2162 if (!IsHandleCreated || item_sorter == null) {
2166 items.Sort (item_sorter);
2171 public override string ToString ()
2173 int count = this.Items.Count;
2176 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2178 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
2180 #endregion // Public Instance Methods
2185 class HeaderControl : Control {
2188 bool column_resize_active = false;
2189 ColumnHeader resize_column;
2190 ColumnHeader clicked_column;
2191 ColumnHeader drag_column;
2193 int drag_to_index = -1;
2195 public HeaderControl (ListView owner)
2198 MouseDown += new MouseEventHandler (HeaderMouseDown);
2199 MouseMove += new MouseEventHandler (HeaderMouseMove);
2200 MouseUp += new MouseEventHandler (HeaderMouseUp);
2203 private ColumnHeader ColumnAtX (int x)
2205 Point pt = new Point (x, 0);
2206 ColumnHeader result = null;
2207 foreach (ColumnHeader col in owner.Columns) {
2208 if (col.Rect.Contains (pt)) {
2216 private int GetReorderedIndex (ColumnHeader col)
2218 if (owner.reordered_column_indices == null)
2221 for (int i = 0; i < owner.Columns.Count; i++)
2222 if (owner.reordered_column_indices [i] == col.Index)
2224 throw new Exception ("Column index missing from reordered array");
2227 private void HeaderMouseDown (object sender, MouseEventArgs me)
2229 if (resize_column != null) {
2230 column_resize_active = true;
2235 clicked_column = ColumnAtX (me.X + owner.h_marker);
2237 if (clicked_column != null) {
2239 if (owner.AllowColumnReorder) {
2241 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
2242 drag_column.column_rect = clicked_column.Rect;
2243 drag_to_index = GetReorderedIndex (clicked_column);
2245 clicked_column.pressed = true;
2246 Rectangle bounds = clicked_column.Rect;
2247 bounds.X -= owner.h_marker;
2248 Invalidate (bounds);
2253 private void HeaderMouseMove (object sender, MouseEventArgs me)
2255 Point pt = new Point (me.X + owner.h_marker, me.Y);
2257 if (column_resize_active) {
2258 resize_column.Width = pt.X - resize_column.X;
2259 if (resize_column.Width < 0)
2260 resize_column.Width = 0;
2264 resize_column = null;
2266 if (clicked_column != null) {
2267 if (owner.AllowColumnReorder) {
2270 r = drag_column.column_rect;
2271 r.X = clicked_column.Rect.X + me.X - drag_x;
2272 drag_column.column_rect = r;
2274 int x = me.X + owner.h_marker;
2275 ColumnHeader over = ColumnAtX (x);
2277 drag_to_index = owner.Columns.Count;
2278 else if (x < over.X + over.Width / 2)
2279 drag_to_index = GetReorderedIndex (over);
2281 drag_to_index = GetReorderedIndex (over) + 1;
2284 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
2285 bool pressed = clicked_column.pressed;
2286 clicked_column.pressed = over == clicked_column;
2287 if (clicked_column.pressed ^ pressed) {
2288 Rectangle bounds = clicked_column.Rect;
2289 bounds.X -= owner.h_marker;
2290 Invalidate (bounds);
2296 for (int i = 0; i < owner.Columns.Count; i++) {
2297 Rectangle zone = owner.Columns [i].Rect;
2298 zone.X = zone.Right - 5;
2300 if (zone.Contains (pt)) {
2301 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
2303 resize_column = owner.Columns [i];
2308 if (resize_column == null)
2309 Cursor = Cursors.Default;
2311 Cursor = Cursors.VSplit;
2314 void HeaderMouseUp (object sender, MouseEventArgs me)
2318 if (column_resize_active) {
2319 column_resize_active = false;
2320 resize_column = null;
2321 Cursor = Cursors.Default;
2325 if (clicked_column != null && clicked_column.pressed) {
2326 clicked_column.pressed = false;
2327 Rectangle bounds = clicked_column.Rect;
2328 bounds.X -= owner.h_marker;
2329 Invalidate (bounds);
2330 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2333 if (drag_column != null && owner.AllowColumnReorder) {
2335 if (drag_to_index > GetReorderedIndex (clicked_column))
2337 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2338 owner.ReorderColumn (clicked_column, drag_to_index);
2343 clicked_column = null;
2346 internal override void OnPaintInternal (PaintEventArgs pe)
2351 Theme theme = ThemeEngine.Current;
2352 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2354 if (drag_column == null)
2358 if (drag_to_index == owner.Columns.Count)
2359 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2361 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2362 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2365 protected override void WndProc (ref Message m)
2367 switch ((Msg)m.Msg) {
2368 case Msg.WM_SETFOCUS:
2372 base.WndProc (ref m);
2378 private class ItemComparer : IComparer {
2379 readonly SortOrder sort_order;
2381 public ItemComparer (SortOrder sortOrder)
2383 sort_order = sortOrder;
2386 public int Compare (object x, object y)
2388 ListViewItem item_x = x as ListViewItem;
2389 ListViewItem item_y = y as ListViewItem;
2390 if (sort_order == SortOrder.Ascending)
2391 return String.Compare (item_x.Text, item_y.Text);
2393 return String.Compare (item_y.Text, item_x.Text);
2397 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2399 private readonly ListView owner;
2401 #region Public Constructor
2402 public CheckedIndexCollection (ListView owner)
2406 #endregion // Public Constructor
2408 #region Public Properties
2411 get { return owner.CheckedItems.Count; }
2414 public bool IsReadOnly {
2415 get { return true; }
2418 public int this [int index] {
2420 int [] indices = GetIndices ();
2421 if (index < 0 || index >= indices.Length)
2422 throw new ArgumentOutOfRangeException ("index");
2423 return indices [index];
2427 bool ICollection.IsSynchronized {
2428 get { return false; }
2431 object ICollection.SyncRoot {
2432 get { return this; }
2435 bool IList.IsFixedSize {
2436 get { return true; }
2439 object IList.this [int index] {
2440 get { return this [index]; }
2441 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2443 #endregion // Public Properties
2445 #region Public Methods
2446 public bool Contains (int checkedIndex)
2448 int [] indices = GetIndices ();
2449 for (int i = 0; i < indices.Length; i++) {
2450 if (indices [i] == checkedIndex)
2456 public IEnumerator GetEnumerator ()
2458 int [] indices = GetIndices ();
2459 return indices.GetEnumerator ();
2462 void ICollection.CopyTo (Array dest, int index)
2464 int [] indices = GetIndices ();
2465 Array.Copy (indices, 0, dest, index, indices.Length);
2468 int IList.Add (object value)
2470 throw new NotSupportedException ("Add operation is not supported.");
2475 throw new NotSupportedException ("Clear operation is not supported.");
2478 bool IList.Contains (object checkedIndex)
2480 if (!(checkedIndex is int))
2482 return Contains ((int) checkedIndex);
2485 int IList.IndexOf (object checkedIndex)
2487 if (!(checkedIndex is int))
2489 return IndexOf ((int) checkedIndex);
2492 void IList.Insert (int index, object value)
2494 throw new NotSupportedException ("Insert operation is not supported.");
2497 void IList.Remove (object value)
2499 throw new NotSupportedException ("Remove operation is not supported.");
2502 void IList.RemoveAt (int index)
2504 throw new NotSupportedException ("RemoveAt operation is not supported.");
2507 public int IndexOf (int checkedIndex)
2509 int [] indices = GetIndices ();
2510 for (int i = 0; i < indices.Length; i++) {
2511 if (indices [i] == checkedIndex)
2516 #endregion // Public Methods
2518 private int [] GetIndices ()
2520 ArrayList checked_items = owner.CheckedItems.List;
2521 int [] indices = new int [checked_items.Count];
2522 for (int i = 0; i < checked_items.Count; i++) {
2523 ListViewItem item = (ListViewItem) checked_items [i];
2524 indices [i] = item.Index;
2528 } // CheckedIndexCollection
2530 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2532 private readonly ListView owner;
2533 private ArrayList list;
2535 #region Public Constructor
2536 public CheckedListViewItemCollection (ListView owner)
2539 this.owner.Items.Changed += new CollectionChangedHandler (
2540 ItemsCollection_Changed);
2542 #endregion // Public Constructor
2544 #region Public Properties
2548 if (!owner.CheckBoxes)
2554 public bool IsReadOnly {
2555 get { return true; }
2558 public ListViewItem this [int index] {
2560 ArrayList checked_items = List;
2561 if (index < 0 || index >= checked_items.Count)
2562 throw new ArgumentOutOfRangeException ("index");
2563 return (ListViewItem) checked_items [index];
2567 bool ICollection.IsSynchronized {
2568 get { return false; }
2571 object ICollection.SyncRoot {
2572 get { return this; }
2575 bool IList.IsFixedSize {
2576 get { return true; }
2579 object IList.this [int index] {
2580 get { return this [index]; }
2581 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2583 #endregion // Public Properties
2585 #region Public Methods
2586 public bool Contains (ListViewItem item)
2588 if (!owner.CheckBoxes)
2590 return List.Contains (item);
2593 public void CopyTo (Array dest, int index)
2595 if (!owner.CheckBoxes)
2597 List.CopyTo (dest, index);
2600 public IEnumerator GetEnumerator ()
2602 if (!owner.CheckBoxes)
2603 return (new ListViewItem [0]).GetEnumerator ();
2604 return List.GetEnumerator ();
2607 int IList.Add (object value)
2609 throw new NotSupportedException ("Add operation is not supported.");
2614 throw new NotSupportedException ("Clear operation is not supported.");
2617 bool IList.Contains (object item)
2619 if (!(item is ListViewItem))
2621 return Contains ((ListViewItem) item);
2624 int IList.IndexOf (object item)
2626 if (!(item is ListViewItem))
2628 return IndexOf ((ListViewItem) item);
2631 void IList.Insert (int index, object value)
2633 throw new NotSupportedException ("Insert operation is not supported.");
2636 void IList.Remove (object value)
2638 throw new NotSupportedException ("Remove operation is not supported.");
2641 void IList.RemoveAt (int index)
2643 throw new NotSupportedException ("RemoveAt operation is not supported.");
2646 public int IndexOf (ListViewItem item)
2648 if (!owner.CheckBoxes)
2650 return List.IndexOf (item);
2652 #endregion // Public Methods
2654 internal ArrayList List {
2657 list = new ArrayList ();
2658 foreach (ListViewItem item in owner.Items) {
2667 internal void Reset ()
2669 // force re-population of list
2673 private void ItemsCollection_Changed ()
2677 } // CheckedListViewItemCollection
2679 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2681 internal ArrayList list;
2682 private ListView owner;
2684 #region Public Constructor
2685 public ColumnHeaderCollection (ListView owner)
2687 list = new ArrayList ();
2690 #endregion // Public Constructor
2692 #region Public Properties
2695 get { return list.Count; }
2698 public bool IsReadOnly {
2699 get { return false; }
2702 public virtual ColumnHeader this [int index] {
2704 if (index < 0 || index >= list.Count)
2705 throw new ArgumentOutOfRangeException ("index");
2706 return (ColumnHeader) list [index];
2710 bool ICollection.IsSynchronized {
2711 get { return true; }
2714 object ICollection.SyncRoot {
2715 get { return this; }
2718 bool IList.IsFixedSize {
2719 get { return list.IsFixedSize; }
2722 object IList.this [int index] {
2723 get { return this [index]; }
2724 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2726 #endregion // Public Properties
2728 #region Public Methods
2729 public virtual int Add (ColumnHeader value)
2732 value.owner = this.owner;
2733 idx = list.Add (value);
2734 if (owner.IsHandleCreated) {
2735 owner.Redraw (true);
2740 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2742 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2743 this.Add (colHeader);
2747 public virtual void AddRange (ColumnHeader [] values)
2749 foreach (ColumnHeader colHeader in values) {
2750 colHeader.owner = this.owner;
2754 owner.Redraw (true);
2757 public virtual void Clear ()
2760 owner.Redraw (true);
2763 public bool Contains (ColumnHeader value)
2765 return list.Contains (value);
2768 public IEnumerator GetEnumerator ()
2770 return list.GetEnumerator ();
2773 void ICollection.CopyTo (Array dest, int index)
2775 list.CopyTo (dest, index);
2778 int IList.Add (object value)
2780 if (! (value is ColumnHeader)) {
2781 throw new ArgumentException ("Not of type ColumnHeader", "value");
2784 return this.Add ((ColumnHeader) value);
2787 bool IList.Contains (object value)
2789 if (! (value is ColumnHeader)) {
2790 throw new ArgumentException ("Not of type ColumnHeader", "value");
2793 return this.Contains ((ColumnHeader) value);
2796 int IList.IndexOf (object value)
2798 if (! (value is ColumnHeader)) {
2799 throw new ArgumentException ("Not of type ColumnHeader", "value");
2802 return this.IndexOf ((ColumnHeader) value);
2805 void IList.Insert (int index, object value)
2807 if (! (value is ColumnHeader)) {
2808 throw new ArgumentException ("Not of type ColumnHeader", "value");
2811 this.Insert (index, (ColumnHeader) value);
2814 void IList.Remove (object value)
2816 if (! (value is ColumnHeader)) {
2817 throw new ArgumentException ("Not of type ColumnHeader", "value");
2820 this.Remove ((ColumnHeader) value);
2823 public int IndexOf (ColumnHeader value)
2825 return list.IndexOf (value);
2828 public void Insert (int index, ColumnHeader value)
2830 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2831 // but it's really only greater.
2832 if (index < 0 || index > list.Count)
2833 throw new ArgumentOutOfRangeException ("index");
2835 value.owner = this.owner;
2836 list.Insert (index, value);
2837 owner.Redraw (true);
2840 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2842 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2843 this.Insert (index, colHeader);
2846 public virtual void Remove (ColumnHeader column)
2848 // TODO: Update Column internal index ?
2849 list.Remove (column);
2850 owner.Redraw (true);
2853 public virtual void RemoveAt (int index)
2855 if (index < 0 || index >= list.Count)
2856 throw new ArgumentOutOfRangeException ("index");
2858 // TODO: Update Column internal index ?
2859 list.RemoveAt (index);
2860 owner.Redraw (true);
2862 #endregion // Public Methods
2865 } // ColumnHeaderCollection
2867 public class ListViewItemCollection : IList, ICollection, IEnumerable
2869 private readonly ArrayList list;
2870 private readonly ListView owner;
2872 #region Public Constructor
2873 public ListViewItemCollection (ListView owner)
2875 list = new ArrayList ();
2878 #endregion // Public Constructor
2880 #region Public Properties
2883 get { return list.Count; }
2886 public bool IsReadOnly {
2887 get { return false; }
2890 public virtual ListViewItem this [int displayIndex] {
2892 if (displayIndex < 0 || displayIndex >= list.Count)
2893 throw new ArgumentOutOfRangeException ("displayIndex");
2894 return (ListViewItem) list [displayIndex];
2898 if (displayIndex < 0 || displayIndex >= list.Count)
2899 throw new ArgumentOutOfRangeException ("displayIndex");
2901 if (list.Contains (value))
2902 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2904 value.Owner = owner;
2905 list [displayIndex] = value;
2908 owner.Redraw (true);
2912 bool ICollection.IsSynchronized {
2913 get { return true; }
2916 object ICollection.SyncRoot {
2917 get { return this; }
2920 bool IList.IsFixedSize {
2921 get { return list.IsFixedSize; }
2924 object IList.this [int index] {
2925 get { return this [index]; }
2927 if (value is ListViewItem)
2928 this [index] = (ListViewItem) value;
2930 this [index] = new ListViewItem (value.ToString ());
2934 #endregion // Public Properties
2936 #region Public Methods
2937 public virtual ListViewItem Add (ListViewItem value)
2939 if (list.Contains (value))
2940 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2942 value.Owner = owner;
2947 owner.Redraw (true);
2951 public virtual ListViewItem Add (string text)
2953 ListViewItem item = new ListViewItem (text);
2954 return this.Add (item);
2957 public virtual ListViewItem Add (string text, int imageIndex)
2959 ListViewItem item = new ListViewItem (text, imageIndex);
2960 return this.Add (item);
2963 public void AddRange (ListViewItem [] values)
2967 foreach (ListViewItem item in values) {
2974 owner.Redraw (true);
2977 public virtual void Clear ()
2979 owner.SetFocusedItem (null);
2980 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2983 owner.Redraw (true);
2986 public bool Contains (ListViewItem item)
2988 return list.Contains (item);
2991 public void CopyTo (Array dest, int index)
2993 list.CopyTo (dest, index);
2996 public IEnumerator GetEnumerator ()
2998 return list.GetEnumerator ();
3001 int IList.Add (object item)
3006 if (item is ListViewItem) {
3007 li = (ListViewItem) item;
3008 if (list.Contains (li))
3009 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3012 li = new ListViewItem (item.ToString ());
3015 result = list.Add (li);
3017 owner.Redraw (true);
3022 bool IList.Contains (object item)
3024 return list.Contains (item);
3027 int IList.IndexOf (object item)
3029 return list.IndexOf (item);
3032 void IList.Insert (int index, object item)
3034 if (item is ListViewItem)
3035 this.Insert (index, (ListViewItem) item);
3037 this.Insert (index, item.ToString ());
3040 void IList.Remove (object item)
3042 Remove ((ListViewItem) item);
3045 public int IndexOf (ListViewItem item)
3047 return list.IndexOf (item);
3050 public ListViewItem Insert (int index, ListViewItem item)
3052 if (index < 0 || index > list.Count)
3053 throw new ArgumentOutOfRangeException ("index");
3055 if (list.Contains (item))
3056 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3059 list.Insert (index, item);
3061 owner.Redraw (true);
3065 public ListViewItem Insert (int index, string text)
3067 return this.Insert (index, new ListViewItem (text));
3070 public ListViewItem Insert (int index, string text, int imageIndex)
3072 return this.Insert (index, new ListViewItem (text, imageIndex));
3075 public virtual void Remove (ListViewItem item)
3077 if (!list.Contains (item))
3082 owner.Redraw (true);
3085 public virtual void RemoveAt (int index)
3087 if (index < 0 || index >= Count)
3088 throw new ArgumentOutOfRangeException ("index");
3089 list.RemoveAt (index);
3091 owner.Redraw (false);
3093 #endregion // Public Methods
3095 internal event CollectionChangedHandler Changed;
3097 internal void Sort (IComparer comparer)
3099 list.Sort (comparer);
3103 internal void OnChange ()
3105 if (Changed != null)
3108 } // ListViewItemCollection
3110 public class SelectedIndexCollection : IList, ICollection, IEnumerable
3112 private readonly ListView owner;
3114 #region Public Constructor
3115 public SelectedIndexCollection (ListView owner)
3119 #endregion // Public Constructor
3121 #region Public Properties
3125 return owner.SelectedItems.Count;
3129 public bool IsReadOnly {
3130 get { return true; }
3133 public int this [int index] {
3135 int [] indices = GetIndices ();
3136 if (index < 0 || index >= indices.Length)
3137 throw new ArgumentOutOfRangeException ("index");
3138 return indices [index];
3142 bool ICollection.IsSynchronized {
3143 get { return false; }
3146 object ICollection.SyncRoot {
3147 get { return this; }
3150 bool IList.IsFixedSize {
3151 get { return true; }
3154 object IList.this [int index] {
3155 get { return this [index]; }
3156 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3158 #endregion // Public Properties
3160 #region Public Methods
3161 public bool Contains (int selectedIndex)
3163 int [] indices = GetIndices ();
3164 for (int i = 0; i < indices.Length; i++) {
3165 if (indices [i] == selectedIndex)
3171 public void CopyTo (Array dest, int index)
3173 int [] indices = GetIndices ();
3174 Array.Copy (indices, 0, dest, index, indices.Length);
3177 public IEnumerator GetEnumerator ()
3179 int [] indices = GetIndices ();
3180 return indices.GetEnumerator ();
3183 int IList.Add (object value)
3185 throw new NotSupportedException ("Add operation is not supported.");
3190 throw new NotSupportedException ("Clear operation is not supported.");
3193 bool IList.Contains (object selectedIndex)
3195 if (!(selectedIndex is int))
3197 return Contains ((int) selectedIndex);
3200 int IList.IndexOf (object selectedIndex)
3202 if (!(selectedIndex is int))
3204 return IndexOf ((int) selectedIndex);
3207 void IList.Insert (int index, object value)
3209 throw new NotSupportedException ("Insert operation is not supported.");
3212 void IList.Remove (object value)
3214 throw new NotSupportedException ("Remove operation is not supported.");
3217 void IList.RemoveAt (int index)
3219 throw new NotSupportedException ("RemoveAt operation is not supported.");
3222 public int IndexOf (int selectedIndex)
3224 int [] indices = GetIndices ();
3225 for (int i = 0; i < indices.Length; i++) {
3226 if (indices [i] == selectedIndex)
3231 #endregion // Public Methods
3233 private int [] GetIndices ()
3235 ArrayList selected_items = owner.SelectedItems.List;
3236 int [] indices = new int [selected_items.Count];
3237 for (int i = 0; i < selected_items.Count; i++) {
3238 ListViewItem item = (ListViewItem) selected_items [i];
3239 indices [i] = item.Index;
3243 } // SelectedIndexCollection
3245 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
3247 private readonly ListView owner;
3248 private ArrayList list;
3250 #region Public Constructor
3251 public SelectedListViewItemCollection (ListView owner)
3254 this.owner.Items.Changed += new CollectionChangedHandler (
3255 ItemsCollection_Changed);
3257 #endregion // Public Constructor
3259 #region Public Properties
3263 if (!owner.IsHandleCreated)
3269 public bool IsReadOnly {
3270 get { return true; }
3273 public ListViewItem this [int index] {
3275 ArrayList selected_items = List;
3276 if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
3277 throw new ArgumentOutOfRangeException ("index");
3278 return (ListViewItem) selected_items [index];
3282 bool ICollection.IsSynchronized {
3283 get { return false; }
3286 object ICollection.SyncRoot {
3287 get { return this; }
3290 bool IList.IsFixedSize {
3291 get { return true; }
3294 object IList.this [int index] {
3295 get { return this [index]; }
3296 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3298 #endregion // Public Properties
3300 #region Public Methods
3301 public void Clear ()
3303 if (!owner.IsHandleCreated)
3306 foreach (ListViewItem item in List)
3307 item.Selected = false;
3310 public bool Contains (ListViewItem item)
3312 if (!owner.IsHandleCreated)
3314 return List.Contains (item);
3317 public void CopyTo (Array dest, int index)
3319 if (!owner.IsHandleCreated)
3321 List.CopyTo (dest, index);
3324 public IEnumerator GetEnumerator ()
3326 if (!owner.IsHandleCreated)
3327 return (new ListViewItem [0]).GetEnumerator ();
3328 return List.GetEnumerator ();
3331 int IList.Add (object value)
3333 throw new NotSupportedException ("Add operation is not supported.");
3336 bool IList.Contains (object item)
3338 if (!(item is ListViewItem))
3340 return Contains ((ListViewItem) item);
3343 int IList.IndexOf (object item)
3345 if (!(item is ListViewItem))
3347 return IndexOf ((ListViewItem) item);
3350 void IList.Insert (int index, object value)
3352 throw new NotSupportedException ("Insert operation is not supported.");
3355 void IList.Remove (object value)
3357 throw new NotSupportedException ("Remove operation is not supported.");
3360 void IList.RemoveAt (int index)
3362 throw new NotSupportedException ("RemoveAt operation is not supported.");
3365 public int IndexOf (ListViewItem item)
3367 if (!owner.IsHandleCreated)
3369 return List.IndexOf (item);
3371 #endregion // Public Methods
3373 internal ArrayList List {
3376 list = new ArrayList ();
3377 foreach (ListViewItem item in owner.Items) {
3386 internal void Reset ()
3388 // force re-population of list
3392 private void ItemsCollection_Changed ()
3396 } // SelectedListViewItemCollection
3398 internal delegate void CollectionChangedHandler ();
3400 #endregion // Subclasses