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;
41 using System.Collections.Generic;
44 namespace System.Windows.Forms
46 [DefaultEvent ("SelectedIndexChanged")]
47 [DefaultProperty ("Items")]
48 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
50 [ClassInterface (ClassInterfaceType.AutoDispatch)]
52 [Docking (DockingBehavior.Ask)]
54 public class ListView : Control
56 private ItemActivation activation = ItemActivation.Standard;
57 private ListViewAlignment alignment = ListViewAlignment.Top;
58 private bool allow_column_reorder;
59 private bool auto_arrange = true;
60 private bool check_boxes;
61 private readonly CheckedIndexCollection checked_indices;
62 private readonly CheckedListViewItemCollection checked_items;
63 private readonly ColumnHeaderCollection columns;
64 internal int focused_item_index = -1;
65 private bool full_row_select;
66 private bool grid_lines;
67 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
68 private bool hide_selection = true;
69 private bool hover_selection;
70 private IComparer item_sorter;
71 private readonly ListViewItemCollection items;
73 private readonly ListViewGroupCollection groups;
74 private bool owner_draw;
75 private bool show_groups = true;
77 private bool label_edit;
78 private bool label_wrap = true;
79 private bool multiselect = true;
80 private bool scrollable = true;
81 private bool hover_pending;
82 private readonly SelectedIndexCollection selected_indices;
83 private readonly SelectedListViewItemCollection selected_items;
84 private SortOrder sort_order = SortOrder.None;
85 private ImageList state_image_list;
86 internal bool updating;
87 private View view = View.LargeIcon;
88 private int layout_wd; // We might draw more than our client area
89 private int layout_ht; // therefore we need to have these two.
90 internal HeaderControl header_control;
91 internal ItemControl item_control;
92 internal ScrollBar h_scroll; // used for scrolling horizontally
93 internal ScrollBar v_scroll; // used for scrolling vertically
94 internal int h_marker; // Position markers for scrolling
95 internal int v_marker;
96 private int keysearch_tickcnt;
97 private string keysearch_text;
98 static private readonly int keysearch_keydelay = 1000;
99 private int[] reordered_column_indices;
100 private int[] reordered_items_indices;
101 private Point [] items_location;
102 private ItemMatrixLocation [] items_matrix_location;
103 private Size item_size; // used for caching item size
104 private int custom_column_width; // used when using Columns with SmallIcon/List views
105 private int hot_item_index = -1;
107 private bool hot_tracking;
108 private ListViewInsertionMark insertion_mark;
109 private bool show_item_tooltips;
110 private ToolTip item_tooltip;
111 private Size tile_size;
112 private bool virtual_mode;
113 private int virtual_list_size;
114 private bool right_to_left_layout;
116 // selection is available after the first time the handle is created, *even* if later
117 // the handle is either recreated or destroyed - so keep this info around.
118 private bool is_selection_available;
120 // internal variables
121 internal ImageList large_image_list;
122 internal ImageList small_image_list;
123 internal Size text_size = Size.Empty;
126 static object AfterLabelEditEvent = new object ();
127 static object BeforeLabelEditEvent = new object ();
128 static object ColumnClickEvent = new object ();
129 static object ItemActivateEvent = new object ();
130 static object ItemCheckEvent = new object ();
131 static object ItemDragEvent = new object ();
132 static object SelectedIndexChangedEvent = new object ();
134 static object DrawColumnHeaderEvent = new object();
135 static object DrawItemEvent = new object();
136 static object DrawSubItemEvent = new object();
137 static object ItemCheckedEvent = new object ();
138 static object ItemMouseHoverEvent = new object ();
139 static object ItemSelectionChangedEvent = new object ();
140 static object CacheVirtualItemsEvent = new object ();
141 static object RetrieveVirtualItemEvent = new object ();
142 static object RightToLeftLayoutChangedEvent = new object ();
143 static object SearchForVirtualItemEvent = new object ();
144 static object VirtualItemsSelectionRangeChangedEvent = new object ();
147 public event LabelEditEventHandler AfterLabelEdit {
148 add { Events.AddHandler (AfterLabelEditEvent, value); }
149 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
154 [EditorBrowsable (EditorBrowsableState.Never)]
155 public new event EventHandler BackgroundImageChanged {
156 add { base.BackgroundImageChanged += value; }
157 remove { base.BackgroundImageChanged -= value; }
163 [EditorBrowsable (EditorBrowsableState.Never)]
164 public new event EventHandler BackgroundImageLayoutChanged {
165 add { base.BackgroundImageLayoutChanged += value; }
166 remove { base.BackgroundImageLayoutChanged -= value; }
170 public event LabelEditEventHandler BeforeLabelEdit {
171 add { Events.AddHandler (BeforeLabelEditEvent, value); }
172 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
175 public event ColumnClickEventHandler ColumnClick {
176 add { Events.AddHandler (ColumnClickEvent, value); }
177 remove { Events.RemoveHandler (ColumnClickEvent, value); }
181 public event DrawListViewColumnHeaderEventHandler DrawColumnHeader {
182 add { Events.AddHandler(DrawColumnHeaderEvent, value); }
183 remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); }
186 public event DrawListViewItemEventHandler DrawItem {
187 add { Events.AddHandler(DrawItemEvent, value); }
188 remove { Events.RemoveHandler(DrawItemEvent, value); }
191 public event DrawListViewSubItemEventHandler DrawSubItem {
192 add { Events.AddHandler(DrawSubItemEvent, value); }
193 remove { Events.RemoveHandler(DrawSubItemEvent, value); }
197 public event EventHandler ItemActivate {
198 add { Events.AddHandler (ItemActivateEvent, value); }
199 remove { Events.RemoveHandler (ItemActivateEvent, value); }
202 public event ItemCheckEventHandler ItemCheck {
203 add { Events.AddHandler (ItemCheckEvent, value); }
204 remove { Events.RemoveHandler (ItemCheckEvent, value); }
208 public event ItemCheckedEventHandler ItemChecked {
209 add { Events.AddHandler (ItemCheckedEvent, value); }
210 remove { Events.RemoveHandler (ItemCheckedEvent, value); }
214 public event ItemDragEventHandler ItemDrag {
215 add { Events.AddHandler (ItemDragEvent, value); }
216 remove { Events.RemoveHandler (ItemDragEvent, value); }
220 public event ListViewItemMouseHoverEventHandler ItemMouseHover {
221 add { Events.AddHandler (ItemMouseHoverEvent, value); }
222 remove { Events.RemoveHandler (ItemMouseHoverEvent, value); }
225 public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged {
226 add { Events.AddHandler (ItemSelectionChangedEvent, value); }
227 remove { Events.RemoveHandler (ItemSelectionChangedEvent, value); }
231 [EditorBrowsable (EditorBrowsableState.Never)]
232 public new event EventHandler PaddingChanged {
233 add { base.PaddingChanged += value; }
234 remove { base.PaddingChanged -= value; }
239 [EditorBrowsable (EditorBrowsableState.Never)]
240 public new event PaintEventHandler Paint {
241 add { base.Paint += value; }
242 remove { base.Paint -= value; }
245 public event EventHandler SelectedIndexChanged {
246 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
247 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
251 [EditorBrowsable (EditorBrowsableState.Never)]
252 public new event EventHandler TextChanged {
253 add { base.TextChanged += value; }
254 remove { base.TextChanged -= value; }
258 public event CacheVirtualItemsEventHandler CacheVirtualItems {
259 add { Events.AddHandler (CacheVirtualItemsEvent, value); }
260 remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); }
263 public event RetrieveVirtualItemEventHandler RetrieveVirtualItem {
264 add { Events.AddHandler (RetrieveVirtualItemEvent, value); }
265 remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); }
268 public event EventHandler RightToLeftLayoutChanged {
269 add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
270 remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
273 public event SearchForVirtualItemEventHandler SearchForVirtualItem {
274 add { Events.AddHandler (SearchForVirtualItemEvent, value); }
275 remove { Events.AddHandler (SearchForVirtualItemEvent, value); }
278 public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged {
279 add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); }
280 remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); }
286 #region Public Constructors
289 background_color = ThemeEngine.Current.ColorWindow;
291 groups = new ListViewGroupCollection (this);
293 items = new ListViewItemCollection (this);
294 items.Changed += new CollectionChangedHandler (OnItemsChanged);
295 checked_indices = new CheckedIndexCollection (this);
296 checked_items = new CheckedListViewItemCollection (this);
297 columns = new ColumnHeaderCollection (this);
298 foreground_color = SystemColors.WindowText;
299 selected_indices = new SelectedIndexCollection (this);
300 selected_items = new SelectedListViewItemCollection (this);
301 items_location = new Point [16];
302 items_matrix_location = new ItemMatrixLocation [16];
303 reordered_items_indices = new int [16];
305 item_tooltip = new ToolTip ();
306 item_tooltip.Active = false;
307 insertion_mark = new ListViewInsertionMark (this);
310 InternalBorderStyle = BorderStyle.Fixed3D;
312 header_control = new HeaderControl (this);
313 header_control.Visible = false;
314 Controls.AddImplicit (header_control);
316 item_control = new ItemControl (this);
317 Controls.AddImplicit (item_control);
319 h_scroll = new ImplicitHScrollBar ();
320 Controls.AddImplicit (this.h_scroll);
322 v_scroll = new ImplicitVScrollBar ();
323 Controls.AddImplicit (this.v_scroll);
325 h_marker = v_marker = 0;
326 keysearch_tickcnt = 0;
328 // scroll bars are disabled initially
329 h_scroll.Visible = false;
330 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
331 v_scroll.Visible = false;
332 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
335 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
336 SizeChanged += new EventHandler (ListView_SizeChanged);
337 GotFocus += new EventHandler (FocusChanged);
338 LostFocus += new EventHandler (FocusChanged);
339 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
340 MouseEnter += new EventHandler (ListView_MouseEnter);
341 Invalidated += new InvalidateEventHandler (ListView_Invalidated);
344 BackgroundImageTiled = false;
347 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
349 | ControlStyles.UseTextForAccessibility
353 #endregion // Public Constructors
355 #region Private Internal Properties
356 internal Size CheckBoxSize {
358 if (this.check_boxes) {
359 if (this.state_image_list != null)
360 return this.state_image_list.ImageSize;
362 return ThemeEngine.Current.ListViewCheckBoxSize;
368 internal Size ItemSize {
370 if (view != View.Details)
373 Size size = new Size ();
374 size.Height = item_size.Height;
375 for (int i = 0; i < columns.Count; i++)
376 size.Width += columns [i].Wd;
385 internal int HotItemIndex {
387 return hot_item_index;
390 hot_item_index = value;
395 internal bool UsingGroups {
397 return show_groups && groups.Count > 0 && view != View.List &&
398 Application.VisualStylesEnabled;
403 internal override bool ScaleChildrenInternal {
404 get { return false; }
407 internal bool UseCustomColumnWidth {
409 return (view == View.List || view == View.SmallIcon) && columns.Count > 0;
413 internal ColumnHeader EnteredColumnHeader {
415 return header_control.EnteredColumnHeader;
418 #endregion // Private Internal Properties
420 #region Protected Properties
421 protected override CreateParams CreateParams {
422 get { return base.CreateParams; }
425 protected override Size DefaultSize {
426 get { return ThemeEngine.Current.ListViewDefaultSize; }
429 protected override bool DoubleBuffered {
431 return base.DoubleBuffered;
434 base.DoubleBuffered = value;
438 #endregion // Protected Properties
440 #region Public Instance Properties
441 [DefaultValue (ItemActivation.Standard)]
442 public ItemActivation Activation {
443 get { return activation; }
445 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
446 value != ItemActivation.TwoClick) {
447 throw new InvalidEnumArgumentException (string.Format
448 ("Enum argument value '{0}' is not valid for Activation", value));
451 if (hot_tracking && value != ItemActivation.OneClick)
452 throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick");
459 [DefaultValue (ListViewAlignment.Top)]
461 public ListViewAlignment Alignment {
462 get { return alignment; }
464 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
465 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
466 throw new InvalidEnumArgumentException (string.Format
467 ("Enum argument value '{0}' is not valid for Alignment", value));
470 if (this.alignment != value) {
472 // alignment does not matter in Details/List views
473 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
479 [DefaultValue (false)]
480 public bool AllowColumnReorder {
481 get { return allow_column_reorder; }
482 set { allow_column_reorder = value; }
485 [DefaultValue (true)]
486 public bool AutoArrange {
487 get { return auto_arrange; }
489 if (auto_arrange != value) {
490 auto_arrange = value;
491 // autoarrange does not matter in Details/List views
492 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
498 public override Color BackColor {
500 if (background_color.IsEmpty)
501 return ThemeEngine.Current.ColorWindow;
503 return background_color;
506 background_color = value;
507 item_control.BackColor = value;
513 [EditorBrowsable (EditorBrowsableState.Never)]
514 public override Image BackgroundImage {
515 get { return base.BackgroundImage; }
516 set { base.BackgroundImage = value; }
522 [EditorBrowsable (EditorBrowsableState.Never)]
523 public override ImageLayout BackgroundImageLayout {
525 return base.BackgroundImageLayout;
528 base.BackgroundImageLayout = value;
532 [DefaultValue (false)]
533 public bool BackgroundImageTiled {
535 return item_control.BackgroundImageLayout == ImageLayout.Tile;
538 ImageLayout new_image_layout = value ? ImageLayout.Tile : ImageLayout.None;
539 if (new_image_layout == item_control.BackgroundImageLayout)
542 item_control.BackgroundImageLayout = new_image_layout;
547 [DefaultValue (BorderStyle.Fixed3D)]
549 public BorderStyle BorderStyle {
550 get { return InternalBorderStyle; }
551 set { InternalBorderStyle = value; }
554 [DefaultValue (false)]
555 public bool CheckBoxes {
556 get { return check_boxes; }
558 if (check_boxes != value) {
560 if (value && View == View.Tile)
561 throw new NotSupportedException ("CheckBoxes are not"
562 + " supported in Tile view. Choose a different"
563 + " view or set CheckBoxes to false.");
570 //UIA Framework: Event used by ListView to set/unset Toggle Pattern
571 OnUIACheckBoxesChanged ();
578 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
579 public CheckedIndexCollection CheckedIndices {
580 get { return checked_indices; }
584 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
585 public CheckedListViewItemCollection CheckedItems {
586 get { return checked_items; }
590 [Editor ("System.Windows.Forms.Design.ColumnHeaderCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
592 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
594 [MergableProperty (false)]
595 public ColumnHeaderCollection Columns {
596 get { return columns; }
600 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
601 public ListViewItem FocusedItem {
603 if (focused_item_index == -1)
606 return GetItemAtDisplayIndex (focused_item_index);
610 if (value == null || value.ListView != this ||
614 SetFocusedItem (value.DisplayIndex);
619 public override Color ForeColor {
621 if (foreground_color.IsEmpty)
622 return ThemeEngine.Current.ColorWindowText;
624 return foreground_color;
626 set { foreground_color = value; }
629 [DefaultValue (false)]
630 public bool FullRowSelect {
631 get { return full_row_select; }
633 if (full_row_select != value) {
634 full_row_select = value;
635 InvalidateSelection ();
640 [DefaultValue (false)]
641 public bool GridLines {
642 get { return grid_lines; }
644 if (grid_lines != value) {
651 [DefaultValue (ColumnHeaderStyle.Clickable)]
652 public ColumnHeaderStyle HeaderStyle {
653 get { return header_style; }
655 if (header_style == value)
659 case ColumnHeaderStyle.Clickable:
660 case ColumnHeaderStyle.Nonclickable:
661 case ColumnHeaderStyle.None:
664 throw new InvalidEnumArgumentException (string.Format
665 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
668 header_style = value;
669 if (view == View.Details)
674 [DefaultValue (true)]
675 public bool HideSelection {
676 get { return hide_selection; }
678 if (hide_selection != value) {
679 hide_selection = value;
680 InvalidateSelection ();
686 [DefaultValue (false)]
687 public bool HotTracking {
692 if (hot_tracking == value)
695 hot_tracking = value;
697 hover_selection = true;
698 activation = ItemActivation.OneClick;
704 [DefaultValue (false)]
705 public bool HoverSelection {
706 get { return hover_selection; }
709 if (hot_tracking && value == false)
710 throw new ArgumentException ("When HotTracking is on, hover selection must be true");
712 hover_selection = value;
717 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
719 public ListViewInsertionMark InsertionMark {
721 return insertion_mark;
727 [Editor ("System.Windows.Forms.Design.ListViewItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
729 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
731 [MergableProperty (false)]
732 public ListViewItemCollection Items {
733 get { return items; }
736 [DefaultValue (false)]
737 public bool LabelEdit {
738 get { return label_edit; }
740 if (value != label_edit) {
744 // UIA Framework: Event used by Value Pattern in ListView.ListItem provider
745 OnUIALabelEditChanged ();
752 [DefaultValue (true)]
754 public bool LabelWrap {
755 get { return label_wrap; }
757 if (label_wrap != value) {
764 [DefaultValue (null)]
765 public ImageList LargeImageList {
766 get { return large_image_list; }
768 large_image_list = value;
774 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
775 public IComparer ListViewItemSorter {
777 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
782 if (item_sorter != value) {
789 [DefaultValue (true)]
790 public bool MultiSelect {
791 get { return multiselect; }
793 if (value != multiselect) {
797 // UIA Framework: Event used by Selection Pattern in ListView.ListItem provider
798 OnUIAMultiSelectChanged ();
806 [DefaultValue(false)]
807 public bool OwnerDraw {
808 get { return owner_draw; }
816 [EditorBrowsable (EditorBrowsableState.Never)]
817 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
818 public new Padding Padding {
823 base.Padding = value;
827 [MonoTODO ("RTL not supported")]
829 [DefaultValue (false)]
830 public virtual bool RightToLeftLayout {
831 get { return right_to_left_layout; }
833 if (right_to_left_layout != value) {
834 right_to_left_layout = value;
835 OnRightToLeftLayoutChanged (EventArgs.Empty);
841 [DefaultValue (true)]
842 public bool Scrollable {
843 get { return scrollable; }
845 if (scrollable != value) {
853 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
854 public SelectedIndexCollection SelectedIndices {
855 get { return selected_indices; }
859 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
860 public SelectedListViewItemCollection SelectedItems {
861 get { return selected_items; }
866 public bool ShowGroups {
867 get { return show_groups; }
869 if (show_groups != value) {
873 // UIA Framework: Used to update a11y Tree
874 OnUIAShowGroupsChanged ();
879 [LocalizableAttribute (true)]
880 [MergableProperty (false)]
881 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
882 [Editor ("System.Windows.Forms.Design.ListViewGroupCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
883 public ListViewGroupCollection Groups {
884 get { return groups; }
887 [DefaultValue (false)]
888 public bool ShowItemToolTips {
890 return show_item_tooltips;
893 show_item_tooltips = value;
894 item_tooltip.Active = false;
899 [DefaultValue (null)]
900 public ImageList SmallImageList {
901 get { return small_image_list; }
903 small_image_list = value;
908 [DefaultValue (SortOrder.None)]
909 public SortOrder Sorting {
910 get { return sort_order; }
912 if (!Enum.IsDefined (typeof (SortOrder), value)) {
913 throw new InvalidEnumArgumentException ("value", (int) value,
917 if (sort_order == value)
923 if (virtual_mode) // Sorting is not allowed in virtual mode
927 if (value == SortOrder.None) {
928 if (item_sorter != null) {
929 // ListViewItemSorter should never be reset for SmallIcon
930 // and LargeIcon view
931 if (View != View.SmallIcon && View != View.LargeIcon)
935 // in .NET 1.1, only internal IComparer would be
937 if (item_sorter is ItemComparer)
943 if (item_sorter == null)
944 item_sorter = new ItemComparer (value);
945 if (item_sorter is ItemComparer) {
947 item_sorter = new ItemComparer (value);
949 // in .NET 1.1, the sort order is not updated for
950 // SmallIcon and LargeIcon views if no custom IComparer
952 if (View != View.SmallIcon && View != View.LargeIcon)
953 item_sorter = new ItemComparer (value);
961 private void OnImageListChanged (object sender, EventArgs args)
963 item_control.Invalidate ();
966 [DefaultValue (null)]
967 public ImageList StateImageList {
968 get { return state_image_list; }
970 if (state_image_list == value)
973 if (state_image_list != null)
974 state_image_list.Images.Changed -= new EventHandler (OnImageListChanged);
976 state_image_list = value;
978 if (state_image_list != null)
979 state_image_list.Images.Changed += new EventHandler (OnImageListChanged);
987 [EditorBrowsable (EditorBrowsableState.Never)]
988 public override string Text {
989 get { return base.Text; }
991 if (value == base.Text)
1001 public Size TileSize {
1006 if (value.Width <= 0 || value.Height <= 0)
1007 throw new ArgumentOutOfRangeException ("value");
1010 if (view == View.Tile)
1017 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1018 public ListViewItem TopItem {
1021 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
1022 throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view.");
1025 if (this.items.Count == 0)
1027 // if contents are not scrolled
1028 // it is the first item
1029 else if (h_marker == 0 && v_marker == 0)
1030 return this.items [0];
1031 // do a hit test for the scrolled position
1033 int header_offset = header_control.Height;
1034 for (int i = 0; i < items.Count; i++) {
1035 Point item_loc = GetItemLocation (i);
1036 if (item_loc.X >= 0 && item_loc.Y - header_offset >= 0)
1044 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
1045 throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view.");
1047 // .Net doesn't throw any exception in the cases below
1048 if (value == null || value.ListView != this)
1051 // Take advantage this property is only valid for Details view.
1052 SetScrollValue (v_scroll, item_size.Height * value.Index);
1058 [EditorBrowsable (EditorBrowsableState.Advanced)]
1059 [DefaultValue (true)]
1061 [MonoInternalNote ("Stub, not implemented")]
1062 public bool UseCompatibleStateImageBehavior {
1071 [DefaultValue (View.LargeIcon)]
1073 get { return view; }
1075 if (!Enum.IsDefined (typeof (View), value))
1076 throw new InvalidEnumArgumentException ("value", (int) value,
1079 if (view != value) {
1081 if (CheckBoxes && value == View.Tile)
1082 throw new NotSupportedException ("CheckBoxes are not"
1083 + " supported in Tile view. Choose a different"
1084 + " view or set CheckBoxes to false.");
1085 if (VirtualMode && value == View.Tile)
1086 throw new NotSupportedException ("VirtualMode is"
1087 + " not supported in Tile view. Choose a different"
1088 + " view or set ViewMode to false.");
1091 h_scroll.Value = v_scroll.Value = 0;
1096 // UIA Framework: Event used to update UIA Tree.
1097 OnUIAViewChanged ();
1104 [DefaultValue (false)]
1105 [RefreshProperties (RefreshProperties.Repaint)]
1106 public bool VirtualMode {
1108 return virtual_mode;
1111 if (virtual_mode == value)
1114 if (!virtual_mode && items.Count > 0)
1115 throw new InvalidOperationException ();
1116 if (value && view == View.Tile)
1117 throw new NotSupportedException ("VirtualMode is"
1118 + " not supported in Tile view. Choose a different"
1119 + " view or set ViewMode to false.");
1121 virtual_mode = value;
1127 [RefreshProperties (RefreshProperties.Repaint)]
1128 public int VirtualListSize {
1130 return virtual_list_size;
1134 throw new ArgumentException ("value");
1136 if (virtual_list_size == value)
1139 virtual_list_size = value;
1141 selected_indices.Reset ();
1147 #endregion // Public Instance Properties
1149 #region Internal Methods Properties
1151 internal int FirstVisibleIndex {
1154 if (this.items.Count == 0)
1157 if (h_marker == 0 && v_marker == 0)
1160 Size item_size = ItemSize;
1162 // In virtual mode we always have fixed positions, and we can infer the positon easily
1167 first = v_marker / item_size.Height;
1169 case View.LargeIcon:
1170 case View.SmallIcon:
1171 first = (v_marker / (item_size.Height + y_spacing)) * cols;
1174 first = (h_marker / (item_size.Width * x_spacing)) * rows;
1178 if (first >= items.Count)
1179 first = items.Count;
1184 for (int i = 0; i < items.Count; i++) {
1185 Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size);
1186 if (item_rect.Right >= 0 && item_rect.Bottom >= 0)
1195 internal int LastVisibleIndex {
1197 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
1198 if (View == View.List || Alignment == ListViewAlignment.Left) {
1199 if (GetItemLocation (i).X > item_control.ClientRectangle.Right)
1202 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
1207 return Items.Count - 1;
1211 internal void OnSelectedIndexChanged ()
1213 if (is_selection_available)
1214 OnSelectedIndexChanged (EventArgs.Empty);
1217 internal int TotalWidth {
1218 get { return Math.Max (this.Width, this.layout_wd); }
1221 internal int TotalHeight {
1222 get { return Math.Max (this.Height, this.layout_ht); }
1225 internal void Redraw (bool recalculate)
1227 // Avoid calculations when control is being updated
1231 // VirtualMode doesn't do any calculations until handle is created
1232 if (virtual_mode && !IsHandleCreated)
1238 CalculateListView (this.alignment);
1243 void InvalidateSelection ()
1245 foreach (int selected_index in SelectedIndices)
1246 items [selected_index].Invalidate ();
1249 const int text_padding = 15;
1251 internal Size GetChildColumnSize (int index)
1253 Size ret_size = Size.Empty;
1254 ColumnHeader col = this.columns [index];
1256 if (col.Width == -2) { // autosize = max(items, columnheader)
1257 Size size = Size.Ceiling (TextRenderer.MeasureString
1258 (col.Text, this.Font));
1259 size.Width += text_padding;
1260 ret_size = BiggestItem (index);
1261 if (size.Width > ret_size.Width)
1264 else { // -1 and all the values < -2 are put under one category
1265 ret_size = BiggestItem (index);
1266 // fall back to empty columns' width if no subitem is available for a column
1267 if (ret_size.IsEmpty) {
1268 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
1269 if (col.Text.Length > 0)
1270 ret_size.Height = Size.Ceiling (TextRenderer.MeasureString
1271 (col.Text, this.Font)).Height;
1273 ret_size.Height = this.Font.Height;
1277 ret_size.Height += text_padding;
1279 // adjust the size for icon and checkbox for 0th column
1281 ret_size.Width += (this.CheckBoxSize.Width + 4);
1282 if (this.small_image_list != null)
1283 ret_size.Width += this.small_image_list.ImageSize.Width;
1288 // Returns the size of biggest item text in a column
1289 // or the sum of the text and indent count if we are on 2.0
1290 private Size BiggestItem (int col)
1292 Size temp = Size.Empty;
1293 Size ret_size = Size.Empty;
1295 bool use_indent_count = small_image_list != null;
1297 // VirtualMode uses the first item text size
1298 if (virtual_mode && items.Count > 0) {
1299 ListViewItem item = items [0];
1300 ret_size = Size.Ceiling (TextRenderer.MeasureString (item.SubItems[col].Text,
1303 if (use_indent_count)
1304 ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width;
1307 // 0th column holds the item text, we check the size of
1308 // the various subitems falling in that column and get
1309 // the biggest one's size.
1310 foreach (ListViewItem item in items) {
1311 if (col >= item.SubItems.Count)
1314 temp = Size.Ceiling (TextRenderer.MeasureString
1315 (item.SubItems [col].Text, Font));
1318 if (use_indent_count)
1319 temp.Width += item.IndentCount * small_image_list.ImageSize.Width;
1322 if (temp.Width > ret_size.Width)
1329 // adjustment for space in Details view
1330 if (!ret_size.IsEmpty && view == View.Details)
1331 ret_size.Width += ThemeEngine.Current.ListViewItemPaddingWidth;
1336 const int max_wrap_padding = 30;
1338 // Sets the size of the biggest item text as per the view
1339 private void CalcTextSize ()
1341 // clear the old value
1342 text_size = Size.Empty;
1344 if (items.Count == 0)
1347 text_size = BiggestItem (0);
1349 if (view == View.LargeIcon && this.label_wrap) {
1350 Size temp = Size.Empty;
1351 if (this.check_boxes)
1352 temp.Width += 2 * this.CheckBoxSize.Width;
1353 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1354 temp.Width += icon_w + max_wrap_padding;
1355 // wrapping is done for two lines only
1356 if (text_size.Width > temp.Width) {
1357 text_size.Width = temp.Width;
1358 text_size.Height *= 2;
1361 else if (view == View.List) {
1362 // in list view max text shown in determined by the
1363 // control width, even if scolling is enabled.
1364 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
1365 if (this.small_image_list != null)
1366 max_wd -= this.small_image_list.ImageSize.Width;
1368 if (text_size.Width > max_wd)
1369 text_size.Width = max_wd;
1372 // we do the default settings, if we have got 0's
1373 if (text_size.Height <= 0)
1374 text_size.Height = this.Font.Height;
1375 if (text_size.Width <= 0)
1376 text_size.Width = this.Width;
1378 // little adjustment
1379 text_size.Width += 2;
1380 text_size.Height += 2;
1383 private void SetScrollValue (ScrollBar scrollbar, int val)
1386 if (scrollbar == h_scroll)
1387 max = h_scroll.Maximum - h_scroll.LargeChange + 1;
1389 max = v_scroll.Maximum - v_scroll.LargeChange + 1;
1393 else if (val < scrollbar.Minimum)
1394 val = scrollbar.Minimum;
1396 scrollbar.Value = val;
1399 private void Scroll (ScrollBar scrollbar, int delta)
1401 if (delta == 0 || !scrollbar.Visible)
1404 SetScrollValue (scrollbar, scrollbar.Value + delta);
1407 private void CalculateScrollBars ()
1409 Rectangle client_area = ClientRectangle;
1410 int height = client_area.Height;
1411 int width = client_area.Width;
1415 h_scroll.Visible = false;
1416 v_scroll.Visible = false;
1417 item_control.Size = new Size (width, height);
1418 header_control.Width = width;
1422 // Don't calculate if the view is not displayable
1423 if (client_area.Height < 0 || client_area.Width < 0)
1426 // making a scroll bar visible might make
1427 // other scroll bar visible
1428 if (layout_wd > client_area.Right) {
1429 h_scroll.Visible = true;
1430 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1431 v_scroll.Visible = true;
1433 v_scroll.Visible = false;
1434 } else if (layout_ht > client_area.Bottom) {
1435 v_scroll.Visible = true;
1436 if ((layout_wd + v_scroll.Width) > client_area.Right)
1437 h_scroll.Visible = true;
1439 h_scroll.Visible = false;
1441 h_scroll.Visible = false;
1442 v_scroll.Visible = false;
1446 item_size = ItemSize;
1448 if (h_scroll.is_visible) {
1449 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1450 h_scroll.Minimum = 0;
1452 // if v_scroll is visible, adjust the maximum of the
1453 // h_scroll to account for the width of v_scroll
1454 if (v_scroll.Visible) {
1455 h_scroll.Maximum = layout_wd + v_scroll.Width;
1456 h_scroll.Width = client_area.Width - v_scroll.Width;
1459 h_scroll.Maximum = layout_wd;
1460 h_scroll.Width = client_area.Width;
1463 if (view == View.List)
1464 h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing;
1466 h_scroll.SmallChange = Font.Height;
1468 h_scroll.LargeChange = client_area.Width;
1469 height -= h_scroll.Height;
1472 if (v_scroll.is_visible) {
1473 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1474 v_scroll.Minimum = 0;
1476 // if h_scroll is visible, adjust the height of
1477 // v_scroll to account for the height of h_scroll
1478 if (h_scroll.Visible) {
1479 v_scroll.Maximum = layout_ht + h_scroll.Height;
1480 v_scroll.Height = client_area.Height - h_scroll.Height;
1482 v_scroll.Maximum = layout_ht;
1483 v_scroll.Height = client_area.Height;
1486 if (view == View.Details) {
1487 // Need to update Maximum if using LargeChange with value other than the visible area
1488 v_scroll.LargeChange = v_scroll.Height - (header_control.Height + item_size.Height);
1489 v_scroll.Maximum -= header_control.Height + item_size.Height;
1491 v_scroll.LargeChange = v_scroll.Height;
1493 v_scroll.SmallChange = item_size.Height;
1494 width -= v_scroll.Width;
1497 item_control.Size = new Size (width, height);
1499 if (header_control.is_visible)
1500 header_control.Width = width;
1504 internal int GetReorderedColumnIndex (ColumnHeader column)
1506 if (reordered_column_indices == null)
1507 return column.Index;
1509 for (int i = 0; i < Columns.Count; i++)
1510 if (reordered_column_indices [i] == column.Index)
1517 internal ColumnHeader GetReorderedColumn (int index)
1519 if (reordered_column_indices == null)
1520 return Columns [index];
1522 return Columns [reordered_column_indices [index]];
1525 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1529 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1531 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1535 header_control.Invalidate ();
1536 item_control.Invalidate ();
1542 int column_count = Columns.Count;
1544 if (reordered_column_indices == null) {
1545 reordered_column_indices = new int [column_count];
1546 for (int i = 0; i < column_count; i++)
1547 reordered_column_indices [i] = i;
1550 if (reordered_column_indices [index] == col.Index)
1553 int[] curr = reordered_column_indices;
1554 int [] result = new int [column_count];
1556 for (int i = 0; i < column_count; i++) {
1557 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1561 result [i] = col.Index;
1563 result [i] = curr [curr_idx++];
1566 ReorderColumns (result, true);
1569 internal void ReorderColumns (int [] display_indices, bool redraw)
1571 reordered_column_indices = display_indices;
1572 for (int i = 0; i < Columns.Count; i++) {
1573 ColumnHeader col = Columns [i];
1574 col.InternalDisplayIndex = reordered_column_indices [i];
1576 if (redraw && view == View.Details && IsHandleCreated) {
1578 header_control.Invalidate ();
1579 item_control.Invalidate ();
1583 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1585 int column_count = Columns.Count;
1586 newCol.SetListView (this);
1588 int [] display_indices = new int [column_count];
1589 for (int i = 0; i < column_count; i++) {
1590 ColumnHeader col = Columns [i];
1592 display_indices [i] = index;
1594 int display_index = col.InternalDisplayIndex;
1595 if (display_index < index) {
1596 display_indices [i] = display_index;
1598 display_indices [i] = (display_index + 1);
1603 ReorderColumns (display_indices, redraw);
1607 Size LargeIconItemSize
1610 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1611 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1612 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1613 int w = Math.Max (text_size.Width, image_w);
1616 w += 2 + CheckBoxSize.Width;
1618 return new Size (w, h);
1622 Size SmallIconItemSize {
1624 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1625 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1626 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1627 int w = text_size.Width + image_w;
1630 w += 2 + CheckBoxSize.Width;
1632 return new Size (w, h);
1639 // Calculate tile size if needed
1640 // It appears that using Font.Size instead of a SizeF value can give us
1641 // a slightly better approach to the proportions defined in .Net
1642 if (tile_size == Size.Empty) {
1643 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1644 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1645 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1646 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1648 tile_size = new Size (w, h);
1656 int GetDetailsItemHeight ()
1659 int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1660 int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1661 item_height = Math.Max (checkbox_height, text_size.Height);
1662 item_height = Math.Max (item_height, small_image_height);
1666 void SetItemLocation (int index, int x, int y, int row, int col)
1668 Point old_location = items_location [index];
1669 if (old_location.X == x && old_location.Y == y)
1672 items_location [index] = new Point (x, y);
1673 items_matrix_location [index] = new ItemMatrixLocation (row, col);
1676 // Initial position matches item's position in ListViewItemCollection
1678 reordered_items_indices [index] = index;
1682 void ShiftItemsPositions (int from, int to, bool forward)
1685 for (int i = to + 1; i > from; i--) {
1686 reordered_items_indices [i] = reordered_items_indices [i - 1];
1688 ListViewItem item = items [reordered_items_indices [i]];
1690 item.DisplayIndex = i;
1694 for (int i = from - 1; i < to; i++) {
1695 reordered_items_indices [i] = reordered_items_indices [i + 1];
1697 ListViewItem item = items [reordered_items_indices [i]];
1699 item.DisplayIndex = i;
1705 internal void ChangeItemLocation (int display_index, Point new_pos)
1707 int new_display_index = GetDisplayIndexFromLocation (new_pos);
1708 if (new_display_index == display_index)
1711 int item_index = reordered_items_indices [display_index];
1712 ListViewItem item = items [item_index];
1714 bool forward = new_display_index < display_index;
1715 int index_from, index_to;
1717 index_from = new_display_index;
1718 index_to = display_index - 1;
1720 index_from = display_index + 1;
1721 index_to = new_display_index;
1724 ShiftItemsPositions (index_from, index_to, forward);
1726 reordered_items_indices [new_display_index] = item_index;
1729 item.DisplayIndex = new_display_index;
1733 int GetDisplayIndexFromLocation (Point loc)
1735 int display_index = -1;
1736 Rectangle item_area;
1739 if (loc.X < 0 || loc.Y < 0)
1742 // Adjustment to put in the next position refered by 'loc'
1743 loc.X -= item_size.Width / 2;
1747 for (int i = 0; i < items.Count; i++) {
1748 item_area = new Rectangle (GetItemLocation (i), item_size);
1749 item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing,
1750 ThemeEngine.Current.ListViewVerticalSpacing);
1752 if (item_area.Contains (loc)) {
1758 // Put in in last position
1759 if (display_index == -1)
1760 display_index = items.Count - 1;
1762 return display_index;
1765 // When using groups, the items with no group assigned
1766 // belong to the DefaultGroup
1767 int GetDefaultGroupItems ()
1770 foreach (ListViewItem item in items)
1771 if (item.Group == null)
1779 // cache the spacing to let virtualmode compute the positions on the fly
1785 int[,] item_index_matrix;
1787 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1789 Rectangle area = ClientRectangle;
1791 if (UseCustomColumnWidth)
1792 CalculateCustomColumnWidth ();
1795 // When groups are used the alignment is always top-aligned
1800 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1801 for (int i = 0; i < groups.InternalCount; i++) {
1802 ListViewGroup group = groups.GetInternalGroup (i);
1803 int items_in_group = group.GetActualItemCount ();
1805 if (items_in_group == 0)
1808 int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1809 if (group_cols <= 0)
1811 int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols);
1813 group.starting_row = rows;
1814 group.rows = group_rows;
1815 group.starting_item = items;
1816 group.current_item = 0; // Reset layout
1818 cols = Math.Max (group_cols, cols);
1820 items += items_in_group;
1825 // Simple matrix if no groups are used
1827 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1830 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1832 if (UseCustomColumnWidth)
1833 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width));
1835 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1840 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1844 item_index_matrix = new int [rows, cols];
1847 // When using custom column width, we look for the minimum one
1848 void CalculateCustomColumnWidth ()
1850 int min_width = Int32.MaxValue;
1851 for (int i = 0; i < columns.Count; i++) {
1852 int col_width = columns [i].Width;
1854 if (col_width < min_width)
1855 min_width = col_width;
1858 custom_column_width = min_width;
1861 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1863 header_control.Visible = false;
1864 header_control.Size = Size.Empty;
1865 item_control.Visible = true;
1866 item_control.Location = Point.Empty;
1867 ItemSize = item_size; // Cache item size
1869 this.x_spacing = x_spacing;
1870 this.y_spacing = y_spacing;
1873 if (items.Count == 0)
1876 Size sz = item_size;
1878 CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing);
1880 layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing;
1881 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1884 if (virtual_mode) { // no actual assignment is needed on items for virtual mode
1885 item_control.Size = new Size (layout_wd, layout_ht);
1889 bool using_groups = UsingGroups;
1890 if (using_groups) // the groups layout will override layout_ht
1891 CalculateGroupsLayout (sz, y_spacing, 0);
1894 int row = 0, col = 0;
1896 int display_index = 0;
1898 for (int i = 0; i < items.Count; i++) {
1899 ListViewItem item = items [i];
1902 ListViewGroup group = item.Group;
1904 group = groups.DefaultGroup;
1906 Point group_items_loc = group.items_area_location;
1907 int current_item = group.current_item++;
1908 int starting_row = group.starting_row;
1910 display_index = group.starting_item + current_item;
1911 row = (current_item / cols);
1912 col = current_item % cols;
1914 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1915 y = row * (item_size.Height + y_spacing) + group_items_loc.Y;
1917 SetItemLocation (display_index, x, y, row + starting_row, col);
1918 SetItemAtDisplayIndex (display_index, i);
1919 item_index_matrix [row + starting_row, col] = i;
1924 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1925 y = row * (item_size.Height + y_spacing);
1926 display_index = i; // Same as item index in Items
1928 SetItemLocation (i, x, y, row, col);
1929 item_index_matrix [row, col] = i;
1938 if (++col == cols) {
1946 item.DisplayIndex = display_index;
1948 item.SetPosition (new Point (x, y));
1952 item_control.Size = new Size (layout_wd, layout_ht);
1956 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin)
1959 bool details = view == View.Details;
1961 for (int i = 0; i < groups.InternalCount; i++) {
1962 ListViewGroup group = groups.GetInternalGroup (i);
1963 if (group.ItemCount == 0)
1966 y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows);
1969 layout_ht = y; // Update height taking into account Groups' headers heights
1972 int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows)
1974 Rectangle client_area = ClientRectangle;
1975 int header_height = Font.Height + 15; // one line height + some padding
1977 group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height);
1978 group.items_area_location = new Point (0, y_origin + header_height);
1980 int items_area_height = ((item_height + y_spacing) * rows);
1981 return header_height + items_area_height + 10; // Add a small bottom margin
1984 void CalculateDetailsGroupItemsCount ()
1988 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1989 for (int i = 0; i < groups.InternalCount; i++) {
1990 ListViewGroup group = groups.GetInternalGroup (i);
1991 int items_in_group = group.GetActualItemCount ();
1993 if (items_in_group == 0)
1996 group.starting_item = items;
1997 group.current_item = 0; // Reset layout.
1998 items += items_in_group;
2003 void LayoutHeader ()
2006 for (int i = 0; i < Columns.Count; i++) {
2007 ColumnHeader col = GetReorderedColumn (i);
2010 col.CalcColumnHeader ();
2016 if (x < ClientRectangle.Width)
2017 x = ClientRectangle.Width;
2019 if (header_style == ColumnHeaderStyle.None) {
2020 header_control.Visible = false;
2021 header_control.Size = Size.Empty;
2022 layout_wd = ClientRectangle.Width;
2024 header_control.Width = x;
2025 header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font);
2026 header_control.Visible = true;
2030 void LayoutDetails ()
2034 if (columns.Count == 0) {
2035 item_control.Visible = false;
2036 layout_wd = ClientRectangle.Width;
2037 layout_ht = ClientRectangle.Height;
2041 item_control.Visible = true;
2042 item_control.Location = Point.Empty;
2043 item_control.Width = ClientRectangle.Width;
2045 int item_height = GetDetailsItemHeight ();
2046 ItemSize = new Size (0, item_height); // We only cache Height for details view
2047 int y = header_control.Height;
2048 layout_ht = y + (item_height * items.Count);
2049 if (items.Count > 0 && grid_lines) // some space for bottom gridline
2053 bool using_groups = UsingGroups;
2055 // Observe that this routines will override our layout_ht value
2056 CalculateDetailsGroupItemsCount ();
2057 CalculateGroupsLayout (ItemSize, 2, y);
2060 if (virtual_mode) // no assgination on items is needed
2064 for (int i = 0; i < items.Count; i++) {
2065 ListViewItem item = items [i];
2072 ListViewGroup group = item.Group;
2074 group = groups.DefaultGroup;
2076 int current_item = group.current_item++;
2077 Point group_items_loc = group.items_area_location;
2078 display_index = group.starting_item + current_item;
2080 y = item_y = current_item * (item_height + 2) + group_items_loc.Y;
2081 SetItemLocation (display_index, 0, item_y, 0, 0);
2082 SetItemAtDisplayIndex (display_index, i);
2088 SetItemLocation (i, 0, item_y, 0, 0);
2093 item.DisplayIndex = display_index;
2095 item.SetPosition (new Point (0, item_y));
2100 private void AdjustItemsPositionArray (int count)
2103 // In virtual mode we compute the positions on the fly.
2107 if (items_location.Length >= count)
2110 // items_location, items_matrix_location and reordered_items_indices must keep the same length
2111 count = Math.Max (count, items_location.Length * 2);
2112 items_location = new Point [count];
2113 items_matrix_location = new ItemMatrixLocation [count];
2114 reordered_items_indices = new int [count];
2117 private void CalculateListView (ListViewAlignment align)
2121 AdjustItemsPositionArray (items.Count);
2128 case View.SmallIcon:
2129 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
2130 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2133 case View.LargeIcon:
2134 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
2135 ThemeEngine.Current.ListViewHorizontalSpacing,
2136 ThemeEngine.Current.ListViewVerticalSpacing);
2140 LayoutIcons (SmallIconItemSize, true,
2141 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2145 if (!Application.VisualStylesEnabled)
2146 goto case View.LargeIcon;
2148 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
2149 ThemeEngine.Current.ListViewHorizontalSpacing,
2150 ThemeEngine.Current.ListViewVerticalSpacing);
2155 CalculateScrollBars ();
2158 internal Point GetItemLocation (int index)
2160 Point loc = Point.Empty;
2163 loc = GetFixedItemLocation (index);
2166 loc = items_location [index];
2168 loc.X -= h_marker; // Adjust to scroll
2175 Point GetFixedItemLocation (int index)
2177 Point loc = Point.Empty;
2180 case View.LargeIcon:
2181 case View.SmallIcon:
2182 loc.X = index % cols * (item_size.Width + x_spacing);
2183 loc.Y = index / cols * (item_size.Height + y_spacing);
2186 loc.X = index / rows * (item_size.Width + x_spacing);
2187 loc.Y = index % rows * (item_size.Height + y_spacing);
2190 loc.Y = header_control.Height + (index * item_size.Height);
2198 internal int GetItemIndex (int display_index)
2202 return display_index; // no reordering in virtual mode.
2204 return reordered_items_indices [display_index];
2207 internal ListViewItem GetItemAtDisplayIndex (int display_index)
2210 // in virtual mode there's no reordering at all.
2212 return items [display_index];
2214 return items [reordered_items_indices [display_index]];
2217 internal void SetItemAtDisplayIndex (int display_index, int index)
2219 reordered_items_indices [display_index] = index;
2222 private bool KeySearchString (KeyEventArgs ke)
2224 int current_tickcnt = Environment.TickCount;
2225 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2226 keysearch_text = string.Empty;
2229 if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2232 keysearch_text += (char)ke.KeyCode;
2233 keysearch_tickcnt = current_tickcnt;
2235 int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex;
2236 int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0;
2238 ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true);
2239 if (item != null && prev_focused != item.DisplayIndex) {
2240 selected_indices.Clear ();
2242 SetFocusedItem (item.DisplayIndex);
2243 item.Selected = true;
2244 EnsureVisible (GetItemIndex (item.DisplayIndex));
2250 private void OnItemsChanged ()
2252 ResetSearchString ();
2255 private void ResetSearchString ()
2257 keysearch_text = String.Empty;
2260 int GetAdjustedIndex (Keys key)
2264 if (View == View.Details) {
2267 result = FocusedItem.DisplayIndex - 1;
2270 result = FocusedItem.DisplayIndex + 1;
2271 if (result == items.Count)
2275 int last_index = LastVisibleIndex;
2276 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2277 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2279 if (FocusedItem.DisplayIndex == last_index) {
2280 if (FocusedItem.DisplayIndex < Items.Count - 1) {
2281 int page_size = item_control.Height / ItemSize.Height - 1;
2282 result = FocusedItem.DisplayIndex + page_size - 1;
2283 if (result >= Items.Count)
2284 result = Items.Count - 1;
2287 result = last_index;
2290 int first_index = FirstVisibleIndex;
2291 if (GetItemLocation (first_index).Y < 0)
2293 if (FocusedItem.DisplayIndex == first_index) {
2294 if (first_index > 0) {
2295 int page_size = item_control.Height / ItemSize.Height - 1;
2296 result = first_index - page_size + 1;
2301 result = first_index;
2309 return GetFixedAdjustedIndex (key);
2312 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex];
2313 int row = item_matrix_location.Row;
2314 int col = item_matrix_location.Col;
2316 int adjusted_index = -1;
2322 adjusted_index = item_index_matrix [row, col - 1];
2326 if (col == (cols - 1))
2328 while (item_index_matrix [row, col + 1] == 0) {
2333 adjusted_index = item_index_matrix [row, col + 1];
2339 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2344 adjusted_index = item_index_matrix [row - 1, col];
2348 if (row == (rows - 1) || row == Items.Count - 1)
2350 while (item_index_matrix [row + 1, col] == 0) {
2355 adjusted_index = item_index_matrix [row + 1, col];
2362 return items [adjusted_index].DisplayIndex;
2366 // Used for virtual mode, where items *cannot* be re-arranged
2367 int GetFixedAdjustedIndex (Keys key)
2373 if (view == View.List)
2374 result = focused_item_index - rows;
2376 result = focused_item_index - 1;
2379 if (view == View.List)
2380 result = focused_item_index + rows;
2382 result = focused_item_index + 1;
2385 if (view != View.List)
2386 result = focused_item_index - cols;
2388 result = focused_item_index - 1;
2391 if (view != View.List)
2392 result = focused_item_index + cols;
2394 result = focused_item_index + 1;
2401 if (result < 0 || result >= items.Count)
2402 result = focused_item_index;
2408 ListViewItem selection_start;
2410 private bool SelectItems (ArrayList sel_items)
2412 bool changed = false;
2413 foreach (ListViewItem item in SelectedItems)
2414 if (!sel_items.Contains (item)) {
2415 item.Selected = false;
2418 foreach (ListViewItem item in sel_items)
2419 if (!item.Selected) {
2420 item.Selected = true;
2426 private void UpdateMultiSelection (int index, bool reselect)
2428 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2429 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2430 ListViewItem item = GetItemAtDisplayIndex (index);
2432 if (shift_pressed && selection_start != null) {
2433 ArrayList list = new ArrayList ();
2434 int start_index = selection_start.DisplayIndex;
2435 int start = Math.Min (start_index, index);
2436 int end = Math.Max (start_index, index);
2437 if (View == View.Details) {
2438 for (int i = start; i <= end; i++)
2439 list.Add (GetItemAtDisplayIndex (i));
2441 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2442 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2443 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2444 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2445 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2446 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2448 for (int i = 0; i < items.Count; i++) {
2449 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2451 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2452 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2453 list.Add (GetItemAtDisplayIndex (i));
2457 } else if (ctrl_pressed) {
2458 item.Selected = !item.Selected;
2459 selection_start = item;
2462 // do not unselect, and reselect the item
2463 foreach (int itemIndex in SelectedIndices) {
2464 if (index == itemIndex)
2466 items [itemIndex].Selected = false;
2469 SelectedItems.Clear ();
2470 item.Selected = true;
2472 selection_start = item;
2476 internal override bool InternalPreProcessMessage (ref Message msg)
2478 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2479 Keys key_data = (Keys)msg.WParam.ToInt32();
2481 HandleNavKeys (key_data);
2484 return base.InternalPreProcessMessage (ref msg);
2487 bool HandleNavKeys (Keys key_data)
2489 if (Items.Count == 0 || !item_control.Visible)
2492 if (FocusedItem == null)
2497 SelectIndex (Items.Count - 1);
2510 SelectIndex (GetAdjustedIndex (key_data));
2514 SelectIndex (focused_item_index);
2515 ToggleItemsCheckState ();
2518 if (selected_indices.Count > 0)
2519 OnItemActivate (EventArgs.Empty);
2529 void ToggleItemsCheckState ()
2534 // Don't modify check state if StateImageList has less than 2 elements
2535 if (StateImageList != null && StateImageList.Images.Count < 2)
2538 if (SelectedIndices.Count > 0) {
2539 for (int i = 0; i < SelectedIndices.Count; i++) {
2540 ListViewItem item = Items [SelectedIndices [i]];
2541 item.Checked = !item.Checked;
2546 if (FocusedItem != null) {
2547 FocusedItem.Checked = !FocusedItem.Checked;
2548 SelectIndex (FocusedItem.Index);
2552 void SelectIndex (int display_index)
2554 if (display_index == -1)
2558 UpdateMultiSelection (display_index, true);
2559 else if (!GetItemAtDisplayIndex (display_index).Selected)
2560 GetItemAtDisplayIndex (display_index).Selected = true;
2562 SetFocusedItem (display_index);
2563 EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index
2566 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2568 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2571 if (ke.Alt || ke.Control)
2574 ke.Handled = KeySearchString (ke);
2577 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2579 Point loc = PointToClient (Control.MousePosition);
2580 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2583 internal class ItemControl : Control {
2586 ListViewItem clicked_item;
2587 ListViewItem last_clicked_item;
2588 bool hover_processed = false;
2589 bool checking = false;
2590 ListViewItem prev_hovered_item;
2592 ListViewItem prev_tooltip_item;
2595 Point drag_begin = new Point (-1, -1);
2596 internal int dragged_item_index = -1;
2598 ListViewLabelEditTextBox edit_text_box;
2599 internal ListViewItem edit_item;
2600 LabelEditEventArgs edit_args;
2602 public ItemControl (ListView owner)
2605 this.SetStyle (ControlStyles.DoubleBuffer, true);
2606 DoubleClick += new EventHandler(ItemsDoubleClick);
2607 MouseDown += new MouseEventHandler(ItemsMouseDown);
2608 MouseMove += new MouseEventHandler(ItemsMouseMove);
2609 MouseHover += new EventHandler(ItemsMouseHover);
2610 MouseUp += new MouseEventHandler(ItemsMouseUp);
2613 void ItemsDoubleClick (object sender, EventArgs e)
2615 if (owner.activation == ItemActivation.Standard)
2616 owner.OnItemActivate (EventArgs.Empty);
2626 BoxSelect box_select_mode = BoxSelect.None;
2627 IList prev_selection;
2628 Point box_select_start;
2630 Rectangle box_select_rect;
2631 internal Rectangle BoxSelectRectangle {
2632 get { return box_select_rect; }
2634 if (box_select_rect == value)
2637 InvalidateBoxSelectRect ();
2638 box_select_rect = value;
2639 InvalidateBoxSelectRect ();
2643 void InvalidateBoxSelectRect ()
2645 if (BoxSelectRectangle.Size.IsEmpty)
2648 Rectangle edge = BoxSelectRectangle;
2654 edge.Y = BoxSelectRectangle.Bottom - 1;
2656 edge.Y = BoxSelectRectangle.Y - 1;
2658 edge.Height = BoxSelectRectangle.Height + 2;
2660 edge.X = BoxSelectRectangle.Right - 1;
2664 private Rectangle CalculateBoxSelectRectangle (Point pt)
2666 int left = Math.Min (box_select_start.X, pt.X);
2667 int right = Math.Max (box_select_start.X, pt.X);
2668 int top = Math.Min (box_select_start.Y, pt.Y);
2669 int bottom = Math.Max (box_select_start.Y, pt.Y);
2670 return Rectangle.FromLTRB (left, top, right, bottom);
2673 bool BoxIntersectsItem (int index)
2675 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2676 if (owner.View != View.Details) {
2678 r.Y += r.Height / 4;
2682 return BoxSelectRectangle.IntersectsWith (r);
2685 bool BoxIntersectsText (int index)
2687 Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds;
2688 return BoxSelectRectangle.IntersectsWith (r);
2691 ArrayList BoxSelectedItems {
2693 ArrayList result = new ArrayList ();
2694 for (int i = 0; i < owner.Items.Count; i++) {
2697 // Can't iterate over specific items properties in virtualmode
2698 if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode)
2700 if (owner.View == View.Details && !owner.FullRowSelect)
2702 intersects = BoxIntersectsText (i);
2704 intersects = BoxIntersectsItem (i);
2707 result.Add (owner.GetItemAtDisplayIndex (i));
2713 private bool PerformBoxSelection (Point pt)
2715 if (box_select_mode == BoxSelect.None)
2718 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2720 ArrayList box_items = BoxSelectedItems;
2724 switch (box_select_mode) {
2726 case BoxSelect.Normal:
2730 case BoxSelect.Control:
2731 items = new ArrayList ();
2732 foreach (int index in prev_selection)
2733 if (!box_items.Contains (owner.Items [index]))
2734 items.Add (owner.Items [index]);
2735 foreach (ListViewItem item in box_items)
2736 if (!prev_selection.Contains (item.Index))
2740 case BoxSelect.Shift:
2742 foreach (ListViewItem item in box_items)
2743 prev_selection.Remove (item.Index);
2744 foreach (int index in prev_selection)
2745 items.Add (owner.Items [index]);
2749 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2753 owner.SelectItems (items);
2759 private void ItemsMouseDown (object sender, MouseEventArgs me)
2761 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2762 if (owner.items.Count == 0)
2765 bool box_selecting = false;
2766 Size item_size = owner.ItemSize;
2767 Point pt = new Point (me.X, me.Y);
2768 for (int i = 0; i < owner.items.Count; i++) {
2769 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2770 if (!item_rect.Contains (pt))
2773 // Actual item in 'i' position
2774 ListViewItem item = owner.GetItemAtDisplayIndex (i);
2776 if (item.CheckRectReal.Contains (pt)) {
2777 // Don't modify check state if we have only one image
2778 // and if we are in 1.1 profile only take into account
2780 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2787 // Generate an extra ItemCheck event when we got two clicks
2788 // (Match weird .Net behaviour)
2790 item.Checked = !item.Checked;
2792 item.Checked = !item.Checked;
2797 if (owner.View == View.Details) {
2798 bool over_text = item.TextBounds.Contains (pt);
2799 if (owner.FullRowSelect) {
2800 clicked_item = item;
2801 bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2802 if (!over_text && over_item_column && owner.MultiSelect)
2803 box_selecting = true;
2804 } else if (over_text)
2805 clicked_item = item;
2807 owner.SetFocusedItem (i);
2809 clicked_item = item;
2815 if (clicked_item != null) {
2816 bool changed = !clicked_item.Selected;
2817 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2818 owner.SetFocusedItem (clicked_item.DisplayIndex);
2820 if (owner.MultiSelect) {
2821 bool reselect = (!owner.LabelEdit || changed);
2822 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2823 owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect);
2825 clicked_item.Selected = true;
2829 if (owner.VirtualMode && changed) {
2830 // Broken event - It's not fired from Item.Selected also
2831 ListViewVirtualItemsSelectionRangeChangedEventArgs args =
2832 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2834 owner.OnVirtualItemsSelectionRangeChanged (args);
2837 // Report clicks only if the item was clicked. On MS the
2838 // clicks are only raised if you click an item
2840 if (me.Clicks > 1) {
2841 if (owner.CheckBoxes)
2842 clicked_item.Checked = !clicked_item.Checked;
2843 } else if (me.Clicks == 1) {
2844 if (owner.LabelEdit && !changed)
2845 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2848 drag_begin = me.Location;
2849 dragged_item_index = clicked_item.Index;
2851 if (owner.MultiSelect)
2852 box_selecting = true;
2853 else if (owner.SelectedItems.Count > 0)
2854 owner.SelectedItems.Clear ();
2857 if (box_selecting) {
2858 Keys mods = XplatUI.State.ModifierKeys;
2859 if ((mods & Keys.Shift) != 0)
2860 box_select_mode = BoxSelect.Shift;
2861 else if ((mods & Keys.Control) != 0)
2862 box_select_mode = BoxSelect.Control;
2864 box_select_mode = BoxSelect.Normal;
2865 box_select_start = pt;
2866 prev_selection = owner.SelectedIndices.List.Clone () as IList;
2870 private void ItemsMouseMove (object sender, MouseEventArgs me)
2872 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2874 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2878 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2879 !hover_processed && owner.Activation != ItemActivation.OneClick
2881 && !owner.ShowItemToolTips
2886 Point pt = PointToClient (Control.MousePosition);
2887 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2889 if (hover_processed && item != null && item != prev_hovered_item) {
2890 hover_processed = false;
2891 XplatUI.ResetMouseHover (Handle);
2894 // Need to invalidate the item in HotTracking to show/hide the underline style
2895 if (owner.Activation == ItemActivation.OneClick) {
2896 if (item == null && owner.HotItemIndex != -1) {
2898 if (owner.HotTracking)
2899 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2902 Cursor = Cursors.Default;
2903 owner.HotItemIndex = -1;
2904 } else if (item != null && owner.HotItemIndex == -1) {
2906 if (owner.HotTracking)
2907 Invalidate (item.Bounds);
2910 Cursor = Cursors.Hand;
2911 owner.HotItemIndex = item.Index;
2915 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2916 if (drag_begin != new Point (-1, -1)) {
2917 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2918 if (!r.Contains (me.X, me.Y)) {
2919 ListViewItem dragged_item = owner.items [dragged_item_index];
2920 owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2922 drag_begin = new Point (-1, -1);
2923 dragged_item_index = -1;
2929 if (owner.ShowItemToolTips) {
2931 owner.item_tooltip.Active = false;
2932 prev_tooltip_item = null;
2933 } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2934 owner.item_tooltip.Active = true;
2935 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2936 prev_tooltip_item = item;
2943 private void ItemsMouseHover (object sender, EventArgs e)
2945 if (owner.hover_pending) {
2946 owner.OnMouseHover (e);
2947 owner.hover_pending = false;
2953 hover_processed = true;
2954 Point pt = PointToClient (Control.MousePosition);
2955 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2959 prev_hovered_item = item;
2961 if (owner.HoverSelection) {
2962 if (owner.MultiSelect)
2963 owner.UpdateMultiSelection (item.Index, true);
2965 item.Selected = true;
2967 owner.SetFocusedItem (item.DisplayIndex);
2968 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2972 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2976 void HandleClicks (MouseEventArgs me)
2978 // if the click is not on an item,
2979 // clicks remains as 0
2982 owner.OnDoubleClick (EventArgs.Empty);
2983 } else if (clicks == 1) {
2984 owner.OnClick (EventArgs.Empty);
2986 owner.OnDoubleClick (EventArgs.Empty);
2987 owner.OnMouseDoubleClick (me);
2988 } else if (clicks == 1) {
2989 owner.OnClick (EventArgs.Empty);
2990 owner.OnMouseClick (me);
2997 private void ItemsMouseUp (object sender, MouseEventArgs me)
2999 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
3000 HandleClicks (owner_me);
3003 if (owner.Items.Count == 0) {
3005 owner.OnMouseUp (owner_me);
3009 Point pt = new Point (me.X, me.Y);
3011 Rectangle rect = Rectangle.Empty;
3012 if (clicked_item != null) {
3013 if (owner.view == View.Details && !owner.full_row_select)
3014 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
3016 rect = clicked_item.Bounds;
3018 if (rect.Contains (pt)) {
3019 switch (owner.activation) {
3020 case ItemActivation.OneClick:
3021 owner.OnItemActivate (EventArgs.Empty);
3024 case ItemActivation.TwoClick:
3025 if (last_clicked_item == clicked_item) {
3026 owner.OnItemActivate (EventArgs.Empty);
3027 last_clicked_item = null;
3029 last_clicked_item = clicked_item;
3032 // DoubleClick activation is handled in another handler
3036 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
3037 // Need this to clean up background clicks
3038 owner.SelectedItems.Clear ();
3042 owner.OnMouseUp (owner_me);
3045 private void ResetMouseState ()
3047 clicked_item = null;
3048 box_select_start = Point.Empty;
3049 BoxSelectRectangle = Rectangle.Empty;
3050 prev_selection = null;
3051 box_select_mode = BoxSelect.None;
3054 // Clean these bits in case the mouse buttons were
3055 // released before firing ItemDrag
3056 dragged_item_index = -1;
3057 drag_begin = new Point (-1, -1);
3060 private void LabelEditFinished (object sender, EventArgs e)
3062 EndEdit (edit_item);
3065 private void LabelEditCancelled (object sender, EventArgs e)
3067 edit_args.SetLabel (null);
3068 EndEdit (edit_item);
3071 private void LabelTextChanged (object sender, EventArgs e)
3073 if (edit_args != null)
3074 edit_args.SetLabel (edit_text_box.Text);
3077 internal void BeginEdit (ListViewItem item)
3079 if (edit_item != null)
3080 EndEdit (edit_item);
3082 if (edit_text_box == null) {
3083 edit_text_box = new ListViewLabelEditTextBox ();
3084 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
3085 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
3086 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
3087 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
3088 edit_text_box.Visible = false;
3089 Controls.Add (edit_text_box);
3092 item.EnsureVisible();
3094 edit_text_box.Reset ();
3096 switch (owner.view) {
3098 case View.SmallIcon:
3100 edit_text_box.TextAlign = HorizontalAlignment.Left;
3101 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
3102 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
3103 edit_text_box.Width = (int)sizef.Width + 4;
3104 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
3105 edit_text_box.WordWrap = false;
3106 edit_text_box.Multiline = false;
3108 case View.LargeIcon:
3109 edit_text_box.TextAlign = HorizontalAlignment.Center;
3110 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
3111 sizef = TextRenderer.MeasureString (item.Text, item.Font);
3112 edit_text_box.Width = (int)sizef.Width + 4;
3113 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
3114 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
3115 edit_text_box.WordWrap = true;
3116 edit_text_box.Multiline = true;
3122 edit_text_box.Text = item.Text;
3123 edit_text_box.Font = item.Font;
3124 edit_text_box.Visible = true;
3125 edit_text_box.Focus ();
3126 edit_text_box.SelectAll ();
3128 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
3129 owner.OnBeforeLabelEdit (edit_args);
3131 if (edit_args.CancelEdit)
3135 internal void CancelEdit (ListViewItem item)
3137 // do nothing if there's no item being edited, or if the
3138 // item being edited is not the one passed in
3139 if (edit_item == null || edit_item != item)
3142 edit_args.SetLabel (null);
3146 internal void EndEdit (ListViewItem item)
3148 // do nothing if there's no item being edited, or if the
3149 // item being edited is not the one passed in
3150 if (edit_item == null || edit_item != item)
3153 if (edit_text_box != null) {
3154 if (edit_text_box.Visible)
3155 edit_text_box.Visible = false;
3156 // ensure listview gets focus
3160 // Same as TreeView.EndEdit: need to have focus in synch
3161 Application.DoEvents ();
3164 // Create a new instance, since we could get a call to BeginEdit
3165 // from the handler and have fields out of synch
3167 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
3170 owner.OnAfterLabelEdit (args);
3171 if (!args.CancelEdit && args.Label != null)
3172 item.Text = args.Label;
3175 internal override void OnPaintInternal (PaintEventArgs pe)
3177 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
3180 protected override void WndProc (ref Message m)
3182 switch ((Msg)m.Msg) {
3183 case Msg.WM_KILLFOCUS:
3184 owner.Select (false, true);
3186 case Msg.WM_SETFOCUS:
3187 owner.Select (false, true);
3189 case Msg.WM_LBUTTONDOWN:
3191 owner.Select (false, true);
3193 case Msg.WM_RBUTTONDOWN:
3195 owner.Select (false, true);
3200 base.WndProc (ref m);
3204 internal class ListViewLabelEditTextBox : TextBox
3209 int max_height = -1;
3210 int min_height = -1;
3212 int old_number_lines = 1;
3214 SizeF text_size_one_char;
3216 public ListViewLabelEditTextBox ()
3218 min_height = DefaultSize.Height;
3219 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3222 public int MaxWidth {
3224 if (value < min_width)
3225 max_width = min_width;
3231 public int MaxHeight {
3233 if (value < min_height)
3234 max_height = min_height;
3240 public new int Width {
3250 public override Font Font {
3256 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3260 protected override void OnTextChanged (EventArgs e)
3262 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3264 int new_width = (int)text_size.Width + 8;
3267 ResizeTextBoxWidth (new_width);
3269 if (Width != max_width)
3270 ResizeTextBoxWidth (new_width);
3272 int number_lines = Lines.Length;
3274 if (number_lines != old_number_lines) {
3275 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3276 old_number_lines = number_lines;
3278 ResizeTextBoxHeight (new_height);
3282 base.OnTextChanged (e);
3285 protected override bool IsInputKey (Keys key_data)
3287 if ((key_data & Keys.Alt) == 0) {
3288 switch (key_data & Keys.KeyCode) {
3295 return base.IsInputKey (key_data);
3298 protected override void OnKeyDown (KeyEventArgs e)
3303 switch (e.KeyCode) {
3307 OnEditingFinished (e);
3312 OnEditingCancelled (e);
3317 protected override void OnLostFocus (EventArgs e)
3320 OnEditingFinished (e);
3324 protected void OnEditingCancelled (EventArgs e)
3326 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3331 protected void OnEditingFinished (EventArgs e)
3333 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3338 private void ResizeTextBoxWidth (int new_width)
3340 if (new_width > max_width)
3341 base.Width = max_width;
3343 if (new_width >= min_width)
3344 base.Width = new_width;
3346 base.Width = min_width;
3349 private void ResizeTextBoxHeight (int new_height)
3351 if (new_height > max_height)
3352 base.Height = max_height;
3354 if (new_height >= min_height)
3355 base.Height = new_height;
3357 base.Height = min_height;
3360 public void Reset ()
3367 old_number_lines = 1;
3369 Text = String.Empty;
3374 static object EditingCancelledEvent = new object ();
3375 public event EventHandler EditingCancelled {
3376 add { Events.AddHandler (EditingCancelledEvent, value); }
3377 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3380 static object EditingFinishedEvent = new object ();
3381 public event EventHandler EditingFinished {
3382 add { Events.AddHandler (EditingFinishedEvent, value); }
3383 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3387 internal override void OnPaintInternal (PaintEventArgs pe)
3392 CalculateScrollBars ();
3395 void FocusChanged (object o, EventArgs args)
3397 if (Items.Count == 0)
3400 if (FocusedItem == null)
3403 ListViewItem focused_item = FocusedItem;
3405 if (focused_item.ListView != null) {
3406 focused_item.Invalidate ();
3407 focused_item.Layout ();
3408 focused_item.Invalidate ();
3412 private void ListView_Invalidated (object sender, InvalidateEventArgs e)
3414 // When the ListView is invalidated, we need to invalidate
3415 // the child controls.
3416 header_control.Invalidate ();
3417 item_control.Invalidate ();
3420 private void ListView_MouseEnter (object sender, EventArgs args)
3422 hover_pending = true; // Need a hover event for every Enter/Leave cycle
3425 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3427 if (Items.Count == 0)
3430 int lines = me.Delta / 120;
3437 case View.SmallIcon:
3438 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3440 case View.LargeIcon:
3441 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
3444 Scroll (h_scroll, -ItemSize.Width * lines);
3448 if (!Application.VisualStylesEnabled)
3449 goto case View.LargeIcon;
3451 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3457 private void ListView_SizeChanged (object sender, EventArgs e)
3462 private void SetFocusedItem (int display_index)
3464 if (display_index != -1)
3465 GetItemAtDisplayIndex (display_index).Focused = true;
3466 else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3467 GetItemAtDisplayIndex (focused_item_index).Focused = false;
3468 focused_item_index = display_index;
3470 if (display_index == -1)
3471 OnUIAFocusedItemChanged ();
3472 // otherwise the event will have been fired
3473 // when the ListViewItem's Focused was set
3477 private void HorizontalScroller (object sender, EventArgs e)
3479 item_control.EndEdit (item_control.edit_item);
3481 // Avoid unnecessary flickering, when button is
3482 // kept pressed at the end
3483 if (h_marker != h_scroll.Value) {
3485 int pixels = h_marker - h_scroll.Value;
3487 h_marker = h_scroll.Value;
3488 if (header_control.Visible)
3489 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3491 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3495 private void VerticalScroller (object sender, EventArgs e)
3497 item_control.EndEdit (item_control.edit_item);
3499 // Avoid unnecessary flickering, when button is
3500 // kept pressed at the end
3501 if (v_marker != v_scroll.Value) {
3502 int pixels = v_marker - v_scroll.Value;
3503 Rectangle area = item_control.ClientRectangle;
3504 if (header_control.Visible) {
3505 area.Y += header_control.Height;
3506 area.Height -= header_control.Height;
3509 v_marker = v_scroll.Value;
3510 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3514 internal override bool IsInputCharInternal (char charCode)
3518 #endregion // Internal Methods Properties
3520 #region Protected Methods
3521 protected override void CreateHandle ()
3523 base.CreateHandle ();
3524 is_selection_available = true;
3525 for (int i = 0; i < SelectedItems.Count; i++)
3526 OnSelectedIndexChanged (EventArgs.Empty);
3529 protected override void Dispose (bool disposing)
3532 h_scroll.Dispose ();
3533 v_scroll.Dispose ();
3535 large_image_list = null;
3536 small_image_list = null;
3537 state_image_list = null;
3539 foreach (ColumnHeader col in columns)
3540 col.SetListView (null);
3543 if (!virtual_mode) // In virtual mode we don't save the items
3545 foreach (ListViewItem item in items)
3549 base.Dispose (disposing);
3552 protected override bool IsInputKey (Keys keyData)
3569 return base.IsInputKey (keyData);
3572 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3574 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3580 protected override void OnBackgroundImageChanged (EventArgs e)
3582 item_control.BackgroundImage = BackgroundImage;
3583 base.OnBackgroundImageChanged (e);
3587 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3589 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3594 protected internal virtual void OnColumnClick (ColumnClickEventArgs e)
3596 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3602 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3604 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3609 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3611 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3616 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3618 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3624 protected override void OnEnabledChanged (EventArgs e)
3626 base.OnEnabledChanged (e);
3630 protected override void OnFontChanged (EventArgs e)
3632 base.OnFontChanged (e);
3636 protected override void OnHandleCreated (EventArgs e)
3638 base.OnHandleCreated (e);
3639 CalculateListView (alignment);
3641 if (!virtual_mode) // Sorting is not allowed in virtual mode
3646 protected override void OnHandleDestroyed (EventArgs e)
3648 base.OnHandleDestroyed (e);
3651 protected virtual void OnItemActivate (EventArgs e)
3653 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3658 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3660 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3666 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3668 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3674 protected virtual void OnItemDrag (ItemDragEventArgs e)
3676 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3682 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3684 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3689 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3691 ListViewItemSelectionChangedEventHandler eh =
3692 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3697 protected override void OnMouseHover (EventArgs e)
3699 base.OnMouseHover (e);
3702 protected override void OnParentChanged (EventArgs e)
3704 base.OnParentChanged (e);
3708 protected virtual void OnSelectedIndexChanged (EventArgs e)
3710 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3715 protected override void OnSystemColorsChanged (EventArgs e)
3717 base.OnSystemColorsChanged (e);
3721 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3723 CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3728 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3730 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3735 [EditorBrowsable (EditorBrowsableState.Advanced)]
3736 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3738 EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3743 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3745 SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3750 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3752 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3753 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3759 protected void RealizeProperties ()
3764 protected void UpdateExtendedStyles ()
3769 bool refocusing = false;
3771 protected override void WndProc (ref Message m)
3773 switch ((Msg)m.Msg) {
3774 case Msg.WM_KILLFOCUS:
3775 Control receiver = Control.FromHandle (m.WParam);
3776 if (receiver == item_control) {
3782 case Msg.WM_SETFOCUS:
3792 base.WndProc (ref m);
3794 #endregion // Protected Methods
3796 #region Public Instance Methods
3797 public void ArrangeIcons ()
3799 ArrangeIcons (this.alignment);
3802 public void ArrangeIcons (ListViewAlignment value)
3804 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3805 if (view == View.LargeIcon || view == View.SmallIcon)
3810 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3812 if (columnIndex < 0 || columnIndex >= columns.Count)
3813 throw new ArgumentOutOfRangeException ("columnIndex");
3815 columns [columnIndex].AutoResize (headerAutoResize);
3818 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3821 foreach (ColumnHeader col in columns)
3822 col.AutoResize (headerAutoResize);
3827 public void BeginUpdate ()
3829 // flag to avoid painting
3833 public void Clear ()
3836 items.Clear (); // Redraw (true) called here
3839 public void EndUpdate ()
3841 // flag to avoid painting
3844 // probably, now we need a redraw with recalculations
3848 public void EnsureVisible (int index)
3850 if (index < 0 || index >= items.Count || scrollable == false || updating)
3853 Rectangle view_rect = item_control.ClientRectangle;
3855 // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items
3856 Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds;
3858 Rectangle bounds = items [index].Bounds;
3861 if (view == View.Details && header_style != ColumnHeaderStyle.None) {
3862 view_rect.Y += header_control.Height;
3863 view_rect.Height -= header_control.Height;
3866 if (view_rect.Contains (bounds))
3869 if (View != View.Details) {
3870 if (bounds.Left < 0)
3871 h_scroll.Value += bounds.Left;
3872 else if (bounds.Right > view_rect.Right)
3873 h_scroll.Value += (bounds.Right - view_rect.Right);
3876 if (bounds.Top < view_rect.Y)
3877 v_scroll.Value += bounds.Top - view_rect.Y;
3878 else if (bounds.Bottom > view_rect.Bottom)
3879 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3883 public ListViewItem FindItemWithText (string text)
3885 if (items.Count == 0)
3888 return FindItemWithText (text, true, 0, true);
3891 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3893 return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3896 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3898 return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3902 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3904 if (startIndex < 0 || startIndex >= items.Count)
3905 throw new ArgumentOutOfRangeException ("startIndex");
3908 throw new ArgumentNullException ("text");
3912 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3913 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty,
3914 SearchDirectionHint.Down, startIndex);
3916 OnSearchForVirtualItem (args);
3917 int idx = args.Index;
3918 if (idx >= 0 && idx < virtual_list_size)
3927 ListViewItem lvi = items [i];
3929 if (isPrefixSearch) { // prefix search
3930 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3932 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3935 if (i + 1 >= items.Count) {
3943 if (i == startIndex)
3947 // Subitems have a minor priority, so we have to do a second linear search
3948 // Also, we don't need to to a roundtrip search for them by now
3949 if (includeSubItemsInSearch) {
3950 for (i = startIndex; i < items.Count; i++) {
3951 ListViewItem lvi = items [i];
3952 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3953 if (isPrefixSearch) {
3954 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text,
3955 text, CompareOptions.IgnoreCase))
3957 } else if (String.Compare (sub_item.Text, text, true) == 0)
3966 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3968 return FindNearestItem (searchDirection, new Point (x, y));
3971 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3973 if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3974 throw new ArgumentOutOfRangeException ("searchDirection");
3976 if (view != View.LargeIcon && view != View.SmallIcon)
3977 throw new InvalidOperationException ();
3980 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3981 false, false, String.Empty, point,
3984 OnSearchForVirtualItem (args);
3985 int idx = args.Index;
3986 if (idx >= 0 && idx < virtual_list_size)
3992 ListViewItem item = null;
3993 int min_dist = Int32.MaxValue;
3996 // It looks like .Net does a previous adjustment
3999 case SearchDirectionHint.Up:
4000 point.Y -= item_size.Height;
4002 case SearchDirectionHint.Down:
4003 point.Y += item_size.Height;
4005 case SearchDirectionHint.Left:
4006 point.X -= item_size.Width;
4008 case SearchDirectionHint.Right:
4009 point.X += item_size.Width;
4013 for (int i = 0; i < items.Count; i++) {
4014 Point item_loc = GetItemLocation (i);
4016 if (dir == SearchDirectionHint.Up) {
4017 if (point.Y < item_loc.Y)
4019 } else if (dir == SearchDirectionHint.Down) {
4020 if (point.Y > item_loc.Y)
4022 } else if (dir == SearchDirectionHint.Left) {
4023 if (point.X < item_loc.X)
4025 } else if (dir == SearchDirectionHint.Right) {
4026 if (point.X > item_loc.X)
4030 int x_dist = point.X - item_loc.X;
4031 int y_dist = point.Y - item_loc.Y;
4033 int dist = x_dist * x_dist + y_dist * y_dist;
4034 if (dist < min_dist) {
4044 public ListViewItem GetItemAt (int x, int y)
4046 Size item_size = ItemSize;
4047 for (int i = 0; i < items.Count; i++) {
4048 Point item_location = GetItemLocation (i);
4049 Rectangle item_rect = new Rectangle (item_location, item_size);
4050 if (item_rect.Contains (x, y))
4057 public Rectangle GetItemRect (int index)
4059 return GetItemRect (index, ItemBoundsPortion.Entire);
4062 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
4064 if (index < 0 || index >= items.Count)
4065 throw new IndexOutOfRangeException ("index");
4067 return items [index].GetBounds (portion);
4071 public ListViewHitTestInfo HitTest (Point point)
4073 return HitTest (point.X, point.Y);
4076 public ListViewHitTestInfo HitTest (int x, int y)
4079 throw new ArgumentOutOfRangeException ("x");
4081 throw new ArgumentOutOfRangeException ("y");
4083 ListViewItem item = GetItemAt (x, y);
4085 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
4087 ListViewHitTestLocations locations = 0;
4088 if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
4089 locations |= ListViewHitTestLocations.Label;
4090 else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
4091 locations |= ListViewHitTestLocations.Image;
4092 else if (item.CheckRectReal.Contains (x, y))
4093 locations |= ListViewHitTestLocations.StateImage;
4095 ListViewItem.ListViewSubItem subitem = null;
4096 if (view == View.Details)
4097 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
4098 if (si.Bounds.Contains (x, y)) {
4103 return new ListViewHitTestInfo (item, subitem, locations);
4106 [EditorBrowsable (EditorBrowsableState.Advanced)]
4107 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
4109 if (startIndex < 0 || startIndex >= items.Count)
4110 throw new ArgumentOutOfRangeException ("startIndex");
4111 if (endIndex < 0 || endIndex >= items.Count)
4112 throw new ArgumentOutOfRangeException ("endIndex");
4113 if (startIndex > endIndex)
4114 throw new ArgumentException ("startIndex");
4119 for (int i = startIndex; i <= endIndex; i++)
4120 items [i].Invalidate ();
4122 if (!invalidateOnly)
4131 throw new InvalidOperationException ();
4137 // we need this overload to reuse the logic for sorting, while allowing
4138 // redrawing to be done by caller or have it done by this method when
4139 // sorting is really performed
4141 // ListViewItemCollection's Add and AddRange methods call this overload
4142 // with redraw set to false, as they take care of redrawing themselves
4143 // (they even want to redraw the listview if no sort is performed, as
4144 // an item was added), while ListView.Sort () only wants to redraw if
4145 // sorting was actually performed
4146 private void Sort (bool redraw)
4148 if (!IsHandleCreated || item_sorter == null) {
4152 items.Sort (item_sorter);
4157 public override string ToString ()
4159 int count = this.Items.Count;
4162 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
4164 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
4166 #endregion // Public Instance Methods
4171 internal class HeaderControl : Control {
4174 bool column_resize_active = false;
4175 ColumnHeader resize_column;
4176 ColumnHeader clicked_column;
4177 ColumnHeader drag_column;
4179 int drag_to_index = -1;
4180 ColumnHeader entered_column_header;
4182 public HeaderControl (ListView owner)
4185 this.SetStyle (ControlStyles.DoubleBuffer, true);
4186 MouseDown += new MouseEventHandler (HeaderMouseDown);
4187 MouseMove += new MouseEventHandler (HeaderMouseMove);
4188 MouseUp += new MouseEventHandler (HeaderMouseUp);
4189 MouseLeave += new EventHandler (OnMouseLeave);
4192 internal ColumnHeader EnteredColumnHeader {
4193 get { return entered_column_header; }
4195 if (entered_column_header == value)
4197 if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
4198 Region region_to_invalidate = new Region ();
4199 region_to_invalidate.MakeEmpty ();
4200 if (entered_column_header != null)
4201 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4202 entered_column_header = value;
4203 if (entered_column_header != null)
4204 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4205 Invalidate (region_to_invalidate);
4206 region_to_invalidate.Dispose ();
4208 entered_column_header = value;
4212 void OnMouseLeave (object sender, EventArgs e)
4214 EnteredColumnHeader = null;
4217 private ColumnHeader ColumnAtX (int x)
4219 Point pt = new Point (x, 0);
4220 ColumnHeader result = null;
4221 foreach (ColumnHeader col in owner.Columns) {
4222 if (col.Rect.Contains (pt)) {
4230 private int GetReorderedIndex (ColumnHeader col)
4232 if (owner.reordered_column_indices == null)
4235 for (int i = 0; i < owner.Columns.Count; i++)
4236 if (owner.reordered_column_indices [i] == col.Index)
4238 throw new Exception ("Column index missing from reordered array");
4241 private void HeaderMouseDown (object sender, MouseEventArgs me)
4243 if (resize_column != null) {
4244 column_resize_active = true;
4249 clicked_column = ColumnAtX (me.X + owner.h_marker);
4251 if (clicked_column != null) {
4253 if (owner.AllowColumnReorder) {
4255 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4256 drag_column.Rect = clicked_column.Rect;
4257 drag_to_index = GetReorderedIndex (clicked_column);
4259 clicked_column.Pressed = true;
4260 Invalidate (clicked_column);
4265 void Invalidate (ColumnHeader columnHeader)
4267 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4270 Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4272 Rectangle bounds = columnHeader.Rect;
4273 bounds.X -= owner.h_marker;
4279 column_resize_active = false;
4280 resize_column = null;
4282 Cursor = Cursors.Default;
4285 private void HeaderMouseMove (object sender, MouseEventArgs me)
4287 Point pt = new Point (me.X + owner.h_marker, me.Y);
4289 if (column_resize_active) {
4290 int width = pt.X - resize_column.X;
4294 if (!owner.CanProceedWithResize (resize_column, width)){
4298 resize_column.Width = width;
4302 resize_column = null;
4304 if (clicked_column != null) {
4305 if (owner.AllowColumnReorder) {
4308 r = drag_column.Rect;
4309 r.X = clicked_column.Rect.X + me.X - drag_x;
4310 drag_column.Rect = r;
4312 int x = me.X + owner.h_marker;
4313 ColumnHeader over = ColumnAtX (x);
4315 drag_to_index = owner.Columns.Count;
4316 else if (x < over.X + over.Width / 2)
4317 drag_to_index = GetReorderedIndex (over);
4319 drag_to_index = GetReorderedIndex (over) + 1;
4322 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4323 bool pressed = clicked_column.Pressed;
4324 clicked_column.Pressed = over == clicked_column;
4325 if (clicked_column.Pressed ^ pressed)
4326 Invalidate (clicked_column);
4331 for (int i = 0; i < owner.Columns.Count; i++) {
4332 Rectangle zone = owner.Columns [i].Rect;
4333 if (zone.Contains (pt))
4334 EnteredColumnHeader = owner.Columns [i];
4335 zone.X = zone.Right - 5;
4337 if (zone.Contains (pt)) {
4338 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4340 resize_column = owner.Columns [i];
4345 if (resize_column == null)
4346 Cursor = Cursors.Default;
4348 Cursor = Cursors.VSplit;
4351 void HeaderMouseUp (object sender, MouseEventArgs me)
4355 if (column_resize_active) {
4356 int column_idx = resize_column.Index;
4358 owner.RaiseColumnWidthChanged (column_idx);
4362 if (clicked_column != null && clicked_column.Pressed) {
4363 clicked_column.Pressed = false;
4364 Invalidate (clicked_column);
4365 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4368 if (drag_column != null && owner.AllowColumnReorder) {
4370 if (drag_to_index > GetReorderedIndex (clicked_column))
4372 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4373 owner.ReorderColumn (clicked_column, drag_to_index, true);
4378 clicked_column = null;
4381 internal override void OnPaintInternal (PaintEventArgs pe)
4386 Theme theme = ThemeEngine.Current;
4387 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4389 if (drag_column == null)
4393 if (drag_to_index == owner.Columns.Count)
4394 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4396 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4397 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4400 protected override void WndProc (ref Message m)
4402 switch ((Msg)m.Msg) {
4403 case Msg.WM_SETFOCUS:
4407 base.WndProc (ref m);
4413 private class ItemComparer : IComparer {
4414 readonly SortOrder sort_order;
4416 public ItemComparer (SortOrder sortOrder)
4418 sort_order = sortOrder;
4421 public int Compare (object x, object y)
4423 ListViewItem item_x = x as ListViewItem;
4424 ListViewItem item_y = y as ListViewItem;
4425 if (sort_order == SortOrder.Ascending)
4426 return String.Compare (item_x.Text, item_y.Text);
4428 return String.Compare (item_y.Text, item_x.Text);
4433 [ListBindable (false)]
4435 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4437 private readonly ListView owner;
4439 #region Public Constructor
4440 public CheckedIndexCollection (ListView owner)
4444 #endregion // Public Constructor
4446 #region Public Properties
4449 get { return owner.CheckedItems.Count; }
4452 public bool IsReadOnly {
4453 get { return true; }
4456 public int this [int index] {
4458 int [] indices = GetIndices ();
4459 if (index < 0 || index >= indices.Length)
4460 throw new ArgumentOutOfRangeException ("index");
4461 return indices [index];
4465 bool ICollection.IsSynchronized {
4466 get { return false; }
4469 object ICollection.SyncRoot {
4470 get { return this; }
4473 bool IList.IsFixedSize {
4474 get { return true; }
4477 object IList.this [int index] {
4478 get { return this [index]; }
4479 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4481 #endregion // Public Properties
4483 #region Public Methods
4484 public bool Contains (int checkedIndex)
4486 int [] indices = GetIndices ();
4487 for (int i = 0; i < indices.Length; i++) {
4488 if (indices [i] == checkedIndex)
4494 public IEnumerator GetEnumerator ()
4496 int [] indices = GetIndices ();
4497 return indices.GetEnumerator ();
4500 void ICollection.CopyTo (Array dest, int index)
4502 int [] indices = GetIndices ();
4503 Array.Copy (indices, 0, dest, index, indices.Length);
4506 int IList.Add (object value)
4508 throw new NotSupportedException ("Add operation is not supported.");
4513 throw new NotSupportedException ("Clear operation is not supported.");
4516 bool IList.Contains (object checkedIndex)
4518 if (!(checkedIndex is int))
4520 return Contains ((int) checkedIndex);
4523 int IList.IndexOf (object checkedIndex)
4525 if (!(checkedIndex is int))
4527 return IndexOf ((int) checkedIndex);
4530 void IList.Insert (int index, object value)
4532 throw new NotSupportedException ("Insert operation is not supported.");
4535 void IList.Remove (object value)
4537 throw new NotSupportedException ("Remove operation is not supported.");
4540 void IList.RemoveAt (int index)
4542 throw new NotSupportedException ("RemoveAt operation is not supported.");
4545 public int IndexOf (int checkedIndex)
4547 int [] indices = GetIndices ();
4548 for (int i = 0; i < indices.Length; i++) {
4549 if (indices [i] == checkedIndex)
4554 #endregion // Public Methods
4556 private int [] GetIndices ()
4558 ArrayList checked_items = owner.CheckedItems.List;
4559 int [] indices = new int [checked_items.Count];
4560 for (int i = 0; i < checked_items.Count; i++) {
4561 ListViewItem item = (ListViewItem) checked_items [i];
4562 indices [i] = item.Index;
4566 } // CheckedIndexCollection
4569 [ListBindable (false)]
4571 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4573 private readonly ListView owner;
4574 private ArrayList list;
4576 #region Public Constructor
4577 public CheckedListViewItemCollection (ListView owner)
4580 this.owner.Items.Changed += new CollectionChangedHandler (
4581 ItemsCollection_Changed);
4583 #endregion // Public Constructor
4585 #region Public Properties
4589 if (!owner.CheckBoxes)
4595 public bool IsReadOnly {
4596 get { return true; }
4599 public ListViewItem this [int index] {
4602 if (owner.VirtualMode)
4603 throw new InvalidOperationException ();
4605 ArrayList checked_items = List;
4606 if (index < 0 || index >= checked_items.Count)
4607 throw new ArgumentOutOfRangeException ("index");
4608 return (ListViewItem) checked_items [index];
4613 public virtual ListViewItem this [string key] {
4615 int idx = IndexOfKey (key);
4616 return idx == -1 ? null : (ListViewItem) List [idx];
4621 bool ICollection.IsSynchronized {
4622 get { return false; }
4625 object ICollection.SyncRoot {
4626 get { return this; }
4629 bool IList.IsFixedSize {
4630 get { return true; }
4633 object IList.this [int index] {
4634 get { return this [index]; }
4635 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4637 #endregion // Public Properties
4639 #region Public Methods
4640 public bool Contains (ListViewItem item)
4642 if (!owner.CheckBoxes)
4644 return List.Contains (item);
4648 public virtual bool ContainsKey (string key)
4650 return IndexOfKey (key) != -1;
4654 public void CopyTo (Array dest, int index)
4657 if (owner.VirtualMode)
4658 throw new InvalidOperationException ();
4660 if (!owner.CheckBoxes)
4662 List.CopyTo (dest, index);
4665 public IEnumerator GetEnumerator ()
4668 if (owner.VirtualMode)
4669 throw new InvalidOperationException ();
4671 if (!owner.CheckBoxes)
4672 return (new ListViewItem [0]).GetEnumerator ();
4673 return List.GetEnumerator ();
4676 int IList.Add (object value)
4678 throw new NotSupportedException ("Add operation is not supported.");
4683 throw new NotSupportedException ("Clear operation is not supported.");
4686 bool IList.Contains (object item)
4688 if (!(item is ListViewItem))
4690 return Contains ((ListViewItem) item);
4693 int IList.IndexOf (object item)
4695 if (!(item is ListViewItem))
4697 return IndexOf ((ListViewItem) item);
4700 void IList.Insert (int index, object value)
4702 throw new NotSupportedException ("Insert operation is not supported.");
4705 void IList.Remove (object value)
4707 throw new NotSupportedException ("Remove operation is not supported.");
4710 void IList.RemoveAt (int index)
4712 throw new NotSupportedException ("RemoveAt operation is not supported.");
4715 public int IndexOf (ListViewItem item)
4718 if (owner.VirtualMode)
4719 throw new InvalidOperationException ();
4721 if (!owner.CheckBoxes)
4723 return List.IndexOf (item);
4727 public virtual int IndexOfKey (string key)
4730 if (owner.VirtualMode)
4731 throw new InvalidOperationException ();
4733 if (key == null || key.Length == 0)
4736 ArrayList checked_items = List;
4737 for (int i = 0; i < checked_items.Count; i++) {
4738 ListViewItem item = (ListViewItem) checked_items [i];
4739 if (String.Compare (key, item.Name, true) == 0)
4746 #endregion // Public Methods
4748 internal ArrayList List {
4751 list = new ArrayList ();
4752 foreach (ListViewItem item in owner.Items) {
4761 internal void Reset ()
4763 // force re-population of list
4767 private void ItemsCollection_Changed ()
4771 } // CheckedListViewItemCollection
4774 [ListBindable (false)]
4776 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4778 internal ArrayList list;
4779 private ListView owner;
4781 #region UIA Framework Events
4784 // We are using Reflection to add/remove internal events.
4785 // Class ListViewProvider uses the events when View is Details.
4787 //Event used to generate UIA StructureChangedEvent
4788 static object UIACollectionChangedEvent = new object ();
4790 internal event CollectionChangeEventHandler UIACollectionChanged {
4793 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4797 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4801 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4806 CollectionChangeEventHandler eh
4807 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4813 #endregion UIA Framework Events
4815 #region Public Constructor
4816 public ColumnHeaderCollection (ListView owner)
4818 list = new ArrayList ();
4821 #endregion // Public Constructor
4823 #region Public Properties
4826 get { return list.Count; }
4829 public bool IsReadOnly {
4830 get { return false; }
4833 public virtual ColumnHeader this [int index] {
4835 if (index < 0 || index >= list.Count)
4836 throw new ArgumentOutOfRangeException ("index");
4837 return (ColumnHeader) list [index];
4842 public virtual ColumnHeader this [string key] {
4844 int idx = IndexOfKey (key);
4848 return (ColumnHeader) list [idx];
4853 bool ICollection.IsSynchronized {
4854 get { return true; }
4857 object ICollection.SyncRoot {
4858 get { return this; }
4861 bool IList.IsFixedSize {
4862 get { return list.IsFixedSize; }
4865 object IList.this [int index] {
4866 get { return this [index]; }
4867 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4869 #endregion // Public Properties
4871 #region Public Methods
4872 public virtual int Add (ColumnHeader value)
4874 int idx = list.Add (value);
4875 owner.AddColumn (value, idx, true);
4878 //UIA Framework event: Item Added
4879 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4886 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4890 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
4893 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4894 this.Add (colHeader);
4899 public virtual ColumnHeader Add (string text)
4901 return Add (String.Empty, text);
4904 public virtual ColumnHeader Add (string text, int width)
4906 return Add (String.Empty, text, width);
4909 public virtual ColumnHeader Add (string key, string text)
4911 ColumnHeader colHeader = new ColumnHeader ();
4912 colHeader.Name = key;
4913 colHeader.Text = text;
4918 public virtual ColumnHeader Add (string key, string text, int width)
4920 return Add (key, text, width, HorizontalAlignment.Left, -1);
4923 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4925 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4926 colHeader.ImageIndex = imageIndex;
4931 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4933 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4934 colHeader.ImageKey = imageKey;
4940 public virtual void AddRange (ColumnHeader [] values)
4942 foreach (ColumnHeader colHeader in values) {
4943 int idx = list.Add (colHeader);
4944 owner.AddColumn (colHeader, idx, false);
4947 owner.Redraw (true);
4950 public virtual void Clear ()
4952 foreach (ColumnHeader col in list)
4953 col.SetListView (null);
4955 owner.ReorderColumns (new int [0], true);
4958 //UIA Framework event: Items cleared
4959 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4964 public bool Contains (ColumnHeader value)
4966 return list.Contains (value);
4970 public virtual bool ContainsKey (string key)
4972 return IndexOfKey (key) != -1;
4976 public IEnumerator GetEnumerator ()
4978 return list.GetEnumerator ();
4981 void ICollection.CopyTo (Array dest, int index)
4983 list.CopyTo (dest, index);
4986 int IList.Add (object value)
4988 if (! (value is ColumnHeader)) {
4989 throw new ArgumentException ("Not of type ColumnHeader", "value");
4992 return this.Add ((ColumnHeader) value);
4995 bool IList.Contains (object value)
4997 if (! (value is ColumnHeader)) {
4998 throw new ArgumentException ("Not of type ColumnHeader", "value");
5001 return this.Contains ((ColumnHeader) value);
5004 int IList.IndexOf (object value)
5006 if (! (value is ColumnHeader)) {
5007 throw new ArgumentException ("Not of type ColumnHeader", "value");
5010 return this.IndexOf ((ColumnHeader) value);
5013 void IList.Insert (int index, object value)
5015 if (! (value is ColumnHeader)) {
5016 throw new ArgumentException ("Not of type ColumnHeader", "value");
5019 this.Insert (index, (ColumnHeader) value);
5022 void IList.Remove (object value)
5024 if (! (value is ColumnHeader)) {
5025 throw new ArgumentException ("Not of type ColumnHeader", "value");
5028 this.Remove ((ColumnHeader) value);
5031 public int IndexOf (ColumnHeader value)
5033 return list.IndexOf (value);
5037 public virtual int IndexOfKey (string key)
5039 if (key == null || key.Length == 0)
5042 for (int i = 0; i < list.Count; i++) {
5043 ColumnHeader col = (ColumnHeader) list [i];
5044 if (String.Compare (key, col.Name, true) == 0)
5052 public void Insert (int index, ColumnHeader value)
5054 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
5055 // but it's really only greater.
5056 if (index < 0 || index > list.Count)
5057 throw new ArgumentOutOfRangeException ("index");
5059 list.Insert (index, value);
5060 owner.AddColumn (value, index, true);
5063 //UIA Framework event: Item added
5064 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5069 public void Insert (int index, string text)
5071 Insert (index, String.Empty, text);
5074 public void Insert (int index, string text, int width)
5076 Insert (index, String.Empty, text, width);
5079 public void Insert (int index, string key, string text)
5081 ColumnHeader colHeader = new ColumnHeader ();
5082 colHeader.Name = key;
5083 colHeader.Text = text;
5084 Insert (index, colHeader);
5087 public void Insert (int index, string key, string text, int width)
5089 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
5090 Insert (index, colHeader);
5093 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
5095 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
5096 colHeader.ImageIndex = imageIndex;
5097 Insert (index, colHeader);
5100 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
5102 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
5103 colHeader.ImageKey = imageKey;
5104 Insert (index, colHeader);
5109 public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
5113 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
5116 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
5117 this.Insert (index, colHeader);
5120 public virtual void Remove (ColumnHeader column)
5122 if (!Contains (column))
5125 list.Remove (column);
5126 column.SetListView (null);
5128 int rem_display_index = column.InternalDisplayIndex;
5129 int [] display_indices = new int [list.Count];
5130 for (int i = 0; i < display_indices.Length; i++) {
5131 ColumnHeader col = (ColumnHeader) list [i];
5132 int display_index = col.InternalDisplayIndex;
5133 if (display_index < rem_display_index) {
5134 display_indices [i] = display_index;
5136 display_indices [i] = (display_index - 1);
5140 column.InternalDisplayIndex = -1;
5141 owner.ReorderColumns (display_indices, true);
5144 //UIA Framework event: Item Removed
5145 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
5150 public virtual void RemoveByKey (string key)
5152 int idx = IndexOfKey (key);
5158 public virtual void RemoveAt (int index)
5160 if (index < 0 || index >= list.Count)
5161 throw new ArgumentOutOfRangeException ("index");
5163 ColumnHeader col = (ColumnHeader) list [index];
5166 #endregion // Public Methods
5169 } // ColumnHeaderCollection
5172 [ListBindable (false)]
5174 public class ListViewItemCollection : IList, ICollection, IEnumerable
5176 private readonly ArrayList list;
5177 private ListView owner;
5179 private ListViewGroup group;
5182 #region UIA Framework Events
5185 // We are using Reflection to add/remove internal events.
5186 // Class ListViewProvider uses the events.
5188 //Event used to generate UIA StructureChangedEvent
5189 static object UIACollectionChangedEvent = new object ();
5191 internal event CollectionChangeEventHandler UIACollectionChanged {
5194 owner.Events.AddHandler (UIACollectionChangedEvent, value);
5198 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
5202 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
5207 CollectionChangeEventHandler eh
5208 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
5214 #endregion UIA Framework Events
5216 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
5217 // In the later case ListViewItem.ListView never gets modified
5218 private bool is_main_collection = true;
5220 #region Public Constructor
5221 public ListViewItemCollection (ListView owner)
5223 list = new ArrayList (0);
5226 #endregion // Public Constructor
5229 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
5232 is_main_collection = false;
5236 #region Public Properties
5241 if (owner != null && owner.VirtualMode)
5242 return owner.VirtualListSize;
5249 public bool IsReadOnly {
5250 get { return false; }
5254 public virtual ListViewItem this [int index] {
5256 public virtual ListViewItem this [int displayIndex] {
5260 int index = displayIndex;
5263 if (index < 0 || index >= Count)
5264 throw new ArgumentOutOfRangeException ("index");
5267 if (owner != null && owner.VirtualMode)
5268 return RetrieveVirtualItemFromOwner (index);
5270 return (ListViewItem) list [index];
5275 int index = displayIndex;
5278 if (index < 0 || index >= Count)
5279 throw new ArgumentOutOfRangeException ("index");
5282 if (owner != null && owner.VirtualMode)
5283 throw new InvalidOperationException ();
5286 if (list.Contains (value))
5287 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5289 if (value.ListView != null && value.ListView != owner)
5290 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");
5292 if (is_main_collection)
5293 value.Owner = owner;
5296 if (value.Group != null)
5297 value.Group.Items.Remove (value);
5299 value.SetGroup (group);
5304 //UIA Framework event: Item Replaced
5305 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5308 list [index] = value;
5310 CollectionChanged (true);
5313 //UIA Framework event: Item Replaced
5314 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5321 public virtual ListViewItem this [string key] {
5323 int idx = IndexOfKey (key);
5332 bool ICollection.IsSynchronized {
5333 get { return true; }
5336 object ICollection.SyncRoot {
5337 get { return this; }
5340 bool IList.IsFixedSize {
5341 get { return list.IsFixedSize; }
5344 object IList.this [int index] {
5345 get { return this [index]; }
5348 //UIA Framework event: Item Replaced
5349 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5352 if (value is ListViewItem)
5353 this [index] = (ListViewItem) value;
5355 this [index] = new ListViewItem (value.ToString ());
5359 //UIA Framework event: Item Replaced
5360 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5364 #endregion // Public Properties
5366 #region Public Methods
5367 public virtual ListViewItem Add (ListViewItem value)
5370 if (owner != null && owner.VirtualMode)
5371 throw new InvalidOperationException ();
5376 // Item is ignored until it has been added to the ListView
5377 if (is_main_collection || value.ListView != null)
5378 CollectionChanged (true);
5381 //UIA Framework event: Item Added
5382 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5388 public virtual ListViewItem Add (string text)
5390 ListViewItem item = new ListViewItem (text);
5391 return this.Add (item);
5394 public virtual ListViewItem Add (string text, int imageIndex)
5396 ListViewItem item = new ListViewItem (text, imageIndex);
5397 return this.Add (item);
5401 public virtual ListViewItem Add (string text, string imageKey)
5403 ListViewItem item = new ListViewItem (text, imageKey);
5404 return this.Add (item);
5407 public virtual ListViewItem Add (string key, string text, int imageIndex)
5409 ListViewItem item = new ListViewItem (text, imageIndex);
5411 return this.Add (item);
5414 public virtual ListViewItem Add (string key, string text, string imageKey)
5416 ListViewItem item = new ListViewItem (text, imageKey);
5418 return this.Add (item);
5423 public void AddRange (ListViewItem [] items)
5426 public void AddRange (ListViewItem [] values)
5428 ListViewItem [] items = values;
5431 throw new ArgumentNullException ("Argument cannot be null!", "items");
5433 if (owner != null && owner.VirtualMode)
5434 throw new InvalidOperationException ();
5437 owner.BeginUpdate ();
5439 foreach (ListViewItem item in items) {
5443 //UIA Framework event: Item Added
5444 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5450 CollectionChanged (true);
5454 public void AddRange (ListViewItemCollection items)
5457 throw new ArgumentNullException ("Argument cannot be null!", "items");
5459 ListViewItem[] itemArray = new ListViewItem[items.Count];
5460 items.CopyTo (itemArray,0);
5461 this.AddRange (itemArray);
5465 public virtual void Clear ()
5468 if (owner != null && owner.VirtualMode)
5469 throw new InvalidOperationException ();
5471 if (is_main_collection && owner != null) {
5472 owner.SetFocusedItem (-1);
5473 owner.h_scroll.Value = owner.v_scroll.Value = 0;
5476 // first remove any item in the groups that *are* part of this LV too
5477 foreach (ListViewGroup group in owner.groups)
5478 group.Items.ClearItemsWithSameListView ();
5481 foreach (ListViewItem item in list) {
5482 owner.item_control.CancelEdit (item);
5488 foreach (ListViewItem item in list)
5489 item.SetGroup (null);
5493 CollectionChanged (false);
5496 //UIA Framework event: Items Removed
5497 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5503 // This method is intended to be used from ListViewGroup.Items, not from ListView.Items,
5504 // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items)
5505 void ClearItemsWithSameListView ()
5507 if (is_main_collection)
5510 int counter = list.Count - 1;
5511 while (counter >= 0) {
5512 ListViewItem item = list [counter] as ListViewItem;
5514 // remove only if the items in group have being added to the ListView too
5515 if (item.ListView == group.ListView) {
5516 list.RemoveAt (counter);
5517 item.SetGroup (null);
5525 public bool Contains (ListViewItem item)
5527 return IndexOf (item) != -1;
5531 public virtual bool ContainsKey (string key)
5533 return IndexOfKey (key) != -1;
5537 public void CopyTo (Array dest, int index)
5539 list.CopyTo (dest, index);
5543 public ListViewItem [] Find (string key, bool searchAllSubItems)
5546 return new ListViewItem [0];
5548 List<ListViewItem> temp_list = new List<ListViewItem> ();
5550 for (int i = 0; i < list.Count; i++) {
5551 ListViewItem lvi = (ListViewItem) list [i];
5552 if (String.Compare (key, lvi.Name, true) == 0)
5553 temp_list.Add (lvi);
5556 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5557 temp_list.CopyTo (retval);
5563 public IEnumerator GetEnumerator ()
5566 if (owner != null && owner.VirtualMode)
5567 throw new InvalidOperationException ();
5570 // This enumerator makes a copy of the collection so
5571 // it can be deleted from in a foreach
5572 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5575 int IList.Add (object item)
5581 if (owner != null && owner.VirtualMode)
5582 throw new InvalidOperationException ();
5585 if (item is ListViewItem) {
5586 li = (ListViewItem) item;
5587 if (list.Contains (li))
5588 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5590 if (li.ListView != null && li.ListView != owner)
5591 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");
5594 li = new ListViewItem (item.ToString ());
5599 result = list.Add (li);
5600 CollectionChanged (true);
5603 //UIA Framework event: Item Added
5604 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5610 bool IList.Contains (object item)
5612 return Contains ((ListViewItem) item);
5615 int IList.IndexOf (object item)
5617 return IndexOf ((ListViewItem) item);
5620 void IList.Insert (int index, object item)
5622 if (item is ListViewItem)
5623 this.Insert (index, (ListViewItem) item);
5625 this.Insert (index, item.ToString ());
5628 //UIA Framework event: Item Added
5629 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5633 void IList.Remove (object item)
5635 Remove ((ListViewItem) item);
5638 public int IndexOf (ListViewItem item)
5641 if (owner != null && owner.VirtualMode) {
5642 for (int i = 0; i < Count; i++)
5643 if (RetrieveVirtualItemFromOwner (i) == item)
5650 return list.IndexOf (item);
5654 public virtual int IndexOfKey (string key)
5656 if (key == null || key.Length == 0)
5659 for (int i = 0; i < Count; i++) {
5660 ListViewItem lvi = this [i];
5661 if (String.Compare (key, lvi.Name, true) == 0)
5669 public ListViewItem Insert (int index, ListViewItem item)
5671 if (index < 0 || index > list.Count)
5672 throw new ArgumentOutOfRangeException ("index");
5675 if (owner != null && owner.VirtualMode)
5676 throw new InvalidOperationException ();
5679 if (list.Contains (item))
5680 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5682 if (item.ListView != null && item.ListView != owner)
5683 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");
5685 if (is_main_collection)
5689 if (item.Group != null)
5690 item.Group.Items.Remove (item);
5692 item.SetGroup (group);
5696 list.Insert (index, item);
5698 if (is_main_collection || item.ListView != null)
5699 CollectionChanged (true);
5702 //UIA Framework event: Item Added
5703 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5709 public ListViewItem Insert (int index, string text)
5711 return this.Insert (index, new ListViewItem (text));
5714 public ListViewItem Insert (int index, string text, int imageIndex)
5716 return this.Insert (index, new ListViewItem (text, imageIndex));
5720 public ListViewItem Insert (int index, string text, string imageKey)
5722 ListViewItem lvi = new ListViewItem (text, imageKey);
5723 return Insert (index, lvi);
5726 public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5728 ListViewItem lvi = new ListViewItem (text, imageIndex);
5730 return Insert (index, lvi);
5733 public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5735 ListViewItem lvi = new ListViewItem (text, imageKey);
5737 return Insert (index, lvi);
5741 public virtual void Remove (ListViewItem item)
5744 if (owner != null && owner.VirtualMode)
5745 throw new InvalidOperationException ();
5748 int idx = list.IndexOf (item);
5753 public virtual void RemoveAt (int index)
5755 if (index < 0 || index >= Count)
5756 throw new ArgumentOutOfRangeException ("index");
5759 if (owner != null && owner.VirtualMode)
5760 throw new InvalidOperationException ();
5763 ListViewItem item = (ListViewItem) list [index];
5765 bool selection_changed = false;
5766 if (is_main_collection && owner != null) {
5768 int display_index = item.DisplayIndex;
5769 if (item.Focused && display_index + 1 == Count) // Last item
5770 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5772 selection_changed = owner.SelectedIndices.Contains (index);
5773 owner.item_control.CancelEdit (item);
5776 list.RemoveAt (index);
5779 if (is_main_collection) {
5781 if (item.Group != null)
5782 item.Group.Items.Remove (item);
5784 item.SetGroup (null);
5789 CollectionChanged (false);
5790 if (selection_changed && owner != null)
5791 owner.OnSelectedIndexChanged (EventArgs.Empty);
5795 //UIA Framework event: Item Removed
5796 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5801 public virtual void RemoveByKey (string key)
5803 int idx = IndexOfKey (key);
5809 #endregion // Public Methods
5811 internal ListView Owner {
5821 internal ListViewGroup Group {
5831 void AddItem (ListViewItem value)
5833 if (list.Contains (value))
5834 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5836 if (value.ListView != null && value.ListView != owner)
5837 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");
5838 if (is_main_collection)
5839 value.Owner = owner;
5842 if (value.Group != null)
5843 value.Group.Items.Remove (value);
5845 value.SetGroup (group);
5853 void CollectionChanged (bool sort)
5855 if (owner != null) {
5860 owner.Redraw (true);
5865 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5867 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5869 owner.OnRetrieveVirtualItem (args);
5870 ListViewItem retval = args.Item;
5871 retval.Owner = owner;
5872 retval.DisplayIndex = displayIndex;
5879 internal event CollectionChangedHandler Changed;
5881 internal void Sort (IComparer comparer)
5883 list.Sort (comparer);
5887 internal void OnChange ()
5889 if (Changed != null)
5892 } // ListViewItemCollection
5895 // In normal mode, the selection information resides in the Items,
5896 // making SelectedIndexCollection.List read-only
5898 // In virtual mode, SelectedIndexCollection directly saves the selection
5899 // information, instead of getting it from Items, making List read-and-write
5901 [ListBindable (false)]
5903 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5905 private readonly ListView owner;
5906 private ArrayList list;
5908 #region Public Constructor
5909 public SelectedIndexCollection (ListView owner)
5912 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5914 #endregion // Public Constructor
5916 #region Public Properties
5920 if (!owner.is_selection_available)
5927 public bool IsReadOnly {
5937 public int this [int index] {
5939 if (!owner.is_selection_available || index < 0 || index >= List.Count)
5940 throw new ArgumentOutOfRangeException ("index");
5942 return (int) List [index];
5946 bool ICollection.IsSynchronized {
5947 get { return false; }
5950 object ICollection.SyncRoot {
5951 get { return this; }
5954 bool IList.IsFixedSize {
5964 object IList.this [int index] {
5965 get { return this [index]; }
5966 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5968 #endregion // Public Properties
5970 #region Public Methods
5972 public int Add (int itemIndex)
5974 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5975 throw new ArgumentOutOfRangeException ("index");
5977 if (owner.virtual_mode && !owner.is_selection_available)
5980 owner.Items [itemIndex].Selected = true;
5982 if (!owner.is_selection_available)
5996 if (!owner.is_selection_available)
5999 int [] indexes = (int []) List.ToArray (typeof (int));
6000 foreach (int index in indexes)
6001 owner.Items [index].Selected = false;
6004 public bool Contains (int selectedIndex)
6006 return IndexOf (selectedIndex) != -1;
6009 public void CopyTo (Array dest, int index)
6011 List.CopyTo (dest, index);
6014 public IEnumerator GetEnumerator ()
6016 return List.GetEnumerator ();
6019 int IList.Add (object value)
6021 throw new NotSupportedException ("Add operation is not supported.");
6029 bool IList.Contains (object selectedIndex)
6031 if (!(selectedIndex is int))
6033 return Contains ((int) selectedIndex);
6036 int IList.IndexOf (object selectedIndex)
6038 if (!(selectedIndex is int))
6040 return IndexOf ((int) selectedIndex);
6043 void IList.Insert (int index, object value)
6045 throw new NotSupportedException ("Insert operation is not supported.");
6048 void IList.Remove (object value)
6050 throw new NotSupportedException ("Remove operation is not supported.");
6053 void IList.RemoveAt (int index)
6055 throw new NotSupportedException ("RemoveAt operation is not supported.");
6058 public int IndexOf (int selectedIndex)
6060 if (!owner.is_selection_available)
6063 return List.IndexOf (selectedIndex);
6067 public void Remove (int itemIndex)
6069 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
6070 throw new ArgumentOutOfRangeException ("itemIndex");
6072 owner.Items [itemIndex].Selected = false;
6075 #endregion // Public Methods
6077 internal ArrayList List {
6080 list = new ArrayList ();
6082 if (!owner.VirtualMode)
6084 for (int i = 0; i < owner.Items.Count; i++) {
6085 if (owner.Items [i].Selected)
6093 internal void Reset ()
6095 // force re-population of list
6099 private void ItemsCollection_Changed ()
6105 internal void RemoveIndex (int index)
6107 int idx = List.BinarySearch (index);
6109 List.RemoveAt (idx);
6112 // actually store index in the collection
6113 // also, keep the collection sorted, as .Net does
6114 internal void InsertIndex (int index)
6117 int iMax = List.Count - 1;
6118 while (iMin <= iMax) {
6119 int iMid = (iMin + iMax) / 2;
6120 int current_index = (int) List [iMid];
6122 if (current_index == index)
6123 return; // Already added
6124 if (current_index > index)
6130 List.Insert (iMin, index);
6134 } // SelectedIndexCollection
6137 [ListBindable (false)]
6139 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
6141 private readonly ListView owner;
6143 #region Public Constructor
6144 public SelectedListViewItemCollection (ListView owner)
6148 #endregion // Public Constructor
6150 #region Public Properties
6154 return owner.SelectedIndices.Count;
6158 public bool IsReadOnly {
6159 get { return true; }
6162 public ListViewItem this [int index] {
6164 if (!owner.is_selection_available || index < 0 || index >= Count)
6165 throw new ArgumentOutOfRangeException ("index");
6167 int item_index = owner.SelectedIndices [index];
6168 return owner.Items [item_index];
6173 public virtual ListViewItem this [string key] {
6175 int idx = IndexOfKey (key);
6184 bool ICollection.IsSynchronized {
6185 get { return false; }
6188 object ICollection.SyncRoot {
6189 get { return this; }
6192 bool IList.IsFixedSize {
6193 get { return true; }
6196 object IList.this [int index] {
6197 get { return this [index]; }
6198 set { throw new NotSupportedException ("SetItem operation is not supported."); }
6200 #endregion // Public Properties
6202 #region Public Methods
6203 public void Clear ()
6205 owner.SelectedIndices.Clear ();
6208 public bool Contains (ListViewItem item)
6210 return IndexOf (item) != -1;
6214 public virtual bool ContainsKey (string key)
6216 return IndexOfKey (key) != -1;
6220 public void CopyTo (Array dest, int index)
6222 if (!owner.is_selection_available)
6224 if (index > Count) // Throws ArgumentException instead of IOOR exception
6225 throw new ArgumentException ("index");
6227 for (int i = 0; i < Count; i++)
6228 dest.SetValue (this [i], index++);
6231 public IEnumerator GetEnumerator ()
6233 if (!owner.is_selection_available)
6234 return (new ListViewItem [0]).GetEnumerator ();
6236 ListViewItem [] items = new ListViewItem [Count];
6237 for (int i = 0; i < Count; i++)
6238 items [i] = this [i];
6240 return items.GetEnumerator ();
6243 int IList.Add (object value)
6245 throw new NotSupportedException ("Add operation is not supported.");
6248 bool IList.Contains (object item)
6250 if (!(item is ListViewItem))
6252 return Contains ((ListViewItem) item);
6255 int IList.IndexOf (object item)
6257 if (!(item is ListViewItem))
6259 return IndexOf ((ListViewItem) item);
6262 void IList.Insert (int index, object value)
6264 throw new NotSupportedException ("Insert operation is not supported.");
6267 void IList.Remove (object value)
6269 throw new NotSupportedException ("Remove operation is not supported.");
6272 void IList.RemoveAt (int index)
6274 throw new NotSupportedException ("RemoveAt operation is not supported.");
6277 public int IndexOf (ListViewItem item)
6279 if (!owner.is_selection_available)
6282 for (int i = 0; i < Count; i++)
6283 if (this [i] == item)
6290 public virtual int IndexOfKey (string key)
6292 if (!owner.is_selection_available || key == null || key.Length == 0)
6295 for (int i = 0; i < Count; i++) {
6296 ListViewItem item = this [i];
6297 if (String.Compare (item.Name, key, true) == 0)
6304 #endregion // Public Methods
6306 } // SelectedListViewItemCollection
6308 internal delegate void CollectionChangedHandler ();
6310 struct ItemMatrixLocation
6315 public ItemMatrixLocation (int row, int col)
6342 #endregion // Subclasses
6344 protected override void OnResize (EventArgs e)
6349 protected override void OnMouseLeave (EventArgs e)
6351 base.OnMouseLeave (e);
6355 // ColumnReorder event
6357 static object ColumnReorderedEvent = new object ();
6358 public event ColumnReorderedEventHandler ColumnReordered {
6359 add { Events.AddHandler (ColumnReorderedEvent, value); }
6360 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
6363 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
6365 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
6372 // ColumnWidthChanged
6374 static object ColumnWidthChangedEvent = new object ();
6375 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
6376 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
6377 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
6380 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
6382 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
6387 void RaiseColumnWidthChanged (int resize_column)
6389 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
6391 OnColumnWidthChanged (n);
6395 // ColumnWidthChanging
6397 static object ColumnWidthChangingEvent = new object ();
6398 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
6399 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
6400 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
6403 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6405 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6411 // 2.0 profile based implementation
6413 bool CanProceedWithResize (ColumnHeader col, int width)
6415 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6419 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6420 cwceh (this, changing);
6421 return !changing.Cancel;
6425 // 1.0 profile based implementation
6427 bool CanProceedWithResize (ColumnHeader col, int width)
6432 void RaiseColumnWidthChanged (int resize_column)
6437 internal void RaiseColumnWidthChanged (ColumnHeader column)
6439 int index = Columns.IndexOf (column);
6440 RaiseColumnWidthChanged (index);
6445 #region UIA Framework: Methods, Properties and Events
6447 static object UIALabelEditChangedEvent = new object ();
6448 static object UIAShowGroupsChangedEvent = new object ();
6449 static object UIAMultiSelectChangedEvent = new object ();
6450 static object UIAViewChangedEvent = new object ();
6451 static object UIACheckBoxesChangedEvent = new object ();
6452 static object UIAFocusedItemChangedEvent = new object ();
6454 internal Rectangle UIAHeaderControl {
6455 get { return header_control.Bounds; }
6458 internal int UIAColumns {
6459 get { return cols; }
6462 internal int UIARows {
6463 get { return rows; }
6466 internal ListViewGroup UIADefaultListViewGroup
6468 get { return groups.DefaultGroup; }
6471 internal ScrollBar UIAHScrollBar {
6472 get { return h_scroll; }
6475 internal ScrollBar UIAVScrollBar {
6476 get { return v_scroll; }
6479 internal event EventHandler UIAShowGroupsChanged {
6480 add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6481 remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6484 internal event EventHandler UIACheckBoxesChanged {
6485 add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6486 remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6489 internal event EventHandler UIAMultiSelectChanged {
6490 add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6491 remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6494 internal event EventHandler UIALabelEditChanged {
6495 add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6496 remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6499 internal event EventHandler UIAViewChanged {
6500 add { Events.AddHandler (UIAViewChangedEvent, value); }
6501 remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6504 internal event EventHandler UIAFocusedItemChanged {
6505 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6506 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6509 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6511 return group.HeaderBounds;
6514 internal int UIAItemsLocationLength
6516 get { return items_location.Length; }
6519 private void OnUIACheckBoxesChanged ()
6521 EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6523 eh (this, EventArgs.Empty);
6526 private void OnUIAShowGroupsChanged ()
6528 EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6530 eh (this, EventArgs.Empty);
6533 private void OnUIAMultiSelectChanged ()
6535 EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6537 eh (this, EventArgs.Empty);
6540 private void OnUIALabelEditChanged ()
6542 EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6544 eh (this, EventArgs.Empty);
6547 private void OnUIAViewChanged ()
6549 EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6551 eh (this, EventArgs.Empty);
6554 internal void OnUIAFocusedItemChanged ()
6556 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6558 eh (this, EventArgs.Empty);
6561 #endregion // UIA Framework: Methods, Properties and Events