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 selected_indices.Reset ();
1039 #endregion // Public Instance Properties
1041 #region Internal Methods Properties
1043 internal int FirstVisibleIndex {
1046 if (this.items.Count == 0)
1049 if (h_marker == 0 && v_marker == 0)
1052 Size item_size = ItemSize;
1053 // In virtual mode we always have fixed positions, and we can infer the positon easily
1058 first = v_marker / item_size.Height;
1060 case View.LargeIcon:
1061 case View.SmallIcon:
1062 first = (v_marker / (item_size.Height + y_spacing)) * cols;
1065 first = (h_marker / (item_size.Width * x_spacing)) * rows;
1069 if (first >= items.Count)
1070 first = items.Count;
1074 for (int i = 0; i < items.Count; i++) {
1075 Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size);
1076 if (item_rect.Right >= 0 && item_rect.Bottom >= 0)
1085 internal int LastVisibleIndex {
1087 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
1088 if (View == View.List || Alignment == ListViewAlignment.Left) {
1089 if (GetItemLocation (i).X > item_control.ClientRectangle.Right)
1092 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
1097 return Items.Count - 1;
1101 internal void OnSelectedIndexChanged ()
1103 if (is_selection_available)
1104 OnSelectedIndexChanged (EventArgs.Empty);
1107 internal int TotalWidth {
1108 get { return Math.Max (this.Width, this.layout_wd); }
1111 internal int TotalHeight {
1112 get { return Math.Max (this.Height, this.layout_ht); }
1115 internal void Redraw (bool recalculate)
1117 // Avoid calculations when control is being updated
1120 // VirtualMode doesn't do any calculations until handle is created
1121 if (virtual_mode && !IsHandleCreated)
1126 CalculateListView (this.alignment);
1131 void InvalidateSelection ()
1133 foreach (int selected_index in SelectedIndices)
1134 items [selected_index].Invalidate ();
1137 const int text_padding = 15;
1139 internal Size GetChildColumnSize (int index)
1141 Size ret_size = Size.Empty;
1142 ColumnHeader col = this.columns [index];
1144 if (col.Width == -2) { // autosize = max(items, columnheader)
1145 Size size = Size.Ceiling (TextRenderer.MeasureString
1146 (col.Text, this.Font));
1147 size.Width += text_padding;
1148 ret_size = BiggestItem (index);
1149 if (size.Width > ret_size.Width)
1152 else { // -1 and all the values < -2 are put under one category
1153 ret_size = BiggestItem (index);
1154 // fall back to empty columns' width if no subitem is available for a column
1155 if (ret_size.IsEmpty) {
1156 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
1157 if (col.Text.Length > 0)
1158 ret_size.Height = Size.Ceiling (TextRenderer.MeasureString
1159 (col.Text, this.Font)).Height;
1161 ret_size.Height = this.Font.Height;
1165 ret_size.Height += text_padding;
1167 // adjust the size for icon and checkbox for 0th column
1169 ret_size.Width += (this.CheckBoxSize.Width + 4);
1170 if (this.small_image_list != null)
1171 ret_size.Width += this.small_image_list.ImageSize.Width;
1176 // Returns the size of biggest item text in a column
1177 // or the sum of the text and indent count if we are on 2.0
1178 private Size BiggestItem (int col)
1180 Size temp = Size.Empty;
1181 Size ret_size = Size.Empty;
1182 bool use_indent_count = small_image_list != null;
1184 // VirtualMode uses the first item text size
1185 if (virtual_mode && items.Count > 0) {
1186 ListViewItem item = items [0];
1187 ret_size = Size.Ceiling (TextRenderer.MeasureString (item.SubItems[col].Text,
1190 if (use_indent_count)
1191 ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width;
1193 // 0th column holds the item text, we check the size of
1194 // the various subitems falling in that column and get
1195 // the biggest one's size.
1196 foreach (ListViewItem item in items) {
1197 if (col >= item.SubItems.Count)
1200 temp = Size.Ceiling (TextRenderer.MeasureString
1201 (item.SubItems [col].Text, Font));
1203 if (use_indent_count)
1204 temp.Width += item.IndentCount * small_image_list.ImageSize.Width;
1206 if (temp.Width > ret_size.Width)
1211 // adjustment for space in Details view
1212 if (!ret_size.IsEmpty && view == View.Details)
1213 ret_size.Width += ThemeEngine.Current.ListViewItemPaddingWidth;
1218 const int max_wrap_padding = 30;
1220 // Sets the size of the biggest item text as per the view
1221 private void CalcTextSize ()
1223 // clear the old value
1224 text_size = Size.Empty;
1226 if (items.Count == 0)
1229 text_size = BiggestItem (0);
1231 if (view == View.LargeIcon && this.label_wrap) {
1232 Size temp = Size.Empty;
1233 if (this.check_boxes)
1234 temp.Width += 2 * this.CheckBoxSize.Width;
1235 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1236 temp.Width += icon_w + max_wrap_padding;
1237 // wrapping is done for two lines only
1238 if (text_size.Width > temp.Width) {
1239 text_size.Width = temp.Width;
1240 text_size.Height *= 2;
1243 else if (view == View.List) {
1244 // in list view max text shown in determined by the
1245 // control width, even if scolling is enabled.
1246 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
1247 if (this.small_image_list != null)
1248 max_wd -= this.small_image_list.ImageSize.Width;
1250 if (text_size.Width > max_wd)
1251 text_size.Width = max_wd;
1254 // we do the default settings, if we have got 0's
1255 if (text_size.Height <= 0)
1256 text_size.Height = this.Font.Height;
1257 if (text_size.Width <= 0)
1258 text_size.Width = this.Width;
1260 // little adjustment
1261 text_size.Width += 2;
1262 text_size.Height += 2;
1265 private void SetScrollValue (ScrollBar scrollbar, int val)
1268 if (scrollbar == h_scroll)
1269 max = h_scroll.Maximum - h_scroll.LargeChange + 1;
1271 max = v_scroll.Maximum - v_scroll.LargeChange + 1;
1275 else if (val < scrollbar.Minimum)
1276 val = scrollbar.Minimum;
1278 scrollbar.Value = val;
1281 private void Scroll (ScrollBar scrollbar, int delta)
1283 if (delta == 0 || !scrollbar.Visible)
1286 SetScrollValue (scrollbar, scrollbar.Value + delta);
1289 private void CalculateScrollBars ()
1291 Rectangle client_area = ClientRectangle;
1292 int height = client_area.Height;
1293 int width = client_area.Width;
1297 h_scroll.Visible = false;
1298 v_scroll.Visible = false;
1299 item_control.Size = new Size (width, height);
1300 header_control.Width = width;
1304 // Don't calculate if the view is not displayable
1305 if (client_area.Height < 0 || client_area.Width < 0)
1308 // making a scroll bar visible might make
1309 // other scroll bar visible
1310 if (layout_wd > client_area.Right) {
1311 h_scroll.Visible = true;
1312 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1313 v_scroll.Visible = true;
1315 v_scroll.Visible = false;
1316 } else if (layout_ht > client_area.Bottom) {
1317 v_scroll.Visible = true;
1318 if ((layout_wd + v_scroll.Width) > client_area.Right)
1319 h_scroll.Visible = true;
1321 h_scroll.Visible = false;
1323 h_scroll.Visible = false;
1324 v_scroll.Visible = false;
1328 item_size = ItemSize;
1330 if (h_scroll.is_visible) {
1331 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1332 h_scroll.Minimum = 0;
1334 // if v_scroll is visible, adjust the maximum of the
1335 // h_scroll to account for the width of v_scroll
1336 if (v_scroll.Visible) {
1337 h_scroll.Maximum = layout_wd + v_scroll.Width;
1338 h_scroll.Width = client_area.Width - v_scroll.Width;
1341 h_scroll.Maximum = layout_wd;
1342 h_scroll.Width = client_area.Width;
1345 if (view == View.List)
1346 h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing;
1348 h_scroll.SmallChange = Font.Height;
1350 h_scroll.LargeChange = client_area.Width;
1351 height -= h_scroll.Height;
1354 if (v_scroll.is_visible) {
1355 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1356 v_scroll.Minimum = 0;
1358 // if h_scroll is visible, adjust the height of
1359 // v_scroll to account for the height of h_scroll
1360 if (h_scroll.Visible) {
1361 v_scroll.Maximum = layout_ht + h_scroll.Height;
1362 v_scroll.Height = client_area.Height > h_scroll.Height ? client_area.Height - h_scroll.Height : 0;
1364 v_scroll.Maximum = layout_ht;
1365 v_scroll.Height = client_area.Height;
1368 if (view == View.Details) {
1369 // Need to update Maximum if using LargeChange with value other than the visible area
1370 int headerPlusOneItem = header_control.Height + item_size.Height;
1371 v_scroll.LargeChange = v_scroll.Height > headerPlusOneItem ? v_scroll.Height - headerPlusOneItem : 0;
1372 v_scroll.Maximum = v_scroll.Maximum > headerPlusOneItem ? v_scroll.Maximum - headerPlusOneItem : 0;
1374 v_scroll.LargeChange = v_scroll.Height;
1376 v_scroll.SmallChange = item_size.Height;
1377 width -= v_scroll.Width;
1380 item_control.Size = new Size (width, height);
1382 if (header_control.is_visible)
1383 header_control.Width = width;
1386 internal int GetReorderedColumnIndex (ColumnHeader column)
1388 if (reordered_column_indices == null)
1389 return column.Index;
1391 for (int i = 0; i < Columns.Count; i++)
1392 if (reordered_column_indices [i] == column.Index)
1398 internal ColumnHeader GetReorderedColumn (int index)
1400 if (reordered_column_indices == null)
1401 return Columns [index];
1403 return Columns [reordered_column_indices [index]];
1406 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1409 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1411 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1415 header_control.Invalidate ();
1416 item_control.Invalidate ();
1421 int column_count = Columns.Count;
1423 if (reordered_column_indices == null) {
1424 reordered_column_indices = new int [column_count];
1425 for (int i = 0; i < column_count; i++)
1426 reordered_column_indices [i] = i;
1429 if (reordered_column_indices [index] == col.Index)
1432 int[] curr = reordered_column_indices;
1433 int [] result = new int [column_count];
1435 for (int i = 0; i < column_count; i++) {
1436 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1440 result [i] = col.Index;
1442 result [i] = curr [curr_idx++];
1445 ReorderColumns (result, true);
1448 internal void ReorderColumns (int [] display_indices, bool redraw)
1450 reordered_column_indices = display_indices;
1451 for (int i = 0; i < Columns.Count; i++) {
1452 ColumnHeader col = Columns [i];
1453 col.InternalDisplayIndex = reordered_column_indices [i];
1455 if (redraw && view == View.Details && IsHandleCreated) {
1457 header_control.Invalidate ();
1458 item_control.Invalidate ();
1462 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1464 int column_count = Columns.Count;
1465 newCol.SetListView (this);
1467 int [] display_indices = new int [column_count];
1468 for (int i = 0; i < column_count; i++) {
1469 ColumnHeader col = Columns [i];
1471 display_indices [i] = index;
1473 int display_index = col.InternalDisplayIndex;
1474 if (display_index < index) {
1475 display_indices [i] = display_index;
1477 display_indices [i] = (display_index + 1);
1482 ReorderColumns (display_indices, redraw);
1486 Size LargeIconItemSize
1489 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1490 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1491 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1492 int w = Math.Max (text_size.Width, image_w);
1495 w += 2 + CheckBoxSize.Width;
1497 return new Size (w, h);
1501 Size SmallIconItemSize {
1503 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1504 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1505 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1506 int w = text_size.Width + image_w;
1509 w += 2 + CheckBoxSize.Width;
1511 return new Size (w, h);
1517 // Calculate tile size if needed
1518 // It appears that using Font.Size instead of a SizeF value can give us
1519 // a slightly better approach to the proportions defined in .Net
1520 if (tile_size == Size.Empty) {
1521 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1522 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1523 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1524 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1526 tile_size = new Size (w, h);
1533 int GetDetailsItemHeight ()
1536 int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1537 int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1538 item_height = Math.Max (checkbox_height, text_size.Height);
1539 item_height = Math.Max (item_height, small_image_height);
1543 void SetItemLocation (int index, int x, int y, int row, int col)
1545 Point old_location = items_location [index];
1546 if (old_location.X == x && old_location.Y == y)
1549 items_location [index] = new Point (x, y);
1550 items_matrix_location [index] = new ItemMatrixLocation (row, col);
1553 // Initial position matches item's position in ListViewItemCollection
1555 reordered_items_indices [index] = index;
1559 void ShiftItemsPositions (int from, int to, bool forward)
1562 for (int i = to + 1; i > from; i--) {
1563 reordered_items_indices [i] = reordered_items_indices [i - 1];
1565 ListViewItem item = items [reordered_items_indices [i]];
1567 item.DisplayIndex = i;
1571 for (int i = from - 1; i < to; i++) {
1572 reordered_items_indices [i] = reordered_items_indices [i + 1];
1574 ListViewItem item = items [reordered_items_indices [i]];
1576 item.DisplayIndex = i;
1582 internal void ChangeItemLocation (int display_index, Point new_pos)
1584 int new_display_index = GetDisplayIndexFromLocation (new_pos);
1585 if (new_display_index == display_index)
1588 int item_index = reordered_items_indices [display_index];
1589 ListViewItem item = items [item_index];
1591 bool forward = new_display_index < display_index;
1592 int index_from, index_to;
1594 index_from = new_display_index;
1595 index_to = display_index - 1;
1597 index_from = display_index + 1;
1598 index_to = new_display_index;
1601 ShiftItemsPositions (index_from, index_to, forward);
1603 reordered_items_indices [new_display_index] = item_index;
1606 item.DisplayIndex = new_display_index;
1610 int GetDisplayIndexFromLocation (Point loc)
1612 int display_index = -1;
1613 Rectangle item_area;
1616 if (loc.X < 0 || loc.Y < 0)
1619 // Adjustment to put in the next position refered by 'loc'
1620 loc.X -= item_size.Width / 2;
1624 for (int i = 0; i < items.Count; i++) {
1625 item_area = new Rectangle (GetItemLocation (i), item_size);
1626 item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing,
1627 ThemeEngine.Current.ListViewVerticalSpacing);
1629 if (item_area.Contains (loc)) {
1635 // Put in in last position
1636 if (display_index == -1)
1637 display_index = items.Count - 1;
1639 return display_index;
1642 // When using groups, the items with no group assigned
1643 // belong to the DefaultGroup
1644 int GetDefaultGroupItems ()
1647 foreach (ListViewItem item in items)
1648 if (item.Group == null)
1654 // cache the spacing to let virtualmode compute the positions on the fly
1659 int[,] item_index_matrix;
1661 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1663 Rectangle area = ClientRectangle;
1665 if (UseCustomColumnWidth)
1666 CalculateCustomColumnWidth ();
1668 // When groups are used the alignment is always top-aligned
1673 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1674 for (int i = 0; i < groups.InternalCount; i++) {
1675 ListViewGroup group = groups.GetInternalGroup (i);
1676 int items_in_group = group.GetActualItemCount ();
1678 if (items_in_group == 0)
1681 int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1682 if (group_cols <= 0)
1684 int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols);
1686 group.starting_row = rows;
1687 group.rows = group_rows;
1688 group.starting_item = items;
1689 group.current_item = 0; // Reset layout
1691 cols = Math.Max (group_cols, cols);
1693 items += items_in_group;
1697 // Simple matrix if no groups are used
1699 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1702 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1704 if (UseCustomColumnWidth)
1705 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width));
1707 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1712 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1716 item_index_matrix = new int [rows, cols];
1719 // When using custom column width, we look for the minimum one
1720 void CalculateCustomColumnWidth ()
1722 int min_width = Int32.MaxValue;
1723 for (int i = 0; i < columns.Count; i++) {
1724 int col_width = columns [i].Width;
1726 if (col_width < min_width)
1727 min_width = col_width;
1730 custom_column_width = min_width;
1733 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1735 header_control.Visible = false;
1736 header_control.Size = Size.Empty;
1737 item_control.Visible = true;
1738 item_control.Location = Point.Empty;
1739 ItemSize = item_size; // Cache item size
1740 this.x_spacing = x_spacing;
1741 this.y_spacing = y_spacing;
1743 if (items.Count == 0)
1746 Size sz = item_size;
1748 CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing);
1750 layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing;
1751 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1753 if (virtual_mode) { // no actual assignment is needed on items for virtual mode
1754 item_control.Size = new Size (layout_wd, layout_ht);
1758 bool using_groups = UsingGroups;
1759 if (using_groups) // the groups layout will override layout_ht
1760 CalculateGroupsLayout (sz, y_spacing, 0);
1762 int row = 0, col = 0;
1764 int display_index = 0;
1766 for (int i = 0; i < items.Count; i++) {
1767 ListViewItem item = items [i];
1769 ListViewGroup group = item.Group;
1771 group = groups.DefaultGroup;
1773 Point group_items_loc = group.items_area_location;
1774 int current_item = group.current_item++;
1775 int starting_row = group.starting_row;
1777 display_index = group.starting_item + current_item;
1778 row = (current_item / cols);
1779 col = current_item % cols;
1781 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1782 y = row * (item_size.Height + y_spacing) + group_items_loc.Y;
1784 SetItemLocation (display_index, x, y, row + starting_row, col);
1785 SetItemAtDisplayIndex (display_index, i);
1786 item_index_matrix [row + starting_row, col] = i;
1790 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1791 y = row * (item_size.Height + y_spacing);
1792 display_index = i; // Same as item index in Items
1794 SetItemLocation (i, x, y, row, col);
1795 item_index_matrix [row, col] = i;
1804 if (++col == cols) {
1812 item.DisplayIndex = display_index;
1813 item.SetPosition (new Point (x, y));
1816 item_control.Size = new Size (layout_wd, layout_ht);
1819 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin)
1822 bool details = view == View.Details;
1824 for (int i = 0; i < groups.InternalCount; i++) {
1825 ListViewGroup group = groups.GetInternalGroup (i);
1826 if (group.ItemCount == 0)
1829 y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows);
1832 layout_ht = y; // Update height taking into account Groups' headers heights
1835 int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows)
1837 Rectangle client_area = ClientRectangle;
1838 int header_height = Font.Height + 15; // one line height + some padding
1840 group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height);
1841 group.items_area_location = new Point (0, y_origin + header_height);
1843 int items_area_height = ((item_height + y_spacing) * rows);
1844 return header_height + items_area_height + 10; // Add a small bottom margin
1847 void CalculateDetailsGroupItemsCount ()
1851 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1852 for (int i = 0; i < groups.InternalCount; i++) {
1853 ListViewGroup group = groups.GetInternalGroup (i);
1854 int items_in_group = group.GetActualItemCount ();
1856 if (items_in_group == 0)
1859 group.starting_item = items;
1860 group.current_item = 0; // Reset layout.
1861 items += items_in_group;
1865 void LayoutHeader ()
1868 for (int i = 0; i < Columns.Count; i++) {
1869 ColumnHeader col = GetReorderedColumn (i);
1872 col.CalcColumnHeader ();
1878 if (x < ClientRectangle.Width)
1879 x = ClientRectangle.Width;
1881 if (header_style == ColumnHeaderStyle.None) {
1882 header_control.Visible = false;
1883 header_control.Size = Size.Empty;
1884 layout_wd = ClientRectangle.Width;
1886 header_control.Width = x;
1887 header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font);
1888 header_control.Visible = true;
1892 void LayoutDetails ()
1896 if (columns.Count == 0) {
1897 item_control.Visible = false;
1898 layout_wd = ClientRectangle.Width;
1899 layout_ht = ClientRectangle.Height;
1903 item_control.Visible = true;
1904 item_control.Location = Point.Empty;
1905 item_control.Width = ClientRectangle.Width;
1906 AdjustChildrenZOrder ();
1908 int item_height = GetDetailsItemHeight ();
1909 ItemSize = new Size (0, item_height); // We only cache Height for details view
1910 int y = header_control.Height;
1911 layout_ht = y + (item_height * items.Count);
1912 if (items.Count > 0 && grid_lines) // some space for bottom gridline
1915 bool using_groups = UsingGroups;
1917 // Observe that this routines will override our layout_ht value
1918 CalculateDetailsGroupItemsCount ();
1919 CalculateGroupsLayout (ItemSize, 2, y);
1922 if (virtual_mode) // no assgination on items is needed
1925 for (int i = 0; i < items.Count; i++) {
1926 ListViewItem item = items [i];
1932 ListViewGroup group = item.Group;
1934 group = groups.DefaultGroup;
1936 int current_item = group.current_item++;
1937 Point group_items_loc = group.items_area_location;
1938 display_index = group.starting_item + current_item;
1940 y = item_y = current_item * (item_height + 2) + group_items_loc.Y;
1941 SetItemLocation (display_index, 0, item_y, 0, 0);
1942 SetItemAtDisplayIndex (display_index, i);
1947 SetItemLocation (i, 0, item_y, 0, 0);
1952 item.DisplayIndex = display_index;
1953 item.SetPosition (new Point (0, item_y));
1957 // Need to make sure HeaderControl is on top, and we can't simply use BringToFront since
1958 // these controls are implicit, so we need to re-populate our collection.
1959 void AdjustChildrenZOrder ()
1962 Controls.ClearImplicit ();
1963 Controls.AddImplicit (header_control);
1964 Controls.AddImplicit (item_control);
1965 Controls.AddImplicit (h_scroll);
1966 Controls.AddImplicit (v_scroll);
1970 private void AdjustItemsPositionArray (int count)
1972 // In virtual mode we compute the positions on the fly.
1975 if (items_location.Length >= count)
1978 // items_location, items_matrix_location and reordered_items_indices must keep the same length
1979 count = Math.Max (count, items_location.Length * 2);
1980 items_location = new Point [count];
1981 items_matrix_location = new ItemMatrixLocation [count];
1982 reordered_items_indices = new int [count];
1985 private void CalculateListView (ListViewAlignment align)
1989 AdjustItemsPositionArray (items.Count);
1996 case View.SmallIcon:
1997 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
1998 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2001 case View.LargeIcon:
2002 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
2003 ThemeEngine.Current.ListViewHorizontalSpacing,
2004 ThemeEngine.Current.ListViewVerticalSpacing);
2008 LayoutIcons (SmallIconItemSize, true,
2009 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2012 if (!Application.VisualStylesEnabled)
2013 goto case View.LargeIcon;
2015 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
2016 ThemeEngine.Current.ListViewHorizontalSpacing,
2017 ThemeEngine.Current.ListViewVerticalSpacing);
2021 CalculateScrollBars ();
2024 internal Point GetItemLocation (int index)
2026 Point loc = Point.Empty;
2028 loc = GetFixedItemLocation (index);
2030 loc = items_location [index];
2032 loc.X -= h_marker; // Adjust to scroll
2038 Point GetFixedItemLocation (int index)
2040 Point loc = Point.Empty;
2043 case View.LargeIcon:
2044 case View.SmallIcon:
2045 loc.X = index % cols * (item_size.Width + x_spacing);
2046 loc.Y = index / cols * (item_size.Height + y_spacing);
2049 loc.X = index / rows * (item_size.Width + x_spacing);
2050 loc.Y = index % rows * (item_size.Height + y_spacing);
2053 loc.Y = header_control.Height + (index * item_size.Height);
2060 internal int GetItemIndex (int display_index)
2063 return display_index; // no reordering in virtual mode.
2064 return reordered_items_indices [display_index];
2067 internal ListViewItem GetItemAtDisplayIndex (int display_index)
2069 // in virtual mode there's no reordering at all.
2071 return items [display_index];
2072 return items [reordered_items_indices [display_index]];
2075 internal void SetItemAtDisplayIndex (int display_index, int index)
2077 reordered_items_indices [display_index] = index;
2080 private bool KeySearchString (KeyEventArgs ke)
2082 int current_tickcnt = Environment.TickCount;
2083 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2084 keysearch_text = string.Empty;
2087 if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2090 keysearch_text += (char)ke.KeyCode;
2091 keysearch_tickcnt = current_tickcnt;
2093 int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex;
2094 int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0;
2096 ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true);
2097 if (item != null && prev_focused != item.DisplayIndex) {
2098 selected_indices.Clear ();
2100 SetFocusedItem (item.DisplayIndex);
2101 item.Selected = true;
2102 EnsureVisible (GetItemIndex (item.DisplayIndex));
2108 private void OnItemsChanged ()
2110 ResetSearchString ();
2113 private void ResetSearchString ()
2115 keysearch_text = String.Empty;
2118 int GetAdjustedIndex (Keys key)
2122 if (View == View.Details) {
2125 result = FocusedItem.DisplayIndex - 1;
2128 result = FocusedItem.DisplayIndex + 1;
2129 if (result == items.Count)
2133 int last_index = LastVisibleIndex;
2134 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2135 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2137 if (FocusedItem.DisplayIndex == last_index) {
2138 if (FocusedItem.DisplayIndex < Items.Count - 1) {
2139 int page_size = item_control.Height / ItemSize.Height - 1;
2140 result = FocusedItem.DisplayIndex + page_size - 1;
2141 if (result >= Items.Count)
2142 result = Items.Count - 1;
2145 result = last_index;
2148 int first_index = FirstVisibleIndex;
2149 if (GetItemLocation (first_index).Y < 0)
2151 if (FocusedItem.DisplayIndex == first_index) {
2152 if (first_index > 0) {
2153 int page_size = item_control.Height / ItemSize.Height - 1;
2154 result = first_index - page_size + 1;
2159 result = first_index;
2166 return GetFixedAdjustedIndex (key);
2168 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex];
2169 int row = item_matrix_location.Row;
2170 int col = item_matrix_location.Col;
2172 int adjusted_index = -1;
2178 adjusted_index = item_index_matrix [row, col - 1];
2182 if (col == (cols - 1))
2184 while (item_index_matrix [row, col + 1] == 0) {
2189 adjusted_index = item_index_matrix [row, col + 1];
2195 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2200 adjusted_index = item_index_matrix [row - 1, col];
2204 if (row == (rows - 1) || row == Items.Count - 1)
2206 while (item_index_matrix [row + 1, col] == 0) {
2211 adjusted_index = item_index_matrix [row + 1, col];
2218 return items [adjusted_index].DisplayIndex;
2221 // Used for virtual mode, where items *cannot* be re-arranged
2222 int GetFixedAdjustedIndex (Keys key)
2228 if (view == View.List)
2229 result = focused_item_index - rows;
2231 result = focused_item_index - 1;
2234 if (view == View.List)
2235 result = focused_item_index + rows;
2237 result = focused_item_index + 1;
2240 if (view != View.List)
2241 result = focused_item_index - cols;
2243 result = focused_item_index - 1;
2246 if (view != View.List)
2247 result = focused_item_index + cols;
2249 result = focused_item_index + 1;
2256 if (result < 0 || result >= items.Count)
2257 result = focused_item_index;
2262 ListViewItem selection_start;
2264 private bool SelectItems (ArrayList sel_items)
2266 bool changed = false;
2267 foreach (ListViewItem item in SelectedItems)
2268 if (!sel_items.Contains (item)) {
2269 item.Selected = false;
2272 foreach (ListViewItem item in sel_items)
2273 if (!item.Selected) {
2274 item.Selected = true;
2280 private void UpdateMultiSelection (int index, bool reselect)
2282 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2283 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2284 ListViewItem item = GetItemAtDisplayIndex (index);
2286 if (shift_pressed && selection_start != null) {
2287 ArrayList list = new ArrayList ();
2288 int start_index = selection_start.DisplayIndex;
2289 int start = Math.Min (start_index, index);
2290 int end = Math.Max (start_index, index);
2291 if (View == View.Details) {
2292 for (int i = start; i <= end; i++)
2293 list.Add (GetItemAtDisplayIndex (i));
2295 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2296 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2297 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2298 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2299 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2300 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2302 for (int i = 0; i < items.Count; i++) {
2303 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2305 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2306 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2307 list.Add (GetItemAtDisplayIndex (i));
2311 } else if (ctrl_pressed) {
2312 item.Selected = !item.Selected;
2313 selection_start = item;
2316 // do not unselect, and reselect the item
2317 foreach (int itemIndex in SelectedIndices) {
2318 if (index == itemIndex)
2320 items [itemIndex].Selected = false;
2323 SelectedItems.Clear ();
2324 item.Selected = true;
2326 selection_start = item;
2330 internal override bool InternalPreProcessMessage (ref Message msg)
2332 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2333 Keys key_data = (Keys)msg.WParam.ToInt32();
2335 HandleNavKeys (key_data);
2338 return base.InternalPreProcessMessage (ref msg);
2341 bool HandleNavKeys (Keys key_data)
2343 if (Items.Count == 0 || !item_control.Visible)
2346 if (FocusedItem == null)
2351 SelectIndex (Items.Count - 1);
2364 SelectIndex (GetAdjustedIndex (key_data));
2368 SelectIndex (focused_item_index);
2369 ToggleItemsCheckState ();
2372 if (selected_indices.Count > 0)
2373 OnItemActivate (EventArgs.Empty);
2383 void ToggleItemsCheckState ()
2388 // Don't modify check state if StateImageList has less than 2 elements
2389 if (StateImageList != null && StateImageList.Images.Count < 2)
2392 if (SelectedIndices.Count > 0) {
2393 for (int i = 0; i < SelectedIndices.Count; i++) {
2394 ListViewItem item = Items [SelectedIndices [i]];
2395 item.Checked = !item.Checked;
2400 if (FocusedItem != null) {
2401 FocusedItem.Checked = !FocusedItem.Checked;
2402 SelectIndex (FocusedItem.Index);
2406 void SelectIndex (int display_index)
2408 if (display_index == -1)
2412 UpdateMultiSelection (display_index, true);
2413 else if (!GetItemAtDisplayIndex (display_index).Selected)
2414 GetItemAtDisplayIndex (display_index).Selected = true;
2416 SetFocusedItem (display_index);
2417 EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index
2420 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2422 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2425 if (ke.Alt || ke.Control)
2428 ke.Handled = KeySearchString (ke);
2431 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2433 Point loc = PointToClient (Control.MousePosition);
2434 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2437 internal class ItemControl : Control {
2440 ListViewItem clicked_item;
2441 ListViewItem last_clicked_item;
2442 bool hover_processed = false;
2443 bool checking = false;
2444 ListViewItem prev_hovered_item;
2445 ListViewItem prev_tooltip_item;
2447 Point drag_begin = new Point (-1, -1);
2448 internal int dragged_item_index = -1;
2450 ListViewLabelEditTextBox edit_text_box;
2451 internal ListViewItem edit_item;
2452 LabelEditEventArgs edit_args;
2454 public ItemControl (ListView owner)
2457 this.SetStyle (ControlStyles.DoubleBuffer, true);
2458 DoubleClick += new EventHandler(ItemsDoubleClick);
2459 MouseDown += new MouseEventHandler(ItemsMouseDown);
2460 MouseMove += new MouseEventHandler(ItemsMouseMove);
2461 MouseHover += new EventHandler(ItemsMouseHover);
2462 MouseUp += new MouseEventHandler(ItemsMouseUp);
2465 void ItemsDoubleClick (object sender, EventArgs e)
2467 if (owner.activation == ItemActivation.Standard)
2468 owner.OnItemActivate (EventArgs.Empty);
2478 BoxSelect box_select_mode = BoxSelect.None;
2479 IList prev_selection;
2480 Point box_select_start;
2482 Rectangle box_select_rect;
2483 internal Rectangle BoxSelectRectangle {
2484 get { return box_select_rect; }
2486 if (box_select_rect == value)
2489 InvalidateBoxSelectRect ();
2490 box_select_rect = value;
2491 InvalidateBoxSelectRect ();
2495 void InvalidateBoxSelectRect ()
2497 if (BoxSelectRectangle.Size.IsEmpty)
2500 Rectangle edge = BoxSelectRectangle;
2506 edge.Y = BoxSelectRectangle.Bottom - 1;
2508 edge.Y = BoxSelectRectangle.Y - 1;
2510 edge.Height = BoxSelectRectangle.Height + 2;
2512 edge.X = BoxSelectRectangle.Right - 1;
2516 private Rectangle CalculateBoxSelectRectangle (Point pt)
2518 int left = Math.Min (box_select_start.X, pt.X);
2519 int right = Math.Max (box_select_start.X, pt.X);
2520 int top = Math.Min (box_select_start.Y, pt.Y);
2521 int bottom = Math.Max (box_select_start.Y, pt.Y);
2522 return Rectangle.FromLTRB (left, top, right, bottom);
2525 bool BoxIntersectsItem (int index)
2527 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2528 if (owner.View != View.Details) {
2530 r.Y += r.Height / 4;
2534 return BoxSelectRectangle.IntersectsWith (r);
2537 bool BoxIntersectsText (int index)
2539 Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds;
2540 return BoxSelectRectangle.IntersectsWith (r);
2543 ArrayList BoxSelectedItems {
2545 ArrayList result = new ArrayList ();
2546 for (int i = 0; i < owner.Items.Count; i++) {
2548 // Can't iterate over specific items properties in virtualmode
2549 if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode)
2550 intersects = BoxIntersectsText (i);
2552 intersects = BoxIntersectsItem (i);
2555 result.Add (owner.GetItemAtDisplayIndex (i));
2561 private bool PerformBoxSelection (Point pt)
2563 if (box_select_mode == BoxSelect.None)
2566 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2568 ArrayList box_items = BoxSelectedItems;
2572 switch (box_select_mode) {
2574 case BoxSelect.Normal:
2578 case BoxSelect.Control:
2579 items = new ArrayList ();
2580 foreach (int index in prev_selection)
2581 if (!box_items.Contains (owner.Items [index]))
2582 items.Add (owner.Items [index]);
2583 foreach (ListViewItem item in box_items)
2584 if (!prev_selection.Contains (item.Index))
2588 case BoxSelect.Shift:
2590 foreach (ListViewItem item in box_items)
2591 prev_selection.Remove (item.Index);
2592 foreach (int index in prev_selection)
2593 items.Add (owner.Items [index]);
2597 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2601 owner.SelectItems (items);
2607 private void ItemsMouseDown (object sender, MouseEventArgs me)
2609 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2610 if (owner.items.Count == 0)
2613 bool box_selecting = false;
2614 Size item_size = owner.ItemSize;
2615 Point pt = new Point (me.X, me.Y);
2616 for (int i = 0; i < owner.items.Count; i++) {
2617 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2618 if (!item_rect.Contains (pt))
2621 // Actual item in 'i' position
2622 ListViewItem item = owner.GetItemAtDisplayIndex (i);
2624 if (item.CheckRectReal.Contains (pt)) {
2625 // Don't modify check state if we have only one image
2626 // and if we are in 1.1 profile only take into account
2628 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2632 // Generate an extra ItemCheck event when we got two clicks
2633 // (Match weird .Net behaviour)
2635 item.Checked = !item.Checked;
2637 item.Checked = !item.Checked;
2642 if (owner.View == View.Details) {
2643 bool over_text = item.TextBounds.Contains (pt);
2644 if (owner.FullRowSelect) {
2645 clicked_item = item;
2646 bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2647 if (!over_text && over_item_column && owner.MultiSelect)
2648 box_selecting = true;
2649 } else if (over_text)
2650 clicked_item = item;
2652 owner.SetFocusedItem (i);
2654 clicked_item = item;
2660 if (clicked_item != null) {
2661 bool changed = !clicked_item.Selected;
2662 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2663 owner.SetFocusedItem (clicked_item.DisplayIndex);
2665 if (owner.MultiSelect) {
2666 bool reselect = (!owner.LabelEdit || changed);
2667 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2668 owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect);
2670 clicked_item.Selected = true;
2673 if (owner.VirtualMode && changed) {
2674 // Broken event - It's not fired from Item.Selected also
2675 ListViewVirtualItemsSelectionRangeChangedEventArgs args =
2676 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2678 owner.OnVirtualItemsSelectionRangeChanged (args);
2680 // Report clicks only if the item was clicked. On MS the
2681 // clicks are only raised if you click an item
2683 if (me.Clicks > 1) {
2684 if (owner.CheckBoxes)
2685 clicked_item.Checked = !clicked_item.Checked;
2686 } else if (me.Clicks == 1) {
2687 if (owner.LabelEdit && !changed)
2688 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2691 drag_begin = me.Location;
2692 dragged_item_index = clicked_item.Index;
2694 if (owner.MultiSelect)
2695 box_selecting = true;
2696 else if (owner.SelectedItems.Count > 0)
2697 owner.SelectedItems.Clear ();
2700 if (box_selecting) {
2701 Keys mods = XplatUI.State.ModifierKeys;
2702 if ((mods & Keys.Shift) != 0)
2703 box_select_mode = BoxSelect.Shift;
2704 else if ((mods & Keys.Control) != 0)
2705 box_select_mode = BoxSelect.Control;
2707 box_select_mode = BoxSelect.Normal;
2708 box_select_start = pt;
2709 prev_selection = owner.SelectedIndices.List.Clone () as IList;
2713 private void ItemsMouseMove (object sender, MouseEventArgs me)
2715 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2717 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2721 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2722 !hover_processed && owner.Activation != ItemActivation.OneClick
2723 && !owner.ShowItemToolTips
2727 Point pt = PointToClient (Control.MousePosition);
2728 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2730 if (hover_processed && item != null && item != prev_hovered_item) {
2731 hover_processed = false;
2732 XplatUI.ResetMouseHover (Handle);
2735 // Need to invalidate the item in HotTracking to show/hide the underline style
2736 if (owner.Activation == ItemActivation.OneClick) {
2737 if (item == null && owner.HotItemIndex != -1) {
2738 if (owner.HotTracking)
2739 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2741 Cursor = Cursors.Default;
2742 owner.HotItemIndex = -1;
2743 } else if (item != null && owner.HotItemIndex == -1) {
2744 if (owner.HotTracking)
2745 Invalidate (item.Bounds);
2747 Cursor = Cursors.Hand;
2748 owner.HotItemIndex = item.Index;
2752 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2753 if (drag_begin != new Point (-1, -1)) {
2754 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2755 if (!r.Contains (me.X, me.Y)) {
2756 ListViewItem dragged_item = owner.items [dragged_item_index];
2757 owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2759 drag_begin = new Point (-1, -1);
2760 dragged_item_index = -1;
2765 if (owner.ShowItemToolTips) {
2767 owner.item_tooltip.Active = false;
2768 prev_tooltip_item = null;
2769 } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2770 owner.item_tooltip.Active = true;
2771 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2772 prev_tooltip_item = item;
2778 private void ItemsMouseHover (object sender, EventArgs e)
2780 if (owner.hover_pending) {
2781 owner.OnMouseHover (e);
2782 owner.hover_pending = false;
2788 hover_processed = true;
2789 Point pt = PointToClient (Control.MousePosition);
2790 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2794 prev_hovered_item = item;
2796 if (owner.HoverSelection) {
2797 if (owner.MultiSelect)
2798 owner.UpdateMultiSelection (item.Index, true);
2800 item.Selected = true;
2802 owner.SetFocusedItem (item.DisplayIndex);
2803 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2806 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2809 void HandleClicks (MouseEventArgs me)
2811 // if the click is not on an item,
2812 // clicks remains as 0
2814 owner.OnDoubleClick (EventArgs.Empty);
2815 owner.OnMouseDoubleClick (me);
2816 } else if (clicks == 1) {
2817 owner.OnClick (EventArgs.Empty);
2818 owner.OnMouseClick (me);
2824 private void ItemsMouseUp (object sender, MouseEventArgs me)
2826 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
2827 HandleClicks (owner_me);
2830 if (owner.Items.Count == 0) {
2832 owner.OnMouseUp (owner_me);
2836 Point pt = new Point (me.X, me.Y);
2838 Rectangle rect = Rectangle.Empty;
2839 if (clicked_item != null) {
2840 if (owner.view == View.Details && !owner.full_row_select)
2841 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
2843 rect = clicked_item.Bounds;
2845 if (rect.Contains (pt)) {
2846 switch (owner.activation) {
2847 case ItemActivation.OneClick:
2848 owner.OnItemActivate (EventArgs.Empty);
2851 case ItemActivation.TwoClick:
2852 if (last_clicked_item == clicked_item) {
2853 owner.OnItemActivate (EventArgs.Empty);
2854 last_clicked_item = null;
2856 last_clicked_item = clicked_item;
2859 // DoubleClick activation is handled in another handler
2863 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
2864 // Need this to clean up background clicks
2865 owner.SelectedItems.Clear ();
2869 owner.OnMouseUp (owner_me);
2872 private void ResetMouseState ()
2874 clicked_item = null;
2875 box_select_start = Point.Empty;
2876 BoxSelectRectangle = Rectangle.Empty;
2877 prev_selection = null;
2878 box_select_mode = BoxSelect.None;
2881 // Clean these bits in case the mouse buttons were
2882 // released before firing ItemDrag
2883 dragged_item_index = -1;
2884 drag_begin = new Point (-1, -1);
2887 private void LabelEditFinished (object sender, EventArgs e)
2889 EndEdit (edit_item);
2892 private void LabelEditCancelled (object sender, EventArgs e)
2894 edit_args.SetLabel (null);
2895 EndEdit (edit_item);
2898 private void LabelTextChanged (object sender, EventArgs e)
2900 if (edit_args != null)
2901 edit_args.SetLabel (edit_text_box.Text);
2904 internal void BeginEdit (ListViewItem item)
2906 if (edit_item != null)
2907 EndEdit (edit_item);
2909 if (edit_text_box == null) {
2910 edit_text_box = new ListViewLabelEditTextBox ();
2911 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
2912 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
2913 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
2914 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
2915 edit_text_box.Visible = false;
2916 Controls.Add (edit_text_box);
2919 item.EnsureVisible();
2921 edit_text_box.Reset ();
2923 switch (owner.view) {
2925 case View.SmallIcon:
2927 edit_text_box.TextAlign = HorizontalAlignment.Left;
2928 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2929 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
2930 edit_text_box.Width = (int)sizef.Width + 4;
2931 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
2932 edit_text_box.WordWrap = false;
2933 edit_text_box.Multiline = false;
2935 case View.LargeIcon:
2936 edit_text_box.TextAlign = HorizontalAlignment.Center;
2937 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2938 sizef = TextRenderer.MeasureString (item.Text, item.Font);
2939 edit_text_box.Width = (int)sizef.Width + 4;
2940 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
2941 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
2942 edit_text_box.WordWrap = true;
2943 edit_text_box.Multiline = true;
2949 edit_text_box.Text = item.Text;
2950 edit_text_box.Font = item.Font;
2951 edit_text_box.Visible = true;
2952 edit_text_box.Focus ();
2953 edit_text_box.SelectAll ();
2955 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
2956 owner.OnBeforeLabelEdit (edit_args);
2958 if (edit_args.CancelEdit)
2962 internal void CancelEdit (ListViewItem item)
2964 // do nothing if there's no item being edited, or if the
2965 // item being edited is not the one passed in
2966 if (edit_item == null || edit_item != item)
2969 edit_args.SetLabel (null);
2973 internal void EndEdit (ListViewItem item)
2975 // do nothing if there's no item being edited, or if the
2976 // item being edited is not the one passed in
2977 if (edit_item == null || edit_item != item)
2980 if (edit_text_box != null) {
2981 if (edit_text_box.Visible)
2982 edit_text_box.Visible = false;
2983 // ensure listview gets focus
2987 // Same as TreeView.EndEdit: need to have focus in synch
2988 Application.DoEvents ();
2991 // Create a new instance, since we could get a call to BeginEdit
2992 // from the handler and have fields out of synch
2994 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
2997 owner.OnAfterLabelEdit (args);
2998 if (!args.CancelEdit && args.Label != null)
2999 item.Text = args.Label;
3002 internal override void OnPaintInternal (PaintEventArgs pe)
3004 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
3007 protected override void WndProc (ref Message m)
3009 switch ((Msg)m.Msg) {
3010 case Msg.WM_KILLFOCUS:
3011 owner.Select (false, true);
3013 case Msg.WM_SETFOCUS:
3014 owner.Select (false, true);
3016 case Msg.WM_LBUTTONDOWN:
3018 owner.Select (false, true);
3020 case Msg.WM_RBUTTONDOWN:
3022 owner.Select (false, true);
3027 base.WndProc (ref m);
3031 internal class ListViewLabelEditTextBox : TextBox
3036 int max_height = -1;
3037 int min_height = -1;
3039 int old_number_lines = 1;
3041 SizeF text_size_one_char;
3043 public ListViewLabelEditTextBox ()
3045 min_height = DefaultSize.Height;
3046 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3049 public int MaxWidth {
3051 if (value < min_width)
3052 max_width = min_width;
3058 public int MaxHeight {
3060 if (value < min_height)
3061 max_height = min_height;
3067 public new int Width {
3077 public override Font Font {
3083 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3087 protected override void OnTextChanged (EventArgs e)
3089 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3091 int new_width = (int)text_size.Width + 8;
3094 ResizeTextBoxWidth (new_width);
3096 if (Width != max_width)
3097 ResizeTextBoxWidth (new_width);
3099 int number_lines = Lines.Length;
3101 if (number_lines != old_number_lines) {
3102 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3103 old_number_lines = number_lines;
3105 ResizeTextBoxHeight (new_height);
3109 base.OnTextChanged (e);
3112 protected override bool IsInputKey (Keys key_data)
3114 if ((key_data & Keys.Alt) == 0) {
3115 switch (key_data & Keys.KeyCode) {
3122 return base.IsInputKey (key_data);
3125 protected override void OnKeyDown (KeyEventArgs e)
3130 switch (e.KeyCode) {
3134 OnEditingFinished (e);
3139 OnEditingCancelled (e);
3144 protected override void OnLostFocus (EventArgs e)
3147 OnEditingFinished (e);
3151 protected void OnEditingCancelled (EventArgs e)
3153 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3158 protected void OnEditingFinished (EventArgs e)
3160 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3165 private void ResizeTextBoxWidth (int new_width)
3167 if (new_width > max_width)
3168 base.Width = max_width;
3170 if (new_width >= min_width)
3171 base.Width = new_width;
3173 base.Width = min_width;
3176 private void ResizeTextBoxHeight (int new_height)
3178 if (new_height > max_height)
3179 base.Height = max_height;
3181 if (new_height >= min_height)
3182 base.Height = new_height;
3184 base.Height = min_height;
3187 public void Reset ()
3194 old_number_lines = 1;
3196 Text = String.Empty;
3201 static object EditingCancelledEvent = new object ();
3202 public event EventHandler EditingCancelled {
3203 add { Events.AddHandler (EditingCancelledEvent, value); }
3204 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3207 static object EditingFinishedEvent = new object ();
3208 public event EventHandler EditingFinished {
3209 add { Events.AddHandler (EditingFinishedEvent, value); }
3210 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3214 internal override void OnPaintInternal (PaintEventArgs pe)
3219 CalculateScrollBars ();
3222 void FocusChanged (object o, EventArgs args)
3224 if (Items.Count == 0)
3227 if (FocusedItem == null)
3230 ListViewItem focused_item = FocusedItem;
3232 if (focused_item.ListView != null) {
3233 focused_item.Invalidate ();
3234 focused_item.Layout ();
3235 focused_item.Invalidate ();
3239 private void ListView_Invalidated (object sender, InvalidateEventArgs e)
3241 // When the ListView is invalidated, we need to invalidate
3242 // the child controls.
3243 header_control.Invalidate ();
3244 item_control.Invalidate ();
3247 private void ListView_MouseEnter (object sender, EventArgs args)
3249 hover_pending = true; // Need a hover event for every Enter/Leave cycle
3252 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3254 if (Items.Count == 0)
3257 int lines = me.Delta / 120;
3264 case View.SmallIcon:
3265 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3267 case View.LargeIcon:
3268 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
3271 Scroll (h_scroll, -ItemSize.Width * lines);
3274 if (!Application.VisualStylesEnabled)
3275 goto case View.LargeIcon;
3277 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3282 private void ListView_SizeChanged (object sender, EventArgs e)
3287 private void SetFocusedItem (int display_index)
3289 if (display_index != -1)
3290 GetItemAtDisplayIndex (display_index).Focused = true;
3291 else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3292 GetItemAtDisplayIndex (focused_item_index).Focused = false;
3293 focused_item_index = display_index;
3294 if (display_index == -1)
3295 OnUIAFocusedItemChanged ();
3296 // otherwise the event will have been fired
3297 // when the ListViewItem's Focused was set
3300 private void HorizontalScroller (object sender, EventArgs e)
3302 item_control.EndEdit (item_control.edit_item);
3304 // Avoid unnecessary flickering, when button is
3305 // kept pressed at the end
3306 if (h_marker != h_scroll.Value) {
3308 int pixels = h_marker - h_scroll.Value;
3310 h_marker = h_scroll.Value;
3311 if (header_control.Visible)
3312 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3314 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3318 private void VerticalScroller (object sender, EventArgs e)
3320 item_control.EndEdit (item_control.edit_item);
3322 // Avoid unnecessary flickering, when button is
3323 // kept pressed at the end
3324 if (v_marker != v_scroll.Value) {
3325 int pixels = v_marker - v_scroll.Value;
3326 Rectangle area = item_control.ClientRectangle;
3327 if (header_control.Visible) {
3328 area.Y += header_control.Height;
3329 area.Height -= header_control.Height;
3332 v_marker = v_scroll.Value;
3333 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3337 internal override bool IsInputCharInternal (char charCode)
3341 #endregion // Internal Methods Properties
3343 #region Protected Methods
3344 protected override void CreateHandle ()
3346 base.CreateHandle ();
3347 is_selection_available = true;
3348 for (int i = 0; i < SelectedItems.Count; i++)
3349 OnSelectedIndexChanged (EventArgs.Empty);
3352 protected override void Dispose (bool disposing)
3355 large_image_list = null;
3356 small_image_list = null;
3357 state_image_list = null;
3359 foreach (ColumnHeader col in columns)
3360 col.SetListView (null);
3362 if (!virtual_mode) // In virtual mode we don't save the items
3363 foreach (ListViewItem item in items)
3367 base.Dispose (disposing);
3370 protected override bool IsInputKey (Keys keyData)
3387 return base.IsInputKey (keyData);
3390 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3392 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3397 protected override void OnBackgroundImageChanged (EventArgs e)
3399 item_control.BackgroundImage = BackgroundImage;
3400 base.OnBackgroundImageChanged (e);
3403 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3405 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3410 protected internal virtual void OnColumnClick (ColumnClickEventArgs e)
3412 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3417 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3419 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3424 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3426 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3431 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3433 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3438 protected override void OnFontChanged (EventArgs e)
3440 base.OnFontChanged (e);
3444 protected override void OnHandleCreated (EventArgs e)
3446 base.OnHandleCreated (e);
3447 CalculateListView (alignment);
3448 if (!virtual_mode) // Sorting is not allowed in virtual mode
3452 protected override void OnHandleDestroyed (EventArgs e)
3454 base.OnHandleDestroyed (e);
3457 protected virtual void OnItemActivate (EventArgs e)
3459 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3464 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3466 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3471 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3473 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3478 protected virtual void OnItemDrag (ItemDragEventArgs e)
3480 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3485 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3487 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3492 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3494 ListViewItemSelectionChangedEventHandler eh =
3495 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3500 protected override void OnMouseHover (EventArgs e)
3502 base.OnMouseHover (e);
3505 protected override void OnParentChanged (EventArgs e)
3507 base.OnParentChanged (e);
3510 protected virtual void OnSelectedIndexChanged (EventArgs e)
3512 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3517 protected override void OnSystemColorsChanged (EventArgs e)
3519 base.OnSystemColorsChanged (e);
3522 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3524 CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3529 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3531 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3536 [EditorBrowsable (EditorBrowsableState.Advanced)]
3537 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3539 EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3544 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3546 SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3551 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3553 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3554 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3559 protected void RealizeProperties ()
3564 protected void UpdateExtendedStyles ()
3569 bool refocusing = false;
3571 protected override void WndProc (ref Message m)
3573 switch ((Msg)m.Msg) {
3574 case Msg.WM_KILLFOCUS:
3575 Control receiver = Control.FromHandle (m.WParam);
3576 if (receiver == item_control) {
3582 case Msg.WM_SETFOCUS:
3592 base.WndProc (ref m);
3594 #endregion // Protected Methods
3596 #region Public Instance Methods
3597 public void ArrangeIcons ()
3599 ArrangeIcons (this.alignment);
3602 public void ArrangeIcons (ListViewAlignment value)
3604 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3605 if (view == View.LargeIcon || view == View.SmallIcon)
3609 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3611 if (columnIndex < 0 || columnIndex >= columns.Count)
3612 throw new ArgumentOutOfRangeException ("columnIndex");
3614 columns [columnIndex].AutoResize (headerAutoResize);
3617 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3620 foreach (ColumnHeader col in columns)
3621 col.AutoResize (headerAutoResize);
3625 public void BeginUpdate ()
3627 // flag to avoid painting
3631 public void Clear ()
3634 items.Clear (); // Redraw (true) called here
3637 public void EndUpdate ()
3639 // flag to avoid painting
3642 // probably, now we need a redraw with recalculations
3646 public void EnsureVisible (int index)
3648 if (index < 0 || index >= items.Count || scrollable == false || updating)
3651 Rectangle view_rect = item_control.ClientRectangle;
3652 // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items
3653 Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds;
3655 if (view == View.Details && header_style != ColumnHeaderStyle.None) {
3656 view_rect.Y += header_control.Height;
3657 view_rect.Height -= header_control.Height;
3660 if (view_rect.Contains (bounds))
3663 if (View != View.Details) {
3664 if (bounds.Left < 0)
3665 h_scroll.Value += bounds.Left;
3666 // Don't shift right unless right-to-left layout is active. (Xamarin bug 22483)
3667 else if (this.RightToLeftLayout && bounds.Right > view_rect.Right)
3668 h_scroll.Value += (bounds.Right - view_rect.Right);
3671 if (bounds.Top < view_rect.Y)
3672 v_scroll.Value += bounds.Top - view_rect.Y;
3673 else if (bounds.Bottom > view_rect.Bottom)
3674 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3677 public ListViewItem FindItemWithText (string text)
3679 if (items.Count == 0)
3682 return FindItemWithText (text, true, 0, true);
3685 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3687 return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3690 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3692 return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3695 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3697 if (startIndex < 0 || startIndex >= items.Count)
3698 throw new ArgumentOutOfRangeException ("startIndex");
3701 throw new ArgumentNullException ("text");
3704 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3705 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty,
3706 SearchDirectionHint.Down, startIndex);
3708 OnSearchForVirtualItem (args);
3709 int idx = args.Index;
3710 if (idx >= 0 && idx < virtual_list_size)
3718 ListViewItem lvi = items [i];
3720 if (isPrefixSearch) { // prefix search
3721 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3723 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3726 if (i + 1 >= items.Count) {
3734 if (i == startIndex)
3738 // Subitems have a minor priority, so we have to do a second linear search
3739 // Also, we don't need to to a roundtrip search for them by now
3740 if (includeSubItemsInSearch) {
3741 for (i = startIndex; i < items.Count; i++) {
3742 ListViewItem lvi = items [i];
3743 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3744 if (isPrefixSearch) {
3745 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text,
3746 text, CompareOptions.IgnoreCase))
3748 } else if (String.Compare (sub_item.Text, text, true) == 0)
3756 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3758 return FindNearestItem (searchDirection, new Point (x, y));
3761 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3763 if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3764 throw new ArgumentOutOfRangeException ("searchDirection");
3766 if (view != View.LargeIcon && view != View.SmallIcon)
3767 throw new InvalidOperationException ();
3770 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3771 false, false, String.Empty, point,
3774 OnSearchForVirtualItem (args);
3775 int idx = args.Index;
3776 if (idx >= 0 && idx < virtual_list_size)
3782 ListViewItem item = null;
3783 int min_dist = Int32.MaxValue;
3786 // It looks like .Net does a previous adjustment
3789 case SearchDirectionHint.Up:
3790 point.Y -= item_size.Height;
3792 case SearchDirectionHint.Down:
3793 point.Y += item_size.Height;
3795 case SearchDirectionHint.Left:
3796 point.X -= item_size.Width;
3798 case SearchDirectionHint.Right:
3799 point.X += item_size.Width;
3803 for (int i = 0; i < items.Count; i++) {
3804 Point item_loc = GetItemLocation (i);
3806 if (dir == SearchDirectionHint.Up) {
3807 if (point.Y < item_loc.Y)
3809 } else if (dir == SearchDirectionHint.Down) {
3810 if (point.Y > item_loc.Y)
3812 } else if (dir == SearchDirectionHint.Left) {
3813 if (point.X < item_loc.X)
3815 } else if (dir == SearchDirectionHint.Right) {
3816 if (point.X > item_loc.X)
3820 int x_dist = point.X - item_loc.X;
3821 int y_dist = point.Y - item_loc.Y;
3823 int dist = x_dist * x_dist + y_dist * y_dist;
3824 if (dist < min_dist) {
3833 public ListViewItem GetItemAt (int x, int y)
3835 Size item_size = ItemSize;
3836 for (int i = 0; i < items.Count; i++) {
3837 Rectangle item_rect = items [i].Bounds;
3838 if (item_rect.Contains (x, y))
3845 public Rectangle GetItemRect (int index)
3847 return GetItemRect (index, ItemBoundsPortion.Entire);
3850 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
3852 if (index < 0 || index >= items.Count)
3853 throw new IndexOutOfRangeException ("index");
3855 return items [index].GetBounds (portion);
3858 public ListViewHitTestInfo HitTest (Point point)
3860 return HitTest (point.X, point.Y);
3863 public ListViewHitTestInfo HitTest (int x, int y)
3866 throw new ArgumentOutOfRangeException ("x");
3868 throw new ArgumentOutOfRangeException ("y");
3870 ListViewItem item = GetItemAt (x, y);
3872 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
3874 ListViewHitTestLocations locations = 0;
3875 if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
3876 locations |= ListViewHitTestLocations.Label;
3877 else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
3878 locations |= ListViewHitTestLocations.Image;
3879 else if (item.CheckRectReal.Contains (x, y))
3880 locations |= ListViewHitTestLocations.StateImage;
3882 ListViewItem.ListViewSubItem subitem = null;
3883 if (view == View.Details)
3884 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
3885 if (si.Bounds.Contains (x, y)) {
3890 return new ListViewHitTestInfo (item, subitem, locations);
3893 [EditorBrowsable (EditorBrowsableState.Advanced)]
3894 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
3896 if (startIndex < 0 || startIndex >= items.Count)
3897 throw new ArgumentOutOfRangeException ("startIndex");
3898 if (endIndex < 0 || endIndex >= items.Count)
3899 throw new ArgumentOutOfRangeException ("endIndex");
3900 if (startIndex > endIndex)
3901 throw new ArgumentException ("startIndex");
3906 for (int i = startIndex; i <= endIndex; i++)
3907 items [i].Invalidate ();
3909 if (!invalidateOnly)
3916 throw new InvalidOperationException ();
3921 // we need this overload to reuse the logic for sorting, while allowing
3922 // redrawing to be done by caller or have it done by this method when
3923 // sorting is really performed
3925 // ListViewItemCollection's Add and AddRange methods call this overload
3926 // with redraw set to false, as they take care of redrawing themselves
3927 // (they even want to redraw the listview if no sort is performed, as
3928 // an item was added), while ListView.Sort () only wants to redraw if
3929 // sorting was actually performed
3930 private void Sort (bool redraw)
3932 if (!IsHandleCreated || item_sorter == null) {
3936 items.Sort (item_sorter);
3941 public override string ToString ()
3943 int count = this.Items.Count;
3946 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
3948 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
3950 #endregion // Public Instance Methods
3955 internal class HeaderControl : Control {
3958 bool column_resize_active = false;
3959 ColumnHeader resize_column;
3960 ColumnHeader clicked_column;
3961 ColumnHeader drag_column;
3963 int drag_to_index = -1;
3964 ColumnHeader entered_column_header;
3966 public HeaderControl (ListView owner)
3969 this.SetStyle (ControlStyles.DoubleBuffer, true);
3970 MouseDown += new MouseEventHandler (HeaderMouseDown);
3971 MouseMove += new MouseEventHandler (HeaderMouseMove);
3972 MouseUp += new MouseEventHandler (HeaderMouseUp);
3973 MouseLeave += new EventHandler (OnMouseLeave);
3976 internal ColumnHeader EnteredColumnHeader {
3977 get { return entered_column_header; }
3979 if (entered_column_header == value)
3981 if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
3982 Region region_to_invalidate = new Region ();
3983 region_to_invalidate.MakeEmpty ();
3984 if (entered_column_header != null)
3985 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
3986 entered_column_header = value;
3987 if (entered_column_header != null)
3988 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
3989 Invalidate (region_to_invalidate);
3990 region_to_invalidate.Dispose ();
3992 entered_column_header = value;
3996 void OnMouseLeave (object sender, EventArgs e)
3998 EnteredColumnHeader = null;
4001 private ColumnHeader ColumnAtX (int x)
4003 Point pt = new Point (x, 0);
4004 ColumnHeader result = null;
4005 foreach (ColumnHeader col in owner.Columns) {
4006 if (col.Rect.Contains (pt)) {
4014 private int GetReorderedIndex (ColumnHeader col)
4016 if (owner.reordered_column_indices == null)
4019 for (int i = 0; i < owner.Columns.Count; i++)
4020 if (owner.reordered_column_indices [i] == col.Index)
4022 throw new Exception ("Column index missing from reordered array");
4025 private void HeaderMouseDown (object sender, MouseEventArgs me)
4027 if (resize_column != null) {
4028 column_resize_active = true;
4033 clicked_column = ColumnAtX (me.X + owner.h_marker);
4035 if (clicked_column != null) {
4037 if (owner.AllowColumnReorder) {
4039 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4040 drag_column.Rect = clicked_column.Rect;
4041 drag_to_index = GetReorderedIndex (clicked_column);
4043 clicked_column.Pressed = true;
4044 Invalidate (clicked_column);
4049 void Invalidate (ColumnHeader columnHeader)
4051 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4054 Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4056 Rectangle bounds = columnHeader.Rect;
4057 bounds.X -= owner.h_marker;
4063 column_resize_active = false;
4064 resize_column = null;
4066 Cursor = Cursors.Default;
4069 private void HeaderMouseMove (object sender, MouseEventArgs me)
4071 Point pt = new Point (me.X + owner.h_marker, me.Y);
4073 if (column_resize_active) {
4074 int width = pt.X - resize_column.X;
4078 if (!owner.CanProceedWithResize (resize_column, width)){
4082 resize_column.Width = width;
4086 resize_column = null;
4088 if (clicked_column != null) {
4089 if (owner.AllowColumnReorder) {
4092 r = drag_column.Rect;
4093 r.X = clicked_column.Rect.X + me.X - drag_x;
4094 drag_column.Rect = r;
4096 int x = me.X + owner.h_marker;
4097 ColumnHeader over = ColumnAtX (x);
4099 drag_to_index = owner.Columns.Count;
4100 else if (x < over.X + over.Width / 2)
4101 drag_to_index = GetReorderedIndex (over);
4103 drag_to_index = GetReorderedIndex (over) + 1;
4106 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4107 bool pressed = clicked_column.Pressed;
4108 clicked_column.Pressed = over == clicked_column;
4109 if (clicked_column.Pressed ^ pressed)
4110 Invalidate (clicked_column);
4115 for (int i = 0; i < owner.Columns.Count; i++) {
4116 Rectangle zone = owner.Columns [i].Rect;
4117 if (zone.Contains (pt))
4118 EnteredColumnHeader = owner.Columns [i];
4119 zone.X = zone.Right - 5;
4121 if (zone.Contains (pt)) {
4122 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4124 resize_column = owner.Columns [i];
4129 if (resize_column == null)
4130 Cursor = Cursors.Default;
4132 Cursor = Cursors.VSplit;
4135 void HeaderMouseUp (object sender, MouseEventArgs me)
4139 if (column_resize_active) {
4140 int column_idx = resize_column.Index;
4142 owner.RaiseColumnWidthChanged (column_idx);
4146 if (clicked_column != null && clicked_column.Pressed) {
4147 clicked_column.Pressed = false;
4148 Invalidate (clicked_column);
4149 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4152 if (drag_column != null && owner.AllowColumnReorder) {
4154 if (drag_to_index > GetReorderedIndex (clicked_column))
4156 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4157 owner.ReorderColumn (clicked_column, drag_to_index, true);
4162 clicked_column = null;
4165 internal override void OnPaintInternal (PaintEventArgs pe)
4170 Theme theme = ThemeEngine.Current;
4171 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4173 if (drag_column == null)
4177 if (drag_to_index == owner.Columns.Count)
4178 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4180 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4181 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4184 protected override void WndProc (ref Message m)
4186 switch ((Msg)m.Msg) {
4187 case Msg.WM_SETFOCUS:
4191 base.WndProc (ref m);
4197 private class ItemComparer : IComparer {
4198 readonly SortOrder sort_order;
4200 public ItemComparer (SortOrder sortOrder)
4202 sort_order = sortOrder;
4205 public int Compare (object x, object y)
4207 ListViewItem item_x = x as ListViewItem;
4208 ListViewItem item_y = y as ListViewItem;
4209 if (sort_order == SortOrder.Ascending)
4210 return String.Compare (item_x.Text, item_y.Text);
4212 return String.Compare (item_y.Text, item_x.Text);
4216 [ListBindable (false)]
4217 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4219 private readonly ListView owner;
4221 #region Public Constructor
4222 public CheckedIndexCollection (ListView owner)
4226 #endregion // Public Constructor
4228 #region Public Properties
4231 get { return owner.CheckedItems.Count; }
4234 public bool IsReadOnly {
4235 get { return true; }
4238 public int this [int index] {
4240 int [] indices = GetIndices ();
4241 if (index < 0 || index >= indices.Length)
4242 throw new ArgumentOutOfRangeException ("index");
4243 return indices [index];
4247 bool ICollection.IsSynchronized {
4248 get { return false; }
4251 object ICollection.SyncRoot {
4252 get { return this; }
4255 bool IList.IsFixedSize {
4256 get { return true; }
4259 object IList.this [int index] {
4260 get { return this [index]; }
4261 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4263 #endregion // Public Properties
4265 #region Public Methods
4266 public bool Contains (int checkedIndex)
4268 int [] indices = GetIndices ();
4269 for (int i = 0; i < indices.Length; i++) {
4270 if (indices [i] == checkedIndex)
4276 public IEnumerator GetEnumerator ()
4278 int [] indices = GetIndices ();
4279 return indices.GetEnumerator ();
4282 void ICollection.CopyTo (Array dest, int index)
4284 int [] indices = GetIndices ();
4285 Array.Copy (indices, 0, dest, index, indices.Length);
4288 int IList.Add (object value)
4290 throw new NotSupportedException ("Add operation is not supported.");
4295 throw new NotSupportedException ("Clear operation is not supported.");
4298 bool IList.Contains (object checkedIndex)
4300 if (!(checkedIndex is int))
4302 return Contains ((int) checkedIndex);
4305 int IList.IndexOf (object checkedIndex)
4307 if (!(checkedIndex is int))
4309 return IndexOf ((int) checkedIndex);
4312 void IList.Insert (int index, object value)
4314 throw new NotSupportedException ("Insert operation is not supported.");
4317 void IList.Remove (object value)
4319 throw new NotSupportedException ("Remove operation is not supported.");
4322 void IList.RemoveAt (int index)
4324 throw new NotSupportedException ("RemoveAt operation is not supported.");
4327 public int IndexOf (int checkedIndex)
4329 int [] indices = GetIndices ();
4330 for (int i = 0; i < indices.Length; i++) {
4331 if (indices [i] == checkedIndex)
4336 #endregion // Public Methods
4338 private int [] GetIndices ()
4340 ArrayList checked_items = owner.CheckedItems.List;
4341 int [] indices = new int [checked_items.Count];
4342 for (int i = 0; i < checked_items.Count; i++) {
4343 ListViewItem item = (ListViewItem) checked_items [i];
4344 indices [i] = item.Index;
4348 } // CheckedIndexCollection
4350 [ListBindable (false)]
4351 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4353 private readonly ListView owner;
4354 private ArrayList list;
4356 #region Public Constructor
4357 public CheckedListViewItemCollection (ListView owner)
4360 this.owner.Items.Changed += new CollectionChangedHandler (
4361 ItemsCollection_Changed);
4363 #endregion // Public Constructor
4365 #region Public Properties
4369 if (!owner.CheckBoxes)
4375 public bool IsReadOnly {
4376 get { return true; }
4379 public ListViewItem this [int index] {
4381 if (owner.VirtualMode)
4382 throw new InvalidOperationException ();
4383 ArrayList checked_items = List;
4384 if (index < 0 || index >= checked_items.Count)
4385 throw new ArgumentOutOfRangeException ("index");
4386 return (ListViewItem) checked_items [index];
4390 public virtual ListViewItem this [string key] {
4392 int idx = IndexOfKey (key);
4393 return idx == -1 ? null : (ListViewItem) List [idx];
4397 bool ICollection.IsSynchronized {
4398 get { return false; }
4401 object ICollection.SyncRoot {
4402 get { return this; }
4405 bool IList.IsFixedSize {
4406 get { return true; }
4409 object IList.this [int index] {
4410 get { return this [index]; }
4411 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4413 #endregion // Public Properties
4415 #region Public Methods
4416 public bool Contains (ListViewItem item)
4418 if (!owner.CheckBoxes)
4420 return List.Contains (item);
4423 public virtual bool ContainsKey (string key)
4425 return IndexOfKey (key) != -1;
4428 public void CopyTo (Array dest, int index)
4430 if (owner.VirtualMode)
4431 throw new InvalidOperationException ();
4432 if (!owner.CheckBoxes)
4434 List.CopyTo (dest, index);
4437 public IEnumerator GetEnumerator ()
4439 if (owner.VirtualMode)
4440 throw new InvalidOperationException ();
4441 if (!owner.CheckBoxes)
4442 return (new ListViewItem [0]).GetEnumerator ();
4443 return List.GetEnumerator ();
4446 int IList.Add (object value)
4448 throw new NotSupportedException ("Add operation is not supported.");
4453 throw new NotSupportedException ("Clear operation is not supported.");
4456 bool IList.Contains (object item)
4458 if (!(item is ListViewItem))
4460 return Contains ((ListViewItem) item);
4463 int IList.IndexOf (object item)
4465 if (!(item is ListViewItem))
4467 return IndexOf ((ListViewItem) item);
4470 void IList.Insert (int index, object value)
4472 throw new NotSupportedException ("Insert operation is not supported.");
4475 void IList.Remove (object value)
4477 throw new NotSupportedException ("Remove operation is not supported.");
4480 void IList.RemoveAt (int index)
4482 throw new NotSupportedException ("RemoveAt operation is not supported.");
4485 public int IndexOf (ListViewItem item)
4487 if (owner.VirtualMode)
4488 throw new InvalidOperationException ();
4489 if (!owner.CheckBoxes)
4491 return List.IndexOf (item);
4494 public virtual int IndexOfKey (string key)
4496 if (owner.VirtualMode)
4497 throw new InvalidOperationException ();
4498 if (key == null || key.Length == 0)
4501 ArrayList checked_items = List;
4502 for (int i = 0; i < checked_items.Count; i++) {
4503 ListViewItem item = (ListViewItem) checked_items [i];
4504 if (String.Compare (key, item.Name, true) == 0)
4510 #endregion // Public Methods
4512 internal ArrayList List {
4515 list = new ArrayList ();
4516 foreach (ListViewItem item in owner.Items) {
4525 internal void Reset ()
4527 // force re-population of list
4531 private void ItemsCollection_Changed ()
4535 } // CheckedListViewItemCollection
4537 [ListBindable (false)]
4538 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4540 internal ArrayList list;
4541 private ListView owner;
4543 #region UIA Framework Events
4545 // We are using Reflection to add/remove internal events.
4546 // Class ListViewProvider uses the events when View is Details.
4548 //Event used to generate UIA StructureChangedEvent
4549 static object UIACollectionChangedEvent = new object ();
4551 internal event CollectionChangeEventHandler UIACollectionChanged {
4554 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4558 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4562 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4567 CollectionChangeEventHandler eh
4568 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4573 #endregion UIA Framework Events
4575 #region Public Constructor
4576 public ColumnHeaderCollection (ListView owner)
4578 list = new ArrayList ();
4581 #endregion // Public Constructor
4583 #region Public Properties
4586 get { return list.Count; }
4589 public bool IsReadOnly {
4590 get { return false; }
4593 public virtual ColumnHeader this [int index] {
4595 if (index < 0 || index >= list.Count)
4596 throw new ArgumentOutOfRangeException ("index");
4597 return (ColumnHeader) list [index];
4601 public virtual ColumnHeader this [string key] {
4603 int idx = IndexOfKey (key);
4607 return (ColumnHeader) list [idx];
4611 bool ICollection.IsSynchronized {
4612 get { return true; }
4615 object ICollection.SyncRoot {
4616 get { return this; }
4619 bool IList.IsFixedSize {
4620 get { return list.IsFixedSize; }
4623 object IList.this [int index] {
4624 get { return this [index]; }
4625 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4627 #endregion // Public Properties
4629 #region Public Methods
4630 public virtual int Add (ColumnHeader value)
4632 int idx = list.Add (value);
4633 owner.AddColumn (value, idx, true);
4635 //UIA Framework event: Item Added
4636 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4641 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4644 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4645 this.Add (colHeader);
4649 public virtual ColumnHeader Add (string text)
4651 return Add (String.Empty, text);
4654 public virtual ColumnHeader Add (string text, int width)
4656 return Add (String.Empty, text, width);
4659 public virtual ColumnHeader Add (string key, string text)
4661 ColumnHeader colHeader = new ColumnHeader ();
4662 colHeader.Name = key;
4663 colHeader.Text = text;
4668 public virtual ColumnHeader Add (string key, string text, int width)
4670 return Add (key, text, width, HorizontalAlignment.Left, -1);
4673 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4675 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4676 colHeader.ImageIndex = imageIndex;
4681 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4683 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4684 colHeader.ImageKey = imageKey;
4689 public virtual void AddRange (ColumnHeader [] values)
4691 foreach (ColumnHeader colHeader in values) {
4692 int idx = list.Add (colHeader);
4693 owner.AddColumn (colHeader, idx, false);
4696 owner.Redraw (true);
4699 public virtual void Clear ()
4701 foreach (ColumnHeader col in list)
4702 col.SetListView (null);
4704 owner.ReorderColumns (new int [0], true);
4706 //UIA Framework event: Items cleared
4707 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4711 public bool Contains (ColumnHeader value)
4713 return list.Contains (value);
4716 public virtual bool ContainsKey (string key)
4718 return IndexOfKey (key) != -1;
4721 public IEnumerator GetEnumerator ()
4723 return list.GetEnumerator ();
4726 void ICollection.CopyTo (Array dest, int index)
4728 list.CopyTo (dest, index);
4731 int IList.Add (object value)
4733 if (! (value is ColumnHeader)) {
4734 throw new ArgumentException ("Not of type ColumnHeader", "value");
4737 return this.Add ((ColumnHeader) value);
4740 bool IList.Contains (object value)
4742 if (! (value is ColumnHeader)) {
4743 throw new ArgumentException ("Not of type ColumnHeader", "value");
4746 return this.Contains ((ColumnHeader) value);
4749 int IList.IndexOf (object value)
4751 if (! (value is ColumnHeader)) {
4752 throw new ArgumentException ("Not of type ColumnHeader", "value");
4755 return this.IndexOf ((ColumnHeader) value);
4758 void IList.Insert (int index, object value)
4760 if (! (value is ColumnHeader)) {
4761 throw new ArgumentException ("Not of type ColumnHeader", "value");
4764 this.Insert (index, (ColumnHeader) value);
4767 void IList.Remove (object value)
4769 if (! (value is ColumnHeader)) {
4770 throw new ArgumentException ("Not of type ColumnHeader", "value");
4773 this.Remove ((ColumnHeader) value);
4776 public int IndexOf (ColumnHeader value)
4778 return list.IndexOf (value);
4781 public virtual int IndexOfKey (string key)
4783 if (key == null || key.Length == 0)
4786 for (int i = 0; i < list.Count; i++) {
4787 ColumnHeader col = (ColumnHeader) list [i];
4788 if (String.Compare (key, col.Name, true) == 0)
4795 public void Insert (int index, ColumnHeader value)
4797 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
4798 // but it's really only greater.
4799 if (index < 0 || index > list.Count)
4800 throw new ArgumentOutOfRangeException ("index");
4802 list.Insert (index, value);
4803 owner.AddColumn (value, index, true);
4805 //UIA Framework event: Item added
4806 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4809 public void Insert (int index, string text)
4811 Insert (index, String.Empty, text);
4814 public void Insert (int index, string text, int width)
4816 Insert (index, String.Empty, text, width);
4819 public void Insert (int index, string key, string text)
4821 ColumnHeader colHeader = new ColumnHeader ();
4822 colHeader.Name = key;
4823 colHeader.Text = text;
4824 Insert (index, colHeader);
4827 public void Insert (int index, string key, string text, int width)
4829 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
4830 Insert (index, colHeader);
4833 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4835 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4836 colHeader.ImageIndex = imageIndex;
4837 Insert (index, colHeader);
4840 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4842 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4843 colHeader.ImageKey = imageKey;
4844 Insert (index, colHeader);
4847 public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
4850 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4851 this.Insert (index, colHeader);
4854 public virtual void Remove (ColumnHeader column)
4856 if (!Contains (column))
4859 list.Remove (column);
4860 column.SetListView (null);
4862 int rem_display_index = column.InternalDisplayIndex;
4863 int [] display_indices = new int [list.Count];
4864 for (int i = 0; i < display_indices.Length; i++) {
4865 ColumnHeader col = (ColumnHeader) list [i];
4866 int display_index = col.InternalDisplayIndex;
4867 if (display_index < rem_display_index) {
4868 display_indices [i] = display_index;
4870 display_indices [i] = (display_index - 1);
4874 column.InternalDisplayIndex = -1;
4875 owner.ReorderColumns (display_indices, true);
4877 //UIA Framework event: Item Removed
4878 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
4881 public virtual void RemoveByKey (string key)
4883 int idx = IndexOfKey (key);
4888 public virtual void RemoveAt (int index)
4890 if (index < 0 || index >= list.Count)
4891 throw new ArgumentOutOfRangeException ("index");
4893 ColumnHeader col = (ColumnHeader) list [index];
4896 #endregion // Public Methods
4899 } // ColumnHeaderCollection
4901 [ListBindable (false)]
4902 public class ListViewItemCollection : IList, ICollection, IEnumerable
4904 private readonly ArrayList list;
4905 private ListView owner;
4906 private ListViewGroup group;
4908 #region UIA Framework Events
4910 // We are using Reflection to add/remove internal events.
4911 // Class ListViewProvider uses the events.
4913 //Event used to generate UIA StructureChangedEvent
4914 static object UIACollectionChangedEvent = new object ();
4916 internal event CollectionChangeEventHandler UIACollectionChanged {
4919 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4923 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4927 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4932 CollectionChangeEventHandler eh
4933 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4938 #endregion UIA Framework Events
4940 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
4941 // In the later case ListViewItem.ListView never gets modified
4942 private bool is_main_collection = true;
4944 #region Public Constructor
4945 public ListViewItemCollection (ListView owner)
4947 list = new ArrayList (0);
4950 #endregion // Public Constructor
4952 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
4955 is_main_collection = false;
4958 #region Public Properties
4962 if (owner != null && owner.VirtualMode)
4963 return owner.VirtualListSize;
4969 public bool IsReadOnly {
4970 get { return false; }
4973 public virtual ListViewItem this [int index] {
4975 if (index < 0 || index >= Count)
4976 throw new ArgumentOutOfRangeException ("index");
4978 if (owner != null && owner.VirtualMode)
4979 return RetrieveVirtualItemFromOwner (index);
4980 return (ListViewItem) list [index];
4984 if (index < 0 || index >= Count)
4985 throw new ArgumentOutOfRangeException ("index");
4987 if (owner != null && owner.VirtualMode)
4988 throw new InvalidOperationException ();
4990 if (list.Contains (value))
4991 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4993 if (value.ListView != null && value.ListView != owner)
4994 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");
4996 if (is_main_collection)
4997 value.Owner = owner;
4999 if (value.Group != null)
5000 value.Group.Items.Remove (value);
5002 value.SetGroup (group);
5005 //UIA Framework event: Item Replaced
5006 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5008 list [index] = value;
5010 CollectionChanged (true);
5012 //UIA Framework event: Item Replaced
5013 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5018 public virtual ListViewItem this [string key] {
5020 int idx = IndexOfKey (key);
5028 bool ICollection.IsSynchronized {
5029 get { return true; }
5032 object ICollection.SyncRoot {
5033 get { return this; }
5036 bool IList.IsFixedSize {
5037 get { return list.IsFixedSize; }
5040 object IList.this [int index] {
5041 get { return this [index]; }
5043 //UIA Framework event: Item Replaced
5044 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5046 if (value is ListViewItem)
5047 this [index] = (ListViewItem) value;
5049 this [index] = new ListViewItem (value.ToString ());
5052 //UIA Framework event: Item Replaced
5053 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5056 #endregion // Public Properties
5058 #region Public Methods
5059 public virtual ListViewItem Add (ListViewItem value)
5061 if (owner != null && owner.VirtualMode)
5062 throw new InvalidOperationException ();
5066 // Item is ignored until it has been added to the ListView
5067 if (is_main_collection || value.ListView != null)
5068 CollectionChanged (true);
5070 //UIA Framework event: Item Added
5071 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5076 public virtual ListViewItem Add (string text)
5078 ListViewItem item = new ListViewItem (text);
5079 return this.Add (item);
5082 public virtual ListViewItem Add (string text, int imageIndex)
5084 ListViewItem item = new ListViewItem (text, imageIndex);
5085 return this.Add (item);
5088 public virtual ListViewItem Add (string text, string imageKey)
5090 ListViewItem item = new ListViewItem (text, imageKey);
5091 return this.Add (item);
5094 public virtual ListViewItem Add (string key, string text, int imageIndex)
5096 ListViewItem item = new ListViewItem (text, imageIndex);
5098 return this.Add (item);
5101 public virtual ListViewItem Add (string key, string text, string imageKey)
5103 ListViewItem item = new ListViewItem (text, imageKey);
5105 return this.Add (item);
5108 public void AddRange (ListViewItem [] items)
5111 throw new ArgumentNullException ("Argument cannot be null!", "items");
5112 if (owner != null && owner.VirtualMode)
5113 throw new InvalidOperationException ();
5115 owner.BeginUpdate ();
5117 foreach (ListViewItem item in items) {
5120 //UIA Framework event: Item Added
5121 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5126 CollectionChanged (true);
5129 public void AddRange (ListViewItemCollection items)
5132 throw new ArgumentNullException ("Argument cannot be null!", "items");
5134 ListViewItem[] itemArray = new ListViewItem[items.Count];
5135 items.CopyTo (itemArray,0);
5136 this.AddRange (itemArray);
5139 public virtual void Clear ()
5141 if (owner != null && owner.VirtualMode)
5142 throw new InvalidOperationException ();
5143 if (is_main_collection && owner != null) {
5144 owner.SetFocusedItem (-1);
5145 owner.h_scroll.Value = owner.v_scroll.Value = 0;
5147 // first remove any item in the groups that *are* part of this LV too
5148 foreach (ListViewGroup group in owner.groups)
5149 group.Items.ClearItemsWithSameListView ();
5151 foreach (ListViewItem item in list) {
5152 owner.item_control.CancelEdit (item);
5157 foreach (ListViewItem item in list)
5158 item.SetGroup (null);
5161 CollectionChanged (false);
5163 //UIA Framework event: Items Removed
5164 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5168 // This method is intended to be used from ListViewGroup.Items, not from ListView.Items,
5169 // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items)
5170 void ClearItemsWithSameListView ()
5172 if (is_main_collection)
5175 int counter = list.Count - 1;
5176 while (counter >= 0) {
5177 ListViewItem item = list [counter] as ListViewItem;
5179 // remove only if the items in group have being added to the ListView too
5180 if (item.ListView == group.ListView) {
5181 list.RemoveAt (counter);
5182 item.SetGroup (null);
5189 public bool Contains (ListViewItem item)
5191 return IndexOf (item) != -1;
5194 public virtual bool ContainsKey (string key)
5196 return IndexOfKey (key) != -1;
5199 public void CopyTo (Array dest, int index)
5201 list.CopyTo (dest, index);
5204 public ListViewItem [] Find (string key, bool searchAllSubItems)
5207 return new ListViewItem [0];
5209 List<ListViewItem> temp_list = new List<ListViewItem> ();
5211 for (int i = 0; i < list.Count; i++) {
5212 ListViewItem lvi = (ListViewItem) list [i];
5213 if (String.Compare (key, lvi.Name, true) == 0)
5214 temp_list.Add (lvi);
5217 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5218 temp_list.CopyTo (retval);
5223 public IEnumerator GetEnumerator ()
5225 if (owner != null && owner.VirtualMode)
5226 throw new InvalidOperationException ();
5228 // This enumerator makes a copy of the collection so
5229 // it can be deleted from in a foreach
5230 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5233 int IList.Add (object item)
5238 if (owner != null && owner.VirtualMode)
5239 throw new InvalidOperationException ();
5241 if (item is ListViewItem) {
5242 li = (ListViewItem) item;
5243 if (list.Contains (li))
5244 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5246 if (li.ListView != null && li.ListView != owner)
5247 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");
5250 li = new ListViewItem (item.ToString ());
5255 result = list.Add (li);
5256 CollectionChanged (true);
5258 //UIA Framework event: Item Added
5259 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5264 bool IList.Contains (object item)
5266 return Contains ((ListViewItem) item);
5269 int IList.IndexOf (object item)
5271 return IndexOf ((ListViewItem) item);
5274 void IList.Insert (int index, object item)
5276 if (item is ListViewItem)
5277 this.Insert (index, (ListViewItem) item);
5279 this.Insert (index, item.ToString ());
5281 //UIA Framework event: Item Added
5282 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5285 void IList.Remove (object item)
5287 Remove ((ListViewItem) item);
5290 public int IndexOf (ListViewItem item)
5292 if (owner != null && owner.VirtualMode) {
5293 for (int i = 0; i < Count; i++)
5294 if (RetrieveVirtualItemFromOwner (i) == item)
5300 return list.IndexOf (item);
5303 public virtual int IndexOfKey (string key)
5305 if (key == null || key.Length == 0)
5308 for (int i = 0; i < Count; i++) {
5309 ListViewItem lvi = this [i];
5310 if (String.Compare (key, lvi.Name, true) == 0)
5317 public ListViewItem Insert (int index, ListViewItem item)
5319 if (index < 0 || index > list.Count)
5320 throw new ArgumentOutOfRangeException ("index");
5322 if (owner != null && owner.VirtualMode)
5323 throw new InvalidOperationException ();
5325 if (list.Contains (item))
5326 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5328 if (item.ListView != null && item.ListView != owner)
5329 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");
5331 if (is_main_collection)
5334 if (item.Group != null)
5335 item.Group.Items.Remove (item);
5337 item.SetGroup (group);
5340 list.Insert (index, item);
5342 if (is_main_collection || item.ListView != null)
5343 CollectionChanged (true);
5345 // force an update of the selected info if the new item is selected.
5347 item.SetSelectedCore (true);
5348 //UIA Framework event: Item Added
5349 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5354 public ListViewItem Insert (int index, string text)
5356 return this.Insert (index, new ListViewItem (text));
5359 public ListViewItem Insert (int index, string text, int imageIndex)
5361 return this.Insert (index, new ListViewItem (text, imageIndex));
5364 public ListViewItem Insert (int index, string text, string imageKey)
5366 ListViewItem lvi = new ListViewItem (text, imageKey);
5367 return Insert (index, lvi);
5370 public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5372 ListViewItem lvi = new ListViewItem (text, imageIndex);
5374 return Insert (index, lvi);
5377 public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5379 ListViewItem lvi = new ListViewItem (text, imageKey);
5381 return Insert (index, lvi);
5384 public virtual void Remove (ListViewItem item)
5386 if (owner != null && owner.VirtualMode)
5387 throw new InvalidOperationException ();
5389 int idx = list.IndexOf (item);
5394 public virtual void RemoveAt (int index)
5396 if (index < 0 || index >= Count)
5397 throw new ArgumentOutOfRangeException ("index");
5399 if (owner != null && owner.VirtualMode)
5400 throw new InvalidOperationException ();
5402 ListViewItem item = (ListViewItem) list [index];
5404 bool selection_changed = false;
5405 if (is_main_collection && owner != null) {
5407 int display_index = item.DisplayIndex;
5408 if (item.Focused && display_index + 1 == Count) // Last item
5409 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5411 selection_changed = owner.SelectedIndices.Contains (index);
5412 owner.item_control.CancelEdit (item);
5415 list.RemoveAt (index);
5417 if (is_main_collection) {
5419 if (item.Group != null)
5420 item.Group.Items.Remove (item);
5422 item.SetGroup (null);
5424 CollectionChanged (false);
5425 if (selection_changed && owner != null)
5426 owner.OnSelectedIndexChanged (EventArgs.Empty);
5429 //UIA Framework event: Item Removed
5430 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5433 public virtual void RemoveByKey (string key)
5435 int idx = IndexOfKey (key);
5440 #endregion // Public Methods
5442 internal ListView Owner {
5451 internal ListViewGroup Group {
5460 void AddItem (ListViewItem value)
5462 if (list.Contains (value))
5463 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5465 if (value.ListView != null && value.ListView != owner)
5466 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");
5467 if (is_main_collection)
5468 value.Owner = owner;
5470 if (value.Group != null)
5471 value.Group.Items.Remove (value);
5473 value.SetGroup (group);
5478 // force an update of the selected info if the new item is selected.
5480 value.SetSelectedCore (true);
5483 void CollectionChanged (bool sort)
5485 if (owner != null) {
5490 owner.Redraw (true);
5494 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5496 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5498 owner.OnRetrieveVirtualItem (args);
5499 ListViewItem retval = args.Item;
5500 retval.Owner = owner;
5501 retval.DisplayIndex = displayIndex;
5507 internal event CollectionChangedHandler Changed;
5509 internal void Sort (IComparer comparer)
5511 list.Sort (comparer);
5515 internal void OnChange ()
5517 if (Changed != null)
5520 } // ListViewItemCollection
5523 // In normal mode, the selection information resides in the Items,
5524 // making SelectedIndexCollection.List read-only
5526 // In virtual mode, SelectedIndexCollection directly saves the selection
5527 // information, instead of getting it from Items, making List read-and-write
5528 [ListBindable (false)]
5529 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5531 private readonly ListView owner;
5532 private ArrayList list;
5534 #region Public Constructor
5535 public SelectedIndexCollection (ListView owner)
5538 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5540 #endregion // Public Constructor
5542 #region Public Properties
5546 if (!owner.is_selection_available)
5553 public bool IsReadOnly {
5559 public int this [int index] {
5561 if (!owner.is_selection_available || index < 0 || index >= List.Count)
5562 throw new ArgumentOutOfRangeException ("index");
5564 return (int) List [index];
5568 bool ICollection.IsSynchronized {
5569 get { return false; }
5572 object ICollection.SyncRoot {
5573 get { return this; }
5576 bool IList.IsFixedSize {
5582 object IList.this [int index] {
5583 get { return this [index]; }
5584 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5586 #endregion // Public Properties
5588 #region Public Methods
5589 public int Add (int itemIndex)
5591 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5592 throw new ArgumentOutOfRangeException ("index");
5594 if (owner.virtual_mode && !owner.is_selection_available)
5597 owner.Items [itemIndex].Selected = true;
5599 if (!owner.is_selection_available)
5605 public void Clear ()
5607 if (!owner.is_selection_available)
5610 int [] indexes = (int []) List.ToArray (typeof (int));
5611 foreach (int index in indexes)
5612 owner.Items [index].Selected = false;
5615 public bool Contains (int selectedIndex)
5617 return IndexOf (selectedIndex) != -1;
5620 public void CopyTo (Array dest, int index)
5622 List.CopyTo (dest, index);
5625 public IEnumerator GetEnumerator ()
5627 return List.GetEnumerator ();
5630 int IList.Add (object value)
5632 throw new NotSupportedException ("Add operation is not supported.");
5640 bool IList.Contains (object selectedIndex)
5642 if (!(selectedIndex is int))
5644 return Contains ((int) selectedIndex);
5647 int IList.IndexOf (object selectedIndex)
5649 if (!(selectedIndex is int))
5651 return IndexOf ((int) selectedIndex);
5654 void IList.Insert (int index, object value)
5656 throw new NotSupportedException ("Insert operation is not supported.");
5659 void IList.Remove (object value)
5661 throw new NotSupportedException ("Remove operation is not supported.");
5664 void IList.RemoveAt (int index)
5666 throw new NotSupportedException ("RemoveAt operation is not supported.");
5669 public int IndexOf (int selectedIndex)
5671 if (!owner.is_selection_available)
5674 return List.IndexOf (selectedIndex);
5677 public void Remove (int itemIndex)
5679 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5680 throw new ArgumentOutOfRangeException ("itemIndex");
5682 owner.Items [itemIndex].Selected = false;
5684 #endregion // Public Methods
5686 internal ArrayList List {
5689 list = new ArrayList ();
5690 if (!owner.VirtualMode)
5691 for (int i = 0; i < owner.Items.Count; i++) {
5692 if (owner.Items [i].Selected)
5700 internal void Reset ()
5702 // force re-population of list
5706 private void ItemsCollection_Changed ()
5711 internal void RemoveIndex (int index)
5713 int idx = List.BinarySearch (index);
5715 List.RemoveAt (idx);
5718 // actually store index in the collection
5719 // also, keep the collection sorted, as .Net does
5720 internal void InsertIndex (int index)
5723 int iMax = List.Count - 1;
5724 while (iMin <= iMax) {
5725 int iMid = (iMin + iMax) / 2;
5726 int current_index = (int) List [iMid];
5728 if (current_index == index)
5729 return; // Already added
5730 if (current_index > index)
5736 List.Insert (iMin, index);
5739 } // SelectedIndexCollection
5741 [ListBindable (false)]
5742 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
5744 private readonly ListView owner;
5746 #region Public Constructor
5747 public SelectedListViewItemCollection (ListView owner)
5751 #endregion // Public Constructor
5753 #region Public Properties
5757 return owner.SelectedIndices.Count;
5761 public bool IsReadOnly {
5762 get { return true; }
5765 public ListViewItem this [int index] {
5767 if (!owner.is_selection_available || index < 0 || index >= Count)
5768 throw new ArgumentOutOfRangeException ("index");
5770 int item_index = owner.SelectedIndices [index];
5771 return owner.Items [item_index];
5775 public virtual ListViewItem this [string key] {
5777 int idx = IndexOfKey (key);
5785 bool ICollection.IsSynchronized {
5786 get { return false; }
5789 object ICollection.SyncRoot {
5790 get { return this; }
5793 bool IList.IsFixedSize {
5794 get { return true; }
5797 object IList.this [int index] {
5798 get { return this [index]; }
5799 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5801 #endregion // Public Properties
5803 #region Public Methods
5804 public void Clear ()
5806 owner.SelectedIndices.Clear ();
5809 public bool Contains (ListViewItem item)
5811 return IndexOf (item) != -1;
5814 public virtual bool ContainsKey (string key)
5816 return IndexOfKey (key) != -1;
5819 public void CopyTo (Array dest, int index)
5821 if (!owner.is_selection_available)
5823 if (index > Count) // Throws ArgumentException instead of IOOR exception
5824 throw new ArgumentException ("index");
5826 for (int i = 0; i < Count; i++)
5827 dest.SetValue (this [i], index++);
5830 public IEnumerator GetEnumerator ()
5832 if (!owner.is_selection_available)
5833 return (new ListViewItem [0]).GetEnumerator ();
5835 ListViewItem [] items = new ListViewItem [Count];
5836 for (int i = 0; i < Count; i++)
5837 items [i] = this [i];
5839 return items.GetEnumerator ();
5842 int IList.Add (object value)
5844 throw new NotSupportedException ("Add operation is not supported.");
5847 bool IList.Contains (object item)
5849 if (!(item is ListViewItem))
5851 return Contains ((ListViewItem) item);
5854 int IList.IndexOf (object item)
5856 if (!(item is ListViewItem))
5858 return IndexOf ((ListViewItem) item);
5861 void IList.Insert (int index, object value)
5863 throw new NotSupportedException ("Insert operation is not supported.");
5866 void IList.Remove (object value)
5868 throw new NotSupportedException ("Remove operation is not supported.");
5871 void IList.RemoveAt (int index)
5873 throw new NotSupportedException ("RemoveAt operation is not supported.");
5876 public int IndexOf (ListViewItem item)
5878 if (!owner.is_selection_available)
5881 for (int i = 0; i < Count; i++)
5882 if (this [i] == item)
5888 public virtual int IndexOfKey (string key)
5890 if (!owner.is_selection_available || key == null || key.Length == 0)
5893 for (int i = 0; i < Count; i++) {
5894 ListViewItem item = this [i];
5895 if (String.Compare (item.Name, key, true) == 0)
5901 #endregion // Public Methods
5903 } // SelectedListViewItemCollection
5905 internal delegate void CollectionChangedHandler ();
5907 struct ItemMatrixLocation
5912 public ItemMatrixLocation (int row, int col)
5939 #endregion // Subclasses
5940 protected override void OnResize (EventArgs e)
5945 protected override void OnMouseLeave (EventArgs e)
5947 base.OnMouseLeave (e);
5951 // ColumnReorder event
5953 static object ColumnReorderedEvent = new object ();
5954 public event ColumnReorderedEventHandler ColumnReordered {
5955 add { Events.AddHandler (ColumnReorderedEvent, value); }
5956 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
5959 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
5961 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
5968 // ColumnWidthChanged
5970 static object ColumnWidthChangedEvent = new object ();
5971 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
5972 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
5973 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
5976 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
5978 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
5983 void RaiseColumnWidthChanged (int resize_column)
5985 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
5987 OnColumnWidthChanged (n);
5991 // ColumnWidthChanging
5993 static object ColumnWidthChangingEvent = new object ();
5994 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
5995 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
5996 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
5999 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6001 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6007 // 2.0 profile based implementation
6009 bool CanProceedWithResize (ColumnHeader col, int width)
6011 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6015 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6016 cwceh (this, changing);
6017 return !changing.Cancel;
6020 internal void RaiseColumnWidthChanged (ColumnHeader column)
6022 int index = Columns.IndexOf (column);
6023 RaiseColumnWidthChanged (index);
6027 #region UIA Framework: Methods, Properties and Events
6029 static object UIALabelEditChangedEvent = new object ();
6030 static object UIAShowGroupsChangedEvent = new object ();
6031 static object UIAMultiSelectChangedEvent = new object ();
6032 static object UIAViewChangedEvent = new object ();
6033 static object UIACheckBoxesChangedEvent = new object ();
6034 static object UIAFocusedItemChangedEvent = new object ();
6036 internal Rectangle UIAHeaderControl {
6037 get { return header_control.Bounds; }
6040 internal int UIAColumns {
6041 get { return cols; }
6044 internal int UIARows {
6045 get { return rows; }
6048 internal ListViewGroup UIADefaultListViewGroup
6050 get { return groups.DefaultGroup; }
6053 internal ScrollBar UIAHScrollBar {
6054 get { return h_scroll; }
6057 internal ScrollBar UIAVScrollBar {
6058 get { return v_scroll; }
6061 internal event EventHandler UIAShowGroupsChanged {
6062 add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6063 remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6066 internal event EventHandler UIACheckBoxesChanged {
6067 add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6068 remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6071 internal event EventHandler UIAMultiSelectChanged {
6072 add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6073 remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6076 internal event EventHandler UIALabelEditChanged {
6077 add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6078 remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6081 internal event EventHandler UIAViewChanged {
6082 add { Events.AddHandler (UIAViewChangedEvent, value); }
6083 remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6086 internal event EventHandler UIAFocusedItemChanged {
6087 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6088 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6091 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6093 return group.HeaderBounds;
6096 internal int UIAItemsLocationLength
6098 get { return items_location.Length; }
6101 private void OnUIACheckBoxesChanged ()
6103 EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6105 eh (this, EventArgs.Empty);
6108 private void OnUIAShowGroupsChanged ()
6110 EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6112 eh (this, EventArgs.Empty);
6115 private void OnUIAMultiSelectChanged ()
6117 EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6119 eh (this, EventArgs.Empty);
6122 private void OnUIALabelEditChanged ()
6124 EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6126 eh (this, EventArgs.Empty);
6129 private void OnUIAViewChanged ()
6131 EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6133 eh (this, EventArgs.Empty);
6136 internal void OnUIAFocusedItemChanged ()
6138 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6140 eh (this, EventArgs.Empty);
6143 #endregion // UIA Framework: Methods, Properties and Events