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)
26 // Daniel Nauck (dna(at)mono-project(dot)de)
27 // Carlos Alberto Cortez <calberto.cortez@gmail.com>
34 using System.Collections;
35 using System.ComponentModel;
36 using System.ComponentModel.Design;
38 using System.Runtime.InteropServices;
39 using System.Globalization;
40 using System.Collections.Generic;
42 namespace System.Windows.Forms
44 [DefaultEvent ("SelectedIndexChanged")]
45 [DefaultProperty ("Items")]
46 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
47 [ClassInterface (ClassInterfaceType.AutoDispatch)]
49 [Docking (DockingBehavior.Ask)]
50 public class ListView : Control
52 private ItemActivation activation = ItemActivation.Standard;
53 private ListViewAlignment alignment = ListViewAlignment.Top;
54 private bool allow_column_reorder;
55 private bool auto_arrange = true;
56 private bool check_boxes;
57 private readonly CheckedIndexCollection checked_indices;
58 private readonly CheckedListViewItemCollection checked_items;
59 private readonly ColumnHeaderCollection columns;
60 internal int focused_item_index = -1;
61 private bool full_row_select;
62 private bool grid_lines;
63 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
64 private bool hide_selection = true;
65 private bool hover_selection;
66 private IComparer item_sorter;
67 private readonly ListViewItemCollection items;
68 private readonly ListViewGroupCollection groups;
69 private bool owner_draw;
70 private bool show_groups = true;
71 private bool label_edit;
72 private bool label_wrap = true;
73 private bool multiselect = true;
74 private bool scrollable = true;
75 private bool hover_pending;
76 private readonly SelectedIndexCollection selected_indices;
77 private readonly SelectedListViewItemCollection selected_items;
78 private SortOrder sort_order = SortOrder.None;
79 private ImageList state_image_list;
80 internal bool updating;
81 private View view = View.LargeIcon;
82 private int layout_wd; // We might draw more than our client area
83 private int layout_ht; // therefore we need to have these two.
84 internal HeaderControl header_control;
85 internal ItemControl item_control;
86 internal ScrollBar h_scroll; // used for scrolling horizontally
87 internal ScrollBar v_scroll; // used for scrolling vertically
88 internal int h_marker; // Position markers for scrolling
89 internal int v_marker;
90 private int keysearch_tickcnt;
91 private string keysearch_text;
92 static private readonly int keysearch_keydelay = 1000;
93 private int[] reordered_column_indices;
94 private int[] reordered_items_indices;
95 private Point [] items_location;
96 private ItemMatrixLocation [] items_matrix_location;
97 private Size item_size; // used for caching item size
98 private int custom_column_width; // used when using Columns with SmallIcon/List views
99 private int hot_item_index = -1;
100 private bool hot_tracking;
101 private ListViewInsertionMark insertion_mark;
102 private bool show_item_tooltips;
103 private ToolTip item_tooltip;
104 private Size tile_size;
105 private bool virtual_mode;
106 private int virtual_list_size;
107 private bool right_to_left_layout;
108 // selection is available after the first time the handle is created, *even* if later
109 // the handle is either recreated or destroyed - so keep this info around.
110 private bool is_selection_available;
112 // internal variables
113 internal ImageList large_image_list;
114 internal ImageList small_image_list;
115 internal Size text_size = Size.Empty;
118 static object AfterLabelEditEvent = new object ();
119 static object BeforeLabelEditEvent = new object ();
120 static object ColumnClickEvent = new object ();
121 static object ItemActivateEvent = new object ();
122 static object ItemCheckEvent = new object ();
123 static object ItemDragEvent = new object ();
124 static object SelectedIndexChangedEvent = new object ();
125 static object DrawColumnHeaderEvent = new object();
126 static object DrawItemEvent = new object();
127 static object DrawSubItemEvent = new object();
128 static object ItemCheckedEvent = new object ();
129 static object ItemMouseHoverEvent = new object ();
130 static object ItemSelectionChangedEvent = new object ();
131 static object CacheVirtualItemsEvent = new object ();
132 static object RetrieveVirtualItemEvent = new object ();
133 static object RightToLeftLayoutChangedEvent = new object ();
134 static object SearchForVirtualItemEvent = new object ();
135 static object VirtualItemsSelectionRangeChangedEvent = new object ();
137 public event LabelEditEventHandler AfterLabelEdit {
138 add { Events.AddHandler (AfterLabelEditEvent, value); }
139 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
144 [EditorBrowsable (EditorBrowsableState.Never)]
145 public new event EventHandler BackgroundImageLayoutChanged {
146 add { base.BackgroundImageLayoutChanged += value; }
147 remove { base.BackgroundImageLayoutChanged -= value; }
150 public event LabelEditEventHandler BeforeLabelEdit {
151 add { Events.AddHandler (BeforeLabelEditEvent, value); }
152 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
155 public event ColumnClickEventHandler ColumnClick {
156 add { Events.AddHandler (ColumnClickEvent, value); }
157 remove { Events.RemoveHandler (ColumnClickEvent, value); }
160 public event DrawListViewColumnHeaderEventHandler DrawColumnHeader {
161 add { Events.AddHandler(DrawColumnHeaderEvent, value); }
162 remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); }
165 public event DrawListViewItemEventHandler DrawItem {
166 add { Events.AddHandler(DrawItemEvent, value); }
167 remove { Events.RemoveHandler(DrawItemEvent, value); }
170 public event DrawListViewSubItemEventHandler DrawSubItem {
171 add { Events.AddHandler(DrawSubItemEvent, value); }
172 remove { Events.RemoveHandler(DrawSubItemEvent, value); }
175 public event EventHandler ItemActivate {
176 add { Events.AddHandler (ItemActivateEvent, value); }
177 remove { Events.RemoveHandler (ItemActivateEvent, value); }
180 public event ItemCheckEventHandler ItemCheck {
181 add { Events.AddHandler (ItemCheckEvent, value); }
182 remove { Events.RemoveHandler (ItemCheckEvent, value); }
185 public event ItemCheckedEventHandler ItemChecked {
186 add { Events.AddHandler (ItemCheckedEvent, value); }
187 remove { Events.RemoveHandler (ItemCheckedEvent, value); }
190 public event ItemDragEventHandler ItemDrag {
191 add { Events.AddHandler (ItemDragEvent, value); }
192 remove { Events.RemoveHandler (ItemDragEvent, value); }
195 public event ListViewItemMouseHoverEventHandler ItemMouseHover {
196 add { Events.AddHandler (ItemMouseHoverEvent, value); }
197 remove { Events.RemoveHandler (ItemMouseHoverEvent, value); }
200 public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged {
201 add { Events.AddHandler (ItemSelectionChangedEvent, value); }
202 remove { Events.RemoveHandler (ItemSelectionChangedEvent, value); }
206 [EditorBrowsable (EditorBrowsableState.Never)]
207 public new event EventHandler PaddingChanged {
208 add { base.PaddingChanged += value; }
209 remove { base.PaddingChanged -= value; }
213 [EditorBrowsable (EditorBrowsableState.Never)]
214 public new event PaintEventHandler Paint {
215 add { base.Paint += value; }
216 remove { base.Paint -= value; }
219 public event EventHandler SelectedIndexChanged {
220 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
221 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
225 [EditorBrowsable (EditorBrowsableState.Never)]
226 public new event EventHandler TextChanged {
227 add { base.TextChanged += value; }
228 remove { base.TextChanged -= value; }
231 public event CacheVirtualItemsEventHandler CacheVirtualItems {
232 add { Events.AddHandler (CacheVirtualItemsEvent, value); }
233 remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); }
236 public event RetrieveVirtualItemEventHandler RetrieveVirtualItem {
237 add { Events.AddHandler (RetrieveVirtualItemEvent, value); }
238 remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); }
241 public event EventHandler RightToLeftLayoutChanged {
242 add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
243 remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
246 public event SearchForVirtualItemEventHandler SearchForVirtualItem {
247 add { Events.AddHandler (SearchForVirtualItemEvent, value); }
248 remove { Events.AddHandler (SearchForVirtualItemEvent, value); }
251 public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged {
252 add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); }
253 remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); }
258 #region Public Constructors
261 background_color = ThemeEngine.Current.ColorWindow;
262 groups = new ListViewGroupCollection (this);
263 items = new ListViewItemCollection (this);
264 items.Changed += new CollectionChangedHandler (OnItemsChanged);
265 checked_indices = new CheckedIndexCollection (this);
266 checked_items = new CheckedListViewItemCollection (this);
267 columns = new ColumnHeaderCollection (this);
268 foreground_color = SystemColors.WindowText;
269 selected_indices = new SelectedIndexCollection (this);
270 selected_items = new SelectedListViewItemCollection (this);
271 items_location = new Point [16];
272 items_matrix_location = new ItemMatrixLocation [16];
273 reordered_items_indices = new int [16];
274 item_tooltip = new ToolTip ();
275 item_tooltip.Active = false;
276 insertion_mark = new ListViewInsertionMark (this);
278 InternalBorderStyle = BorderStyle.Fixed3D;
280 header_control = new HeaderControl (this);
281 header_control.Visible = false;
282 Controls.AddImplicit (header_control);
284 item_control = new ItemControl (this);
285 Controls.AddImplicit (item_control);
287 h_scroll = new ImplicitHScrollBar ();
288 Controls.AddImplicit (this.h_scroll);
290 v_scroll = new ImplicitVScrollBar ();
291 Controls.AddImplicit (this.v_scroll);
293 h_marker = v_marker = 0;
294 keysearch_tickcnt = 0;
296 // scroll bars are disabled initially
297 h_scroll.Visible = false;
298 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
299 v_scroll.Visible = false;
300 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
303 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
304 SizeChanged += new EventHandler (ListView_SizeChanged);
305 GotFocus += new EventHandler (FocusChanged);
306 LostFocus += new EventHandler (FocusChanged);
307 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
308 MouseEnter += new EventHandler (ListView_MouseEnter);
309 Invalidated += new InvalidateEventHandler (ListView_Invalidated);
311 BackgroundImageTiled = false;
313 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
314 | ControlStyles.UseTextForAccessibility
317 #endregion // Public Constructors
319 #region Private Internal Properties
320 internal Size CheckBoxSize {
322 if (this.check_boxes) {
323 if (this.state_image_list != null)
324 return this.state_image_list.ImageSize;
326 return ThemeEngine.Current.ListViewCheckBoxSize;
332 internal Size ItemSize {
334 if (view != View.Details)
337 Size size = new Size ();
338 size.Height = item_size.Height;
339 for (int i = 0; i < columns.Count; i++)
340 size.Width += columns [i].Wd;
349 internal int HotItemIndex {
351 return hot_item_index;
354 hot_item_index = value;
358 internal bool UsingGroups {
360 return show_groups && groups.Count > 0 && view != View.List &&
361 Application.VisualStylesEnabled;
365 internal override bool ScaleChildrenInternal {
366 get { return false; }
369 internal bool UseCustomColumnWidth {
371 return (view == View.List || view == View.SmallIcon) && columns.Count > 0;
375 internal ColumnHeader EnteredColumnHeader {
377 return header_control.EnteredColumnHeader;
380 #endregion // Private Internal Properties
382 #region Protected Properties
383 protected override CreateParams CreateParams {
384 get { return base.CreateParams; }
387 protected override Size DefaultSize {
388 get { return ThemeEngine.Current.ListViewDefaultSize; }
390 protected override bool DoubleBuffered {
392 return base.DoubleBuffered;
395 base.DoubleBuffered = value;
398 #endregion // Protected Properties
400 #region Public Instance Properties
401 [DefaultValue (ItemActivation.Standard)]
402 public ItemActivation Activation {
403 get { return activation; }
405 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
406 value != ItemActivation.TwoClick) {
407 throw new InvalidEnumArgumentException (string.Format
408 ("Enum argument value '{0}' is not valid for Activation", value));
410 if (hot_tracking && value != ItemActivation.OneClick)
411 throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick");
417 [DefaultValue (ListViewAlignment.Top)]
419 public ListViewAlignment Alignment {
420 get { return alignment; }
422 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
423 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
424 throw new InvalidEnumArgumentException (string.Format
425 ("Enum argument value '{0}' is not valid for Alignment", value));
428 if (this.alignment != value) {
430 // alignment does not matter in Details/List views
431 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
437 [DefaultValue (false)]
438 public bool AllowColumnReorder {
439 get { return allow_column_reorder; }
440 set { allow_column_reorder = value; }
443 [DefaultValue (true)]
444 public bool AutoArrange {
445 get { return auto_arrange; }
447 if (auto_arrange != value) {
448 auto_arrange = value;
449 // autoarrange does not matter in Details/List views
450 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
456 public override Color BackColor {
458 if (background_color.IsEmpty)
459 return ThemeEngine.Current.ColorWindow;
461 return background_color;
464 background_color = value;
465 item_control.BackColor = value;
470 [EditorBrowsable (EditorBrowsableState.Never)]
471 public override ImageLayout BackgroundImageLayout {
473 return base.BackgroundImageLayout;
476 base.BackgroundImageLayout = value;
480 [DefaultValue (false)]
481 public bool BackgroundImageTiled {
483 return item_control.BackgroundImageLayout == ImageLayout.Tile;
486 ImageLayout new_image_layout = value ? ImageLayout.Tile : ImageLayout.None;
487 if (new_image_layout == item_control.BackgroundImageLayout)
490 item_control.BackgroundImageLayout = new_image_layout;
494 [DefaultValue (BorderStyle.Fixed3D)]
496 public BorderStyle BorderStyle {
497 get { return InternalBorderStyle; }
498 set { InternalBorderStyle = value; }
501 [DefaultValue (false)]
502 public bool CheckBoxes {
503 get { return check_boxes; }
505 if (check_boxes != value) {
506 if (value && View == View.Tile)
507 throw new NotSupportedException ("CheckBoxes are not"
508 + " supported in Tile view. Choose a different"
509 + " view or set CheckBoxes to false.");
514 //UIA Framework: Event used by ListView to set/unset Toggle Pattern
515 OnUIACheckBoxesChanged ();
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 public CheckedIndexCollection CheckedIndices {
523 get { return checked_indices; }
527 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
528 public CheckedListViewItemCollection CheckedItems {
529 get { return checked_items; }
532 [Editor ("System.Windows.Forms.Design.ColumnHeaderCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
533 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
535 [MergableProperty (false)]
536 public ColumnHeaderCollection Columns {
537 get { return columns; }
541 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
542 public ListViewItem FocusedItem {
544 if (focused_item_index == -1)
547 return GetItemAtDisplayIndex (focused_item_index);
550 if (value == null || value.ListView != this ||
554 SetFocusedItem (value.DisplayIndex);
558 public override Color ForeColor {
560 if (foreground_color.IsEmpty)
561 return ThemeEngine.Current.ColorWindowText;
563 return foreground_color;
565 set { foreground_color = value; }
568 [DefaultValue (false)]
569 public bool FullRowSelect {
570 get { return full_row_select; }
572 if (full_row_select != value) {
573 full_row_select = value;
574 InvalidateSelection ();
579 [DefaultValue (false)]
580 public bool GridLines {
581 get { return grid_lines; }
583 if (grid_lines != value) {
590 [DefaultValue (ColumnHeaderStyle.Clickable)]
591 public ColumnHeaderStyle HeaderStyle {
592 get { return header_style; }
594 if (header_style == value)
598 case ColumnHeaderStyle.Clickable:
599 case ColumnHeaderStyle.Nonclickable:
600 case ColumnHeaderStyle.None:
603 throw new InvalidEnumArgumentException (string.Format
604 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
607 header_style = value;
608 if (view == View.Details)
613 [DefaultValue (true)]
614 public bool HideSelection {
615 get { return hide_selection; }
617 if (hide_selection != value) {
618 hide_selection = value;
619 InvalidateSelection ();
624 [DefaultValue (false)]
625 public bool HotTracking {
630 if (hot_tracking == value)
633 hot_tracking = value;
635 hover_selection = true;
636 activation = ItemActivation.OneClick;
641 [DefaultValue (false)]
642 public bool HoverSelection {
643 get { return hover_selection; }
645 if (hot_tracking && value == false)
646 throw new ArgumentException ("When HotTracking is on, hover selection must be true");
647 hover_selection = value;
651 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
653 public ListViewInsertionMark InsertionMark {
655 return insertion_mark;
659 [Editor ("System.Windows.Forms.Design.ListViewItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
660 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
662 [MergableProperty (false)]
663 public ListViewItemCollection Items {
664 get { return items; }
667 [DefaultValue (false)]
668 public bool LabelEdit {
669 get { return label_edit; }
671 if (value != label_edit) {
674 // UIA Framework: Event used by Value Pattern in ListView.ListItem provider
675 OnUIALabelEditChanged ();
681 [DefaultValue (true)]
683 public bool LabelWrap {
684 get { return label_wrap; }
686 if (label_wrap != value) {
693 [DefaultValue (null)]
694 public ImageList LargeImageList {
695 get { return large_image_list; }
697 large_image_list = value;
703 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
704 public IComparer ListViewItemSorter {
706 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
711 if (item_sorter != value) {
718 [DefaultValue (true)]
719 public bool MultiSelect {
720 get { return multiselect; }
722 if (value != multiselect) {
725 // UIA Framework: Event used by Selection Pattern in ListView.ListItem provider
726 OnUIAMultiSelectChanged ();
732 [DefaultValue(false)]
733 public bool OwnerDraw {
734 get { return owner_draw; }
742 [EditorBrowsable (EditorBrowsableState.Never)]
743 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
744 public new Padding Padding {
749 base.Padding = value;
753 [MonoTODO ("RTL not supported")]
755 [DefaultValue (false)]
756 public virtual bool RightToLeftLayout {
757 get { return right_to_left_layout; }
759 if (right_to_left_layout != value) {
760 right_to_left_layout = value;
761 OnRightToLeftLayoutChanged (EventArgs.Empty);
766 [DefaultValue (true)]
767 public bool Scrollable {
768 get { return scrollable; }
770 if (scrollable != value) {
778 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
779 public SelectedIndexCollection SelectedIndices {
780 get { return selected_indices; }
784 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
785 public SelectedListViewItemCollection SelectedItems {
786 get { return selected_items; }
790 public bool ShowGroups {
791 get { return show_groups; }
793 if (show_groups != value) {
797 // UIA Framework: Used to update a11y Tree
798 OnUIAShowGroupsChanged ();
803 [LocalizableAttribute (true)]
804 [MergableProperty (false)]
805 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
806 [Editor ("System.Windows.Forms.Design.ListViewGroupCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
807 public ListViewGroupCollection Groups {
808 get { return groups; }
811 [DefaultValue (false)]
812 public bool ShowItemToolTips {
814 return show_item_tooltips;
817 show_item_tooltips = value;
818 item_tooltip.Active = false;
822 [DefaultValue (null)]
823 public ImageList SmallImageList {
824 get { return small_image_list; }
826 small_image_list = value;
831 [DefaultValue (SortOrder.None)]
832 public SortOrder Sorting {
833 get { return sort_order; }
835 if (!Enum.IsDefined (typeof (SortOrder), value)) {
836 throw new InvalidEnumArgumentException ("value", (int) value,
840 if (sort_order == value)
845 if (virtual_mode) // Sorting is not allowed in virtual mode
848 if (value == SortOrder.None) {
849 if (item_sorter != null) {
850 // ListViewItemSorter should never be reset for SmallIcon
851 // and LargeIcon view
852 if (View != View.SmallIcon && View != View.LargeIcon)
857 if (item_sorter == null)
858 item_sorter = new ItemComparer (value);
859 if (item_sorter is ItemComparer) {
860 item_sorter = new ItemComparer (value);
867 private void OnImageListChanged (object sender, EventArgs args)
869 item_control.Invalidate ();
872 [DefaultValue (null)]
873 public ImageList StateImageList {
874 get { return state_image_list; }
876 if (state_image_list == value)
879 if (state_image_list != null)
880 state_image_list.Images.Changed -= new EventHandler (OnImageListChanged);
882 state_image_list = value;
884 if (state_image_list != null)
885 state_image_list.Images.Changed += new EventHandler (OnImageListChanged);
893 [EditorBrowsable (EditorBrowsableState.Never)]
894 public override string Text {
895 get { return base.Text; }
897 if (value == base.Text)
906 public Size TileSize {
911 if (value.Width <= 0 || value.Height <= 0)
912 throw new ArgumentOutOfRangeException ("value");
915 if (view == View.Tile)
921 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
922 public ListViewItem TopItem {
924 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
925 throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view.");
927 if (this.items.Count == 0)
929 // if contents are not scrolled
930 // it is the first item
931 else if (h_marker == 0 && v_marker == 0)
932 return this.items [0];
933 // do a hit test for the scrolled position
935 int header_offset = header_control.Height;
936 for (int i = 0; i < items.Count; i++) {
937 Point item_loc = GetItemLocation (i);
938 if (item_loc.X >= 0 && item_loc.Y - header_offset >= 0)
945 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
946 throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view.");
948 // .Net doesn't throw any exception in the cases below
949 if (value == null || value.ListView != this)
952 // Take advantage this property is only valid for Details view.
953 SetScrollValue (v_scroll, item_size.Height * value.Index);
957 [EditorBrowsable (EditorBrowsableState.Advanced)]
958 [DefaultValue (true)]
960 [MonoInternalNote ("Stub, not implemented")]
961 public bool UseCompatibleStateImageBehavior {
969 [DefaultValue (View.LargeIcon)]
973 if (!Enum.IsDefined (typeof (View), value))
974 throw new InvalidEnumArgumentException ("value", (int) value,
978 if (CheckBoxes && value == View.Tile)
979 throw new NotSupportedException ("CheckBoxes are not"
980 + " supported in Tile view. Choose a different"
981 + " view or set CheckBoxes to false.");
982 if (VirtualMode && value == View.Tile)
983 throw new NotSupportedException ("VirtualMode is"
984 + " not supported in Tile view. Choose a different"
985 + " view or set ViewMode to false.");
987 h_scroll.Value = v_scroll.Value = 0;
991 // UIA Framework: Event used to update UIA Tree.
997 [DefaultValue (false)]
998 [RefreshProperties (RefreshProperties.Repaint)]
999 public bool VirtualMode {
1001 return virtual_mode;
1004 if (virtual_mode == value)
1007 if (!virtual_mode && items.Count > 0)
1008 throw new InvalidOperationException ();
1009 if (value && view == View.Tile)
1010 throw new NotSupportedException ("VirtualMode is"
1011 + " not supported in Tile view. Choose a different"
1012 + " view or set ViewMode to false.");
1014 virtual_mode = value;
1020 [RefreshProperties (RefreshProperties.Repaint)]
1021 public int VirtualListSize {
1023 return virtual_list_size;
1027 throw new ArgumentException ("value");
1029 if (virtual_list_size == value)
1032 virtual_list_size = value;
1034 focused_item_index = -1;
1035 selected_indices.Reset ();
1040 #endregion // Public Instance Properties
1042 #region Internal Methods Properties
1044 internal int FirstVisibleIndex {
1047 if (this.items.Count == 0)
1050 if (h_marker == 0 && v_marker == 0)
1053 Size item_size = ItemSize;
1054 // In virtual mode we always have fixed positions, and we can infer the positon easily
1059 first = v_marker / item_size.Height;
1061 case View.LargeIcon:
1062 case View.SmallIcon:
1063 first = (v_marker / (item_size.Height + y_spacing)) * cols;
1066 first = (h_marker / (item_size.Width * x_spacing)) * rows;
1070 if (first >= items.Count)
1071 first = items.Count;
1075 for (int i = 0; i < items.Count; i++) {
1076 Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size);
1077 if (item_rect.Right >= 0 && item_rect.Bottom >= 0)
1086 internal int LastVisibleIndex {
1088 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
1089 if (View == View.List || Alignment == ListViewAlignment.Left) {
1090 if (GetItemLocation (i).X > item_control.ClientRectangle.Right)
1093 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
1098 return Items.Count - 1;
1102 internal void OnSelectedIndexChanged ()
1104 if (is_selection_available)
1105 OnSelectedIndexChanged (EventArgs.Empty);
1108 internal int TotalWidth {
1109 get { return Math.Max (this.Width, this.layout_wd); }
1112 internal int TotalHeight {
1113 get { return Math.Max (this.Height, this.layout_ht); }
1116 internal void Redraw (bool recalculate)
1118 // Avoid calculations when control is being updated
1121 // VirtualMode doesn't do any calculations until handle is created
1122 if (virtual_mode && !IsHandleCreated)
1127 CalculateListView (this.alignment);
1132 void InvalidateSelection ()
1134 foreach (int selected_index in SelectedIndices)
1135 items [selected_index].Invalidate ();
1138 const int text_padding = 15;
1140 internal Size GetChildColumnSize (int index)
1142 Size ret_size = Size.Empty;
1143 ColumnHeader col = this.columns [index];
1145 if (col.Width == -2) { // autosize = max(items, columnheader)
1146 Size size = Size.Ceiling (TextRenderer.MeasureString
1147 (col.Text, this.Font));
1148 size.Width += text_padding;
1149 ret_size = BiggestItem (index);
1150 if (size.Width > ret_size.Width)
1153 else { // -1 and all the values < -2 are put under one category
1154 ret_size = BiggestItem (index);
1155 // fall back to empty columns' width if no subitem is available for a column
1156 if (ret_size.IsEmpty) {
1157 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
1158 if (col.Text.Length > 0)
1159 ret_size.Height = Size.Ceiling (TextRenderer.MeasureString
1160 (col.Text, this.Font)).Height;
1162 ret_size.Height = this.Font.Height;
1166 ret_size.Height += text_padding;
1168 // adjust the size for icon and checkbox for 0th column
1170 ret_size.Width += (this.CheckBoxSize.Width + 4);
1171 if (this.small_image_list != null)
1172 ret_size.Width += this.small_image_list.ImageSize.Width;
1177 // Returns the size of biggest item text in a column
1178 // or the sum of the text and indent count if we are on 2.0
1179 private Size BiggestItem (int col)
1181 Size temp = Size.Empty;
1182 Size ret_size = Size.Empty;
1183 bool use_indent_count = small_image_list != null;
1185 // VirtualMode uses the first item text size
1186 if (virtual_mode && items.Count > 0) {
1187 ListViewItem item = items [0];
1188 ret_size = Size.Ceiling (TextRenderer.MeasureString (item.SubItems[col].Text,
1191 if (use_indent_count)
1192 ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width;
1194 // 0th column holds the item text, we check the size of
1195 // the various subitems falling in that column and get
1196 // the biggest one's size.
1197 foreach (ListViewItem item in items) {
1198 if (col >= item.SubItems.Count)
1201 temp = Size.Ceiling (TextRenderer.MeasureString
1202 (item.SubItems [col].Text, Font));
1204 if (use_indent_count)
1205 temp.Width += item.IndentCount * small_image_list.ImageSize.Width;
1207 if (temp.Width > ret_size.Width)
1212 // adjustment for space in Details view
1213 if (!ret_size.IsEmpty && view == View.Details)
1214 ret_size.Width += ThemeEngine.Current.ListViewItemPaddingWidth;
1219 const int max_wrap_padding = 30;
1221 // Sets the size of the biggest item text as per the view
1222 private void CalcTextSize ()
1224 // clear the old value
1225 text_size = Size.Empty;
1227 if (items.Count == 0)
1230 text_size = BiggestItem (0);
1232 if (view == View.LargeIcon && this.label_wrap) {
1233 Size temp = Size.Empty;
1234 if (this.check_boxes)
1235 temp.Width += 2 * this.CheckBoxSize.Width;
1236 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1237 temp.Width += icon_w + max_wrap_padding;
1238 // wrapping is done for two lines only
1239 if (text_size.Width > temp.Width) {
1240 text_size.Width = temp.Width;
1241 text_size.Height *= 2;
1244 else if (view == View.List) {
1245 // in list view max text shown in determined by the
1246 // control width, even if scolling is enabled.
1247 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
1248 if (this.small_image_list != null)
1249 max_wd -= this.small_image_list.ImageSize.Width;
1251 if (text_size.Width > max_wd)
1252 text_size.Width = max_wd;
1255 // we do the default settings, if we have got 0's
1256 if (text_size.Height <= 0)
1257 text_size.Height = this.Font.Height;
1258 if (text_size.Width <= 0)
1259 text_size.Width = this.Width;
1261 // little adjustment
1262 text_size.Width += 2;
1263 text_size.Height += 2;
1266 private void SetScrollValue (ScrollBar scrollbar, int val)
1269 if (scrollbar == h_scroll)
1270 max = h_scroll.Maximum - h_scroll.LargeChange + 1;
1272 max = v_scroll.Maximum - v_scroll.LargeChange + 1;
1276 else if (val < scrollbar.Minimum)
1277 val = scrollbar.Minimum;
1279 scrollbar.Value = val;
1282 private void Scroll (ScrollBar scrollbar, int delta)
1284 if (delta == 0 || !scrollbar.Visible)
1287 SetScrollValue (scrollbar, scrollbar.Value + delta);
1290 private void CalculateScrollBars ()
1292 Rectangle client_area = ClientRectangle;
1293 int height = client_area.Height;
1294 int width = client_area.Width;
1298 h_scroll.Visible = false;
1299 v_scroll.Visible = false;
1300 item_control.Size = new Size (width, height);
1301 header_control.Width = width;
1305 // Don't calculate if the view is not displayable
1306 if (client_area.Height < 0 || client_area.Width < 0)
1309 // making a scroll bar visible might make
1310 // other scroll bar visible
1311 if (layout_wd > client_area.Right) {
1312 h_scroll.Visible = true;
1313 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1314 v_scroll.Visible = true;
1316 v_scroll.Visible = false;
1317 } else if (layout_ht > client_area.Bottom) {
1318 v_scroll.Visible = true;
1319 if ((layout_wd + v_scroll.Width) > client_area.Right)
1320 h_scroll.Visible = true;
1322 h_scroll.Visible = false;
1324 h_scroll.Visible = false;
1325 v_scroll.Visible = false;
1329 item_size = ItemSize;
1331 if (h_scroll.is_visible) {
1332 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1333 h_scroll.Minimum = 0;
1335 // if v_scroll is visible, adjust the maximum of the
1336 // h_scroll to account for the width of v_scroll
1337 if (v_scroll.Visible) {
1338 h_scroll.Maximum = layout_wd + v_scroll.Width;
1339 h_scroll.Width = client_area.Width - v_scroll.Width;
1342 h_scroll.Maximum = layout_wd;
1343 h_scroll.Width = client_area.Width;
1346 if (view == View.List)
1347 h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing;
1349 h_scroll.SmallChange = Font.Height;
1351 h_scroll.LargeChange = client_area.Width;
1352 height -= h_scroll.Height;
1355 if (v_scroll.is_visible) {
1356 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1357 v_scroll.Minimum = 0;
1359 // if h_scroll is visible, adjust the height of
1360 // v_scroll to account for the height of h_scroll
1361 if (h_scroll.Visible) {
1362 v_scroll.Maximum = layout_ht + h_scroll.Height;
1363 v_scroll.Height = client_area.Height > h_scroll.Height ? client_area.Height - h_scroll.Height : 0;
1365 v_scroll.Maximum = layout_ht;
1366 v_scroll.Height = client_area.Height;
1369 if (view == View.Details) {
1370 // Need to update Maximum if using LargeChange with value other than the visible area
1371 int headerPlusOneItem = header_control.Height + item_size.Height;
1372 v_scroll.LargeChange = v_scroll.Height > headerPlusOneItem ? v_scroll.Height - headerPlusOneItem : 0;
1373 v_scroll.Maximum = v_scroll.Maximum > headerPlusOneItem ? v_scroll.Maximum - headerPlusOneItem : 0;
1375 v_scroll.LargeChange = v_scroll.Height;
1377 v_scroll.SmallChange = item_size.Height;
1378 width -= v_scroll.Width;
1381 item_control.Size = new Size (width, height);
1383 if (header_control.is_visible)
1384 header_control.Width = width;
1387 internal int GetReorderedColumnIndex (ColumnHeader column)
1389 if (reordered_column_indices == null)
1390 return column.Index;
1392 for (int i = 0; i < Columns.Count; i++)
1393 if (reordered_column_indices [i] == column.Index)
1399 internal ColumnHeader GetReorderedColumn (int index)
1401 if (reordered_column_indices == null)
1402 return Columns [index];
1404 return Columns [reordered_column_indices [index]];
1407 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1410 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1412 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1416 header_control.Invalidate ();
1417 item_control.Invalidate ();
1422 int column_count = Columns.Count;
1424 if (reordered_column_indices == null) {
1425 reordered_column_indices = new int [column_count];
1426 for (int i = 0; i < column_count; i++)
1427 reordered_column_indices [i] = i;
1430 if (reordered_column_indices [index] == col.Index)
1433 int[] curr = reordered_column_indices;
1434 int [] result = new int [column_count];
1436 for (int i = 0; i < column_count; i++) {
1437 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1441 result [i] = col.Index;
1443 result [i] = curr [curr_idx++];
1446 ReorderColumns (result, true);
1449 internal void ReorderColumns (int [] display_indices, bool redraw)
1451 reordered_column_indices = display_indices;
1452 for (int i = 0; i < Columns.Count; i++) {
1453 ColumnHeader col = Columns [i];
1454 col.InternalDisplayIndex = reordered_column_indices [i];
1456 if (redraw && view == View.Details && IsHandleCreated) {
1458 header_control.Invalidate ();
1459 item_control.Invalidate ();
1463 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1465 int column_count = Columns.Count;
1466 newCol.SetListView (this);
1468 int [] display_indices = new int [column_count];
1469 for (int i = 0; i < column_count; i++) {
1470 ColumnHeader col = Columns [i];
1472 display_indices [i] = index;
1474 int display_index = col.InternalDisplayIndex;
1475 if (display_index < index) {
1476 display_indices [i] = display_index;
1478 display_indices [i] = (display_index + 1);
1483 ReorderColumns (display_indices, redraw);
1487 Size LargeIconItemSize
1490 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1491 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1492 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1493 int w = Math.Max (text_size.Width, image_w);
1496 w += 2 + CheckBoxSize.Width;
1498 return new Size (w, h);
1502 Size SmallIconItemSize {
1504 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1505 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1506 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1507 int w = text_size.Width + image_w;
1510 w += 2 + CheckBoxSize.Width;
1512 return new Size (w, h);
1518 // Calculate tile size if needed
1519 // It appears that using Font.Size instead of a SizeF value can give us
1520 // a slightly better approach to the proportions defined in .Net
1521 if (tile_size == Size.Empty) {
1522 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1523 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1524 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1525 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1527 tile_size = new Size (w, h);
1534 int GetDetailsItemHeight ()
1537 int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1538 int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1539 item_height = Math.Max (checkbox_height, text_size.Height);
1540 item_height = Math.Max (item_height, small_image_height);
1544 void SetItemLocation (int index, int x, int y, int row, int col)
1546 Point old_location = items_location [index];
1547 if (old_location.X == x && old_location.Y == y)
1550 items_location [index] = new Point (x, y);
1551 items_matrix_location [index] = new ItemMatrixLocation (row, col);
1554 // Initial position matches item's position in ListViewItemCollection
1556 reordered_items_indices [index] = index;
1560 void ShiftItemsPositions (int from, int to, bool forward)
1563 for (int i = to + 1; i > from; i--) {
1564 reordered_items_indices [i] = reordered_items_indices [i - 1];
1566 ListViewItem item = items [reordered_items_indices [i]];
1568 item.DisplayIndex = i;
1572 for (int i = from - 1; i < to; i++) {
1573 reordered_items_indices [i] = reordered_items_indices [i + 1];
1575 ListViewItem item = items [reordered_items_indices [i]];
1577 item.DisplayIndex = i;
1583 internal void ChangeItemLocation (int display_index, Point new_pos)
1585 int new_display_index = GetDisplayIndexFromLocation (new_pos);
1586 if (new_display_index == display_index)
1589 int item_index = reordered_items_indices [display_index];
1590 ListViewItem item = items [item_index];
1592 bool forward = new_display_index < display_index;
1593 int index_from, index_to;
1595 index_from = new_display_index;
1596 index_to = display_index - 1;
1598 index_from = display_index + 1;
1599 index_to = new_display_index;
1602 ShiftItemsPositions (index_from, index_to, forward);
1604 reordered_items_indices [new_display_index] = item_index;
1607 item.DisplayIndex = new_display_index;
1611 int GetDisplayIndexFromLocation (Point loc)
1613 int display_index = -1;
1614 Rectangle item_area;
1617 if (loc.X < 0 || loc.Y < 0)
1620 // Adjustment to put in the next position refered by 'loc'
1621 loc.X -= item_size.Width / 2;
1625 for (int i = 0; i < items.Count; i++) {
1626 item_area = new Rectangle (GetItemLocation (i), item_size);
1627 item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing,
1628 ThemeEngine.Current.ListViewVerticalSpacing);
1630 if (item_area.Contains (loc)) {
1636 // Put in in last position
1637 if (display_index == -1)
1638 display_index = items.Count - 1;
1640 return display_index;
1643 // When using groups, the items with no group assigned
1644 // belong to the DefaultGroup
1645 int GetDefaultGroupItems ()
1648 foreach (ListViewItem item in items)
1649 if (item.Group == null)
1655 // cache the spacing to let virtualmode compute the positions on the fly
1660 int[,] item_index_matrix;
1662 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1664 Rectangle area = ClientRectangle;
1666 if (UseCustomColumnWidth)
1667 CalculateCustomColumnWidth ();
1669 // When groups are used the alignment is always top-aligned
1674 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1675 for (int i = 0; i < groups.InternalCount; i++) {
1676 ListViewGroup group = groups.GetInternalGroup (i);
1677 int items_in_group = group.GetActualItemCount ();
1679 if (items_in_group == 0)
1682 int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1683 if (group_cols <= 0)
1685 int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols);
1687 group.starting_row = rows;
1688 group.rows = group_rows;
1689 group.starting_item = items;
1690 group.current_item = 0; // Reset layout
1692 cols = Math.Max (group_cols, cols);
1694 items += items_in_group;
1698 // Simple matrix if no groups are used
1700 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1703 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1705 if (UseCustomColumnWidth)
1706 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width));
1708 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1713 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1717 item_index_matrix = new int [rows, cols];
1720 // When using custom column width, we look for the minimum one
1721 void CalculateCustomColumnWidth ()
1723 int min_width = Int32.MaxValue;
1724 for (int i = 0; i < columns.Count; i++) {
1725 int col_width = columns [i].Width;
1727 if (col_width < min_width)
1728 min_width = col_width;
1731 custom_column_width = min_width;
1734 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1736 header_control.Visible = false;
1737 header_control.Size = Size.Empty;
1738 item_control.Visible = true;
1739 item_control.Location = Point.Empty;
1740 ItemSize = item_size; // Cache item size
1741 this.x_spacing = x_spacing;
1742 this.y_spacing = y_spacing;
1744 if (items.Count == 0)
1747 Size sz = item_size;
1749 CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing);
1751 layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing;
1752 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1754 if (virtual_mode) { // no actual assignment is needed on items for virtual mode
1755 item_control.Size = new Size (layout_wd, layout_ht);
1759 bool using_groups = UsingGroups;
1760 if (using_groups) // the groups layout will override layout_ht
1761 CalculateGroupsLayout (sz, y_spacing, 0);
1763 int row = 0, col = 0;
1765 int display_index = 0;
1767 for (int i = 0; i < items.Count; i++) {
1768 ListViewItem item = items [i];
1770 ListViewGroup group = item.Group;
1772 group = groups.DefaultGroup;
1774 Point group_items_loc = group.items_area_location;
1775 int current_item = group.current_item++;
1776 int starting_row = group.starting_row;
1778 display_index = group.starting_item + current_item;
1779 row = (current_item / cols);
1780 col = current_item % cols;
1782 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1783 y = row * (item_size.Height + y_spacing) + group_items_loc.Y;
1785 SetItemLocation (display_index, x, y, row + starting_row, col);
1786 SetItemAtDisplayIndex (display_index, i);
1787 item_index_matrix [row + starting_row, col] = i;
1791 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1792 y = row * (item_size.Height + y_spacing);
1793 display_index = i; // Same as item index in Items
1795 SetItemLocation (i, x, y, row, col);
1796 item_index_matrix [row, col] = i;
1805 if (++col == cols) {
1813 item.DisplayIndex = display_index;
1814 item.SetPosition (new Point (x, y));
1817 item_control.Size = new Size (layout_wd, layout_ht);
1820 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin)
1823 bool details = view == View.Details;
1825 for (int i = 0; i < groups.InternalCount; i++) {
1826 ListViewGroup group = groups.GetInternalGroup (i);
1827 if (group.ItemCount == 0)
1830 y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows);
1833 layout_ht = y; // Update height taking into account Groups' headers heights
1836 int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows)
1838 Rectangle client_area = ClientRectangle;
1839 int header_height = Font.Height + 15; // one line height + some padding
1841 group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height);
1842 group.items_area_location = new Point (0, y_origin + header_height);
1844 int items_area_height = ((item_height + y_spacing) * rows);
1845 return header_height + items_area_height + 10; // Add a small bottom margin
1848 void CalculateDetailsGroupItemsCount ()
1852 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1853 for (int i = 0; i < groups.InternalCount; i++) {
1854 ListViewGroup group = groups.GetInternalGroup (i);
1855 int items_in_group = group.GetActualItemCount ();
1857 if (items_in_group == 0)
1860 group.starting_item = items;
1861 group.current_item = 0; // Reset layout.
1862 items += items_in_group;
1866 void LayoutHeader ()
1869 for (int i = 0; i < Columns.Count; i++) {
1870 ColumnHeader col = GetReorderedColumn (i);
1873 col.CalcColumnHeader ();
1879 if (x < ClientRectangle.Width)
1880 x = ClientRectangle.Width;
1882 if (header_style == ColumnHeaderStyle.None) {
1883 header_control.Visible = false;
1884 header_control.Size = Size.Empty;
1885 layout_wd = ClientRectangle.Width;
1887 header_control.Width = x;
1888 header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font);
1889 header_control.Visible = true;
1893 void LayoutDetails ()
1897 if (columns.Count == 0) {
1898 item_control.Visible = false;
1899 layout_wd = ClientRectangle.Width;
1900 layout_ht = ClientRectangle.Height;
1904 item_control.Visible = true;
1905 item_control.Location = Point.Empty;
1906 item_control.Width = ClientRectangle.Width;
1907 AdjustChildrenZOrder ();
1909 int item_height = GetDetailsItemHeight ();
1910 ItemSize = new Size (0, item_height); // We only cache Height for details view
1911 int y = header_control.Height;
1912 layout_ht = y + (item_height * items.Count);
1913 if (items.Count > 0 && grid_lines) // some space for bottom gridline
1916 bool using_groups = UsingGroups;
1918 // Observe that this routines will override our layout_ht value
1919 CalculateDetailsGroupItemsCount ();
1920 CalculateGroupsLayout (ItemSize, 2, y);
1923 if (virtual_mode) // no assgination on items is needed
1926 for (int i = 0; i < items.Count; i++) {
1927 ListViewItem item = items [i];
1933 ListViewGroup group = item.Group;
1935 group = groups.DefaultGroup;
1937 int current_item = group.current_item++;
1938 Point group_items_loc = group.items_area_location;
1939 display_index = group.starting_item + current_item;
1941 y = item_y = current_item * (item_height + 2) + group_items_loc.Y;
1942 SetItemLocation (display_index, 0, item_y, 0, 0);
1943 SetItemAtDisplayIndex (display_index, i);
1948 SetItemLocation (i, 0, item_y, 0, 0);
1953 item.DisplayIndex = display_index;
1954 item.SetPosition (new Point (0, item_y));
1958 // Need to make sure HeaderControl is on top, and we can't simply use BringToFront since
1959 // these controls are implicit, so we need to re-populate our collection.
1960 void AdjustChildrenZOrder ()
1963 Controls.ClearImplicit ();
1964 Controls.AddImplicit (header_control);
1965 Controls.AddImplicit (item_control);
1966 Controls.AddImplicit (h_scroll);
1967 Controls.AddImplicit (v_scroll);
1971 private void AdjustItemsPositionArray (int count)
1973 // In virtual mode we compute the positions on the fly.
1976 if (items_location.Length >= count)
1979 // items_location, items_matrix_location and reordered_items_indices must keep the same length
1980 count = Math.Max (count, items_location.Length * 2);
1981 items_location = new Point [count];
1982 items_matrix_location = new ItemMatrixLocation [count];
1983 reordered_items_indices = new int [count];
1986 private void CalculateListView (ListViewAlignment align)
1990 AdjustItemsPositionArray (items.Count);
1997 case View.SmallIcon:
1998 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
1999 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2002 case View.LargeIcon:
2003 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
2004 ThemeEngine.Current.ListViewHorizontalSpacing,
2005 ThemeEngine.Current.ListViewVerticalSpacing);
2009 LayoutIcons (SmallIconItemSize, true,
2010 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2013 if (!Application.VisualStylesEnabled)
2014 goto case View.LargeIcon;
2016 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
2017 ThemeEngine.Current.ListViewHorizontalSpacing,
2018 ThemeEngine.Current.ListViewVerticalSpacing);
2022 CalculateScrollBars ();
2025 internal Point GetItemLocation (int index)
2027 Point loc = Point.Empty;
2029 loc = GetFixedItemLocation (index);
2031 loc = items_location [index];
2033 loc.X -= h_marker; // Adjust to scroll
2039 Point GetFixedItemLocation (int index)
2041 Point loc = Point.Empty;
2044 case View.LargeIcon:
2045 case View.SmallIcon:
2046 loc.X = index % cols * (item_size.Width + x_spacing);
2047 loc.Y = index / cols * (item_size.Height + y_spacing);
2050 loc.X = index / rows * (item_size.Width + x_spacing);
2051 loc.Y = index % rows * (item_size.Height + y_spacing);
2054 loc.Y = header_control.Height + (index * item_size.Height);
2061 internal int GetItemIndex (int display_index)
2064 return display_index; // no reordering in virtual mode.
2065 return reordered_items_indices [display_index];
2068 internal ListViewItem GetItemAtDisplayIndex (int display_index)
2070 // in virtual mode there's no reordering at all.
2072 return items [display_index];
2073 return items [reordered_items_indices [display_index]];
2076 internal void SetItemAtDisplayIndex (int display_index, int index)
2078 reordered_items_indices [display_index] = index;
2081 private bool KeySearchString (KeyEventArgs ke)
2083 int current_tickcnt = Environment.TickCount;
2084 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2085 keysearch_text = string.Empty;
2088 if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2091 keysearch_text += (char)ke.KeyCode;
2092 keysearch_tickcnt = current_tickcnt;
2094 int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex;
2095 int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0;
2097 ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true);
2098 if (item != null && prev_focused != item.DisplayIndex) {
2099 selected_indices.Clear ();
2101 SetFocusedItem (item.DisplayIndex);
2102 item.Selected = true;
2103 EnsureVisible (GetItemIndex (item.DisplayIndex));
2109 private void OnItemsChanged ()
2111 ResetSearchString ();
2114 private void ResetSearchString ()
2116 keysearch_text = String.Empty;
2119 int GetAdjustedIndex (Keys key)
2123 if (View == View.Details) {
2126 result = FocusedItem.DisplayIndex - 1;
2129 result = FocusedItem.DisplayIndex + 1;
2130 if (result == items.Count)
2134 int last_index = LastVisibleIndex;
2135 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2136 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2138 if (FocusedItem.DisplayIndex == last_index) {
2139 if (FocusedItem.DisplayIndex < Items.Count - 1) {
2140 int page_size = item_control.Height / ItemSize.Height - 1;
2141 result = FocusedItem.DisplayIndex + page_size - 1;
2142 if (result >= Items.Count)
2143 result = Items.Count - 1;
2146 result = last_index;
2149 int first_index = FirstVisibleIndex;
2150 if (GetItemLocation (first_index).Y < 0)
2152 if (FocusedItem.DisplayIndex == first_index) {
2153 if (first_index > 0) {
2154 int page_size = item_control.Height / ItemSize.Height - 1;
2155 result = first_index - page_size + 1;
2160 result = first_index;
2167 return GetFixedAdjustedIndex (key);
2169 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex];
2170 int row = item_matrix_location.Row;
2171 int col = item_matrix_location.Col;
2173 int adjusted_index = -1;
2179 adjusted_index = item_index_matrix [row, col - 1];
2183 if (col == (cols - 1))
2185 while (item_index_matrix [row, col + 1] == 0) {
2190 adjusted_index = item_index_matrix [row, col + 1];
2196 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2201 adjusted_index = item_index_matrix [row - 1, col];
2205 if (row == (rows - 1) || row == Items.Count - 1)
2207 while (item_index_matrix [row + 1, col] == 0) {
2212 adjusted_index = item_index_matrix [row + 1, col];
2219 return items [adjusted_index].DisplayIndex;
2222 // Used for virtual mode, where items *cannot* be re-arranged
2223 int GetFixedAdjustedIndex (Keys key)
2229 if (view == View.List)
2230 result = focused_item_index - rows;
2232 result = focused_item_index - 1;
2235 if (view == View.List)
2236 result = focused_item_index + rows;
2238 result = focused_item_index + 1;
2241 if (view != View.List)
2242 result = focused_item_index - cols;
2244 result = focused_item_index - 1;
2247 if (view != View.List)
2248 result = focused_item_index + cols;
2250 result = focused_item_index + 1;
2257 if (result < 0 || result >= items.Count)
2258 result = focused_item_index;
2263 ListViewItem selection_start;
2265 private bool SelectItems (ArrayList sel_items)
2267 bool changed = false;
2268 foreach (ListViewItem item in SelectedItems)
2269 if (!sel_items.Contains (item)) {
2270 item.Selected = false;
2273 foreach (ListViewItem item in sel_items)
2274 if (!item.Selected) {
2275 item.Selected = true;
2281 private void UpdateMultiSelection (int index, bool reselect)
2283 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2284 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2285 ListViewItem item = GetItemAtDisplayIndex (index);
2287 if (shift_pressed && selection_start != null) {
2288 ArrayList list = new ArrayList ();
2289 int start_index = selection_start.DisplayIndex;
2290 int start = Math.Min (start_index, index);
2291 int end = Math.Max (start_index, index);
2292 if (View == View.Details) {
2293 for (int i = start; i <= end; i++)
2294 list.Add (GetItemAtDisplayIndex (i));
2296 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2297 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2298 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2299 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2300 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2301 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2303 for (int i = 0; i < items.Count; i++) {
2304 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2306 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2307 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2308 list.Add (GetItemAtDisplayIndex (i));
2312 } else if (ctrl_pressed) {
2313 item.Selected = !item.Selected;
2314 selection_start = item;
2317 // do not unselect, and reselect the item
2318 foreach (int itemIndex in SelectedIndices) {
2319 if (index == itemIndex)
2321 items [itemIndex].Selected = false;
2324 SelectedItems.Clear ();
2325 item.Selected = true;
2327 selection_start = item;
2331 internal override bool InternalPreProcessMessage (ref Message msg)
2333 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2334 Keys key_data = (Keys)msg.WParam.ToInt32();
2336 HandleNavKeys (key_data);
2339 return base.InternalPreProcessMessage (ref msg);
2342 bool HandleNavKeys (Keys key_data)
2344 if (Items.Count == 0 || !item_control.Visible)
2347 if (FocusedItem == null)
2352 SelectIndex (Items.Count - 1);
2365 SelectIndex (GetAdjustedIndex (key_data));
2369 SelectIndex (focused_item_index);
2370 ToggleItemsCheckState ();
2373 if (selected_indices.Count > 0)
2374 OnItemActivate (EventArgs.Empty);
2384 void ToggleItemsCheckState ()
2389 // Don't modify check state if StateImageList has less than 2 elements
2390 if (StateImageList != null && StateImageList.Images.Count < 2)
2393 if (SelectedIndices.Count > 0) {
2394 for (int i = 0; i < SelectedIndices.Count; i++) {
2395 ListViewItem item = Items [SelectedIndices [i]];
2396 item.Checked = !item.Checked;
2401 if (FocusedItem != null) {
2402 FocusedItem.Checked = !FocusedItem.Checked;
2403 SelectIndex (FocusedItem.Index);
2407 void SelectIndex (int display_index)
2409 if (display_index == -1)
2413 UpdateMultiSelection (display_index, true);
2414 else if (!GetItemAtDisplayIndex (display_index).Selected)
2415 GetItemAtDisplayIndex (display_index).Selected = true;
2417 SetFocusedItem (display_index);
2418 EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index
2421 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2423 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2426 if (ke.Alt || ke.Control)
2429 ke.Handled = KeySearchString (ke);
2432 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2434 Point loc = PointToClient (Control.MousePosition);
2435 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2438 internal class ItemControl : Control {
2441 ListViewItem clicked_item;
2442 ListViewItem last_clicked_item;
2443 bool hover_processed = false;
2444 bool checking = false;
2445 ListViewItem prev_hovered_item;
2446 ListViewItem prev_tooltip_item;
2448 Point drag_begin = new Point (-1, -1);
2449 internal int dragged_item_index = -1;
2451 ListViewLabelEditTextBox edit_text_box;
2452 internal ListViewItem edit_item;
2453 LabelEditEventArgs edit_args;
2455 public ItemControl (ListView owner)
2458 this.SetStyle (ControlStyles.DoubleBuffer, true);
2459 DoubleClick += new EventHandler(ItemsDoubleClick);
2460 MouseDown += new MouseEventHandler(ItemsMouseDown);
2461 MouseMove += new MouseEventHandler(ItemsMouseMove);
2462 MouseHover += new EventHandler(ItemsMouseHover);
2463 MouseUp += new MouseEventHandler(ItemsMouseUp);
2466 void ItemsDoubleClick (object sender, EventArgs e)
2468 if (owner.activation == ItemActivation.Standard)
2469 owner.OnItemActivate (EventArgs.Empty);
2479 BoxSelect box_select_mode = BoxSelect.None;
2480 IList prev_selection;
2481 Point box_select_start;
2483 Rectangle box_select_rect;
2484 internal Rectangle BoxSelectRectangle {
2485 get { return box_select_rect; }
2487 if (box_select_rect == value)
2490 InvalidateBoxSelectRect ();
2491 box_select_rect = value;
2492 InvalidateBoxSelectRect ();
2496 void InvalidateBoxSelectRect ()
2498 if (BoxSelectRectangle.Size.IsEmpty)
2501 Rectangle edge = BoxSelectRectangle;
2507 edge.Y = BoxSelectRectangle.Bottom - 1;
2509 edge.Y = BoxSelectRectangle.Y - 1;
2511 edge.Height = BoxSelectRectangle.Height + 2;
2513 edge.X = BoxSelectRectangle.Right - 1;
2517 private Rectangle CalculateBoxSelectRectangle (Point pt)
2519 int left = Math.Min (box_select_start.X, pt.X);
2520 int right = Math.Max (box_select_start.X, pt.X);
2521 int top = Math.Min (box_select_start.Y, pt.Y);
2522 int bottom = Math.Max (box_select_start.Y, pt.Y);
2523 return Rectangle.FromLTRB (left, top, right, bottom);
2526 bool BoxIntersectsItem (int index)
2528 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2529 if (owner.View != View.Details) {
2531 r.Y += r.Height / 4;
2535 return BoxSelectRectangle.IntersectsWith (r);
2538 bool BoxIntersectsText (int index)
2540 Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds;
2541 return BoxSelectRectangle.IntersectsWith (r);
2544 ArrayList BoxSelectedItems {
2546 ArrayList result = new ArrayList ();
2547 for (int i = 0; i < owner.Items.Count; i++) {
2549 // Can't iterate over specific items properties in virtualmode
2550 if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode)
2551 intersects = BoxIntersectsText (i);
2553 intersects = BoxIntersectsItem (i);
2556 result.Add (owner.GetItemAtDisplayIndex (i));
2562 private bool PerformBoxSelection (Point pt)
2564 if (box_select_mode == BoxSelect.None)
2567 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2569 ArrayList box_items = BoxSelectedItems;
2573 switch (box_select_mode) {
2575 case BoxSelect.Normal:
2579 case BoxSelect.Control:
2580 items = new ArrayList ();
2581 foreach (int index in prev_selection)
2582 if (!box_items.Contains (owner.Items [index]))
2583 items.Add (owner.Items [index]);
2584 foreach (ListViewItem item in box_items)
2585 if (!prev_selection.Contains (item.Index))
2589 case BoxSelect.Shift:
2591 foreach (ListViewItem item in box_items)
2592 prev_selection.Remove (item.Index);
2593 foreach (int index in prev_selection)
2594 items.Add (owner.Items [index]);
2598 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2602 owner.SelectItems (items);
2608 private void ItemsMouseDown (object sender, MouseEventArgs me)
2610 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2611 if (owner.items.Count == 0)
2614 bool box_selecting = false;
2615 Size item_size = owner.ItemSize;
2616 Point pt = new Point (me.X, me.Y);
2617 for (int i = 0; i < owner.items.Count; i++) {
2618 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2619 if (!item_rect.Contains (pt))
2622 // Actual item in 'i' position
2623 ListViewItem item = owner.GetItemAtDisplayIndex (i);
2625 if (item.CheckRectReal.Contains (pt)) {
2626 // Don't modify check state if we have only one image
2627 // and if we are in 1.1 profile only take into account
2629 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2633 // Generate an extra ItemCheck event when we got two clicks
2634 // (Match weird .Net behaviour)
2636 item.Checked = !item.Checked;
2638 item.Checked = !item.Checked;
2643 if (owner.View == View.Details) {
2644 bool over_text = item.TextBounds.Contains (pt);
2645 if (owner.FullRowSelect) {
2646 clicked_item = item;
2647 bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2648 if (!over_text && over_item_column && owner.MultiSelect)
2649 box_selecting = true;
2650 } else if (over_text)
2651 clicked_item = item;
2653 owner.SetFocusedItem (i);
2655 clicked_item = item;
2661 if (clicked_item != null) {
2662 bool changed = !clicked_item.Selected;
2663 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2664 owner.SetFocusedItem (clicked_item.DisplayIndex);
2666 if (owner.MultiSelect) {
2667 bool reselect = (!owner.LabelEdit || changed);
2668 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2669 owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect);
2671 clicked_item.Selected = true;
2672 // Side-effects to setting Selected can possibly result in ItemsMouseUp() being called
2673 // and clicked_item being set to null. (See Xamarin bug 23591.) In such a case, assume
2674 // that there's nothing more we can do here.
2675 if (clicked_item == null)
2679 if (owner.VirtualMode && changed) {
2680 // Broken event - It's not fired from Item.Selected also
2681 ListViewVirtualItemsSelectionRangeChangedEventArgs args =
2682 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2684 owner.OnVirtualItemsSelectionRangeChanged (args);
2686 // Report clicks only if the item was clicked. On MS the
2687 // clicks are only raised if you click an item
2689 if (me.Clicks > 1) {
2690 if (owner.CheckBoxes)
2691 clicked_item.Checked = !clicked_item.Checked;
2692 } else if (me.Clicks == 1) {
2693 if (owner.LabelEdit && !changed)
2694 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2697 drag_begin = me.Location;
2698 dragged_item_index = clicked_item.Index;
2700 if (owner.MultiSelect)
2701 box_selecting = true;
2702 else if (owner.SelectedItems.Count > 0)
2703 owner.SelectedItems.Clear ();
2706 if (box_selecting) {
2707 Keys mods = XplatUI.State.ModifierKeys;
2708 if ((mods & Keys.Shift) != 0)
2709 box_select_mode = BoxSelect.Shift;
2710 else if ((mods & Keys.Control) != 0)
2711 box_select_mode = BoxSelect.Control;
2713 box_select_mode = BoxSelect.Normal;
2714 box_select_start = pt;
2715 prev_selection = owner.SelectedIndices.List.Clone () as IList;
2719 private void ItemsMouseMove (object sender, MouseEventArgs me)
2721 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2723 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2727 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2728 !hover_processed && owner.Activation != ItemActivation.OneClick
2729 && !owner.ShowItemToolTips
2733 Point pt = PointToClient (Control.MousePosition);
2734 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2736 if (hover_processed && item != null && item != prev_hovered_item) {
2737 hover_processed = false;
2738 XplatUI.ResetMouseHover (Handle);
2741 // Need to invalidate the item in HotTracking to show/hide the underline style
2742 if (owner.Activation == ItemActivation.OneClick) {
2743 if (item == null && owner.HotItemIndex != -1) {
2744 if (owner.HotTracking)
2745 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2747 Cursor = Cursors.Default;
2748 owner.HotItemIndex = -1;
2749 } else if (item != null && owner.HotItemIndex == -1) {
2750 if (owner.HotTracking)
2751 Invalidate (item.Bounds);
2753 Cursor = Cursors.Hand;
2754 owner.HotItemIndex = item.Index;
2758 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2759 if (drag_begin != new Point (-1, -1)) {
2760 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2761 if (!r.Contains (me.X, me.Y)) {
2762 ListViewItem dragged_item = owner.items [dragged_item_index];
2763 owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2765 drag_begin = new Point (-1, -1);
2766 dragged_item_index = -1;
2771 if (owner.ShowItemToolTips) {
2773 owner.item_tooltip.Active = false;
2774 prev_tooltip_item = null;
2775 } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2776 owner.item_tooltip.Active = true;
2777 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2778 prev_tooltip_item = item;
2784 private void ItemsMouseHover (object sender, EventArgs e)
2786 if (owner.hover_pending) {
2787 owner.OnMouseHover (e);
2788 owner.hover_pending = false;
2794 hover_processed = true;
2795 Point pt = PointToClient (Control.MousePosition);
2796 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2800 prev_hovered_item = item;
2802 if (owner.HoverSelection) {
2803 if (owner.MultiSelect)
2804 owner.UpdateMultiSelection (item.Index, true);
2806 item.Selected = true;
2808 owner.SetFocusedItem (item.DisplayIndex);
2809 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2812 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2815 void HandleClicks (MouseEventArgs me)
2817 // if the click is not on an item,
2818 // clicks remains as 0
2820 owner.OnDoubleClick (EventArgs.Empty);
2821 owner.OnMouseDoubleClick (me);
2822 } else if (clicks == 1) {
2823 owner.OnClick (EventArgs.Empty);
2824 owner.OnMouseClick (me);
2830 private void ItemsMouseUp (object sender, MouseEventArgs me)
2832 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
2833 HandleClicks (owner_me);
2836 if (owner.Items.Count == 0) {
2838 owner.OnMouseUp (owner_me);
2842 Point pt = new Point (me.X, me.Y);
2844 Rectangle rect = Rectangle.Empty;
2845 if (clicked_item != null) {
2846 if (owner.view == View.Details && !owner.full_row_select)
2847 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
2849 rect = clicked_item.Bounds;
2851 if (rect.Contains (pt)) {
2852 switch (owner.activation) {
2853 case ItemActivation.OneClick:
2854 owner.OnItemActivate (EventArgs.Empty);
2857 case ItemActivation.TwoClick:
2858 if (last_clicked_item == clicked_item) {
2859 owner.OnItemActivate (EventArgs.Empty);
2860 last_clicked_item = null;
2862 last_clicked_item = clicked_item;
2865 // DoubleClick activation is handled in another handler
2869 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
2870 // Need this to clean up background clicks
2871 owner.SelectedItems.Clear ();
2875 owner.OnMouseUp (owner_me);
2878 private void ResetMouseState ()
2880 clicked_item = null;
2881 box_select_start = Point.Empty;
2882 BoxSelectRectangle = Rectangle.Empty;
2883 prev_selection = null;
2884 box_select_mode = BoxSelect.None;
2887 // Clean these bits in case the mouse buttons were
2888 // released before firing ItemDrag
2889 dragged_item_index = -1;
2890 drag_begin = new Point (-1, -1);
2893 private void LabelEditFinished (object sender, EventArgs e)
2895 EndEdit (edit_item);
2898 private void LabelEditCancelled (object sender, EventArgs e)
2900 edit_args.SetLabel (null);
2901 EndEdit (edit_item);
2904 private void LabelTextChanged (object sender, EventArgs e)
2906 if (edit_args != null)
2907 edit_args.SetLabel (edit_text_box.Text);
2910 internal void BeginEdit (ListViewItem item)
2912 if (edit_item != null)
2913 EndEdit (edit_item);
2915 if (edit_text_box == null) {
2916 edit_text_box = new ListViewLabelEditTextBox ();
2917 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
2918 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
2919 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
2920 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
2921 edit_text_box.Visible = false;
2922 Controls.Add (edit_text_box);
2925 item.EnsureVisible();
2927 edit_text_box.Reset ();
2929 switch (owner.view) {
2931 case View.SmallIcon:
2933 edit_text_box.TextAlign = HorizontalAlignment.Left;
2934 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2935 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
2936 edit_text_box.Width = (int)sizef.Width + 4;
2937 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
2938 edit_text_box.WordWrap = false;
2939 edit_text_box.Multiline = false;
2941 case View.LargeIcon:
2942 edit_text_box.TextAlign = HorizontalAlignment.Center;
2943 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2944 sizef = TextRenderer.MeasureString (item.Text, item.Font);
2945 edit_text_box.Width = (int)sizef.Width + 4;
2946 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
2947 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
2948 edit_text_box.WordWrap = true;
2949 edit_text_box.Multiline = true;
2955 edit_text_box.Text = item.Text;
2956 edit_text_box.Font = item.Font;
2957 edit_text_box.Visible = true;
2958 edit_text_box.Focus ();
2959 edit_text_box.SelectAll ();
2961 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
2962 owner.OnBeforeLabelEdit (edit_args);
2964 if (edit_args.CancelEdit)
2968 internal void CancelEdit (ListViewItem item)
2970 // do nothing if there's no item being edited, or if the
2971 // item being edited is not the one passed in
2972 if (edit_item == null || edit_item != item)
2975 edit_args.SetLabel (null);
2979 internal void EndEdit (ListViewItem item)
2981 // do nothing if there's no item being edited, or if the
2982 // item being edited is not the one passed in
2983 if (edit_item == null || edit_item != item)
2986 if (edit_text_box != null) {
2987 if (edit_text_box.Visible)
2988 edit_text_box.Visible = false;
2989 // ensure listview gets focus
2993 // Same as TreeView.EndEdit: need to have focus in synch
2994 Application.DoEvents ();
2997 // Create a new instance, since we could get a call to BeginEdit
2998 // from the handler and have fields out of synch
3000 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
3003 owner.OnAfterLabelEdit (args);
3004 if (!args.CancelEdit && args.Label != null)
3005 item.Text = args.Label;
3008 internal override void OnPaintInternal (PaintEventArgs pe)
3010 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
3013 protected override void WndProc (ref Message m)
3015 switch ((Msg)m.Msg) {
3016 case Msg.WM_KILLFOCUS:
3017 owner.Select (false, true);
3019 case Msg.WM_SETFOCUS:
3020 owner.Select (false, true);
3022 case Msg.WM_LBUTTONDOWN:
3024 owner.Select (false, true);
3026 case Msg.WM_RBUTTONDOWN:
3028 owner.Select (false, true);
3033 base.WndProc (ref m);
3037 internal class ListViewLabelEditTextBox : TextBox
3042 int max_height = -1;
3043 int min_height = -1;
3045 int old_number_lines = 1;
3047 SizeF text_size_one_char;
3049 public ListViewLabelEditTextBox ()
3051 min_height = DefaultSize.Height;
3052 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3055 public int MaxWidth {
3057 if (value < min_width)
3058 max_width = min_width;
3064 public int MaxHeight {
3066 if (value < min_height)
3067 max_height = min_height;
3073 public new int Width {
3083 public override Font Font {
3089 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3093 protected override void OnTextChanged (EventArgs e)
3095 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3097 int new_width = (int)text_size.Width + 8;
3100 ResizeTextBoxWidth (new_width);
3102 if (Width != max_width)
3103 ResizeTextBoxWidth (new_width);
3105 int number_lines = Lines.Length;
3107 if (number_lines != old_number_lines) {
3108 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3109 old_number_lines = number_lines;
3111 ResizeTextBoxHeight (new_height);
3115 base.OnTextChanged (e);
3118 protected override bool IsInputKey (Keys key_data)
3120 if ((key_data & Keys.Alt) == 0) {
3121 switch (key_data & Keys.KeyCode) {
3128 return base.IsInputKey (key_data);
3131 protected override void OnKeyDown (KeyEventArgs e)
3136 switch (e.KeyCode) {
3140 OnEditingFinished (e);
3145 OnEditingCancelled (e);
3150 protected override void OnLostFocus (EventArgs e)
3153 OnEditingFinished (e);
3157 protected void OnEditingCancelled (EventArgs e)
3159 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3164 protected void OnEditingFinished (EventArgs e)
3166 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3171 private void ResizeTextBoxWidth (int new_width)
3173 if (new_width > max_width)
3174 base.Width = max_width;
3176 if (new_width >= min_width)
3177 base.Width = new_width;
3179 base.Width = min_width;
3182 private void ResizeTextBoxHeight (int new_height)
3184 if (new_height > max_height)
3185 base.Height = max_height;
3187 if (new_height >= min_height)
3188 base.Height = new_height;
3190 base.Height = min_height;
3193 public void Reset ()
3200 old_number_lines = 1;
3202 Text = String.Empty;
3207 static object EditingCancelledEvent = new object ();
3208 public event EventHandler EditingCancelled {
3209 add { Events.AddHandler (EditingCancelledEvent, value); }
3210 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3213 static object EditingFinishedEvent = new object ();
3214 public event EventHandler EditingFinished {
3215 add { Events.AddHandler (EditingFinishedEvent, value); }
3216 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3220 internal override void OnPaintInternal (PaintEventArgs pe)
3225 CalculateScrollBars ();
3228 void FocusChanged (object o, EventArgs args)
3230 if (Items.Count == 0)
3233 if (FocusedItem == null)
3236 ListViewItem focused_item = FocusedItem;
3238 if (focused_item.ListView != null) {
3239 focused_item.Invalidate ();
3240 focused_item.Layout ();
3241 focused_item.Invalidate ();
3245 private void ListView_Invalidated (object sender, InvalidateEventArgs e)
3247 // When the ListView is invalidated, we need to invalidate
3248 // the child controls.
3249 header_control.Invalidate ();
3250 item_control.Invalidate ();
3253 private void ListView_MouseEnter (object sender, EventArgs args)
3255 hover_pending = true; // Need a hover event for every Enter/Leave cycle
3258 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3260 if (Items.Count == 0)
3263 int lines = me.Delta / 120;
3270 case View.SmallIcon:
3271 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3273 case View.LargeIcon:
3274 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
3277 Scroll (h_scroll, -ItemSize.Width * lines);
3280 if (!Application.VisualStylesEnabled)
3281 goto case View.LargeIcon;
3283 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3288 private void ListView_SizeChanged (object sender, EventArgs e)
3293 private void SetFocusedItem (int display_index)
3295 if (display_index != -1)
3296 GetItemAtDisplayIndex (display_index).Focused = true;
3297 else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3298 GetItemAtDisplayIndex (focused_item_index).Focused = false;
3299 focused_item_index = display_index;
3300 if (display_index == -1)
3301 OnUIAFocusedItemChanged ();
3302 // otherwise the event will have been fired
3303 // when the ListViewItem's Focused was set
3306 private void HorizontalScroller (object sender, EventArgs e)
3308 item_control.EndEdit (item_control.edit_item);
3310 // Avoid unnecessary flickering, when button is
3311 // kept pressed at the end
3312 if (h_marker != h_scroll.Value) {
3314 int pixels = h_marker - h_scroll.Value;
3316 h_marker = h_scroll.Value;
3317 if (header_control.Visible)
3318 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3320 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3324 private void VerticalScroller (object sender, EventArgs e)
3326 item_control.EndEdit (item_control.edit_item);
3328 // Avoid unnecessary flickering, when button is
3329 // kept pressed at the end
3330 if (v_marker != v_scroll.Value) {
3331 int pixels = v_marker - v_scroll.Value;
3332 Rectangle area = item_control.ClientRectangle;
3333 if (header_control.Visible) {
3334 area.Y += header_control.Height;
3335 area.Height -= header_control.Height;
3338 v_marker = v_scroll.Value;
3339 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3343 internal override bool IsInputCharInternal (char charCode)
3347 #endregion // Internal Methods Properties
3349 #region Protected Methods
3350 protected override void CreateHandle ()
3352 base.CreateHandle ();
3353 is_selection_available = true;
3354 for (int i = 0; i < SelectedItems.Count; i++)
3355 OnSelectedIndexChanged (EventArgs.Empty);
3358 protected override void Dispose (bool disposing)
3361 large_image_list = null;
3362 small_image_list = null;
3363 state_image_list = null;
3365 foreach (ColumnHeader col in columns)
3366 col.SetListView (null);
3368 if (!virtual_mode) // In virtual mode we don't save the items
3369 foreach (ListViewItem item in items)
3373 base.Dispose (disposing);
3376 protected override bool IsInputKey (Keys keyData)
3393 return base.IsInputKey (keyData);
3396 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3398 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3403 protected override void OnBackgroundImageChanged (EventArgs e)
3405 item_control.BackgroundImage = BackgroundImage;
3406 base.OnBackgroundImageChanged (e);
3409 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3411 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3416 protected internal virtual void OnColumnClick (ColumnClickEventArgs e)
3418 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3423 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3425 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3430 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3432 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3437 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3439 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3444 protected override void OnFontChanged (EventArgs e)
3446 base.OnFontChanged (e);
3450 protected override void OnHandleCreated (EventArgs e)
3452 base.OnHandleCreated (e);
3453 CalculateListView (alignment);
3454 if (!virtual_mode) // Sorting is not allowed in virtual mode
3458 protected override void OnHandleDestroyed (EventArgs e)
3460 base.OnHandleDestroyed (e);
3463 protected virtual void OnItemActivate (EventArgs e)
3465 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3470 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3472 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3477 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3479 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3484 protected virtual void OnItemDrag (ItemDragEventArgs e)
3486 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3491 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3493 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3498 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3500 ListViewItemSelectionChangedEventHandler eh =
3501 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3506 protected override void OnMouseHover (EventArgs e)
3508 base.OnMouseHover (e);
3511 protected override void OnParentChanged (EventArgs e)
3513 base.OnParentChanged (e);
3516 protected virtual void OnSelectedIndexChanged (EventArgs e)
3518 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3523 protected override void OnSystemColorsChanged (EventArgs e)
3525 base.OnSystemColorsChanged (e);
3528 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3530 CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3535 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3537 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3542 [EditorBrowsable (EditorBrowsableState.Advanced)]
3543 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3545 EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3550 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3552 SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3557 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3559 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3560 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3565 protected void RealizeProperties ()
3570 protected void UpdateExtendedStyles ()
3575 bool refocusing = false;
3577 protected override void WndProc (ref Message m)
3579 switch ((Msg)m.Msg) {
3580 case Msg.WM_KILLFOCUS:
3581 Control receiver = Control.FromHandle (m.WParam);
3582 if (receiver == item_control) {
3588 case Msg.WM_SETFOCUS:
3598 base.WndProc (ref m);
3600 #endregion // Protected Methods
3602 #region Public Instance Methods
3603 public void ArrangeIcons ()
3605 ArrangeIcons (this.alignment);
3608 public void ArrangeIcons (ListViewAlignment value)
3610 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3611 if (view == View.LargeIcon || view == View.SmallIcon)
3615 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3617 if (columnIndex < 0 || columnIndex >= columns.Count)
3618 throw new ArgumentOutOfRangeException ("columnIndex");
3620 columns [columnIndex].AutoResize (headerAutoResize);
3623 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3626 foreach (ColumnHeader col in columns)
3627 col.AutoResize (headerAutoResize);
3631 public void BeginUpdate ()
3633 // flag to avoid painting
3637 public void Clear ()
3640 items.Clear (); // Redraw (true) called here
3643 public void EndUpdate ()
3645 // flag to avoid painting
3648 // probably, now we need a redraw with recalculations
3652 public void EnsureVisible (int index)
3654 if (index < 0 || index >= items.Count || scrollable == false || updating)
3657 Rectangle view_rect = item_control.ClientRectangle;
3658 // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items
3659 Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds;
3661 if (view == View.Details && header_style != ColumnHeaderStyle.None) {
3662 view_rect.Y += header_control.Height;
3663 view_rect.Height -= header_control.Height;
3666 if (view_rect.Contains (bounds))
3669 if (View != View.Details) {
3670 if (bounds.Left < 0)
3671 h_scroll.Value += bounds.Left;
3672 // Don't shift right unless right-to-left layout is active. (Xamarin bug 22483)
3673 else if (this.RightToLeftLayout && bounds.Right > view_rect.Right)
3674 h_scroll.Value += (bounds.Right - view_rect.Right);
3677 if (bounds.Top < view_rect.Y)
3678 v_scroll.Value += bounds.Top - view_rect.Y;
3679 else if (bounds.Bottom > view_rect.Bottom)
3680 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3683 public ListViewItem FindItemWithText (string text)
3685 if (items.Count == 0)
3688 return FindItemWithText (text, true, 0, true);
3691 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3693 return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3696 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3698 return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3701 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3703 if (startIndex < 0 || startIndex >= items.Count)
3704 throw new ArgumentOutOfRangeException ("startIndex");
3707 throw new ArgumentNullException ("text");
3710 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3711 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty,
3712 SearchDirectionHint.Down, startIndex);
3714 OnSearchForVirtualItem (args);
3715 int idx = args.Index;
3716 if (idx >= 0 && idx < virtual_list_size)
3724 ListViewItem lvi = items [i];
3726 if (isPrefixSearch) { // prefix search
3727 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3729 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3732 if (i + 1 >= items.Count) {
3740 if (i == startIndex)
3744 // Subitems have a minor priority, so we have to do a second linear search
3745 // Also, we don't need to to a roundtrip search for them by now
3746 if (includeSubItemsInSearch) {
3747 for (i = startIndex; i < items.Count; i++) {
3748 ListViewItem lvi = items [i];
3749 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3750 if (isPrefixSearch) {
3751 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text,
3752 text, CompareOptions.IgnoreCase))
3754 } else if (String.Compare (sub_item.Text, text, true) == 0)
3762 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3764 return FindNearestItem (searchDirection, new Point (x, y));
3767 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3769 if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3770 throw new ArgumentOutOfRangeException ("searchDirection");
3772 if (view != View.LargeIcon && view != View.SmallIcon)
3773 throw new InvalidOperationException ();
3776 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3777 false, false, String.Empty, point,
3780 OnSearchForVirtualItem (args);
3781 int idx = args.Index;
3782 if (idx >= 0 && idx < virtual_list_size)
3788 ListViewItem item = null;
3789 int min_dist = Int32.MaxValue;
3792 // It looks like .Net does a previous adjustment
3795 case SearchDirectionHint.Up:
3796 point.Y -= item_size.Height;
3798 case SearchDirectionHint.Down:
3799 point.Y += item_size.Height;
3801 case SearchDirectionHint.Left:
3802 point.X -= item_size.Width;
3804 case SearchDirectionHint.Right:
3805 point.X += item_size.Width;
3809 for (int i = 0; i < items.Count; i++) {
3810 Point item_loc = GetItemLocation (i);
3812 if (dir == SearchDirectionHint.Up) {
3813 if (point.Y < item_loc.Y)
3815 } else if (dir == SearchDirectionHint.Down) {
3816 if (point.Y > item_loc.Y)
3818 } else if (dir == SearchDirectionHint.Left) {
3819 if (point.X < item_loc.X)
3821 } else if (dir == SearchDirectionHint.Right) {
3822 if (point.X > item_loc.X)
3826 int x_dist = point.X - item_loc.X;
3827 int y_dist = point.Y - item_loc.Y;
3829 int dist = x_dist * x_dist + y_dist * y_dist;
3830 if (dist < min_dist) {
3839 public ListViewItem GetItemAt (int x, int y)
3841 Size item_size = ItemSize;
3842 for (int i = 0; i < items.Count; i++) {
3843 Rectangle item_rect = items [i].Bounds;
3844 if (item_rect.Contains (x, y))
3851 public Rectangle GetItemRect (int index)
3853 return GetItemRect (index, ItemBoundsPortion.Entire);
3856 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
3858 if (index < 0 || index >= items.Count)
3859 throw new IndexOutOfRangeException ("index");
3861 return items [index].GetBounds (portion);
3864 public ListViewHitTestInfo HitTest (Point point)
3866 return HitTest (point.X, point.Y);
3869 public ListViewHitTestInfo HitTest (int x, int y)
3872 throw new ArgumentOutOfRangeException ("x");
3874 throw new ArgumentOutOfRangeException ("y");
3876 ListViewItem item = GetItemAt (x, y);
3878 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
3880 ListViewHitTestLocations locations = 0;
3881 if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
3882 locations |= ListViewHitTestLocations.Label;
3883 else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
3884 locations |= ListViewHitTestLocations.Image;
3885 else if (item.CheckRectReal.Contains (x, y))
3886 locations |= ListViewHitTestLocations.StateImage;
3888 ListViewItem.ListViewSubItem subitem = null;
3889 if (view == View.Details)
3890 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
3891 if (si.Bounds.Contains (x, y)) {
3896 return new ListViewHitTestInfo (item, subitem, locations);
3899 [EditorBrowsable (EditorBrowsableState.Advanced)]
3900 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
3902 if (startIndex < 0 || startIndex >= items.Count)
3903 throw new ArgumentOutOfRangeException ("startIndex");
3904 if (endIndex < 0 || endIndex >= items.Count)
3905 throw new ArgumentOutOfRangeException ("endIndex");
3906 if (startIndex > endIndex)
3907 throw new ArgumentException ("startIndex");
3912 for (int i = startIndex; i <= endIndex; i++)
3913 items [i].Invalidate ();
3915 if (!invalidateOnly)
3922 throw new InvalidOperationException ();
3927 // we need this overload to reuse the logic for sorting, while allowing
3928 // redrawing to be done by caller or have it done by this method when
3929 // sorting is really performed
3931 // ListViewItemCollection's Add and AddRange methods call this overload
3932 // with redraw set to false, as they take care of redrawing themselves
3933 // (they even want to redraw the listview if no sort is performed, as
3934 // an item was added), while ListView.Sort () only wants to redraw if
3935 // sorting was actually performed
3936 private void Sort (bool redraw)
3938 if (!IsHandleCreated || item_sorter == null) {
3942 items.Sort (item_sorter);
3947 public override string ToString ()
3949 int count = this.Items.Count;
3952 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
3954 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
3956 #endregion // Public Instance Methods
3961 internal class HeaderControl : Control {
3964 bool column_resize_active = false;
3965 ColumnHeader resize_column;
3966 ColumnHeader clicked_column;
3967 ColumnHeader drag_column;
3969 int drag_to_index = -1;
3970 ColumnHeader entered_column_header;
3972 public HeaderControl (ListView owner)
3975 this.SetStyle (ControlStyles.DoubleBuffer, true);
3976 MouseDown += new MouseEventHandler (HeaderMouseDown);
3977 MouseMove += new MouseEventHandler (HeaderMouseMove);
3978 MouseUp += new MouseEventHandler (HeaderMouseUp);
3979 MouseLeave += new EventHandler (OnMouseLeave);
3982 internal ColumnHeader EnteredColumnHeader {
3983 get { return entered_column_header; }
3985 if (entered_column_header == value)
3987 if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
3988 Region region_to_invalidate = new Region ();
3989 region_to_invalidate.MakeEmpty ();
3990 if (entered_column_header != null)
3991 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
3992 entered_column_header = value;
3993 if (entered_column_header != null)
3994 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
3995 Invalidate (region_to_invalidate);
3996 region_to_invalidate.Dispose ();
3998 entered_column_header = value;
4002 void OnMouseLeave (object sender, EventArgs e)
4004 EnteredColumnHeader = null;
4007 private ColumnHeader ColumnAtX (int x)
4009 Point pt = new Point (x, 0);
4010 ColumnHeader result = null;
4011 foreach (ColumnHeader col in owner.Columns) {
4012 if (col.Rect.Contains (pt)) {
4020 private int GetReorderedIndex (ColumnHeader col)
4022 if (owner.reordered_column_indices == null)
4025 for (int i = 0; i < owner.Columns.Count; i++)
4026 if (owner.reordered_column_indices [i] == col.Index)
4028 throw new Exception ("Column index missing from reordered array");
4031 private void HeaderMouseDown (object sender, MouseEventArgs me)
4033 if (resize_column != null) {
4034 column_resize_active = true;
4039 clicked_column = ColumnAtX (me.X + owner.h_marker);
4041 if (clicked_column != null) {
4043 if (owner.AllowColumnReorder) {
4045 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4046 drag_column.Rect = clicked_column.Rect;
4047 drag_to_index = GetReorderedIndex (clicked_column);
4049 clicked_column.Pressed = true;
4050 Invalidate (clicked_column);
4055 void Invalidate (ColumnHeader columnHeader)
4057 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4060 Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4062 Rectangle bounds = columnHeader.Rect;
4063 bounds.X -= owner.h_marker;
4069 column_resize_active = false;
4070 resize_column = null;
4072 Cursor = Cursors.Default;
4075 private void HeaderMouseMove (object sender, MouseEventArgs me)
4077 Point pt = new Point (me.X + owner.h_marker, me.Y);
4079 if (column_resize_active) {
4080 int width = pt.X - resize_column.X;
4084 if (!owner.CanProceedWithResize (resize_column, width)){
4088 resize_column.Width = width;
4092 resize_column = null;
4094 if (clicked_column != null) {
4095 if (owner.AllowColumnReorder) {
4098 r = drag_column.Rect;
4099 r.X = clicked_column.Rect.X + me.X - drag_x;
4100 drag_column.Rect = r;
4102 int x = me.X + owner.h_marker;
4103 ColumnHeader over = ColumnAtX (x);
4105 drag_to_index = owner.Columns.Count;
4106 else if (x < over.X + over.Width / 2)
4107 drag_to_index = GetReorderedIndex (over);
4109 drag_to_index = GetReorderedIndex (over) + 1;
4112 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4113 bool pressed = clicked_column.Pressed;
4114 clicked_column.Pressed = over == clicked_column;
4115 if (clicked_column.Pressed ^ pressed)
4116 Invalidate (clicked_column);
4121 for (int i = 0; i < owner.Columns.Count; i++) {
4122 Rectangle zone = owner.Columns [i].Rect;
4123 if (zone.Contains (pt))
4124 EnteredColumnHeader = owner.Columns [i];
4125 zone.X = zone.Right - 5;
4127 if (zone.Contains (pt)) {
4128 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4130 resize_column = owner.Columns [i];
4135 if (resize_column == null)
4136 Cursor = Cursors.Default;
4138 Cursor = Cursors.VSplit;
4141 void HeaderMouseUp (object sender, MouseEventArgs me)
4145 if (column_resize_active) {
4146 int column_idx = resize_column.Index;
4148 owner.RaiseColumnWidthChanged (column_idx);
4152 if (clicked_column != null && clicked_column.Pressed) {
4153 clicked_column.Pressed = false;
4154 Invalidate (clicked_column);
4155 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4158 if (drag_column != null && owner.AllowColumnReorder) {
4160 if (drag_to_index > GetReorderedIndex (clicked_column))
4162 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4163 owner.ReorderColumn (clicked_column, drag_to_index, true);
4168 clicked_column = null;
4171 internal override void OnPaintInternal (PaintEventArgs pe)
4176 Theme theme = ThemeEngine.Current;
4177 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4179 if (drag_column == null)
4183 if (drag_to_index == owner.Columns.Count)
4184 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4186 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4187 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4190 protected override void WndProc (ref Message m)
4192 switch ((Msg)m.Msg) {
4193 case Msg.WM_SETFOCUS:
4197 base.WndProc (ref m);
4203 private class ItemComparer : IComparer {
4204 readonly SortOrder sort_order;
4206 public ItemComparer (SortOrder sortOrder)
4208 sort_order = sortOrder;
4211 public int Compare (object x, object y)
4213 ListViewItem item_x = x as ListViewItem;
4214 ListViewItem item_y = y as ListViewItem;
4215 if (sort_order == SortOrder.Ascending)
4216 return String.Compare (item_x.Text, item_y.Text);
4218 return String.Compare (item_y.Text, item_x.Text);
4222 [ListBindable (false)]
4223 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4225 private readonly ListView owner;
4227 #region Public Constructor
4228 public CheckedIndexCollection (ListView owner)
4232 #endregion // Public Constructor
4234 #region Public Properties
4237 get { return owner.CheckedItems.Count; }
4240 public bool IsReadOnly {
4241 get { return true; }
4244 public int this [int index] {
4246 int [] indices = GetIndices ();
4247 if (index < 0 || index >= indices.Length)
4248 throw new ArgumentOutOfRangeException ("index");
4249 return indices [index];
4253 bool ICollection.IsSynchronized {
4254 get { return false; }
4257 object ICollection.SyncRoot {
4258 get { return this; }
4261 bool IList.IsFixedSize {
4262 get { return true; }
4265 object IList.this [int index] {
4266 get { return this [index]; }
4267 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4269 #endregion // Public Properties
4271 #region Public Methods
4272 public bool Contains (int checkedIndex)
4274 int [] indices = GetIndices ();
4275 for (int i = 0; i < indices.Length; i++) {
4276 if (indices [i] == checkedIndex)
4282 public IEnumerator GetEnumerator ()
4284 int [] indices = GetIndices ();
4285 return indices.GetEnumerator ();
4288 void ICollection.CopyTo (Array dest, int index)
4290 int [] indices = GetIndices ();
4291 Array.Copy (indices, 0, dest, index, indices.Length);
4294 int IList.Add (object value)
4296 throw new NotSupportedException ("Add operation is not supported.");
4301 throw new NotSupportedException ("Clear operation is not supported.");
4304 bool IList.Contains (object checkedIndex)
4306 if (!(checkedIndex is int))
4308 return Contains ((int) checkedIndex);
4311 int IList.IndexOf (object checkedIndex)
4313 if (!(checkedIndex is int))
4315 return IndexOf ((int) checkedIndex);
4318 void IList.Insert (int index, object value)
4320 throw new NotSupportedException ("Insert operation is not supported.");
4323 void IList.Remove (object value)
4325 throw new NotSupportedException ("Remove operation is not supported.");
4328 void IList.RemoveAt (int index)
4330 throw new NotSupportedException ("RemoveAt operation is not supported.");
4333 public int IndexOf (int checkedIndex)
4335 int [] indices = GetIndices ();
4336 for (int i = 0; i < indices.Length; i++) {
4337 if (indices [i] == checkedIndex)
4342 #endregion // Public Methods
4344 private int [] GetIndices ()
4346 ArrayList checked_items = owner.CheckedItems.List;
4347 int [] indices = new int [checked_items.Count];
4348 for (int i = 0; i < checked_items.Count; i++) {
4349 ListViewItem item = (ListViewItem) checked_items [i];
4350 indices [i] = item.Index;
4354 } // CheckedIndexCollection
4356 [ListBindable (false)]
4357 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4359 private readonly ListView owner;
4360 private ArrayList list;
4362 #region Public Constructor
4363 public CheckedListViewItemCollection (ListView owner)
4366 this.owner.Items.Changed += new CollectionChangedHandler (
4367 ItemsCollection_Changed);
4369 #endregion // Public Constructor
4371 #region Public Properties
4375 if (!owner.CheckBoxes)
4381 public bool IsReadOnly {
4382 get { return true; }
4385 public ListViewItem this [int index] {
4387 if (owner.VirtualMode)
4388 throw new InvalidOperationException ();
4389 ArrayList checked_items = List;
4390 if (index < 0 || index >= checked_items.Count)
4391 throw new ArgumentOutOfRangeException ("index");
4392 return (ListViewItem) checked_items [index];
4396 public virtual ListViewItem this [string key] {
4398 int idx = IndexOfKey (key);
4399 return idx == -1 ? null : (ListViewItem) List [idx];
4403 bool ICollection.IsSynchronized {
4404 get { return false; }
4407 object ICollection.SyncRoot {
4408 get { return this; }
4411 bool IList.IsFixedSize {
4412 get { return true; }
4415 object IList.this [int index] {
4416 get { return this [index]; }
4417 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4419 #endregion // Public Properties
4421 #region Public Methods
4422 public bool Contains (ListViewItem item)
4424 if (!owner.CheckBoxes)
4426 return List.Contains (item);
4429 public virtual bool ContainsKey (string key)
4431 return IndexOfKey (key) != -1;
4434 public void CopyTo (Array dest, int index)
4436 if (owner.VirtualMode)
4437 throw new InvalidOperationException ();
4438 if (!owner.CheckBoxes)
4440 List.CopyTo (dest, index);
4443 public IEnumerator GetEnumerator ()
4445 if (owner.VirtualMode)
4446 throw new InvalidOperationException ();
4447 if (!owner.CheckBoxes)
4448 return (new ListViewItem [0]).GetEnumerator ();
4449 return List.GetEnumerator ();
4452 int IList.Add (object value)
4454 throw new NotSupportedException ("Add operation is not supported.");
4459 throw new NotSupportedException ("Clear operation is not supported.");
4462 bool IList.Contains (object item)
4464 if (!(item is ListViewItem))
4466 return Contains ((ListViewItem) item);
4469 int IList.IndexOf (object item)
4471 if (!(item is ListViewItem))
4473 return IndexOf ((ListViewItem) item);
4476 void IList.Insert (int index, object value)
4478 throw new NotSupportedException ("Insert operation is not supported.");
4481 void IList.Remove (object value)
4483 throw new NotSupportedException ("Remove operation is not supported.");
4486 void IList.RemoveAt (int index)
4488 throw new NotSupportedException ("RemoveAt operation is not supported.");
4491 public int IndexOf (ListViewItem item)
4493 if (owner.VirtualMode)
4494 throw new InvalidOperationException ();
4495 if (!owner.CheckBoxes)
4497 return List.IndexOf (item);
4500 public virtual int IndexOfKey (string key)
4502 if (owner.VirtualMode)
4503 throw new InvalidOperationException ();
4504 if (key == null || key.Length == 0)
4507 ArrayList checked_items = List;
4508 for (int i = 0; i < checked_items.Count; i++) {
4509 ListViewItem item = (ListViewItem) checked_items [i];
4510 if (String.Compare (key, item.Name, true) == 0)
4516 #endregion // Public Methods
4518 internal ArrayList List {
4521 list = new ArrayList ();
4522 foreach (ListViewItem item in owner.Items) {
4531 internal void Reset ()
4533 // force re-population of list
4537 private void ItemsCollection_Changed ()
4541 } // CheckedListViewItemCollection
4543 [ListBindable (false)]
4544 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4546 internal ArrayList list;
4547 private ListView owner;
4549 #region UIA Framework Events
4551 // We are using Reflection to add/remove internal events.
4552 // Class ListViewProvider uses the events when View is Details.
4554 //Event used to generate UIA StructureChangedEvent
4555 static object UIACollectionChangedEvent = new object ();
4557 internal event CollectionChangeEventHandler UIACollectionChanged {
4560 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4564 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4568 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4573 CollectionChangeEventHandler eh
4574 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4579 #endregion UIA Framework Events
4581 #region Public Constructor
4582 public ColumnHeaderCollection (ListView owner)
4584 list = new ArrayList ();
4587 #endregion // Public Constructor
4589 #region Public Properties
4592 get { return list.Count; }
4595 public bool IsReadOnly {
4596 get { return false; }
4599 public virtual ColumnHeader this [int index] {
4601 if (index < 0 || index >= list.Count)
4602 throw new ArgumentOutOfRangeException ("index");
4603 return (ColumnHeader) list [index];
4607 public virtual ColumnHeader this [string key] {
4609 int idx = IndexOfKey (key);
4613 return (ColumnHeader) list [idx];
4617 bool ICollection.IsSynchronized {
4618 get { return true; }
4621 object ICollection.SyncRoot {
4622 get { return this; }
4625 bool IList.IsFixedSize {
4626 get { return list.IsFixedSize; }
4629 object IList.this [int index] {
4630 get { return this [index]; }
4631 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4633 #endregion // Public Properties
4635 #region Public Methods
4636 public virtual int Add (ColumnHeader value)
4638 int idx = list.Add (value);
4639 owner.AddColumn (value, idx, true);
4641 //UIA Framework event: Item Added
4642 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4647 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4650 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4651 this.Add (colHeader);
4655 public virtual ColumnHeader Add (string text)
4657 return Add (String.Empty, text);
4660 public virtual ColumnHeader Add (string text, int width)
4662 return Add (String.Empty, text, width);
4665 public virtual ColumnHeader Add (string key, string text)
4667 ColumnHeader colHeader = new ColumnHeader ();
4668 colHeader.Name = key;
4669 colHeader.Text = text;
4674 public virtual ColumnHeader Add (string key, string text, int width)
4676 return Add (key, text, width, HorizontalAlignment.Left, -1);
4679 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4681 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4682 colHeader.ImageIndex = imageIndex;
4687 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4689 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4690 colHeader.ImageKey = imageKey;
4695 public virtual void AddRange (ColumnHeader [] values)
4697 foreach (ColumnHeader colHeader in values) {
4698 int idx = list.Add (colHeader);
4699 owner.AddColumn (colHeader, idx, false);
4702 owner.Redraw (true);
4705 public virtual void Clear ()
4707 foreach (ColumnHeader col in list)
4708 col.SetListView (null);
4710 owner.ReorderColumns (new int [0], true);
4712 //UIA Framework event: Items cleared
4713 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4717 public bool Contains (ColumnHeader value)
4719 return list.Contains (value);
4722 public virtual bool ContainsKey (string key)
4724 return IndexOfKey (key) != -1;
4727 public IEnumerator GetEnumerator ()
4729 return list.GetEnumerator ();
4732 void ICollection.CopyTo (Array dest, int index)
4734 list.CopyTo (dest, index);
4737 int IList.Add (object value)
4739 if (! (value is ColumnHeader)) {
4740 throw new ArgumentException ("Not of type ColumnHeader", "value");
4743 return this.Add ((ColumnHeader) value);
4746 bool IList.Contains (object value)
4748 if (! (value is ColumnHeader)) {
4749 throw new ArgumentException ("Not of type ColumnHeader", "value");
4752 return this.Contains ((ColumnHeader) value);
4755 int IList.IndexOf (object value)
4757 if (! (value is ColumnHeader)) {
4758 throw new ArgumentException ("Not of type ColumnHeader", "value");
4761 return this.IndexOf ((ColumnHeader) value);
4764 void IList.Insert (int index, object value)
4766 if (! (value is ColumnHeader)) {
4767 throw new ArgumentException ("Not of type ColumnHeader", "value");
4770 this.Insert (index, (ColumnHeader) value);
4773 void IList.Remove (object value)
4775 if (! (value is ColumnHeader)) {
4776 throw new ArgumentException ("Not of type ColumnHeader", "value");
4779 this.Remove ((ColumnHeader) value);
4782 public int IndexOf (ColumnHeader value)
4784 return list.IndexOf (value);
4787 public virtual int IndexOfKey (string key)
4789 if (key == null || key.Length == 0)
4792 for (int i = 0; i < list.Count; i++) {
4793 ColumnHeader col = (ColumnHeader) list [i];
4794 if (String.Compare (key, col.Name, true) == 0)
4801 public void Insert (int index, ColumnHeader value)
4803 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
4804 // but it's really only greater.
4805 if (index < 0 || index > list.Count)
4806 throw new ArgumentOutOfRangeException ("index");
4808 list.Insert (index, value);
4809 owner.AddColumn (value, index, true);
4811 //UIA Framework event: Item added
4812 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4815 public void Insert (int index, string text)
4817 Insert (index, String.Empty, text);
4820 public void Insert (int index, string text, int width)
4822 Insert (index, String.Empty, text, width);
4825 public void Insert (int index, string key, string text)
4827 ColumnHeader colHeader = new ColumnHeader ();
4828 colHeader.Name = key;
4829 colHeader.Text = text;
4830 Insert (index, colHeader);
4833 public void Insert (int index, string key, string text, int width)
4835 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
4836 Insert (index, colHeader);
4839 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4841 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4842 colHeader.ImageIndex = imageIndex;
4843 Insert (index, colHeader);
4846 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4848 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4849 colHeader.ImageKey = imageKey;
4850 Insert (index, colHeader);
4853 public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
4856 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4857 this.Insert (index, colHeader);
4860 public virtual void Remove (ColumnHeader column)
4862 if (!Contains (column))
4865 list.Remove (column);
4866 column.SetListView (null);
4868 int rem_display_index = column.InternalDisplayIndex;
4869 int [] display_indices = new int [list.Count];
4870 for (int i = 0; i < display_indices.Length; i++) {
4871 ColumnHeader col = (ColumnHeader) list [i];
4872 int display_index = col.InternalDisplayIndex;
4873 if (display_index < rem_display_index) {
4874 display_indices [i] = display_index;
4876 display_indices [i] = (display_index - 1);
4880 column.InternalDisplayIndex = -1;
4881 owner.ReorderColumns (display_indices, true);
4883 //UIA Framework event: Item Removed
4884 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
4887 public virtual void RemoveByKey (string key)
4889 int idx = IndexOfKey (key);
4894 public virtual void RemoveAt (int index)
4896 if (index < 0 || index >= list.Count)
4897 throw new ArgumentOutOfRangeException ("index");
4899 ColumnHeader col = (ColumnHeader) list [index];
4902 #endregion // Public Methods
4905 } // ColumnHeaderCollection
4907 [ListBindable (false)]
4908 public class ListViewItemCollection : IList, ICollection, IEnumerable
4910 private readonly ArrayList list;
4911 private ListView owner;
4912 private ListViewGroup group;
4914 #region UIA Framework Events
4916 // We are using Reflection to add/remove internal events.
4917 // Class ListViewProvider uses the events.
4919 //Event used to generate UIA StructureChangedEvent
4920 static object UIACollectionChangedEvent = new object ();
4922 internal event CollectionChangeEventHandler UIACollectionChanged {
4925 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4929 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4933 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4938 CollectionChangeEventHandler eh
4939 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4944 #endregion UIA Framework Events
4946 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
4947 // In the later case ListViewItem.ListView never gets modified
4948 private bool is_main_collection = true;
4950 #region Public Constructor
4951 public ListViewItemCollection (ListView owner)
4953 list = new ArrayList (0);
4956 #endregion // Public Constructor
4958 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
4961 is_main_collection = false;
4964 #region Public Properties
4968 if (owner != null && owner.VirtualMode)
4969 return owner.VirtualListSize;
4975 public bool IsReadOnly {
4976 get { return false; }
4979 public virtual ListViewItem this [int index] {
4981 if (index < 0 || index >= Count)
4982 throw new ArgumentOutOfRangeException ("index");
4984 if (owner != null && owner.VirtualMode)
4985 return RetrieveVirtualItemFromOwner (index);
4986 return (ListViewItem) list [index];
4990 if (index < 0 || index >= Count)
4991 throw new ArgumentOutOfRangeException ("index");
4993 if (owner != null && owner.VirtualMode)
4994 throw new InvalidOperationException ();
4996 if (list.Contains (value))
4997 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4999 if (value.ListView != null && value.ListView != owner)
5000 throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value");
5002 if (is_main_collection)
5003 value.Owner = owner;
5005 if (value.Group != null)
5006 value.Group.Items.Remove (value);
5008 value.SetGroup (group);
5011 //UIA Framework event: Item Replaced
5012 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5014 list [index] = value;
5016 CollectionChanged (true);
5018 //UIA Framework event: Item Replaced
5019 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5024 public virtual ListViewItem this [string key] {
5026 int idx = IndexOfKey (key);
5034 bool ICollection.IsSynchronized {
5035 get { return true; }
5038 object ICollection.SyncRoot {
5039 get { return this; }
5042 bool IList.IsFixedSize {
5043 get { return list.IsFixedSize; }
5046 object IList.this [int index] {
5047 get { return this [index]; }
5049 //UIA Framework event: Item Replaced
5050 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5052 if (value is ListViewItem)
5053 this [index] = (ListViewItem) value;
5055 this [index] = new ListViewItem (value.ToString ());
5058 //UIA Framework event: Item Replaced
5059 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5062 #endregion // Public Properties
5064 #region Public Methods
5065 public virtual ListViewItem Add (ListViewItem value)
5067 if (owner != null && owner.VirtualMode)
5068 throw new InvalidOperationException ();
5072 // Item is ignored until it has been added to the ListView
5073 if (is_main_collection || value.ListView != null)
5074 CollectionChanged (true);
5076 //UIA Framework event: Item Added
5077 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5082 public virtual ListViewItem Add (string text)
5084 ListViewItem item = new ListViewItem (text);
5085 return this.Add (item);
5088 public virtual ListViewItem Add (string text, int imageIndex)
5090 ListViewItem item = new ListViewItem (text, imageIndex);
5091 return this.Add (item);
5094 public virtual ListViewItem Add (string text, string imageKey)
5096 ListViewItem item = new ListViewItem (text, imageKey);
5097 return this.Add (item);
5100 public virtual ListViewItem Add (string key, string text, int imageIndex)
5102 ListViewItem item = new ListViewItem (text, imageIndex);
5104 return this.Add (item);
5107 public virtual ListViewItem Add (string key, string text, string imageKey)
5109 ListViewItem item = new ListViewItem (text, imageKey);
5111 return this.Add (item);
5114 public void AddRange (ListViewItem [] items)
5117 throw new ArgumentNullException ("Argument cannot be null!", "items");
5118 if (owner != null && owner.VirtualMode)
5119 throw new InvalidOperationException ();
5121 owner.BeginUpdate ();
5123 foreach (ListViewItem item in items) {
5126 //UIA Framework event: Item Added
5127 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5132 CollectionChanged (true);
5135 public void AddRange (ListViewItemCollection items)
5138 throw new ArgumentNullException ("Argument cannot be null!", "items");
5140 ListViewItem[] itemArray = new ListViewItem[items.Count];
5141 items.CopyTo (itemArray,0);
5142 this.AddRange (itemArray);
5145 public virtual void Clear ()
5147 if (owner != null && owner.VirtualMode)
5148 throw new InvalidOperationException ();
5149 if (is_main_collection && owner != null) {
5150 owner.SetFocusedItem (-1);
5151 owner.h_scroll.Value = owner.v_scroll.Value = 0;
5153 // first remove any item in the groups that *are* part of this LV too
5154 foreach (ListViewGroup group in owner.groups)
5155 group.Items.ClearItemsWithSameListView ();
5157 foreach (ListViewItem item in list) {
5158 owner.item_control.CancelEdit (item);
5163 foreach (ListViewItem item in list)
5164 item.SetGroup (null);
5167 CollectionChanged (false);
5169 //UIA Framework event: Items Removed
5170 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5174 // This method is intended to be used from ListViewGroup.Items, not from ListView.Items,
5175 // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items)
5176 void ClearItemsWithSameListView ()
5178 if (is_main_collection)
5181 int counter = list.Count - 1;
5182 while (counter >= 0) {
5183 ListViewItem item = list [counter] as ListViewItem;
5185 // remove only if the items in group have being added to the ListView too
5186 if (item.ListView == group.ListView) {
5187 list.RemoveAt (counter);
5188 item.SetGroup (null);
5195 public bool Contains (ListViewItem item)
5197 return IndexOf (item) != -1;
5200 public virtual bool ContainsKey (string key)
5202 return IndexOfKey (key) != -1;
5205 public void CopyTo (Array dest, int index)
5207 list.CopyTo (dest, index);
5210 public ListViewItem [] Find (string key, bool searchAllSubItems)
5213 return new ListViewItem [0];
5215 List<ListViewItem> temp_list = new List<ListViewItem> ();
5217 for (int i = 0; i < list.Count; i++) {
5218 ListViewItem lvi = (ListViewItem) list [i];
5219 if (String.Compare (key, lvi.Name, true) == 0)
5220 temp_list.Add (lvi);
5223 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5224 temp_list.CopyTo (retval);
5229 public IEnumerator GetEnumerator ()
5231 if (owner != null && owner.VirtualMode)
5232 throw new InvalidOperationException ();
5234 // This enumerator makes a copy of the collection so
5235 // it can be deleted from in a foreach
5236 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5239 int IList.Add (object item)
5244 if (owner != null && owner.VirtualMode)
5245 throw new InvalidOperationException ();
5247 if (item is ListViewItem) {
5248 li = (ListViewItem) item;
5249 if (list.Contains (li))
5250 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5252 if (li.ListView != null && li.ListView != owner)
5253 throw new ArgumentException ("Cannot add or insert the item '" + li.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item");
5256 li = new ListViewItem (item.ToString ());
5261 result = list.Add (li);
5262 CollectionChanged (true);
5264 //UIA Framework event: Item Added
5265 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5270 bool IList.Contains (object item)
5272 return Contains ((ListViewItem) item);
5275 int IList.IndexOf (object item)
5277 return IndexOf ((ListViewItem) item);
5280 void IList.Insert (int index, object item)
5282 if (item is ListViewItem)
5283 this.Insert (index, (ListViewItem) item);
5285 this.Insert (index, item.ToString ());
5287 //UIA Framework event: Item Added
5288 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5291 void IList.Remove (object item)
5293 Remove ((ListViewItem) item);
5296 public int IndexOf (ListViewItem item)
5298 if (owner != null && owner.VirtualMode) {
5299 for (int i = 0; i < Count; i++)
5300 if (RetrieveVirtualItemFromOwner (i) == item)
5306 return list.IndexOf (item);
5309 public virtual int IndexOfKey (string key)
5311 if (key == null || key.Length == 0)
5314 for (int i = 0; i < Count; i++) {
5315 ListViewItem lvi = this [i];
5316 if (String.Compare (key, lvi.Name, true) == 0)
5323 public ListViewItem Insert (int index, ListViewItem item)
5325 if (index < 0 || index > list.Count)
5326 throw new ArgumentOutOfRangeException ("index");
5328 if (owner != null && owner.VirtualMode)
5329 throw new InvalidOperationException ();
5331 if (list.Contains (item))
5332 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5334 if (item.ListView != null && item.ListView != owner)
5335 throw new ArgumentException ("Cannot add or insert the item '" + item.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item");
5337 if (is_main_collection)
5340 if (item.Group != null)
5341 item.Group.Items.Remove (item);
5343 item.SetGroup (group);
5346 list.Insert (index, item);
5348 if (is_main_collection || item.ListView != null)
5349 CollectionChanged (true);
5351 // force an update of the selected info if the new item is selected.
5353 item.SetSelectedCore (true);
5354 //UIA Framework event: Item Added
5355 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5360 public ListViewItem Insert (int index, string text)
5362 return this.Insert (index, new ListViewItem (text));
5365 public ListViewItem Insert (int index, string text, int imageIndex)
5367 return this.Insert (index, new ListViewItem (text, imageIndex));
5370 public ListViewItem Insert (int index, string text, string imageKey)
5372 ListViewItem lvi = new ListViewItem (text, imageKey);
5373 return Insert (index, lvi);
5376 public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5378 ListViewItem lvi = new ListViewItem (text, imageIndex);
5380 return Insert (index, lvi);
5383 public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5385 ListViewItem lvi = new ListViewItem (text, imageKey);
5387 return Insert (index, lvi);
5390 public virtual void Remove (ListViewItem item)
5392 if (owner != null && owner.VirtualMode)
5393 throw new InvalidOperationException ();
5395 int idx = list.IndexOf (item);
5400 public virtual void RemoveAt (int index)
5402 if (index < 0 || index >= Count)
5403 throw new ArgumentOutOfRangeException ("index");
5405 if (owner != null && owner.VirtualMode)
5406 throw new InvalidOperationException ();
5408 ListViewItem item = (ListViewItem) list [index];
5410 bool selection_changed = false;
5411 if (is_main_collection && owner != null) {
5413 int display_index = item.DisplayIndex;
5414 if (item.Focused && display_index + 1 == Count) // Last item
5415 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5417 selection_changed = owner.SelectedIndices.Contains (index);
5418 owner.item_control.CancelEdit (item);
5421 list.RemoveAt (index);
5423 if (is_main_collection) {
5425 if (item.Group != null)
5426 item.Group.Items.Remove (item);
5428 item.SetGroup (null);
5430 CollectionChanged (false);
5431 if (selection_changed && owner != null)
5432 owner.OnSelectedIndexChanged (EventArgs.Empty);
5435 //UIA Framework event: Item Removed
5436 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5439 public virtual void RemoveByKey (string key)
5441 int idx = IndexOfKey (key);
5446 #endregion // Public Methods
5448 internal ListView Owner {
5457 internal ListViewGroup Group {
5466 void AddItem (ListViewItem value)
5468 if (list.Contains (value))
5469 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5471 if (value.ListView != null && value.ListView != owner)
5472 throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value");
5473 if (is_main_collection)
5474 value.Owner = owner;
5476 if (value.Group != null)
5477 value.Group.Items.Remove (value);
5479 value.SetGroup (group);
5484 // force an update of the selected info if the new item is selected.
5486 value.SetSelectedCore (true);
5489 void CollectionChanged (bool sort)
5491 if (owner != null) {
5496 owner.Redraw (true);
5500 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5502 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5504 owner.OnRetrieveVirtualItem (args);
5505 ListViewItem retval = args.Item;
5506 retval.Owner = owner;
5507 retval.DisplayIndex = displayIndex;
5513 internal event CollectionChangedHandler Changed;
5515 internal void Sort (IComparer comparer)
5517 list.Sort (comparer);
5521 internal void OnChange ()
5523 if (Changed != null)
5526 } // ListViewItemCollection
5529 // In normal mode, the selection information resides in the Items,
5530 // making SelectedIndexCollection.List read-only
5532 // In virtual mode, SelectedIndexCollection directly saves the selection
5533 // information, instead of getting it from Items, making List read-and-write
5534 [ListBindable (false)]
5535 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5537 private readonly ListView owner;
5538 private ArrayList list;
5540 #region Public Constructor
5541 public SelectedIndexCollection (ListView owner)
5544 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5546 #endregion // Public Constructor
5548 #region Public Properties
5552 if (!owner.is_selection_available)
5559 public bool IsReadOnly {
5565 public int this [int index] {
5567 if (!owner.is_selection_available || index < 0 || index >= List.Count)
5568 throw new ArgumentOutOfRangeException ("index");
5570 return (int) List [index];
5574 bool ICollection.IsSynchronized {
5575 get { return false; }
5578 object ICollection.SyncRoot {
5579 get { return this; }
5582 bool IList.IsFixedSize {
5588 object IList.this [int index] {
5589 get { return this [index]; }
5590 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5592 #endregion // Public Properties
5594 #region Public Methods
5595 public int Add (int itemIndex)
5597 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5598 throw new ArgumentOutOfRangeException ("index");
5600 if (owner.virtual_mode && !owner.is_selection_available)
5603 owner.Items [itemIndex].Selected = true;
5605 if (!owner.is_selection_available)
5611 public void Clear ()
5613 if (!owner.is_selection_available)
5616 int [] indexes = (int []) List.ToArray (typeof (int));
5617 foreach (int index in indexes)
5618 owner.Items [index].Selected = false;
5621 public bool Contains (int selectedIndex)
5623 return IndexOf (selectedIndex) != -1;
5626 public void CopyTo (Array dest, int index)
5628 List.CopyTo (dest, index);
5631 public IEnumerator GetEnumerator ()
5633 return List.GetEnumerator ();
5636 int IList.Add (object value)
5638 throw new NotSupportedException ("Add operation is not supported.");
5646 bool IList.Contains (object selectedIndex)
5648 if (!(selectedIndex is int))
5650 return Contains ((int) selectedIndex);
5653 int IList.IndexOf (object selectedIndex)
5655 if (!(selectedIndex is int))
5657 return IndexOf ((int) selectedIndex);
5660 void IList.Insert (int index, object value)
5662 throw new NotSupportedException ("Insert operation is not supported.");
5665 void IList.Remove (object value)
5667 throw new NotSupportedException ("Remove operation is not supported.");
5670 void IList.RemoveAt (int index)
5672 throw new NotSupportedException ("RemoveAt operation is not supported.");
5675 public int IndexOf (int selectedIndex)
5677 if (!owner.is_selection_available)
5680 return List.IndexOf (selectedIndex);
5683 public void Remove (int itemIndex)
5685 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5686 throw new ArgumentOutOfRangeException ("itemIndex");
5688 owner.Items [itemIndex].Selected = false;
5690 #endregion // Public Methods
5692 internal ArrayList List {
5695 list = new ArrayList ();
5696 if (!owner.VirtualMode)
5697 for (int i = 0; i < owner.Items.Count; i++) {
5698 if (owner.Items [i].Selected)
5706 internal void Reset ()
5708 // force re-population of list
5712 private void ItemsCollection_Changed ()
5717 internal void RemoveIndex (int index)
5719 int idx = List.BinarySearch (index);
5721 List.RemoveAt (idx);
5724 // actually store index in the collection
5725 // also, keep the collection sorted, as .Net does
5726 internal void InsertIndex (int index)
5729 int iMax = List.Count - 1;
5730 while (iMin <= iMax) {
5731 int iMid = (iMin + iMax) / 2;
5732 int current_index = (int) List [iMid];
5734 if (current_index == index)
5735 return; // Already added
5736 if (current_index > index)
5742 List.Insert (iMin, index);
5745 } // SelectedIndexCollection
5747 [ListBindable (false)]
5748 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
5750 private readonly ListView owner;
5752 #region Public Constructor
5753 public SelectedListViewItemCollection (ListView owner)
5757 #endregion // Public Constructor
5759 #region Public Properties
5763 return owner.SelectedIndices.Count;
5767 public bool IsReadOnly {
5768 get { return true; }
5771 public ListViewItem this [int index] {
5773 if (!owner.is_selection_available || index < 0 || index >= Count)
5774 throw new ArgumentOutOfRangeException ("index");
5776 int item_index = owner.SelectedIndices [index];
5777 return owner.Items [item_index];
5781 public virtual ListViewItem this [string key] {
5783 int idx = IndexOfKey (key);
5791 bool ICollection.IsSynchronized {
5792 get { return false; }
5795 object ICollection.SyncRoot {
5796 get { return this; }
5799 bool IList.IsFixedSize {
5800 get { return true; }
5803 object IList.this [int index] {
5804 get { return this [index]; }
5805 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5807 #endregion // Public Properties
5809 #region Public Methods
5810 public void Clear ()
5812 owner.SelectedIndices.Clear ();
5815 public bool Contains (ListViewItem item)
5817 return IndexOf (item) != -1;
5820 public virtual bool ContainsKey (string key)
5822 return IndexOfKey (key) != -1;
5825 public void CopyTo (Array dest, int index)
5827 if (!owner.is_selection_available)
5829 if (index > Count) // Throws ArgumentException instead of IOOR exception
5830 throw new ArgumentException ("index");
5832 for (int i = 0; i < Count; i++)
5833 dest.SetValue (this [i], index++);
5836 public IEnumerator GetEnumerator ()
5838 if (!owner.is_selection_available)
5839 return (new ListViewItem [0]).GetEnumerator ();
5841 ListViewItem [] items = new ListViewItem [Count];
5842 for (int i = 0; i < Count; i++)
5843 items [i] = this [i];
5845 return items.GetEnumerator ();
5848 int IList.Add (object value)
5850 throw new NotSupportedException ("Add operation is not supported.");
5853 bool IList.Contains (object item)
5855 if (!(item is ListViewItem))
5857 return Contains ((ListViewItem) item);
5860 int IList.IndexOf (object item)
5862 if (!(item is ListViewItem))
5864 return IndexOf ((ListViewItem) item);
5867 void IList.Insert (int index, object value)
5869 throw new NotSupportedException ("Insert operation is not supported.");
5872 void IList.Remove (object value)
5874 throw new NotSupportedException ("Remove operation is not supported.");
5877 void IList.RemoveAt (int index)
5879 throw new NotSupportedException ("RemoveAt operation is not supported.");
5882 public int IndexOf (ListViewItem item)
5884 if (!owner.is_selection_available)
5887 for (int i = 0; i < Count; i++)
5888 if (this [i] == item)
5894 public virtual int IndexOfKey (string key)
5896 if (!owner.is_selection_available || key == null || key.Length == 0)
5899 for (int i = 0; i < Count; i++) {
5900 ListViewItem item = this [i];
5901 if (String.Compare (item.Name, key, true) == 0)
5907 #endregion // Public Methods
5909 } // SelectedListViewItemCollection
5911 internal delegate void CollectionChangedHandler ();
5913 struct ItemMatrixLocation
5918 public ItemMatrixLocation (int row, int col)
5945 #endregion // Subclasses
5946 protected override void OnResize (EventArgs e)
5951 protected override void OnMouseLeave (EventArgs e)
5953 base.OnMouseLeave (e);
5957 // ColumnReorder event
5959 static object ColumnReorderedEvent = new object ();
5960 public event ColumnReorderedEventHandler ColumnReordered {
5961 add { Events.AddHandler (ColumnReorderedEvent, value); }
5962 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
5965 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
5967 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
5974 // ColumnWidthChanged
5976 static object ColumnWidthChangedEvent = new object ();
5977 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
5978 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
5979 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
5982 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
5984 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
5989 void RaiseColumnWidthChanged (int resize_column)
5991 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
5993 OnColumnWidthChanged (n);
5997 // ColumnWidthChanging
5999 static object ColumnWidthChangingEvent = new object ();
6000 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
6001 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
6002 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
6005 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6007 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6013 // 2.0 profile based implementation
6015 bool CanProceedWithResize (ColumnHeader col, int width)
6017 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6021 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6022 cwceh (this, changing);
6023 return !changing.Cancel;
6026 internal void RaiseColumnWidthChanged (ColumnHeader column)
6028 int index = Columns.IndexOf (column);
6029 RaiseColumnWidthChanged (index);
6033 #region UIA Framework: Methods, Properties and Events
6035 static object UIALabelEditChangedEvent = new object ();
6036 static object UIAShowGroupsChangedEvent = new object ();
6037 static object UIAMultiSelectChangedEvent = new object ();
6038 static object UIAViewChangedEvent = new object ();
6039 static object UIACheckBoxesChangedEvent = new object ();
6040 static object UIAFocusedItemChangedEvent = new object ();
6042 internal Rectangle UIAHeaderControl {
6043 get { return header_control.Bounds; }
6046 internal int UIAColumns {
6047 get { return cols; }
6050 internal int UIARows {
6051 get { return rows; }
6054 internal ListViewGroup UIADefaultListViewGroup
6056 get { return groups.DefaultGroup; }
6059 internal ScrollBar UIAHScrollBar {
6060 get { return h_scroll; }
6063 internal ScrollBar UIAVScrollBar {
6064 get { return v_scroll; }
6067 internal event EventHandler UIAShowGroupsChanged {
6068 add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6069 remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6072 internal event EventHandler UIACheckBoxesChanged {
6073 add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6074 remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6077 internal event EventHandler UIAMultiSelectChanged {
6078 add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6079 remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6082 internal event EventHandler UIALabelEditChanged {
6083 add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6084 remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6087 internal event EventHandler UIAViewChanged {
6088 add { Events.AddHandler (UIAViewChangedEvent, value); }
6089 remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6092 internal event EventHandler UIAFocusedItemChanged {
6093 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6094 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6097 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6099 return group.HeaderBounds;
6102 internal int UIAItemsLocationLength
6104 get { return items_location.Length; }
6107 private void OnUIACheckBoxesChanged ()
6109 EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6111 eh (this, EventArgs.Empty);
6114 private void OnUIAShowGroupsChanged ()
6116 EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6118 eh (this, EventArgs.Empty);
6121 private void OnUIAMultiSelectChanged ()
6123 EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6125 eh (this, EventArgs.Empty);
6128 private void OnUIALabelEditChanged ()
6130 EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6132 eh (this, EventArgs.Empty);
6135 private void OnUIAViewChanged ()
6137 EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6139 eh (this, EventArgs.Empty);
6142 internal void OnUIAFocusedItemChanged ()
6144 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6146 eh (this, EventArgs.Empty);
6149 #endregion // UIA Framework: Methods, Properties and Events