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 ImplicitHScrollBar ();
151 Controls.AddImplicit (this.h_scroll);
153 v_scroll = new ImplicitVScrollBar ();
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 void OnSelectedIndexChanged ()
669 OnSelectedIndexChanged (EventArgs.Empty);
672 internal int TotalWidth {
673 get { return Math.Max (this.Width, this.layout_wd); }
676 internal int TotalHeight {
677 get { return Math.Max (this.Height, this.layout_ht); }
680 internal void Redraw (bool recalculate)
682 // Avoid calculations when control is being updated
687 CalculateListView (this.alignment);
692 internal Size GetChildColumnSize (int index)
694 Size ret_size = Size.Empty;
695 ColumnHeader col = this.columns [index];
697 if (col.Width == -2) { // autosize = max(items, columnheader)
698 Size size = Size.Ceiling (this.DeviceContext.MeasureString
699 (col.Text, this.Font));
700 ret_size = BiggestItem (index);
701 if (size.Width > ret_size.Width)
704 else { // -1 and all the values < -2 are put under one category
705 ret_size = BiggestItem (index);
706 // fall back to empty columns' width if no subitem is available for a column
707 if (ret_size.IsEmpty) {
708 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
709 if (col.Text.Length > 0)
710 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
711 (col.Text, this.Font)).Height;
713 ret_size.Height = this.Font.Height;
717 // adjust the size for icon and checkbox for 0th column
719 ret_size.Width += (this.CheckBoxSize.Width + 4);
720 if (this.small_image_list != null)
721 ret_size.Width += this.small_image_list.ImageSize.Width;
726 // Returns the size of biggest item text in a column.
727 private Size BiggestItem (int col)
729 Size temp = Size.Empty;
730 Size ret_size = Size.Empty;
732 // 0th column holds the item text, we check the size of
733 // the various subitems falling in that column and get
734 // the biggest one's size.
735 foreach (ListViewItem item in items) {
736 if (col >= item.SubItems.Count)
739 temp = Size.Ceiling (this.DeviceContext.MeasureString
740 (item.SubItems [col].Text, this.Font));
741 if (temp.Width > ret_size.Width)
745 // adjustment for space
746 if (!ret_size.IsEmpty)
752 const int max_wrap_padding = 38;
754 // Sets the size of the biggest item text as per the view
755 private void CalcTextSize ()
757 // clear the old value
758 text_size = Size.Empty;
760 if (items.Count == 0)
763 text_size = BiggestItem (0);
765 if (view == View.LargeIcon && this.label_wrap) {
766 Size temp = Size.Empty;
767 if (this.check_boxes)
768 temp.Width += 2 * this.CheckBoxSize.Width;
769 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
770 temp.Width += icon_w + max_wrap_padding;
771 // wrapping is done for two lines only
772 if (text_size.Width > temp.Width) {
773 text_size.Width = temp.Width;
774 text_size.Height *= 2;
777 else if (view == View.List) {
778 // in list view max text shown in determined by the
779 // control width, even if scolling is enabled.
780 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
781 if (this.small_image_list != null)
782 max_wd -= this.small_image_list.ImageSize.Width;
784 if (text_size.Width > max_wd)
785 text_size.Width = max_wd;
788 // we do the default settings, if we have got 0's
789 if (text_size.Height <= 0)
790 text_size.Height = this.Font.Height;
791 if (text_size.Width <= 0)
792 text_size.Width = this.Width;
795 text_size.Width += 4;
796 text_size.Height += 2;
799 private void Scroll (ScrollBar scrollbar, int delta)
801 if (delta == 0 || !scrollbar.Visible)
805 if (scrollbar == h_scroll)
806 max = h_scroll.Maximum - item_control.Width;
808 max = v_scroll.Maximum - item_control.Height;
810 int val = scrollbar.Value + delta;
813 else if (val < scrollbar.Minimum)
814 val = scrollbar.Minimum;
815 scrollbar.Value = val;
818 private void CalculateScrollBars ()
820 Rectangle client_area = ClientRectangle;
822 if (!this.scrollable || this.items.Count <= 0) {
823 h_scroll.Visible = false;
824 v_scroll.Visible = false;
825 item_control.Location = new Point (0, header_control.Height);
826 item_control.Height = ClientRectangle.Width - header_control.Height;
827 item_control.Width = ClientRectangle.Width;
828 header_control.Width = ClientRectangle.Width;
832 // Don't calculate if the view is not displayable
833 if (client_area.Height < 0 || client_area.Width < 0)
836 // making a scroll bar visible might make
837 // other scroll bar visible
838 if (layout_wd > client_area.Right) {
839 h_scroll.Visible = true;
840 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
841 v_scroll.Visible = true;
843 v_scroll.Visible = false;
844 } else if (layout_ht > client_area.Bottom) {
845 v_scroll.Visible = true;
846 if ((layout_wd + v_scroll.Width) > client_area.Right)
847 h_scroll.Visible = true;
849 h_scroll.Visible = false;
851 h_scroll.Visible = false;
852 v_scroll.Visible = false;
855 item_control.Height = ClientRectangle.Height - header_control.Height;
857 if (h_scroll.is_visible) {
858 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
859 h_scroll.Minimum = 0;
861 // if v_scroll is visible, adjust the maximum of the
862 // h_scroll to account for the width of v_scroll
863 if (v_scroll.Visible) {
864 h_scroll.Maximum = layout_wd + v_scroll.Width;
865 h_scroll.Width = client_area.Width - v_scroll.Width;
868 h_scroll.Maximum = layout_wd;
869 h_scroll.Width = client_area.Width;
872 h_scroll.LargeChange = client_area.Width;
873 h_scroll.SmallChange = Font.Height;
874 item_control.Height -= h_scroll.Height;
877 if (header_control.is_visible)
878 header_control.Width = ClientRectangle.Width;
879 item_control.Width = ClientRectangle.Width;
881 if (v_scroll.is_visible) {
882 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
883 v_scroll.Minimum = 0;
885 // if h_scroll is visible, adjust the maximum of the
886 // v_scroll to account for the height of h_scroll
887 if (h_scroll.Visible) {
888 v_scroll.Maximum = layout_ht + h_scroll.Height;
889 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
891 v_scroll.Maximum = layout_ht;
892 v_scroll.Height = client_area.Height;
895 v_scroll.LargeChange = client_area.Height;
896 v_scroll.SmallChange = Font.Height;
897 if (header_control.Visible)
898 header_control.Width -= v_scroll.Width;
899 item_control.Width -= v_scroll.Width;
903 ColumnHeader GetReorderedColumn (int index)
905 if (reordered_column_indices == null)
906 return Columns [index];
908 return Columns [reordered_column_indices [index]];
911 void ReorderColumn (ColumnHeader col, int index)
913 if (reordered_column_indices == null) {
914 reordered_column_indices = new int [Columns.Count];
915 for (int i = 0; i < Columns.Count; i++)
916 reordered_column_indices [i] = i;
919 if (reordered_column_indices [index] == col.Index)
922 int[] curr = reordered_column_indices;
923 int[] result = new int [Columns.Count];
925 for (int i = 0; i < Columns.Count; i++) {
926 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
930 result [i] = col.Index;
932 result [i] = curr [curr_idx++];
935 reordered_column_indices = result;
937 header_control.Invalidate ();
938 item_control.Invalidate ();
941 Size LargeIconItemSize {
943 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
944 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
945 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
946 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
947 return new Size (w, h);
951 Size SmallIconItemSize {
953 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
954 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
955 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
956 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
957 return new Size (w, h);
963 ListViewItem[,] item_matrix;
965 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
967 header_control.Visible = false;
968 header_control.Size = Size.Empty;
969 item_control.Visible = true;
970 item_control.Location = Point.Empty;
972 if (items.Count == 0)
975 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
977 Rectangle area = ClientRectangle;
980 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
983 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
985 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
988 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
991 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
992 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
993 item_matrix = new ListViewItem [rows, cols];
996 foreach (ListViewItem item in items) {
997 int x = col * (sz.Width + x_spacing);
998 int y = row * (sz.Height + y_spacing);
999 item.Location = new Point (x, y);
1003 item_matrix [row, col] = item;
1005 if (++row == rows) {
1010 if (++col == cols) {
1017 item_control.Size = new Size (layout_wd, layout_ht);
1020 void LayoutHeader ()
1023 for (int i = 0; i < Columns.Count; i++) {
1024 ColumnHeader col = GetReorderedColumn (i);
1027 col.CalcColumnHeader ();
1031 if (x < ClientRectangle.Width)
1032 x = ClientRectangle.Width;
1034 if (header_style == ColumnHeaderStyle.None) {
1035 header_control.Visible = false;
1036 header_control.Size = Size.Empty;
1038 header_control.Width = x;
1039 header_control.Height = columns [0].Ht;
1040 header_control.Visible = true;
1044 void LayoutDetails ()
1046 if (columns.Count == 0) {
1047 header_control.Visible = false;
1048 item_control.Visible = false;
1054 item_control.Visible = true;
1055 item_control.Location = new Point (0, header_control.Height);
1058 if (items.Count > 0) {
1059 foreach (ListViewItem item in items) {
1061 item.Location = new Point (0, y);
1062 y += item.Bounds.Height + 2;
1065 // some space for bottom gridline
1070 layout_wd = Math.Max (header_control.Width, item_control.Width);
1071 layout_ht = y + header_control.Height;
1074 private void CalculateListView (ListViewAlignment align)
1083 case View.SmallIcon:
1084 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1087 case View.LargeIcon:
1088 LayoutIcons (true, alignment == ListViewAlignment.Left,
1089 ThemeEngine.Current.ListViewHorizontalSpacing,
1090 ThemeEngine.Current.ListViewVerticalSpacing);
1094 LayoutIcons (false, true, 4, 2);
1098 CalculateScrollBars ();
1103 return (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0;
1107 private bool KeySearchString (KeyEventArgs ke)
1109 int current_tickcnt = Environment.TickCount;
1110 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1111 keysearch_text = string.Empty;
1114 keysearch_text += (char) ke.KeyData;
1115 keysearch_tickcnt = current_tickcnt;
1117 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1120 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1121 CompareOptions.IgnoreCase)) {
1122 SetFocusedItem (Items [i]);
1123 items [i].Selected = true;
1127 i = (i + 1 < Items.Count) ? i+1 : 0;
1135 int GetAdjustedIndex (Keys key)
1139 if (View == View.Details) {
1141 result = FocusedItem.Index - 1;
1142 else if (key == Keys.Down) {
1143 result = FocusedItem.Index + 1;
1144 if (result == items.Count)
1150 int row = FocusedItem.row;
1151 int col = FocusedItem.col;
1157 return item_matrix [row, col - 1].Index;
1160 if (col == (cols - 1))
1162 while (item_matrix [row, col + 1] == null)
1164 return item_matrix [row, col + 1].Index;
1169 return item_matrix [row - 1, col].Index;
1172 if (row == (rows - 1) || row == Items.Count - 1)
1174 while (item_matrix [row + 1, col] == null)
1176 return item_matrix [row + 1, col].Index;
1183 ListViewItem selection_start;
1185 private bool SelectItems (ArrayList sel_items)
1187 bool changed = false;
1188 ArrayList curr_items = SelectedItems.List;
1189 foreach (ListViewItem item in curr_items)
1190 if (!sel_items.Contains (item)) {
1191 item.Selected = false;
1194 foreach (ListViewItem item in sel_items)
1195 if (!item.Selected) {
1196 item.Selected = true;
1202 private void UpdateMultiSelection (int index)
1204 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1205 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1206 ListViewItem item = items [index];
1208 if (shift_pressed && selection_start != null) {
1209 ArrayList list = new ArrayList ();
1210 int start = Math.Min (selection_start.Index, index);
1211 int end = Math.Max (selection_start.Index, index);
1212 if (View == View.Details) {
1213 for (int i = start; i <= end; i++)
1214 list.Add (items [i]);
1216 int left = Math.Min (items [start].col, items [end].col);
1217 int right = Math.Max (items [start].col, items [end].col);
1218 int top = Math.Min (items [start].row, items [end].row);
1219 int bottom = Math.Max (items [start].row, items [end].row);
1220 foreach (ListViewItem curr in items)
1221 if (curr.row >= top && curr.row <= bottom &&
1222 curr.col >= left && curr.col <= right)
1225 if (SelectItems (list))
1226 OnSelectedIndexChanged (EventArgs.Empty);
1227 } else if (ctrl_pressed) {
1228 item.Selected = !item.Selected;
1229 selection_start = item;
1230 OnSelectedIndexChanged (EventArgs.Empty);
1232 SelectedItems.Clear ();
1233 item.Selected = true;
1234 selection_start = item;
1235 OnSelectedIndexChanged (EventArgs.Empty);
1239 internal override bool InternalPreProcessMessage (ref Message msg)
1241 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
1242 Keys key_data = (Keys)msg.WParam.ToInt32();
1243 if (HandleNavKeys (key_data))
1246 return base.InternalPreProcessMessage (ref msg);
1249 bool HandleNavKeys (Keys key_data)
1251 if (Items.Count == 0 || !item_control.Visible)
1254 if (FocusedItem == null)
1255 SetFocusedItem (Items [0]);
1259 SelectIndex (Items.Count - 1);
1270 SelectIndex (GetAdjustedIndex (key_data));
1280 void SelectIndex (int index)
1286 UpdateMultiSelection (index);
1287 else if (!items [index].Selected) {
1288 items [index].Selected = true;
1289 OnSelectedIndexChanged (EventArgs.Empty);
1292 SetFocusedItem (items [index]);
1293 EnsureVisible (index);
1296 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1298 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1301 ke.Handled = KeySearchString (ke);
1304 internal class ItemControl : Control {
1307 ListViewItem clicked_item;
1308 ListViewItem last_clicked_item;
1309 bool hover_processed = false;
1310 bool checking = false;
1312 ListViewLabelEditTextBox edit_text_box;
1313 internal ListViewItem edit_item;
1314 LabelEditEventArgs edit_args;
1316 public ItemControl (ListView owner)
1319 DoubleClick += new EventHandler(ItemsDoubleClick);
1320 MouseDown += new MouseEventHandler(ItemsMouseDown);
1321 MouseMove += new MouseEventHandler(ItemsMouseMove);
1322 MouseHover += new EventHandler(ItemsMouseHover);
1323 MouseUp += new MouseEventHandler(ItemsMouseUp);
1326 void ItemsDoubleClick (object sender, EventArgs e)
1328 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1329 owner.ItemActivate (this, e);
1339 BoxSelect box_select_mode = BoxSelect.None;
1340 ArrayList prev_selection;
1341 Point box_select_start;
1343 Rectangle box_select_rect;
1344 internal Rectangle BoxSelectRectangle {
1345 get { return box_select_rect; }
1347 if (box_select_rect == value)
1350 InvalidateBoxSelectRect ();
1351 box_select_rect = value;
1352 InvalidateBoxSelectRect ();
1356 void InvalidateBoxSelectRect ()
1358 if (BoxSelectRectangle.Size.IsEmpty)
1361 Rectangle edge = BoxSelectRectangle;
1367 edge.Y = BoxSelectRectangle.Bottom - 1;
1369 edge.Y = BoxSelectRectangle.Y - 1;
1371 edge.Height = BoxSelectRectangle.Height + 2;
1373 edge.X = BoxSelectRectangle.Right - 1;
1377 private Rectangle CalculateBoxSelectRectangle (Point pt)
1379 int left = Math.Min (box_select_start.X, pt.X);
1380 int right = Math.Max (box_select_start.X, pt.X);
1381 int top = Math.Min (box_select_start.Y, pt.Y);
1382 int bottom = Math.Max (box_select_start.Y, pt.Y);
1383 return Rectangle.FromLTRB (left, top, right, bottom);
1386 ArrayList BoxSelectedItems {
1388 ArrayList result = new ArrayList ();
1389 foreach (ListViewItem item in owner.Items) {
1390 Rectangle r = item.Bounds;
1392 r.Y += r.Height / 4;
1395 if (BoxSelectRectangle.IntersectsWith (r))
1402 private bool PerformBoxSelection (Point pt)
1404 if (box_select_mode == BoxSelect.None)
1407 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1409 ArrayList box_items = BoxSelectedItems;
1413 switch (box_select_mode) {
1415 case BoxSelect.Normal:
1419 case BoxSelect.Control:
1420 items = new ArrayList ();
1421 foreach (ListViewItem item in prev_selection)
1422 if (!box_items.Contains (item))
1424 foreach (ListViewItem item in box_items)
1425 if (!prev_selection.Contains (item))
1429 case BoxSelect.Shift:
1431 foreach (ListViewItem item in box_items)
1432 prev_selection.Remove (item);
1433 foreach (ListViewItem item in prev_selection)
1438 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1442 owner.SelectItems (items);
1448 private void ToggleCheckState (ListViewItem item)
1450 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1451 item.Checked = !item.Checked;
1452 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1454 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1455 owner.OnItemCheck (ice);
1458 private void ItemsMouseDown (object sender, MouseEventArgs me)
1460 if (owner.items.Count == 0)
1463 Point pt = new Point (me.X, me.Y);
1464 foreach (ListViewItem item in owner.items) {
1465 if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
1469 ToggleCheckState (item);
1473 if (owner.View == View.Details && !owner.FullRowSelect) {
1474 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1475 clicked_item = item;
1479 if (item.Bounds.Contains (pt)) {
1480 clicked_item = item;
1487 if (clicked_item != null) {
1488 owner.SetFocusedItem (clicked_item);
1489 bool changed = !clicked_item.Selected;
1490 if (owner.MultiSelect)
1491 owner.UpdateMultiSelection (clicked_item.Index);
1493 clicked_item.Selected = true;
1496 owner.OnSelectedIndexChanged (EventArgs.Empty);
1498 // Raise double click if the item was clicked. On MS the
1499 // double click is only raised if you double click an item
1500 if (me.Clicks > 1) {
1501 owner.OnDoubleClick (EventArgs.Empty);
1502 if (owner.CheckBoxes)
1503 ToggleCheckState (clicked_item);
1504 } else if (me.Clicks == 1) {
1505 owner.OnClick (EventArgs.Empty);
1506 if (owner.LabelEdit && !changed)
1507 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
1510 if (owner.MultiSelect) {
1511 Keys mods = XplatUI.State.ModifierKeys;
1512 if ((mods & Keys.Shift) != 0)
1513 box_select_mode = BoxSelect.Shift;
1514 else if ((mods & Keys.Control) != 0)
1515 box_select_mode = BoxSelect.Control;
1517 box_select_mode = BoxSelect.Normal;
1518 box_select_start = pt;
1519 prev_selection = owner.SelectedItems.List;
1520 } else if (owner.SelectedItems.Count > 0) {
1521 owner.SelectedItems.Clear ();
1522 owner.OnSelectedIndexChanged (EventArgs.Empty);
1527 private void ItemsMouseMove (object sender, MouseEventArgs me)
1529 if (PerformBoxSelection (new Point (me.X, me.Y)))
1532 if (owner.HoverSelection && hover_processed) {
1534 Point pt = PointToClient (Control.MousePosition);
1535 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1536 if (item == null || item.Selected)
1539 hover_processed = false;
1540 XplatUI.ResetMouseHover (Handle);
1545 private void ItemsMouseHover (object sender, EventArgs e)
1547 if (Capture || !owner.HoverSelection)
1550 hover_processed = true;
1551 Point pt = PointToClient (Control.MousePosition);
1552 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1557 item.Selected = true;
1558 owner.OnSelectedIndexChanged (new EventArgs ());
1561 private void ItemsMouseUp (object sender, MouseEventArgs me)
1564 if (owner.Items.Count == 0)
1567 Point pt = new Point (me.X, me.Y);
1569 Rectangle rect = Rectangle.Empty;
1570 if (clicked_item != null) {
1571 if (owner.view == View.Details && !owner.full_row_select)
1572 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1574 rect = clicked_item.Bounds;
1576 if (rect.Contains (pt)) {
1577 switch (owner.activation) {
1578 case ItemActivation.OneClick:
1579 owner.OnItemActivate (EventArgs.Empty);
1582 case ItemActivation.TwoClick:
1583 if (last_clicked_item == clicked_item) {
1584 owner.OnItemActivate (EventArgs.Empty);
1585 last_clicked_item = null;
1587 last_clicked_item = clicked_item;
1590 // DoubleClick activation is handled in another handler
1594 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1595 // Need this to clean up background clicks
1596 owner.SelectedItems.Clear ();
1597 owner.OnSelectedIndexChanged (EventArgs.Empty);
1600 clicked_item = null;
1601 box_select_start = Point.Empty;
1602 BoxSelectRectangle = Rectangle.Empty;
1603 prev_selection = null;
1604 box_select_mode = BoxSelect.None;
1608 internal void LabelEditFinished (object sender, EventArgs e)
1610 EndEdit (edit_item);
1613 internal void BeginEdit (ListViewItem item)
1615 if (edit_item != null)
1616 EndEdit (edit_item);
1618 if (edit_text_box == null) {
1619 edit_text_box = new ListViewLabelEditTextBox ();
1620 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1621 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1622 edit_text_box.Visible = false;
1623 Controls.Add (edit_text_box);
1626 item.EnsureVisible();
1628 edit_text_box.Reset ();
1630 switch (owner.view) {
1632 case View.SmallIcon:
1634 edit_text_box.TextAlign = HorizontalAlignment.Left;
1635 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1636 SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
1637 edit_text_box.Width = (int)sizef.Width + 4;
1638 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
1639 edit_text_box.WordWrap = false;
1640 edit_text_box.Multiline = false;
1642 case View.LargeIcon:
1643 edit_text_box.TextAlign = HorizontalAlignment.Center;
1644 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1645 sizef = DeviceContext.MeasureString (item.Text, item.Font);
1646 edit_text_box.Width = (int)sizef.Width + 4;
1647 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
1648 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
1649 edit_text_box.WordWrap = true;
1650 edit_text_box.Multiline = true;
1654 edit_text_box.Text = item.Text;
1655 edit_text_box.Font = item.Font;
1656 edit_text_box.Visible = true;
1657 edit_text_box.Focus ();
1658 edit_text_box.SelectAll ();
1660 edit_args = new LabelEditEventArgs (owner.Items.IndexOf(edit_item));
1661 owner.OnBeforeLabelEdit (edit_args);
1663 if (edit_args.CancelEdit)
1669 internal void EndEdit (ListViewItem item)
1671 if (edit_text_box != null && edit_text_box.Visible) {
1672 edit_text_box.Visible = false;
1675 if (edit_item != null && edit_item == item) {
1676 owner.OnAfterLabelEdit (edit_args);
1678 if (!edit_args.CancelEdit) {
1679 if (edit_args.Label != null)
1680 edit_item.Text = edit_args.Label;
1682 edit_item.Text = edit_text_box.Text;
1691 internal override void OnPaintInternal (PaintEventArgs pe)
1693 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1696 internal override void OnGotFocusInternal (EventArgs e)
1702 internal class ListViewLabelEditTextBox : TextBox
1707 int max_height = -1;
1708 int min_height = -1;
1710 int old_number_lines = 1;
1712 SizeF text_size_one_char;
1714 public ListViewLabelEditTextBox ()
1716 min_height = DefaultSize.Height;
1717 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1720 public int MaxWidth {
1722 if (value < min_width)
1723 max_width = min_width;
1729 public int MaxHeight {
1731 if (value < min_height)
1732 max_height = min_height;
1738 public new int Width {
1748 public override Font Font {
1754 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1758 protected override void OnTextChanged (EventArgs e)
1760 SizeF text_size = DeviceContext.MeasureString (Text, Font);
1762 int new_width = (int)text_size.Width + 8;
1765 ResizeTextBoxWidth (new_width);
1767 if (Width != max_width)
1768 ResizeTextBoxWidth (new_width);
1770 int number_lines = Lines.Length;
1772 if (number_lines != old_number_lines) {
1773 int new_height = number_lines * (int)text_size_one_char.Height + 4;
1774 old_number_lines = number_lines;
1776 ResizeTextBoxHeight (new_height);
1780 base.OnTextChanged (e);
1783 protected override bool IsInputKey (Keys key_data)
1785 if ((key_data & Keys.Alt) == 0) {
1786 switch (key_data & Keys.KeyCode) {
1791 return base.IsInputKey (key_data);
1794 protected override void OnKeyDown (KeyEventArgs e)
1796 if (e.KeyCode == Keys.Return && Visible) {
1797 this.Visible = false;
1798 OnEditingFinished (e);
1802 protected override void OnLostFocus (EventArgs e)
1805 OnEditingFinished (e);
1809 protected void OnEditingFinished (EventArgs e)
1811 if (EditingFinished != null)
1812 EditingFinished (this, EventArgs.Empty);
1815 private void ResizeTextBoxWidth (int new_width)
1817 if (new_width > max_width)
1818 base.Width = max_width;
1820 if (new_width >= min_width)
1821 base.Width = new_width;
1823 base.Width = min_width;
1826 private void ResizeTextBoxHeight (int new_height)
1828 if (new_height > max_height)
1829 base.Height = max_height;
1831 if (new_height >= min_height)
1832 base.Height = new_height;
1834 base.Height = min_height;
1837 public void Reset ()
1844 old_number_lines = 1;
1846 Text = String.Empty;
1851 public event EventHandler EditingFinished;
1854 internal override void OnPaintInternal (PaintEventArgs pe)
1859 CalculateScrollBars ();
1862 void FocusChanged (object o, EventArgs args)
1864 if (Items.Count == 0)
1867 if (FocusedItem == null)
1868 SetFocusedItem (Items [0]);
1870 item_control.Invalidate (FocusedItem.Bounds);
1873 private void ListView_MouseWheel (object sender, MouseEventArgs me)
1875 if (Items.Count == 0)
1878 int lines = me.Delta / 120;
1885 case View.SmallIcon:
1886 Scroll (v_scroll, -Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1888 case View.LargeIcon:
1889 Scroll (v_scroll, -(Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1892 Scroll (h_scroll, -Items [0].Bounds.Width * lines);
1897 private void ListView_SizeChanged (object sender, EventArgs e)
1899 CalculateListView (alignment);
1902 private void SetFocusedItem (ListViewItem item)
1904 if (focused_item != null)
1905 focused_item.Focused = false;
1908 item.Focused = true;
1910 focused_item = item;
1913 private void HorizontalScroller (object sender, EventArgs e)
1915 item_control.EndEdit (item_control.edit_item);
1917 // Avoid unnecessary flickering, when button is
1918 // kept pressed at the end
1919 if (h_marker != h_scroll.Value) {
1921 int pixels = h_marker - h_scroll.Value;
1923 h_marker = h_scroll.Value;
1924 if (header_control.Visible)
1925 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1927 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1931 private void VerticalScroller (object sender, EventArgs e)
1933 item_control.EndEdit (item_control.edit_item);
1935 // Avoid unnecessary flickering, when button is
1936 // kept pressed at the end
1937 if (v_marker != v_scroll.Value) {
1938 int pixels = v_marker - v_scroll.Value;
1939 Rectangle area = item_control.ClientRectangle;
1940 v_marker = v_scroll.Value;
1941 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1944 #endregion // Internal Methods Properties
1946 #region Protected Methods
1947 protected override void CreateHandle ()
1949 base.CreateHandle ();
1950 for (int i = 0; i < SelectedItems.Count; i++)
1951 OnSelectedIndexChanged (EventArgs.Empty);
1954 protected override void Dispose (bool disposing)
1957 h_scroll.Dispose ();
1958 v_scroll.Dispose ();
1960 large_image_list = null;
1961 small_image_list = null;
1962 state_image_list = null;
1965 base.Dispose (disposing);
1968 protected override bool IsInputKey (Keys keyData)
1985 return base.IsInputKey (keyData);
1988 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1990 if (AfterLabelEdit != null)
1991 AfterLabelEdit (this, e);
1994 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1996 if (BeforeLabelEdit != null)
1997 BeforeLabelEdit (this, e);
2000 protected virtual void OnColumnClick (ColumnClickEventArgs e)
2002 if (ColumnClick != null)
2003 ColumnClick (this, e);
2006 protected override void OnEnabledChanged (EventArgs e)
2008 base.OnEnabledChanged (e);
2011 protected override void OnFontChanged (EventArgs e)
2013 base.OnFontChanged (e);
2017 protected override void OnHandleCreated (EventArgs e)
2019 base.OnHandleCreated (e);
2023 protected override void OnHandleDestroyed (EventArgs e)
2025 base.OnHandleDestroyed (e);
2028 protected virtual void OnItemActivate (EventArgs e)
2030 if (ItemActivate != null)
2031 ItemActivate (this, e);
2034 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
2036 if (ItemCheck != null)
2037 ItemCheck (this, ice);
2040 protected virtual void OnItemDrag (ItemDragEventArgs e)
2042 if (ItemDrag != null)
2046 protected virtual void OnSelectedIndexChanged (EventArgs e)
2048 if (SelectedIndexChanged != null)
2049 SelectedIndexChanged (this, e);
2052 protected override void OnSystemColorsChanged (EventArgs e)
2054 base.OnSystemColorsChanged (e);
2057 protected void RealizeProperties ()
2062 protected void UpdateExtendedStyles ()
2067 protected override void WndProc (ref Message m)
2069 base.WndProc (ref m);
2071 #endregion // Protected Methods
2073 #region Public Instance Methods
2074 public void ArrangeIcons ()
2076 ArrangeIcons (this.alignment);
2079 public void ArrangeIcons (ListViewAlignment alignment)
2081 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2082 if (view == View.LargeIcon || view == View.SmallIcon) {
2083 this.CalculateListView (alignment);
2084 // we have done the calculations already
2085 this.Redraw (false);
2089 public void BeginUpdate ()
2091 // flag to avoid painting
2095 public void Clear ()
2098 items.Clear (); // Redraw (true) called here
2101 public void EndUpdate ()
2103 // flag to avoid painting
2106 // probably, now we need a redraw with recalculations
2110 public void EnsureVisible (int index)
2112 if (index < 0 || index >= items.Count || scrollable == false)
2115 Rectangle view_rect = item_control.ClientRectangle;
2116 Rectangle bounds = items [index].Bounds;
2118 if (view_rect.Contains (bounds))
2121 if (bounds.Left < 0)
2122 h_scroll.Value += bounds.Left;
2123 else if (bounds.Right > view_rect.Right)
2124 h_scroll.Value += (bounds.Right - view_rect.Right);
2127 v_scroll.Value += bounds.Top;
2128 else if (bounds.Bottom > view_rect.Bottom)
2129 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
2132 public ListViewItem GetItemAt (int x, int y)
2134 foreach (ListViewItem item in items) {
2135 if (item.Bounds.Contains (x, y))
2141 public Rectangle GetItemRect (int index)
2143 return GetItemRect (index, ItemBoundsPortion.Entire);
2146 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
2148 if (index < 0 || index >= items.Count)
2149 throw new IndexOutOfRangeException ("index");
2151 return items [index].GetBounds (portion);
2159 // we need this overload to reuse the logic for sorting, while allowing
2160 // redrawing to be done by caller or have it done by this method when
2161 // sorting is really performed
2163 // ListViewItemCollection's Add and AddRange methods call this overload
2164 // with redraw set to false, as they take care of redrawing themselves
2165 // (they even want to redraw the listview if no sort is performed, as
2166 // an item was added), while ListView.Sort () only wants to redraw if
2167 // sorting was actually performed
2168 private void Sort (bool redraw)
2170 if (!IsHandleCreated || item_sorter == null) {
2174 items.Sort (item_sorter);
2179 public override string ToString ()
2181 int count = this.Items.Count;
2184 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2186 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
2188 #endregion // Public Instance Methods
2193 class HeaderControl : Control {
2196 bool column_resize_active = false;
2197 ColumnHeader resize_column;
2198 ColumnHeader clicked_column;
2199 ColumnHeader drag_column;
2201 int drag_to_index = -1;
2203 public HeaderControl (ListView owner)
2206 MouseDown += new MouseEventHandler (HeaderMouseDown);
2207 MouseMove += new MouseEventHandler (HeaderMouseMove);
2208 MouseUp += new MouseEventHandler (HeaderMouseUp);
2211 private ColumnHeader ColumnAtX (int x)
2213 Point pt = new Point (x, 0);
2214 ColumnHeader result = null;
2215 foreach (ColumnHeader col in owner.Columns) {
2216 if (col.Rect.Contains (pt)) {
2224 private int GetReorderedIndex (ColumnHeader col)
2226 if (owner.reordered_column_indices == null)
2229 for (int i = 0; i < owner.Columns.Count; i++)
2230 if (owner.reordered_column_indices [i] == col.Index)
2232 throw new Exception ("Column index missing from reordered array");
2235 private void HeaderMouseDown (object sender, MouseEventArgs me)
2237 if (resize_column != null) {
2238 column_resize_active = true;
2243 clicked_column = ColumnAtX (me.X + owner.h_marker);
2245 if (clicked_column != null) {
2247 if (owner.AllowColumnReorder) {
2249 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
2250 drag_column.column_rect = clicked_column.Rect;
2251 drag_to_index = GetReorderedIndex (clicked_column);
2253 clicked_column.pressed = true;
2254 Rectangle bounds = clicked_column.Rect;
2255 bounds.X -= owner.h_marker;
2256 Invalidate (bounds);
2261 private void HeaderMouseMove (object sender, MouseEventArgs me)
2263 Point pt = new Point (me.X + owner.h_marker, me.Y);
2265 if (column_resize_active) {
2266 resize_column.Width = pt.X - resize_column.X;
2267 if (resize_column.Width < 0)
2268 resize_column.Width = 0;
2272 resize_column = null;
2274 if (clicked_column != null) {
2275 if (owner.AllowColumnReorder) {
2278 r = drag_column.column_rect;
2279 r.X = clicked_column.Rect.X + me.X - drag_x;
2280 drag_column.column_rect = r;
2282 int x = me.X + owner.h_marker;
2283 ColumnHeader over = ColumnAtX (x);
2285 drag_to_index = owner.Columns.Count;
2286 else if (x < over.X + over.Width / 2)
2287 drag_to_index = GetReorderedIndex (over);
2289 drag_to_index = GetReorderedIndex (over) + 1;
2292 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
2293 bool pressed = clicked_column.pressed;
2294 clicked_column.pressed = over == clicked_column;
2295 if (clicked_column.pressed ^ pressed) {
2296 Rectangle bounds = clicked_column.Rect;
2297 bounds.X -= owner.h_marker;
2298 Invalidate (bounds);
2304 for (int i = 0; i < owner.Columns.Count; i++) {
2305 Rectangle zone = owner.Columns [i].Rect;
2306 zone.X = zone.Right - 5;
2308 if (zone.Contains (pt)) {
2309 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
2311 resize_column = owner.Columns [i];
2316 if (resize_column == null)
2317 Cursor = Cursors.Default;
2319 Cursor = Cursors.VSplit;
2322 void HeaderMouseUp (object sender, MouseEventArgs me)
2326 if (column_resize_active) {
2327 column_resize_active = false;
2328 resize_column = null;
2329 Cursor = Cursors.Default;
2333 if (clicked_column != null && clicked_column.pressed) {
2334 clicked_column.pressed = false;
2335 Rectangle bounds = clicked_column.Rect;
2336 bounds.X -= owner.h_marker;
2337 Invalidate (bounds);
2338 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2341 if (drag_column != null && owner.AllowColumnReorder) {
2343 if (drag_to_index > GetReorderedIndex (clicked_column))
2345 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2346 owner.ReorderColumn (clicked_column, drag_to_index);
2351 clicked_column = null;
2354 internal override void OnPaintInternal (PaintEventArgs pe)
2359 Theme theme = ThemeEngine.Current;
2360 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2362 if (drag_column == null)
2366 if (drag_to_index == owner.Columns.Count)
2367 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2369 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2370 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2373 protected override void WndProc (ref Message m)
2375 switch ((Msg)m.Msg) {
2376 case Msg.WM_SETFOCUS:
2380 base.WndProc (ref m);
2386 private class ItemComparer : IComparer {
2387 readonly SortOrder sort_order;
2389 public ItemComparer (SortOrder sortOrder)
2391 sort_order = sortOrder;
2394 public int Compare (object x, object y)
2396 ListViewItem item_x = x as ListViewItem;
2397 ListViewItem item_y = y as ListViewItem;
2398 if (sort_order == SortOrder.Ascending)
2399 return String.Compare (item_x.Text, item_y.Text);
2401 return String.Compare (item_y.Text, item_x.Text);
2405 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2407 private readonly ListView owner;
2409 #region Public Constructor
2410 public CheckedIndexCollection (ListView owner)
2414 #endregion // Public Constructor
2416 #region Public Properties
2419 get { return owner.CheckedItems.Count; }
2422 public bool IsReadOnly {
2423 get { return true; }
2426 public int this [int index] {
2428 int [] indices = GetIndices ();
2429 if (index < 0 || index >= indices.Length)
2430 throw new ArgumentOutOfRangeException ("index");
2431 return indices [index];
2435 bool ICollection.IsSynchronized {
2436 get { return false; }
2439 object ICollection.SyncRoot {
2440 get { return this; }
2443 bool IList.IsFixedSize {
2444 get { return true; }
2447 object IList.this [int index] {
2448 get { return this [index]; }
2449 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2451 #endregion // Public Properties
2453 #region Public Methods
2454 public bool Contains (int checkedIndex)
2456 int [] indices = GetIndices ();
2457 for (int i = 0; i < indices.Length; i++) {
2458 if (indices [i] == checkedIndex)
2464 public IEnumerator GetEnumerator ()
2466 int [] indices = GetIndices ();
2467 return indices.GetEnumerator ();
2470 void ICollection.CopyTo (Array dest, int index)
2472 int [] indices = GetIndices ();
2473 Array.Copy (indices, 0, dest, index, indices.Length);
2476 int IList.Add (object value)
2478 throw new NotSupportedException ("Add operation is not supported.");
2483 throw new NotSupportedException ("Clear operation is not supported.");
2486 bool IList.Contains (object checkedIndex)
2488 if (!(checkedIndex is int))
2490 return Contains ((int) checkedIndex);
2493 int IList.IndexOf (object checkedIndex)
2495 if (!(checkedIndex is int))
2497 return IndexOf ((int) checkedIndex);
2500 void IList.Insert (int index, object value)
2502 throw new NotSupportedException ("Insert operation is not supported.");
2505 void IList.Remove (object value)
2507 throw new NotSupportedException ("Remove operation is not supported.");
2510 void IList.RemoveAt (int index)
2512 throw new NotSupportedException ("RemoveAt operation is not supported.");
2515 public int IndexOf (int checkedIndex)
2517 int [] indices = GetIndices ();
2518 for (int i = 0; i < indices.Length; i++) {
2519 if (indices [i] == checkedIndex)
2524 #endregion // Public Methods
2526 private int [] GetIndices ()
2528 ArrayList checked_items = owner.CheckedItems.List;
2529 int [] indices = new int [checked_items.Count];
2530 for (int i = 0; i < checked_items.Count; i++) {
2531 ListViewItem item = (ListViewItem) checked_items [i];
2532 indices [i] = item.Index;
2536 } // CheckedIndexCollection
2538 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2540 private readonly ListView owner;
2541 private ArrayList list;
2543 #region Public Constructor
2544 public CheckedListViewItemCollection (ListView owner)
2547 this.owner.Items.Changed += new CollectionChangedHandler (
2548 ItemsCollection_Changed);
2550 #endregion // Public Constructor
2552 #region Public Properties
2556 if (!owner.CheckBoxes)
2562 public bool IsReadOnly {
2563 get { return true; }
2566 public ListViewItem this [int index] {
2568 ArrayList checked_items = List;
2569 if (index < 0 || index >= checked_items.Count)
2570 throw new ArgumentOutOfRangeException ("index");
2571 return (ListViewItem) checked_items [index];
2575 bool ICollection.IsSynchronized {
2576 get { return false; }
2579 object ICollection.SyncRoot {
2580 get { return this; }
2583 bool IList.IsFixedSize {
2584 get { return true; }
2587 object IList.this [int index] {
2588 get { return this [index]; }
2589 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2591 #endregion // Public Properties
2593 #region Public Methods
2594 public bool Contains (ListViewItem item)
2596 if (!owner.CheckBoxes)
2598 return List.Contains (item);
2601 public void CopyTo (Array dest, int index)
2603 if (!owner.CheckBoxes)
2605 List.CopyTo (dest, index);
2608 public IEnumerator GetEnumerator ()
2610 if (!owner.CheckBoxes)
2611 return (new ListViewItem [0]).GetEnumerator ();
2612 return List.GetEnumerator ();
2615 int IList.Add (object value)
2617 throw new NotSupportedException ("Add operation is not supported.");
2622 throw new NotSupportedException ("Clear operation is not supported.");
2625 bool IList.Contains (object item)
2627 if (!(item is ListViewItem))
2629 return Contains ((ListViewItem) item);
2632 int IList.IndexOf (object item)
2634 if (!(item is ListViewItem))
2636 return IndexOf ((ListViewItem) item);
2639 void IList.Insert (int index, object value)
2641 throw new NotSupportedException ("Insert operation is not supported.");
2644 void IList.Remove (object value)
2646 throw new NotSupportedException ("Remove operation is not supported.");
2649 void IList.RemoveAt (int index)
2651 throw new NotSupportedException ("RemoveAt operation is not supported.");
2654 public int IndexOf (ListViewItem item)
2656 if (!owner.CheckBoxes)
2658 return List.IndexOf (item);
2660 #endregion // Public Methods
2662 internal ArrayList List {
2665 list = new ArrayList ();
2666 foreach (ListViewItem item in owner.Items) {
2675 internal void Reset ()
2677 // force re-population of list
2681 private void ItemsCollection_Changed ()
2685 } // CheckedListViewItemCollection
2687 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2689 internal ArrayList list;
2690 private ListView owner;
2692 #region Public Constructor
2693 public ColumnHeaderCollection (ListView owner)
2695 list = new ArrayList ();
2698 #endregion // Public Constructor
2700 #region Public Properties
2703 get { return list.Count; }
2706 public bool IsReadOnly {
2707 get { return false; }
2710 public virtual ColumnHeader this [int index] {
2712 if (index < 0 || index >= list.Count)
2713 throw new ArgumentOutOfRangeException ("index");
2714 return (ColumnHeader) list [index];
2718 bool ICollection.IsSynchronized {
2719 get { return true; }
2722 object ICollection.SyncRoot {
2723 get { return this; }
2726 bool IList.IsFixedSize {
2727 get { return list.IsFixedSize; }
2730 object IList.this [int index] {
2731 get { return this [index]; }
2732 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2734 #endregion // Public Properties
2736 #region Public Methods
2737 public virtual int Add (ColumnHeader value)
2740 value.owner = this.owner;
2741 idx = list.Add (value);
2742 if (owner.IsHandleCreated) {
2743 owner.Redraw (true);
2748 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2750 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2751 this.Add (colHeader);
2755 public virtual void AddRange (ColumnHeader [] values)
2757 foreach (ColumnHeader colHeader in values) {
2758 colHeader.owner = this.owner;
2762 owner.Redraw (true);
2765 public virtual void Clear ()
2768 owner.Redraw (true);
2771 public bool Contains (ColumnHeader value)
2773 return list.Contains (value);
2776 public IEnumerator GetEnumerator ()
2778 return list.GetEnumerator ();
2781 void ICollection.CopyTo (Array dest, int index)
2783 list.CopyTo (dest, index);
2786 int IList.Add (object value)
2788 if (! (value is ColumnHeader)) {
2789 throw new ArgumentException ("Not of type ColumnHeader", "value");
2792 return this.Add ((ColumnHeader) value);
2795 bool IList.Contains (object value)
2797 if (! (value is ColumnHeader)) {
2798 throw new ArgumentException ("Not of type ColumnHeader", "value");
2801 return this.Contains ((ColumnHeader) value);
2804 int IList.IndexOf (object value)
2806 if (! (value is ColumnHeader)) {
2807 throw new ArgumentException ("Not of type ColumnHeader", "value");
2810 return this.IndexOf ((ColumnHeader) value);
2813 void IList.Insert (int index, object value)
2815 if (! (value is ColumnHeader)) {
2816 throw new ArgumentException ("Not of type ColumnHeader", "value");
2819 this.Insert (index, (ColumnHeader) value);
2822 void IList.Remove (object value)
2824 if (! (value is ColumnHeader)) {
2825 throw new ArgumentException ("Not of type ColumnHeader", "value");
2828 this.Remove ((ColumnHeader) value);
2831 public int IndexOf (ColumnHeader value)
2833 return list.IndexOf (value);
2836 public void Insert (int index, ColumnHeader value)
2838 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2839 // but it's really only greater.
2840 if (index < 0 || index > list.Count)
2841 throw new ArgumentOutOfRangeException ("index");
2843 value.owner = this.owner;
2844 list.Insert (index, value);
2845 owner.Redraw (true);
2848 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2850 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2851 this.Insert (index, colHeader);
2854 public virtual void Remove (ColumnHeader column)
2856 // TODO: Update Column internal index ?
2857 list.Remove (column);
2858 owner.Redraw (true);
2861 public virtual void RemoveAt (int index)
2863 if (index < 0 || index >= list.Count)
2864 throw new ArgumentOutOfRangeException ("index");
2866 // TODO: Update Column internal index ?
2867 list.RemoveAt (index);
2868 owner.Redraw (true);
2870 #endregion // Public Methods
2873 } // ColumnHeaderCollection
2875 public class ListViewItemCollection : IList, ICollection, IEnumerable
2877 private readonly ArrayList list;
2878 private readonly ListView owner;
2880 #region Public Constructor
2881 public ListViewItemCollection (ListView owner)
2883 list = new ArrayList ();
2886 #endregion // Public Constructor
2888 #region Public Properties
2891 get { return list.Count; }
2894 public bool IsReadOnly {
2895 get { return false; }
2898 public virtual ListViewItem this [int displayIndex] {
2900 if (displayIndex < 0 || displayIndex >= list.Count)
2901 throw new ArgumentOutOfRangeException ("displayIndex");
2902 return (ListViewItem) list [displayIndex];
2906 if (displayIndex < 0 || displayIndex >= list.Count)
2907 throw new ArgumentOutOfRangeException ("displayIndex");
2909 if (list.Contains (value))
2910 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2912 value.Owner = owner;
2913 list [displayIndex] = value;
2916 owner.Redraw (true);
2920 bool ICollection.IsSynchronized {
2921 get { return true; }
2924 object ICollection.SyncRoot {
2925 get { return this; }
2928 bool IList.IsFixedSize {
2929 get { return list.IsFixedSize; }
2932 object IList.this [int index] {
2933 get { return this [index]; }
2935 if (value is ListViewItem)
2936 this [index] = (ListViewItem) value;
2938 this [index] = new ListViewItem (value.ToString ());
2942 #endregion // Public Properties
2944 #region Public Methods
2945 public virtual ListViewItem Add (ListViewItem value)
2947 if (list.Contains (value))
2948 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2950 value.Owner = owner;
2955 owner.Redraw (true);
2959 public virtual ListViewItem Add (string text)
2961 ListViewItem item = new ListViewItem (text);
2962 return this.Add (item);
2965 public virtual ListViewItem Add (string text, int imageIndex)
2967 ListViewItem item = new ListViewItem (text, imageIndex);
2968 return this.Add (item);
2971 public void AddRange (ListViewItem [] values)
2975 foreach (ListViewItem item in values) {
2982 owner.Redraw (true);
2985 public virtual void Clear ()
2987 owner.SetFocusedItem (null);
2988 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2991 owner.Redraw (true);
2994 public bool Contains (ListViewItem item)
2996 return list.Contains (item);
2999 public void CopyTo (Array dest, int index)
3001 list.CopyTo (dest, index);
3004 public IEnumerator GetEnumerator ()
3006 return list.GetEnumerator ();
3009 int IList.Add (object item)
3014 if (item is ListViewItem) {
3015 li = (ListViewItem) item;
3016 if (list.Contains (li))
3017 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3020 li = new ListViewItem (item.ToString ());
3023 result = list.Add (li);
3025 owner.Redraw (true);
3030 bool IList.Contains (object item)
3032 return list.Contains (item);
3035 int IList.IndexOf (object item)
3037 return list.IndexOf (item);
3040 void IList.Insert (int index, object item)
3042 if (item is ListViewItem)
3043 this.Insert (index, (ListViewItem) item);
3045 this.Insert (index, item.ToString ());
3048 void IList.Remove (object item)
3050 Remove ((ListViewItem) item);
3053 public int IndexOf (ListViewItem item)
3055 return list.IndexOf (item);
3058 public ListViewItem Insert (int index, ListViewItem item)
3060 if (index < 0 || index > list.Count)
3061 throw new ArgumentOutOfRangeException ("index");
3063 if (list.Contains (item))
3064 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3067 list.Insert (index, item);
3069 owner.Redraw (true);
3073 public ListViewItem Insert (int index, string text)
3075 return this.Insert (index, new ListViewItem (text));
3078 public ListViewItem Insert (int index, string text, int imageIndex)
3080 return this.Insert (index, new ListViewItem (text, imageIndex));
3083 public virtual void Remove (ListViewItem item)
3085 if (!list.Contains (item))
3088 bool selection_changed = owner.SelectedItems.Contains (item);
3091 owner.Redraw (true);
3092 if (selection_changed)
3093 owner.OnSelectedIndexChanged (EventArgs.Empty);
3096 public virtual void RemoveAt (int index)
3098 if (index < 0 || index >= Count)
3099 throw new ArgumentOutOfRangeException ("index");
3100 bool selection_changed = owner.SelectedIndices.Contains (index);
3101 list.RemoveAt (index);
3103 owner.Redraw (false);
3104 if (selection_changed)
3105 owner.OnSelectedIndexChanged (EventArgs.Empty);
3107 #endregion // Public Methods
3109 internal event CollectionChangedHandler Changed;
3111 internal void Sort (IComparer comparer)
3113 list.Sort (comparer);
3117 internal void OnChange ()
3119 if (Changed != null)
3122 } // ListViewItemCollection
3124 public class SelectedIndexCollection : IList, ICollection, IEnumerable
3126 private readonly ListView owner;
3128 #region Public Constructor
3129 public SelectedIndexCollection (ListView owner)
3133 #endregion // Public Constructor
3135 #region Public Properties
3139 return owner.SelectedItems.Count;
3143 public bool IsReadOnly {
3144 get { return true; }
3147 public int this [int index] {
3149 int [] indices = GetIndices ();
3150 if (index < 0 || index >= indices.Length)
3151 throw new ArgumentOutOfRangeException ("index");
3152 return indices [index];
3156 bool ICollection.IsSynchronized {
3157 get { return false; }
3160 object ICollection.SyncRoot {
3161 get { return this; }
3164 bool IList.IsFixedSize {
3165 get { return true; }
3168 object IList.this [int index] {
3169 get { return this [index]; }
3170 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3172 #endregion // Public Properties
3174 #region Public Methods
3175 public bool Contains (int selectedIndex)
3177 int [] indices = GetIndices ();
3178 for (int i = 0; i < indices.Length; i++) {
3179 if (indices [i] == selectedIndex)
3185 public void CopyTo (Array dest, int index)
3187 int [] indices = GetIndices ();
3188 Array.Copy (indices, 0, dest, index, indices.Length);
3191 public IEnumerator GetEnumerator ()
3193 int [] indices = GetIndices ();
3194 return indices.GetEnumerator ();
3197 int IList.Add (object value)
3199 throw new NotSupportedException ("Add operation is not supported.");
3204 throw new NotSupportedException ("Clear operation is not supported.");
3207 bool IList.Contains (object selectedIndex)
3209 if (!(selectedIndex is int))
3211 return Contains ((int) selectedIndex);
3214 int IList.IndexOf (object selectedIndex)
3216 if (!(selectedIndex is int))
3218 return IndexOf ((int) selectedIndex);
3221 void IList.Insert (int index, object value)
3223 throw new NotSupportedException ("Insert operation is not supported.");
3226 void IList.Remove (object value)
3228 throw new NotSupportedException ("Remove operation is not supported.");
3231 void IList.RemoveAt (int index)
3233 throw new NotSupportedException ("RemoveAt operation is not supported.");
3236 public int IndexOf (int selectedIndex)
3238 int [] indices = GetIndices ();
3239 for (int i = 0; i < indices.Length; i++) {
3240 if (indices [i] == selectedIndex)
3245 #endregion // Public Methods
3247 private int [] GetIndices ()
3249 ArrayList selected_items = owner.SelectedItems.List;
3250 int [] indices = new int [selected_items.Count];
3251 for (int i = 0; i < selected_items.Count; i++) {
3252 ListViewItem item = (ListViewItem) selected_items [i];
3253 indices [i] = item.Index;
3257 } // SelectedIndexCollection
3259 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
3261 private readonly ListView owner;
3262 private ArrayList list;
3264 #region Public Constructor
3265 public SelectedListViewItemCollection (ListView owner)
3268 this.owner.Items.Changed += new CollectionChangedHandler (
3269 ItemsCollection_Changed);
3271 #endregion // Public Constructor
3273 #region Public Properties
3277 if (!owner.IsHandleCreated)
3283 public bool IsReadOnly {
3284 get { return true; }
3287 public ListViewItem this [int index] {
3289 ArrayList selected_items = List;
3290 if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
3291 throw new ArgumentOutOfRangeException ("index");
3292 return (ListViewItem) selected_items [index];
3296 bool ICollection.IsSynchronized {
3297 get { return false; }
3300 object ICollection.SyncRoot {
3301 get { return this; }
3304 bool IList.IsFixedSize {
3305 get { return true; }
3308 object IList.this [int index] {
3309 get { return this [index]; }
3310 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3312 #endregion // Public Properties
3314 #region Public Methods
3315 public void Clear ()
3317 if (!owner.IsHandleCreated)
3320 foreach (ListViewItem item in List)
3321 item.Selected = false;
3324 public bool Contains (ListViewItem item)
3326 if (!owner.IsHandleCreated)
3328 return List.Contains (item);
3331 public void CopyTo (Array dest, int index)
3333 if (!owner.IsHandleCreated)
3335 List.CopyTo (dest, index);
3338 public IEnumerator GetEnumerator ()
3340 if (!owner.IsHandleCreated)
3341 return (new ListViewItem [0]).GetEnumerator ();
3342 return List.GetEnumerator ();
3345 int IList.Add (object value)
3347 throw new NotSupportedException ("Add operation is not supported.");
3350 bool IList.Contains (object item)
3352 if (!(item is ListViewItem))
3354 return Contains ((ListViewItem) item);
3357 int IList.IndexOf (object item)
3359 if (!(item is ListViewItem))
3361 return IndexOf ((ListViewItem) item);
3364 void IList.Insert (int index, object value)
3366 throw new NotSupportedException ("Insert operation is not supported.");
3369 void IList.Remove (object value)
3371 throw new NotSupportedException ("Remove operation is not supported.");
3374 void IList.RemoveAt (int index)
3376 throw new NotSupportedException ("RemoveAt operation is not supported.");
3379 public int IndexOf (ListViewItem item)
3381 if (!owner.IsHandleCreated)
3383 return List.IndexOf (item);
3385 #endregion // Public Methods
3387 internal ArrayList List {
3390 list = new ArrayList ();
3391 foreach (ListViewItem item in owner.Items) {
3400 internal void Reset ()
3402 // force re-population of list
3406 private void ItemsCollection_Changed ()
3410 } // SelectedListViewItemCollection
3412 internal delegate void CollectionChangedHandler ();
3414 #endregion // Subclasses