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;
2044 AdjustChildrenZOrder ();
2046 int item_height = GetDetailsItemHeight ();
2047 ItemSize = new Size (0, item_height); // We only cache Height for details view
2048 int y = header_control.Height;
2049 layout_ht = y + (item_height * items.Count);
2050 if (items.Count > 0 && grid_lines) // some space for bottom gridline
2054 bool using_groups = UsingGroups;
2056 // Observe that this routines will override our layout_ht value
2057 CalculateDetailsGroupItemsCount ();
2058 CalculateGroupsLayout (ItemSize, 2, y);
2061 if (virtual_mode) // no assgination on items is needed
2065 for (int i = 0; i < items.Count; i++) {
2066 ListViewItem item = items [i];
2073 ListViewGroup group = item.Group;
2075 group = groups.DefaultGroup;
2077 int current_item = group.current_item++;
2078 Point group_items_loc = group.items_area_location;
2079 display_index = group.starting_item + current_item;
2081 y = item_y = current_item * (item_height + 2) + group_items_loc.Y;
2082 SetItemLocation (display_index, 0, item_y, 0, 0);
2083 SetItemAtDisplayIndex (display_index, i);
2089 SetItemLocation (i, 0, item_y, 0, 0);
2094 item.DisplayIndex = display_index;
2096 item.SetPosition (new Point (0, item_y));
2101 // Need to make sure HeaderControl is on top, and we can't simply use BringToFront since
2102 // these controls are implicit, so we need to re-populate our collection.
2103 void AdjustChildrenZOrder ()
2106 Controls.ClearImplicit ();
2107 Controls.AddImplicit (header_control);
2108 Controls.AddImplicit (item_control);
2109 Controls.AddImplicit (h_scroll);
2110 Controls.AddImplicit (v_scroll);
2114 private void AdjustItemsPositionArray (int count)
2117 // In virtual mode we compute the positions on the fly.
2121 if (items_location.Length >= count)
2124 // items_location, items_matrix_location and reordered_items_indices must keep the same length
2125 count = Math.Max (count, items_location.Length * 2);
2126 items_location = new Point [count];
2127 items_matrix_location = new ItemMatrixLocation [count];
2128 reordered_items_indices = new int [count];
2131 private void CalculateListView (ListViewAlignment align)
2135 AdjustItemsPositionArray (items.Count);
2142 case View.SmallIcon:
2143 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
2144 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2147 case View.LargeIcon:
2148 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
2149 ThemeEngine.Current.ListViewHorizontalSpacing,
2150 ThemeEngine.Current.ListViewVerticalSpacing);
2154 LayoutIcons (SmallIconItemSize, true,
2155 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2159 if (!Application.VisualStylesEnabled)
2160 goto case View.LargeIcon;
2162 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
2163 ThemeEngine.Current.ListViewHorizontalSpacing,
2164 ThemeEngine.Current.ListViewVerticalSpacing);
2169 CalculateScrollBars ();
2172 internal Point GetItemLocation (int index)
2174 Point loc = Point.Empty;
2177 loc = GetFixedItemLocation (index);
2180 loc = items_location [index];
2182 loc.X -= h_marker; // Adjust to scroll
2189 Point GetFixedItemLocation (int index)
2191 Point loc = Point.Empty;
2194 case View.LargeIcon:
2195 case View.SmallIcon:
2196 loc.X = index % cols * (item_size.Width + x_spacing);
2197 loc.Y = index / cols * (item_size.Height + y_spacing);
2200 loc.X = index / rows * (item_size.Width + x_spacing);
2201 loc.Y = index % rows * (item_size.Height + y_spacing);
2204 loc.Y = header_control.Height + (index * item_size.Height);
2212 internal int GetItemIndex (int display_index)
2216 return display_index; // no reordering in virtual mode.
2218 return reordered_items_indices [display_index];
2221 internal ListViewItem GetItemAtDisplayIndex (int display_index)
2224 // in virtual mode there's no reordering at all.
2226 return items [display_index];
2228 return items [reordered_items_indices [display_index]];
2231 internal void SetItemAtDisplayIndex (int display_index, int index)
2233 reordered_items_indices [display_index] = index;
2236 private bool KeySearchString (KeyEventArgs ke)
2238 int current_tickcnt = Environment.TickCount;
2239 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2240 keysearch_text = string.Empty;
2243 if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2246 keysearch_text += (char)ke.KeyCode;
2247 keysearch_tickcnt = current_tickcnt;
2249 int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex;
2250 int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0;
2252 ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true);
2253 if (item != null && prev_focused != item.DisplayIndex) {
2254 selected_indices.Clear ();
2256 SetFocusedItem (item.DisplayIndex);
2257 item.Selected = true;
2258 EnsureVisible (GetItemIndex (item.DisplayIndex));
2264 private void OnItemsChanged ()
2266 ResetSearchString ();
2269 private void ResetSearchString ()
2271 keysearch_text = String.Empty;
2274 int GetAdjustedIndex (Keys key)
2278 if (View == View.Details) {
2281 result = FocusedItem.DisplayIndex - 1;
2284 result = FocusedItem.DisplayIndex + 1;
2285 if (result == items.Count)
2289 int last_index = LastVisibleIndex;
2290 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2291 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2293 if (FocusedItem.DisplayIndex == last_index) {
2294 if (FocusedItem.DisplayIndex < Items.Count - 1) {
2295 int page_size = item_control.Height / ItemSize.Height - 1;
2296 result = FocusedItem.DisplayIndex + page_size - 1;
2297 if (result >= Items.Count)
2298 result = Items.Count - 1;
2301 result = last_index;
2304 int first_index = FirstVisibleIndex;
2305 if (GetItemLocation (first_index).Y < 0)
2307 if (FocusedItem.DisplayIndex == first_index) {
2308 if (first_index > 0) {
2309 int page_size = item_control.Height / ItemSize.Height - 1;
2310 result = first_index - page_size + 1;
2315 result = first_index;
2323 return GetFixedAdjustedIndex (key);
2326 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex];
2327 int row = item_matrix_location.Row;
2328 int col = item_matrix_location.Col;
2330 int adjusted_index = -1;
2336 adjusted_index = item_index_matrix [row, col - 1];
2340 if (col == (cols - 1))
2342 while (item_index_matrix [row, col + 1] == 0) {
2347 adjusted_index = item_index_matrix [row, col + 1];
2353 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2358 adjusted_index = item_index_matrix [row - 1, col];
2362 if (row == (rows - 1) || row == Items.Count - 1)
2364 while (item_index_matrix [row + 1, col] == 0) {
2369 adjusted_index = item_index_matrix [row + 1, col];
2376 return items [adjusted_index].DisplayIndex;
2380 // Used for virtual mode, where items *cannot* be re-arranged
2381 int GetFixedAdjustedIndex (Keys key)
2387 if (view == View.List)
2388 result = focused_item_index - rows;
2390 result = focused_item_index - 1;
2393 if (view == View.List)
2394 result = focused_item_index + rows;
2396 result = focused_item_index + 1;
2399 if (view != View.List)
2400 result = focused_item_index - cols;
2402 result = focused_item_index - 1;
2405 if (view != View.List)
2406 result = focused_item_index + cols;
2408 result = focused_item_index + 1;
2415 if (result < 0 || result >= items.Count)
2416 result = focused_item_index;
2422 ListViewItem selection_start;
2424 private bool SelectItems (ArrayList sel_items)
2426 bool changed = false;
2427 foreach (ListViewItem item in SelectedItems)
2428 if (!sel_items.Contains (item)) {
2429 item.Selected = false;
2432 foreach (ListViewItem item in sel_items)
2433 if (!item.Selected) {
2434 item.Selected = true;
2440 private void UpdateMultiSelection (int index, bool reselect)
2442 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2443 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2444 ListViewItem item = GetItemAtDisplayIndex (index);
2446 if (shift_pressed && selection_start != null) {
2447 ArrayList list = new ArrayList ();
2448 int start_index = selection_start.DisplayIndex;
2449 int start = Math.Min (start_index, index);
2450 int end = Math.Max (start_index, index);
2451 if (View == View.Details) {
2452 for (int i = start; i <= end; i++)
2453 list.Add (GetItemAtDisplayIndex (i));
2455 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2456 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2457 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2458 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2459 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2460 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2462 for (int i = 0; i < items.Count; i++) {
2463 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2465 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2466 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2467 list.Add (GetItemAtDisplayIndex (i));
2471 } else if (ctrl_pressed) {
2472 item.Selected = !item.Selected;
2473 selection_start = item;
2476 // do not unselect, and reselect the item
2477 foreach (int itemIndex in SelectedIndices) {
2478 if (index == itemIndex)
2480 items [itemIndex].Selected = false;
2483 SelectedItems.Clear ();
2484 item.Selected = true;
2486 selection_start = item;
2490 internal override bool InternalPreProcessMessage (ref Message msg)
2492 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2493 Keys key_data = (Keys)msg.WParam.ToInt32();
2495 HandleNavKeys (key_data);
2498 return base.InternalPreProcessMessage (ref msg);
2501 bool HandleNavKeys (Keys key_data)
2503 if (Items.Count == 0 || !item_control.Visible)
2506 if (FocusedItem == null)
2511 SelectIndex (Items.Count - 1);
2524 SelectIndex (GetAdjustedIndex (key_data));
2528 SelectIndex (focused_item_index);
2529 ToggleItemsCheckState ();
2532 if (selected_indices.Count > 0)
2533 OnItemActivate (EventArgs.Empty);
2543 void ToggleItemsCheckState ()
2548 // Don't modify check state if StateImageList has less than 2 elements
2549 if (StateImageList != null && StateImageList.Images.Count < 2)
2552 if (SelectedIndices.Count > 0) {
2553 for (int i = 0; i < SelectedIndices.Count; i++) {
2554 ListViewItem item = Items [SelectedIndices [i]];
2555 item.Checked = !item.Checked;
2560 if (FocusedItem != null) {
2561 FocusedItem.Checked = !FocusedItem.Checked;
2562 SelectIndex (FocusedItem.Index);
2566 void SelectIndex (int display_index)
2568 if (display_index == -1)
2572 UpdateMultiSelection (display_index, true);
2573 else if (!GetItemAtDisplayIndex (display_index).Selected)
2574 GetItemAtDisplayIndex (display_index).Selected = true;
2576 SetFocusedItem (display_index);
2577 EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index
2580 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2582 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2585 if (ke.Alt || ke.Control)
2588 ke.Handled = KeySearchString (ke);
2591 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2593 Point loc = PointToClient (Control.MousePosition);
2594 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2597 internal class ItemControl : Control {
2600 ListViewItem clicked_item;
2601 ListViewItem last_clicked_item;
2602 bool hover_processed = false;
2603 bool checking = false;
2604 ListViewItem prev_hovered_item;
2606 ListViewItem prev_tooltip_item;
2609 Point drag_begin = new Point (-1, -1);
2610 internal int dragged_item_index = -1;
2612 ListViewLabelEditTextBox edit_text_box;
2613 internal ListViewItem edit_item;
2614 LabelEditEventArgs edit_args;
2616 public ItemControl (ListView owner)
2619 this.SetStyle (ControlStyles.DoubleBuffer, true);
2620 DoubleClick += new EventHandler(ItemsDoubleClick);
2621 MouseDown += new MouseEventHandler(ItemsMouseDown);
2622 MouseMove += new MouseEventHandler(ItemsMouseMove);
2623 MouseHover += new EventHandler(ItemsMouseHover);
2624 MouseUp += new MouseEventHandler(ItemsMouseUp);
2627 void ItemsDoubleClick (object sender, EventArgs e)
2629 if (owner.activation == ItemActivation.Standard)
2630 owner.OnItemActivate (EventArgs.Empty);
2640 BoxSelect box_select_mode = BoxSelect.None;
2641 IList prev_selection;
2642 Point box_select_start;
2644 Rectangle box_select_rect;
2645 internal Rectangle BoxSelectRectangle {
2646 get { return box_select_rect; }
2648 if (box_select_rect == value)
2651 InvalidateBoxSelectRect ();
2652 box_select_rect = value;
2653 InvalidateBoxSelectRect ();
2657 void InvalidateBoxSelectRect ()
2659 if (BoxSelectRectangle.Size.IsEmpty)
2662 Rectangle edge = BoxSelectRectangle;
2668 edge.Y = BoxSelectRectangle.Bottom - 1;
2670 edge.Y = BoxSelectRectangle.Y - 1;
2672 edge.Height = BoxSelectRectangle.Height + 2;
2674 edge.X = BoxSelectRectangle.Right - 1;
2678 private Rectangle CalculateBoxSelectRectangle (Point pt)
2680 int left = Math.Min (box_select_start.X, pt.X);
2681 int right = Math.Max (box_select_start.X, pt.X);
2682 int top = Math.Min (box_select_start.Y, pt.Y);
2683 int bottom = Math.Max (box_select_start.Y, pt.Y);
2684 return Rectangle.FromLTRB (left, top, right, bottom);
2687 bool BoxIntersectsItem (int index)
2689 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2690 if (owner.View != View.Details) {
2692 r.Y += r.Height / 4;
2696 return BoxSelectRectangle.IntersectsWith (r);
2699 bool BoxIntersectsText (int index)
2701 Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds;
2702 return BoxSelectRectangle.IntersectsWith (r);
2705 ArrayList BoxSelectedItems {
2707 ArrayList result = new ArrayList ();
2708 for (int i = 0; i < owner.Items.Count; i++) {
2711 // Can't iterate over specific items properties in virtualmode
2712 if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode)
2714 if (owner.View == View.Details && !owner.FullRowSelect)
2716 intersects = BoxIntersectsText (i);
2718 intersects = BoxIntersectsItem (i);
2721 result.Add (owner.GetItemAtDisplayIndex (i));
2727 private bool PerformBoxSelection (Point pt)
2729 if (box_select_mode == BoxSelect.None)
2732 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2734 ArrayList box_items = BoxSelectedItems;
2738 switch (box_select_mode) {
2740 case BoxSelect.Normal:
2744 case BoxSelect.Control:
2745 items = new ArrayList ();
2746 foreach (int index in prev_selection)
2747 if (!box_items.Contains (owner.Items [index]))
2748 items.Add (owner.Items [index]);
2749 foreach (ListViewItem item in box_items)
2750 if (!prev_selection.Contains (item.Index))
2754 case BoxSelect.Shift:
2756 foreach (ListViewItem item in box_items)
2757 prev_selection.Remove (item.Index);
2758 foreach (int index in prev_selection)
2759 items.Add (owner.Items [index]);
2763 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2767 owner.SelectItems (items);
2773 private void ItemsMouseDown (object sender, MouseEventArgs me)
2775 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2776 if (owner.items.Count == 0)
2779 bool box_selecting = false;
2780 Size item_size = owner.ItemSize;
2781 Point pt = new Point (me.X, me.Y);
2782 for (int i = 0; i < owner.items.Count; i++) {
2783 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2784 if (!item_rect.Contains (pt))
2787 // Actual item in 'i' position
2788 ListViewItem item = owner.GetItemAtDisplayIndex (i);
2790 if (item.CheckRectReal.Contains (pt)) {
2791 // Don't modify check state if we have only one image
2792 // and if we are in 1.1 profile only take into account
2794 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2801 // Generate an extra ItemCheck event when we got two clicks
2802 // (Match weird .Net behaviour)
2804 item.Checked = !item.Checked;
2806 item.Checked = !item.Checked;
2811 if (owner.View == View.Details) {
2812 bool over_text = item.TextBounds.Contains (pt);
2813 if (owner.FullRowSelect) {
2814 clicked_item = item;
2815 bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2816 if (!over_text && over_item_column && owner.MultiSelect)
2817 box_selecting = true;
2818 } else if (over_text)
2819 clicked_item = item;
2821 owner.SetFocusedItem (i);
2823 clicked_item = item;
2829 if (clicked_item != null) {
2830 bool changed = !clicked_item.Selected;
2831 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2832 owner.SetFocusedItem (clicked_item.DisplayIndex);
2834 if (owner.MultiSelect) {
2835 bool reselect = (!owner.LabelEdit || changed);
2836 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2837 owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect);
2839 clicked_item.Selected = true;
2843 if (owner.VirtualMode && changed) {
2844 // Broken event - It's not fired from Item.Selected also
2845 ListViewVirtualItemsSelectionRangeChangedEventArgs args =
2846 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2848 owner.OnVirtualItemsSelectionRangeChanged (args);
2851 // Report clicks only if the item was clicked. On MS the
2852 // clicks are only raised if you click an item
2854 if (me.Clicks > 1) {
2855 if (owner.CheckBoxes)
2856 clicked_item.Checked = !clicked_item.Checked;
2857 } else if (me.Clicks == 1) {
2858 if (owner.LabelEdit && !changed)
2859 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2862 drag_begin = me.Location;
2863 dragged_item_index = clicked_item.Index;
2865 if (owner.MultiSelect)
2866 box_selecting = true;
2867 else if (owner.SelectedItems.Count > 0)
2868 owner.SelectedItems.Clear ();
2871 if (box_selecting) {
2872 Keys mods = XplatUI.State.ModifierKeys;
2873 if ((mods & Keys.Shift) != 0)
2874 box_select_mode = BoxSelect.Shift;
2875 else if ((mods & Keys.Control) != 0)
2876 box_select_mode = BoxSelect.Control;
2878 box_select_mode = BoxSelect.Normal;
2879 box_select_start = pt;
2880 prev_selection = owner.SelectedIndices.List.Clone () as IList;
2884 private void ItemsMouseMove (object sender, MouseEventArgs me)
2886 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2888 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2892 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2893 !hover_processed && owner.Activation != ItemActivation.OneClick
2895 && !owner.ShowItemToolTips
2900 Point pt = PointToClient (Control.MousePosition);
2901 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2903 if (hover_processed && item != null && item != prev_hovered_item) {
2904 hover_processed = false;
2905 XplatUI.ResetMouseHover (Handle);
2908 // Need to invalidate the item in HotTracking to show/hide the underline style
2909 if (owner.Activation == ItemActivation.OneClick) {
2910 if (item == null && owner.HotItemIndex != -1) {
2912 if (owner.HotTracking)
2913 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2916 Cursor = Cursors.Default;
2917 owner.HotItemIndex = -1;
2918 } else if (item != null && owner.HotItemIndex == -1) {
2920 if (owner.HotTracking)
2921 Invalidate (item.Bounds);
2924 Cursor = Cursors.Hand;
2925 owner.HotItemIndex = item.Index;
2929 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2930 if (drag_begin != new Point (-1, -1)) {
2931 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2932 if (!r.Contains (me.X, me.Y)) {
2933 ListViewItem dragged_item = owner.items [dragged_item_index];
2934 owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2936 drag_begin = new Point (-1, -1);
2937 dragged_item_index = -1;
2943 if (owner.ShowItemToolTips) {
2945 owner.item_tooltip.Active = false;
2946 prev_tooltip_item = null;
2947 } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2948 owner.item_tooltip.Active = true;
2949 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2950 prev_tooltip_item = item;
2957 private void ItemsMouseHover (object sender, EventArgs e)
2959 if (owner.hover_pending) {
2960 owner.OnMouseHover (e);
2961 owner.hover_pending = false;
2967 hover_processed = true;
2968 Point pt = PointToClient (Control.MousePosition);
2969 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2973 prev_hovered_item = item;
2975 if (owner.HoverSelection) {
2976 if (owner.MultiSelect)
2977 owner.UpdateMultiSelection (item.Index, true);
2979 item.Selected = true;
2981 owner.SetFocusedItem (item.DisplayIndex);
2982 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2986 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2990 void HandleClicks (MouseEventArgs me)
2992 // if the click is not on an item,
2993 // clicks remains as 0
2996 owner.OnDoubleClick (EventArgs.Empty);
2997 } else if (clicks == 1) {
2998 owner.OnClick (EventArgs.Empty);
3000 owner.OnDoubleClick (EventArgs.Empty);
3001 owner.OnMouseDoubleClick (me);
3002 } else if (clicks == 1) {
3003 owner.OnClick (EventArgs.Empty);
3004 owner.OnMouseClick (me);
3011 private void ItemsMouseUp (object sender, MouseEventArgs me)
3013 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
3014 HandleClicks (owner_me);
3017 if (owner.Items.Count == 0) {
3019 owner.OnMouseUp (owner_me);
3023 Point pt = new Point (me.X, me.Y);
3025 Rectangle rect = Rectangle.Empty;
3026 if (clicked_item != null) {
3027 if (owner.view == View.Details && !owner.full_row_select)
3028 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
3030 rect = clicked_item.Bounds;
3032 if (rect.Contains (pt)) {
3033 switch (owner.activation) {
3034 case ItemActivation.OneClick:
3035 owner.OnItemActivate (EventArgs.Empty);
3038 case ItemActivation.TwoClick:
3039 if (last_clicked_item == clicked_item) {
3040 owner.OnItemActivate (EventArgs.Empty);
3041 last_clicked_item = null;
3043 last_clicked_item = clicked_item;
3046 // DoubleClick activation is handled in another handler
3050 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
3051 // Need this to clean up background clicks
3052 owner.SelectedItems.Clear ();
3056 owner.OnMouseUp (owner_me);
3059 private void ResetMouseState ()
3061 clicked_item = null;
3062 box_select_start = Point.Empty;
3063 BoxSelectRectangle = Rectangle.Empty;
3064 prev_selection = null;
3065 box_select_mode = BoxSelect.None;
3068 // Clean these bits in case the mouse buttons were
3069 // released before firing ItemDrag
3070 dragged_item_index = -1;
3071 drag_begin = new Point (-1, -1);
3074 private void LabelEditFinished (object sender, EventArgs e)
3076 EndEdit (edit_item);
3079 private void LabelEditCancelled (object sender, EventArgs e)
3081 edit_args.SetLabel (null);
3082 EndEdit (edit_item);
3085 private void LabelTextChanged (object sender, EventArgs e)
3087 if (edit_args != null)
3088 edit_args.SetLabel (edit_text_box.Text);
3091 internal void BeginEdit (ListViewItem item)
3093 if (edit_item != null)
3094 EndEdit (edit_item);
3096 if (edit_text_box == null) {
3097 edit_text_box = new ListViewLabelEditTextBox ();
3098 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
3099 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
3100 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
3101 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
3102 edit_text_box.Visible = false;
3103 Controls.Add (edit_text_box);
3106 item.EnsureVisible();
3108 edit_text_box.Reset ();
3110 switch (owner.view) {
3112 case View.SmallIcon:
3114 edit_text_box.TextAlign = HorizontalAlignment.Left;
3115 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
3116 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
3117 edit_text_box.Width = (int)sizef.Width + 4;
3118 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
3119 edit_text_box.WordWrap = false;
3120 edit_text_box.Multiline = false;
3122 case View.LargeIcon:
3123 edit_text_box.TextAlign = HorizontalAlignment.Center;
3124 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
3125 sizef = TextRenderer.MeasureString (item.Text, item.Font);
3126 edit_text_box.Width = (int)sizef.Width + 4;
3127 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
3128 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
3129 edit_text_box.WordWrap = true;
3130 edit_text_box.Multiline = true;
3136 edit_text_box.Text = item.Text;
3137 edit_text_box.Font = item.Font;
3138 edit_text_box.Visible = true;
3139 edit_text_box.Focus ();
3140 edit_text_box.SelectAll ();
3142 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
3143 owner.OnBeforeLabelEdit (edit_args);
3145 if (edit_args.CancelEdit)
3149 internal void CancelEdit (ListViewItem item)
3151 // do nothing if there's no item being edited, or if the
3152 // item being edited is not the one passed in
3153 if (edit_item == null || edit_item != item)
3156 edit_args.SetLabel (null);
3160 internal void EndEdit (ListViewItem item)
3162 // do nothing if there's no item being edited, or if the
3163 // item being edited is not the one passed in
3164 if (edit_item == null || edit_item != item)
3167 if (edit_text_box != null) {
3168 if (edit_text_box.Visible)
3169 edit_text_box.Visible = false;
3170 // ensure listview gets focus
3174 // Same as TreeView.EndEdit: need to have focus in synch
3175 Application.DoEvents ();
3178 // Create a new instance, since we could get a call to BeginEdit
3179 // from the handler and have fields out of synch
3181 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
3184 owner.OnAfterLabelEdit (args);
3185 if (!args.CancelEdit && args.Label != null)
3186 item.Text = args.Label;
3189 internal override void OnPaintInternal (PaintEventArgs pe)
3191 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
3194 protected override void WndProc (ref Message m)
3196 switch ((Msg)m.Msg) {
3197 case Msg.WM_KILLFOCUS:
3198 owner.Select (false, true);
3200 case Msg.WM_SETFOCUS:
3201 owner.Select (false, true);
3203 case Msg.WM_LBUTTONDOWN:
3205 owner.Select (false, true);
3207 case Msg.WM_RBUTTONDOWN:
3209 owner.Select (false, true);
3214 base.WndProc (ref m);
3218 internal class ListViewLabelEditTextBox : TextBox
3223 int max_height = -1;
3224 int min_height = -1;
3226 int old_number_lines = 1;
3228 SizeF text_size_one_char;
3230 public ListViewLabelEditTextBox ()
3232 min_height = DefaultSize.Height;
3233 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3236 public int MaxWidth {
3238 if (value < min_width)
3239 max_width = min_width;
3245 public int MaxHeight {
3247 if (value < min_height)
3248 max_height = min_height;
3254 public new int Width {
3264 public override Font Font {
3270 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3274 protected override void OnTextChanged (EventArgs e)
3276 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3278 int new_width = (int)text_size.Width + 8;
3281 ResizeTextBoxWidth (new_width);
3283 if (Width != max_width)
3284 ResizeTextBoxWidth (new_width);
3286 int number_lines = Lines.Length;
3288 if (number_lines != old_number_lines) {
3289 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3290 old_number_lines = number_lines;
3292 ResizeTextBoxHeight (new_height);
3296 base.OnTextChanged (e);
3299 protected override bool IsInputKey (Keys key_data)
3301 if ((key_data & Keys.Alt) == 0) {
3302 switch (key_data & Keys.KeyCode) {
3309 return base.IsInputKey (key_data);
3312 protected override void OnKeyDown (KeyEventArgs e)
3317 switch (e.KeyCode) {
3321 OnEditingFinished (e);
3326 OnEditingCancelled (e);
3331 protected override void OnLostFocus (EventArgs e)
3334 OnEditingFinished (e);
3338 protected void OnEditingCancelled (EventArgs e)
3340 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3345 protected void OnEditingFinished (EventArgs e)
3347 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3352 private void ResizeTextBoxWidth (int new_width)
3354 if (new_width > max_width)
3355 base.Width = max_width;
3357 if (new_width >= min_width)
3358 base.Width = new_width;
3360 base.Width = min_width;
3363 private void ResizeTextBoxHeight (int new_height)
3365 if (new_height > max_height)
3366 base.Height = max_height;
3368 if (new_height >= min_height)
3369 base.Height = new_height;
3371 base.Height = min_height;
3374 public void Reset ()
3381 old_number_lines = 1;
3383 Text = String.Empty;
3388 static object EditingCancelledEvent = new object ();
3389 public event EventHandler EditingCancelled {
3390 add { Events.AddHandler (EditingCancelledEvent, value); }
3391 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3394 static object EditingFinishedEvent = new object ();
3395 public event EventHandler EditingFinished {
3396 add { Events.AddHandler (EditingFinishedEvent, value); }
3397 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3401 internal override void OnPaintInternal (PaintEventArgs pe)
3406 CalculateScrollBars ();
3409 void FocusChanged (object o, EventArgs args)
3411 if (Items.Count == 0)
3414 if (FocusedItem == null)
3417 ListViewItem focused_item = FocusedItem;
3419 if (focused_item.ListView != null) {
3420 focused_item.Invalidate ();
3421 focused_item.Layout ();
3422 focused_item.Invalidate ();
3426 private void ListView_Invalidated (object sender, InvalidateEventArgs e)
3428 // When the ListView is invalidated, we need to invalidate
3429 // the child controls.
3430 header_control.Invalidate ();
3431 item_control.Invalidate ();
3434 private void ListView_MouseEnter (object sender, EventArgs args)
3436 hover_pending = true; // Need a hover event for every Enter/Leave cycle
3439 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3441 if (Items.Count == 0)
3444 int lines = me.Delta / 120;
3451 case View.SmallIcon:
3452 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3454 case View.LargeIcon:
3455 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
3458 Scroll (h_scroll, -ItemSize.Width * lines);
3462 if (!Application.VisualStylesEnabled)
3463 goto case View.LargeIcon;
3465 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3471 private void ListView_SizeChanged (object sender, EventArgs e)
3476 private void SetFocusedItem (int display_index)
3478 if (display_index != -1)
3479 GetItemAtDisplayIndex (display_index).Focused = true;
3480 else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3481 GetItemAtDisplayIndex (focused_item_index).Focused = false;
3482 focused_item_index = display_index;
3484 if (display_index == -1)
3485 OnUIAFocusedItemChanged ();
3486 // otherwise the event will have been fired
3487 // when the ListViewItem's Focused was set
3491 private void HorizontalScroller (object sender, EventArgs e)
3493 item_control.EndEdit (item_control.edit_item);
3495 // Avoid unnecessary flickering, when button is
3496 // kept pressed at the end
3497 if (h_marker != h_scroll.Value) {
3499 int pixels = h_marker - h_scroll.Value;
3501 h_marker = h_scroll.Value;
3502 if (header_control.Visible)
3503 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3505 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3509 private void VerticalScroller (object sender, EventArgs e)
3511 item_control.EndEdit (item_control.edit_item);
3513 // Avoid unnecessary flickering, when button is
3514 // kept pressed at the end
3515 if (v_marker != v_scroll.Value) {
3516 int pixels = v_marker - v_scroll.Value;
3517 Rectangle area = item_control.ClientRectangle;
3518 if (header_control.Visible) {
3519 area.Y += header_control.Height;
3520 area.Height -= header_control.Height;
3523 v_marker = v_scroll.Value;
3524 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3528 internal override bool IsInputCharInternal (char charCode)
3532 #endregion // Internal Methods Properties
3534 #region Protected Methods
3535 protected override void CreateHandle ()
3537 base.CreateHandle ();
3538 is_selection_available = true;
3539 for (int i = 0; i < SelectedItems.Count; i++)
3540 OnSelectedIndexChanged (EventArgs.Empty);
3543 protected override void Dispose (bool disposing)
3546 large_image_list = null;
3547 small_image_list = null;
3548 state_image_list = null;
3550 foreach (ColumnHeader col in columns)
3551 col.SetListView (null);
3554 if (!virtual_mode) // In virtual mode we don't save the items
3556 foreach (ListViewItem item in items)
3560 base.Dispose (disposing);
3563 protected override bool IsInputKey (Keys keyData)
3580 return base.IsInputKey (keyData);
3583 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3585 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3591 protected override void OnBackgroundImageChanged (EventArgs e)
3593 item_control.BackgroundImage = BackgroundImage;
3594 base.OnBackgroundImageChanged (e);
3598 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3600 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3605 protected internal virtual void OnColumnClick (ColumnClickEventArgs e)
3607 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3613 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3615 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3620 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3622 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3627 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3629 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3635 protected override void OnEnabledChanged (EventArgs e)
3637 base.OnEnabledChanged (e);
3641 protected override void OnFontChanged (EventArgs e)
3643 base.OnFontChanged (e);
3647 protected override void OnHandleCreated (EventArgs e)
3649 base.OnHandleCreated (e);
3650 CalculateListView (alignment);
3652 if (!virtual_mode) // Sorting is not allowed in virtual mode
3657 protected override void OnHandleDestroyed (EventArgs e)
3659 base.OnHandleDestroyed (e);
3662 protected virtual void OnItemActivate (EventArgs e)
3664 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3669 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3671 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3677 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3679 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3685 protected virtual void OnItemDrag (ItemDragEventArgs e)
3687 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3693 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3695 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3700 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3702 ListViewItemSelectionChangedEventHandler eh =
3703 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3708 protected override void OnMouseHover (EventArgs e)
3710 base.OnMouseHover (e);
3713 protected override void OnParentChanged (EventArgs e)
3715 base.OnParentChanged (e);
3719 protected virtual void OnSelectedIndexChanged (EventArgs e)
3721 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3726 protected override void OnSystemColorsChanged (EventArgs e)
3728 base.OnSystemColorsChanged (e);
3732 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3734 CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3739 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3741 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3746 [EditorBrowsable (EditorBrowsableState.Advanced)]
3747 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3749 EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3754 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3756 SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3761 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3763 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3764 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3770 protected void RealizeProperties ()
3775 protected void UpdateExtendedStyles ()
3780 bool refocusing = false;
3782 protected override void WndProc (ref Message m)
3784 switch ((Msg)m.Msg) {
3785 case Msg.WM_KILLFOCUS:
3786 Control receiver = Control.FromHandle (m.WParam);
3787 if (receiver == item_control) {
3793 case Msg.WM_SETFOCUS:
3803 base.WndProc (ref m);
3805 #endregion // Protected Methods
3807 #region Public Instance Methods
3808 public void ArrangeIcons ()
3810 ArrangeIcons (this.alignment);
3813 public void ArrangeIcons (ListViewAlignment value)
3815 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3816 if (view == View.LargeIcon || view == View.SmallIcon)
3821 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3823 if (columnIndex < 0 || columnIndex >= columns.Count)
3824 throw new ArgumentOutOfRangeException ("columnIndex");
3826 columns [columnIndex].AutoResize (headerAutoResize);
3829 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3832 foreach (ColumnHeader col in columns)
3833 col.AutoResize (headerAutoResize);
3838 public void BeginUpdate ()
3840 // flag to avoid painting
3844 public void Clear ()
3847 items.Clear (); // Redraw (true) called here
3850 public void EndUpdate ()
3852 // flag to avoid painting
3855 // probably, now we need a redraw with recalculations
3859 public void EnsureVisible (int index)
3861 if (index < 0 || index >= items.Count || scrollable == false || updating)
3864 Rectangle view_rect = item_control.ClientRectangle;
3866 // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items
3867 Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds;
3869 Rectangle bounds = items [index].Bounds;
3872 if (view == View.Details && header_style != ColumnHeaderStyle.None) {
3873 view_rect.Y += header_control.Height;
3874 view_rect.Height -= header_control.Height;
3877 if (view_rect.Contains (bounds))
3880 if (View != View.Details) {
3881 if (bounds.Left < 0)
3882 h_scroll.Value += bounds.Left;
3883 else if (bounds.Right > view_rect.Right)
3884 h_scroll.Value += (bounds.Right - view_rect.Right);
3887 if (bounds.Top < view_rect.Y)
3888 v_scroll.Value += bounds.Top - view_rect.Y;
3889 else if (bounds.Bottom > view_rect.Bottom)
3890 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3894 public ListViewItem FindItemWithText (string text)
3896 if (items.Count == 0)
3899 return FindItemWithText (text, true, 0, true);
3902 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3904 return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3907 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3909 return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3913 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3915 if (startIndex < 0 || startIndex >= items.Count)
3916 throw new ArgumentOutOfRangeException ("startIndex");
3919 throw new ArgumentNullException ("text");
3923 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3924 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty,
3925 SearchDirectionHint.Down, startIndex);
3927 OnSearchForVirtualItem (args);
3928 int idx = args.Index;
3929 if (idx >= 0 && idx < virtual_list_size)
3938 ListViewItem lvi = items [i];
3940 if (isPrefixSearch) { // prefix search
3941 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3943 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3946 if (i + 1 >= items.Count) {
3954 if (i == startIndex)
3958 // Subitems have a minor priority, so we have to do a second linear search
3959 // Also, we don't need to to a roundtrip search for them by now
3960 if (includeSubItemsInSearch) {
3961 for (i = startIndex; i < items.Count; i++) {
3962 ListViewItem lvi = items [i];
3963 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3964 if (isPrefixSearch) {
3965 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text,
3966 text, CompareOptions.IgnoreCase))
3968 } else if (String.Compare (sub_item.Text, text, true) == 0)
3977 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3979 return FindNearestItem (searchDirection, new Point (x, y));
3982 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3984 if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3985 throw new ArgumentOutOfRangeException ("searchDirection");
3987 if (view != View.LargeIcon && view != View.SmallIcon)
3988 throw new InvalidOperationException ();
3991 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3992 false, false, String.Empty, point,
3995 OnSearchForVirtualItem (args);
3996 int idx = args.Index;
3997 if (idx >= 0 && idx < virtual_list_size)
4003 ListViewItem item = null;
4004 int min_dist = Int32.MaxValue;
4007 // It looks like .Net does a previous adjustment
4010 case SearchDirectionHint.Up:
4011 point.Y -= item_size.Height;
4013 case SearchDirectionHint.Down:
4014 point.Y += item_size.Height;
4016 case SearchDirectionHint.Left:
4017 point.X -= item_size.Width;
4019 case SearchDirectionHint.Right:
4020 point.X += item_size.Width;
4024 for (int i = 0; i < items.Count; i++) {
4025 Point item_loc = GetItemLocation (i);
4027 if (dir == SearchDirectionHint.Up) {
4028 if (point.Y < item_loc.Y)
4030 } else if (dir == SearchDirectionHint.Down) {
4031 if (point.Y > item_loc.Y)
4033 } else if (dir == SearchDirectionHint.Left) {
4034 if (point.X < item_loc.X)
4036 } else if (dir == SearchDirectionHint.Right) {
4037 if (point.X > item_loc.X)
4041 int x_dist = point.X - item_loc.X;
4042 int y_dist = point.Y - item_loc.Y;
4044 int dist = x_dist * x_dist + y_dist * y_dist;
4045 if (dist < min_dist) {
4055 public ListViewItem GetItemAt (int x, int y)
4057 Size item_size = ItemSize;
4058 for (int i = 0; i < items.Count; i++) {
4059 Point item_location = GetItemLocation (i);
4060 Rectangle item_rect = new Rectangle (item_location, item_size);
4061 if (item_rect.Contains (x, y))
4068 public Rectangle GetItemRect (int index)
4070 return GetItemRect (index, ItemBoundsPortion.Entire);
4073 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
4075 if (index < 0 || index >= items.Count)
4076 throw new IndexOutOfRangeException ("index");
4078 return items [index].GetBounds (portion);
4082 public ListViewHitTestInfo HitTest (Point point)
4084 return HitTest (point.X, point.Y);
4087 public ListViewHitTestInfo HitTest (int x, int y)
4090 throw new ArgumentOutOfRangeException ("x");
4092 throw new ArgumentOutOfRangeException ("y");
4094 ListViewItem item = GetItemAt (x, y);
4096 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
4098 ListViewHitTestLocations locations = 0;
4099 if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
4100 locations |= ListViewHitTestLocations.Label;
4101 else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
4102 locations |= ListViewHitTestLocations.Image;
4103 else if (item.CheckRectReal.Contains (x, y))
4104 locations |= ListViewHitTestLocations.StateImage;
4106 ListViewItem.ListViewSubItem subitem = null;
4107 if (view == View.Details)
4108 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
4109 if (si.Bounds.Contains (x, y)) {
4114 return new ListViewHitTestInfo (item, subitem, locations);
4117 [EditorBrowsable (EditorBrowsableState.Advanced)]
4118 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
4120 if (startIndex < 0 || startIndex >= items.Count)
4121 throw new ArgumentOutOfRangeException ("startIndex");
4122 if (endIndex < 0 || endIndex >= items.Count)
4123 throw new ArgumentOutOfRangeException ("endIndex");
4124 if (startIndex > endIndex)
4125 throw new ArgumentException ("startIndex");
4130 for (int i = startIndex; i <= endIndex; i++)
4131 items [i].Invalidate ();
4133 if (!invalidateOnly)
4142 throw new InvalidOperationException ();
4148 // we need this overload to reuse the logic for sorting, while allowing
4149 // redrawing to be done by caller or have it done by this method when
4150 // sorting is really performed
4152 // ListViewItemCollection's Add and AddRange methods call this overload
4153 // with redraw set to false, as they take care of redrawing themselves
4154 // (they even want to redraw the listview if no sort is performed, as
4155 // an item was added), while ListView.Sort () only wants to redraw if
4156 // sorting was actually performed
4157 private void Sort (bool redraw)
4159 if (!IsHandleCreated || item_sorter == null) {
4163 items.Sort (item_sorter);
4168 public override string ToString ()
4170 int count = this.Items.Count;
4173 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
4175 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
4177 #endregion // Public Instance Methods
4182 internal class HeaderControl : Control {
4185 bool column_resize_active = false;
4186 ColumnHeader resize_column;
4187 ColumnHeader clicked_column;
4188 ColumnHeader drag_column;
4190 int drag_to_index = -1;
4191 ColumnHeader entered_column_header;
4193 public HeaderControl (ListView owner)
4196 this.SetStyle (ControlStyles.DoubleBuffer, true);
4197 MouseDown += new MouseEventHandler (HeaderMouseDown);
4198 MouseMove += new MouseEventHandler (HeaderMouseMove);
4199 MouseUp += new MouseEventHandler (HeaderMouseUp);
4200 MouseLeave += new EventHandler (OnMouseLeave);
4203 internal ColumnHeader EnteredColumnHeader {
4204 get { return entered_column_header; }
4206 if (entered_column_header == value)
4208 if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
4209 Region region_to_invalidate = new Region ();
4210 region_to_invalidate.MakeEmpty ();
4211 if (entered_column_header != null)
4212 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4213 entered_column_header = value;
4214 if (entered_column_header != null)
4215 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4216 Invalidate (region_to_invalidate);
4217 region_to_invalidate.Dispose ();
4219 entered_column_header = value;
4223 void OnMouseLeave (object sender, EventArgs e)
4225 EnteredColumnHeader = null;
4228 private ColumnHeader ColumnAtX (int x)
4230 Point pt = new Point (x, 0);
4231 ColumnHeader result = null;
4232 foreach (ColumnHeader col in owner.Columns) {
4233 if (col.Rect.Contains (pt)) {
4241 private int GetReorderedIndex (ColumnHeader col)
4243 if (owner.reordered_column_indices == null)
4246 for (int i = 0; i < owner.Columns.Count; i++)
4247 if (owner.reordered_column_indices [i] == col.Index)
4249 throw new Exception ("Column index missing from reordered array");
4252 private void HeaderMouseDown (object sender, MouseEventArgs me)
4254 if (resize_column != null) {
4255 column_resize_active = true;
4260 clicked_column = ColumnAtX (me.X + owner.h_marker);
4262 if (clicked_column != null) {
4264 if (owner.AllowColumnReorder) {
4266 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4267 drag_column.Rect = clicked_column.Rect;
4268 drag_to_index = GetReorderedIndex (clicked_column);
4270 clicked_column.Pressed = true;
4271 Invalidate (clicked_column);
4276 void Invalidate (ColumnHeader columnHeader)
4278 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4281 Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4283 Rectangle bounds = columnHeader.Rect;
4284 bounds.X -= owner.h_marker;
4290 column_resize_active = false;
4291 resize_column = null;
4293 Cursor = Cursors.Default;
4296 private void HeaderMouseMove (object sender, MouseEventArgs me)
4298 Point pt = new Point (me.X + owner.h_marker, me.Y);
4300 if (column_resize_active) {
4301 int width = pt.X - resize_column.X;
4305 if (!owner.CanProceedWithResize (resize_column, width)){
4309 resize_column.Width = width;
4313 resize_column = null;
4315 if (clicked_column != null) {
4316 if (owner.AllowColumnReorder) {
4319 r = drag_column.Rect;
4320 r.X = clicked_column.Rect.X + me.X - drag_x;
4321 drag_column.Rect = r;
4323 int x = me.X + owner.h_marker;
4324 ColumnHeader over = ColumnAtX (x);
4326 drag_to_index = owner.Columns.Count;
4327 else if (x < over.X + over.Width / 2)
4328 drag_to_index = GetReorderedIndex (over);
4330 drag_to_index = GetReorderedIndex (over) + 1;
4333 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4334 bool pressed = clicked_column.Pressed;
4335 clicked_column.Pressed = over == clicked_column;
4336 if (clicked_column.Pressed ^ pressed)
4337 Invalidate (clicked_column);
4342 for (int i = 0; i < owner.Columns.Count; i++) {
4343 Rectangle zone = owner.Columns [i].Rect;
4344 if (zone.Contains (pt))
4345 EnteredColumnHeader = owner.Columns [i];
4346 zone.X = zone.Right - 5;
4348 if (zone.Contains (pt)) {
4349 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4351 resize_column = owner.Columns [i];
4356 if (resize_column == null)
4357 Cursor = Cursors.Default;
4359 Cursor = Cursors.VSplit;
4362 void HeaderMouseUp (object sender, MouseEventArgs me)
4366 if (column_resize_active) {
4367 int column_idx = resize_column.Index;
4369 owner.RaiseColumnWidthChanged (column_idx);
4373 if (clicked_column != null && clicked_column.Pressed) {
4374 clicked_column.Pressed = false;
4375 Invalidate (clicked_column);
4376 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4379 if (drag_column != null && owner.AllowColumnReorder) {
4381 if (drag_to_index > GetReorderedIndex (clicked_column))
4383 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4384 owner.ReorderColumn (clicked_column, drag_to_index, true);
4389 clicked_column = null;
4392 internal override void OnPaintInternal (PaintEventArgs pe)
4397 Theme theme = ThemeEngine.Current;
4398 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4400 if (drag_column == null)
4404 if (drag_to_index == owner.Columns.Count)
4405 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4407 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4408 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4411 protected override void WndProc (ref Message m)
4413 switch ((Msg)m.Msg) {
4414 case Msg.WM_SETFOCUS:
4418 base.WndProc (ref m);
4424 private class ItemComparer : IComparer {
4425 readonly SortOrder sort_order;
4427 public ItemComparer (SortOrder sortOrder)
4429 sort_order = sortOrder;
4432 public int Compare (object x, object y)
4434 ListViewItem item_x = x as ListViewItem;
4435 ListViewItem item_y = y as ListViewItem;
4436 if (sort_order == SortOrder.Ascending)
4437 return String.Compare (item_x.Text, item_y.Text);
4439 return String.Compare (item_y.Text, item_x.Text);
4444 [ListBindable (false)]
4446 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4448 private readonly ListView owner;
4450 #region Public Constructor
4451 public CheckedIndexCollection (ListView owner)
4455 #endregion // Public Constructor
4457 #region Public Properties
4460 get { return owner.CheckedItems.Count; }
4463 public bool IsReadOnly {
4464 get { return true; }
4467 public int this [int index] {
4469 int [] indices = GetIndices ();
4470 if (index < 0 || index >= indices.Length)
4471 throw new ArgumentOutOfRangeException ("index");
4472 return indices [index];
4476 bool ICollection.IsSynchronized {
4477 get { return false; }
4480 object ICollection.SyncRoot {
4481 get { return this; }
4484 bool IList.IsFixedSize {
4485 get { return true; }
4488 object IList.this [int index] {
4489 get { return this [index]; }
4490 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4492 #endregion // Public Properties
4494 #region Public Methods
4495 public bool Contains (int checkedIndex)
4497 int [] indices = GetIndices ();
4498 for (int i = 0; i < indices.Length; i++) {
4499 if (indices [i] == checkedIndex)
4505 public IEnumerator GetEnumerator ()
4507 int [] indices = GetIndices ();
4508 return indices.GetEnumerator ();
4511 void ICollection.CopyTo (Array dest, int index)
4513 int [] indices = GetIndices ();
4514 Array.Copy (indices, 0, dest, index, indices.Length);
4517 int IList.Add (object value)
4519 throw new NotSupportedException ("Add operation is not supported.");
4524 throw new NotSupportedException ("Clear operation is not supported.");
4527 bool IList.Contains (object checkedIndex)
4529 if (!(checkedIndex is int))
4531 return Contains ((int) checkedIndex);
4534 int IList.IndexOf (object checkedIndex)
4536 if (!(checkedIndex is int))
4538 return IndexOf ((int) checkedIndex);
4541 void IList.Insert (int index, object value)
4543 throw new NotSupportedException ("Insert operation is not supported.");
4546 void IList.Remove (object value)
4548 throw new NotSupportedException ("Remove operation is not supported.");
4551 void IList.RemoveAt (int index)
4553 throw new NotSupportedException ("RemoveAt operation is not supported.");
4556 public int IndexOf (int checkedIndex)
4558 int [] indices = GetIndices ();
4559 for (int i = 0; i < indices.Length; i++) {
4560 if (indices [i] == checkedIndex)
4565 #endregion // Public Methods
4567 private int [] GetIndices ()
4569 ArrayList checked_items = owner.CheckedItems.List;
4570 int [] indices = new int [checked_items.Count];
4571 for (int i = 0; i < checked_items.Count; i++) {
4572 ListViewItem item = (ListViewItem) checked_items [i];
4573 indices [i] = item.Index;
4577 } // CheckedIndexCollection
4580 [ListBindable (false)]
4582 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4584 private readonly ListView owner;
4585 private ArrayList list;
4587 #region Public Constructor
4588 public CheckedListViewItemCollection (ListView owner)
4591 this.owner.Items.Changed += new CollectionChangedHandler (
4592 ItemsCollection_Changed);
4594 #endregion // Public Constructor
4596 #region Public Properties
4600 if (!owner.CheckBoxes)
4606 public bool IsReadOnly {
4607 get { return true; }
4610 public ListViewItem this [int index] {
4613 if (owner.VirtualMode)
4614 throw new InvalidOperationException ();
4616 ArrayList checked_items = List;
4617 if (index < 0 || index >= checked_items.Count)
4618 throw new ArgumentOutOfRangeException ("index");
4619 return (ListViewItem) checked_items [index];
4624 public virtual ListViewItem this [string key] {
4626 int idx = IndexOfKey (key);
4627 return idx == -1 ? null : (ListViewItem) List [idx];
4632 bool ICollection.IsSynchronized {
4633 get { return false; }
4636 object ICollection.SyncRoot {
4637 get { return this; }
4640 bool IList.IsFixedSize {
4641 get { return true; }
4644 object IList.this [int index] {
4645 get { return this [index]; }
4646 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4648 #endregion // Public Properties
4650 #region Public Methods
4651 public bool Contains (ListViewItem item)
4653 if (!owner.CheckBoxes)
4655 return List.Contains (item);
4659 public virtual bool ContainsKey (string key)
4661 return IndexOfKey (key) != -1;
4665 public void CopyTo (Array dest, int index)
4668 if (owner.VirtualMode)
4669 throw new InvalidOperationException ();
4671 if (!owner.CheckBoxes)
4673 List.CopyTo (dest, index);
4676 public IEnumerator GetEnumerator ()
4679 if (owner.VirtualMode)
4680 throw new InvalidOperationException ();
4682 if (!owner.CheckBoxes)
4683 return (new ListViewItem [0]).GetEnumerator ();
4684 return List.GetEnumerator ();
4687 int IList.Add (object value)
4689 throw new NotSupportedException ("Add operation is not supported.");
4694 throw new NotSupportedException ("Clear operation is not supported.");
4697 bool IList.Contains (object item)
4699 if (!(item is ListViewItem))
4701 return Contains ((ListViewItem) item);
4704 int IList.IndexOf (object item)
4706 if (!(item is ListViewItem))
4708 return IndexOf ((ListViewItem) item);
4711 void IList.Insert (int index, object value)
4713 throw new NotSupportedException ("Insert operation is not supported.");
4716 void IList.Remove (object value)
4718 throw new NotSupportedException ("Remove operation is not supported.");
4721 void IList.RemoveAt (int index)
4723 throw new NotSupportedException ("RemoveAt operation is not supported.");
4726 public int IndexOf (ListViewItem item)
4729 if (owner.VirtualMode)
4730 throw new InvalidOperationException ();
4732 if (!owner.CheckBoxes)
4734 return List.IndexOf (item);
4738 public virtual int IndexOfKey (string key)
4741 if (owner.VirtualMode)
4742 throw new InvalidOperationException ();
4744 if (key == null || key.Length == 0)
4747 ArrayList checked_items = List;
4748 for (int i = 0; i < checked_items.Count; i++) {
4749 ListViewItem item = (ListViewItem) checked_items [i];
4750 if (String.Compare (key, item.Name, true) == 0)
4757 #endregion // Public Methods
4759 internal ArrayList List {
4762 list = new ArrayList ();
4763 foreach (ListViewItem item in owner.Items) {
4772 internal void Reset ()
4774 // force re-population of list
4778 private void ItemsCollection_Changed ()
4782 } // CheckedListViewItemCollection
4785 [ListBindable (false)]
4787 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4789 internal ArrayList list;
4790 private ListView owner;
4792 #region UIA Framework Events
4795 // We are using Reflection to add/remove internal events.
4796 // Class ListViewProvider uses the events when View is Details.
4798 //Event used to generate UIA StructureChangedEvent
4799 static object UIACollectionChangedEvent = new object ();
4801 internal event CollectionChangeEventHandler UIACollectionChanged {
4804 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4808 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4812 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4817 CollectionChangeEventHandler eh
4818 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4824 #endregion UIA Framework Events
4826 #region Public Constructor
4827 public ColumnHeaderCollection (ListView owner)
4829 list = new ArrayList ();
4832 #endregion // Public Constructor
4834 #region Public Properties
4837 get { return list.Count; }
4840 public bool IsReadOnly {
4841 get { return false; }
4844 public virtual ColumnHeader this [int index] {
4846 if (index < 0 || index >= list.Count)
4847 throw new ArgumentOutOfRangeException ("index");
4848 return (ColumnHeader) list [index];
4853 public virtual ColumnHeader this [string key] {
4855 int idx = IndexOfKey (key);
4859 return (ColumnHeader) list [idx];
4864 bool ICollection.IsSynchronized {
4865 get { return true; }
4868 object ICollection.SyncRoot {
4869 get { return this; }
4872 bool IList.IsFixedSize {
4873 get { return list.IsFixedSize; }
4876 object IList.this [int index] {
4877 get { return this [index]; }
4878 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4880 #endregion // Public Properties
4882 #region Public Methods
4883 public virtual int Add (ColumnHeader value)
4885 int idx = list.Add (value);
4886 owner.AddColumn (value, idx, true);
4889 //UIA Framework event: Item Added
4890 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4897 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4901 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
4904 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4905 this.Add (colHeader);
4910 public virtual ColumnHeader Add (string text)
4912 return Add (String.Empty, text);
4915 public virtual ColumnHeader Add (string text, int width)
4917 return Add (String.Empty, text, width);
4920 public virtual ColumnHeader Add (string key, string text)
4922 ColumnHeader colHeader = new ColumnHeader ();
4923 colHeader.Name = key;
4924 colHeader.Text = text;
4929 public virtual ColumnHeader Add (string key, string text, int width)
4931 return Add (key, text, width, HorizontalAlignment.Left, -1);
4934 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4936 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4937 colHeader.ImageIndex = imageIndex;
4942 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4944 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4945 colHeader.ImageKey = imageKey;
4951 public virtual void AddRange (ColumnHeader [] values)
4953 foreach (ColumnHeader colHeader in values) {
4954 int idx = list.Add (colHeader);
4955 owner.AddColumn (colHeader, idx, false);
4958 owner.Redraw (true);
4961 public virtual void Clear ()
4963 foreach (ColumnHeader col in list)
4964 col.SetListView (null);
4966 owner.ReorderColumns (new int [0], true);
4969 //UIA Framework event: Items cleared
4970 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4975 public bool Contains (ColumnHeader value)
4977 return list.Contains (value);
4981 public virtual bool ContainsKey (string key)
4983 return IndexOfKey (key) != -1;
4987 public IEnumerator GetEnumerator ()
4989 return list.GetEnumerator ();
4992 void ICollection.CopyTo (Array dest, int index)
4994 list.CopyTo (dest, index);
4997 int IList.Add (object value)
4999 if (! (value is ColumnHeader)) {
5000 throw new ArgumentException ("Not of type ColumnHeader", "value");
5003 return this.Add ((ColumnHeader) value);
5006 bool IList.Contains (object value)
5008 if (! (value is ColumnHeader)) {
5009 throw new ArgumentException ("Not of type ColumnHeader", "value");
5012 return this.Contains ((ColumnHeader) value);
5015 int IList.IndexOf (object value)
5017 if (! (value is ColumnHeader)) {
5018 throw new ArgumentException ("Not of type ColumnHeader", "value");
5021 return this.IndexOf ((ColumnHeader) value);
5024 void IList.Insert (int index, object value)
5026 if (! (value is ColumnHeader)) {
5027 throw new ArgumentException ("Not of type ColumnHeader", "value");
5030 this.Insert (index, (ColumnHeader) value);
5033 void IList.Remove (object value)
5035 if (! (value is ColumnHeader)) {
5036 throw new ArgumentException ("Not of type ColumnHeader", "value");
5039 this.Remove ((ColumnHeader) value);
5042 public int IndexOf (ColumnHeader value)
5044 return list.IndexOf (value);
5048 public virtual int IndexOfKey (string key)
5050 if (key == null || key.Length == 0)
5053 for (int i = 0; i < list.Count; i++) {
5054 ColumnHeader col = (ColumnHeader) list [i];
5055 if (String.Compare (key, col.Name, true) == 0)
5063 public void Insert (int index, ColumnHeader value)
5065 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
5066 // but it's really only greater.
5067 if (index < 0 || index > list.Count)
5068 throw new ArgumentOutOfRangeException ("index");
5070 list.Insert (index, value);
5071 owner.AddColumn (value, index, true);
5074 //UIA Framework event: Item added
5075 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5080 public void Insert (int index, string text)
5082 Insert (index, String.Empty, text);
5085 public void Insert (int index, string text, int width)
5087 Insert (index, String.Empty, text, width);
5090 public void Insert (int index, string key, string text)
5092 ColumnHeader colHeader = new ColumnHeader ();
5093 colHeader.Name = key;
5094 colHeader.Text = text;
5095 Insert (index, colHeader);
5098 public void Insert (int index, string key, string text, int width)
5100 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
5101 Insert (index, colHeader);
5104 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
5106 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
5107 colHeader.ImageIndex = imageIndex;
5108 Insert (index, colHeader);
5111 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
5113 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
5114 colHeader.ImageKey = imageKey;
5115 Insert (index, colHeader);
5120 public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
5124 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
5127 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
5128 this.Insert (index, colHeader);
5131 public virtual void Remove (ColumnHeader column)
5133 if (!Contains (column))
5136 list.Remove (column);
5137 column.SetListView (null);
5139 int rem_display_index = column.InternalDisplayIndex;
5140 int [] display_indices = new int [list.Count];
5141 for (int i = 0; i < display_indices.Length; i++) {
5142 ColumnHeader col = (ColumnHeader) list [i];
5143 int display_index = col.InternalDisplayIndex;
5144 if (display_index < rem_display_index) {
5145 display_indices [i] = display_index;
5147 display_indices [i] = (display_index - 1);
5151 column.InternalDisplayIndex = -1;
5152 owner.ReorderColumns (display_indices, true);
5155 //UIA Framework event: Item Removed
5156 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
5161 public virtual void RemoveByKey (string key)
5163 int idx = IndexOfKey (key);
5169 public virtual void RemoveAt (int index)
5171 if (index < 0 || index >= list.Count)
5172 throw new ArgumentOutOfRangeException ("index");
5174 ColumnHeader col = (ColumnHeader) list [index];
5177 #endregion // Public Methods
5180 } // ColumnHeaderCollection
5183 [ListBindable (false)]
5185 public class ListViewItemCollection : IList, ICollection, IEnumerable
5187 private readonly ArrayList list;
5188 private ListView owner;
5190 private ListViewGroup group;
5193 #region UIA Framework Events
5196 // We are using Reflection to add/remove internal events.
5197 // Class ListViewProvider uses the events.
5199 //Event used to generate UIA StructureChangedEvent
5200 static object UIACollectionChangedEvent = new object ();
5202 internal event CollectionChangeEventHandler UIACollectionChanged {
5205 owner.Events.AddHandler (UIACollectionChangedEvent, value);
5209 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
5213 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
5218 CollectionChangeEventHandler eh
5219 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
5225 #endregion UIA Framework Events
5227 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
5228 // In the later case ListViewItem.ListView never gets modified
5229 private bool is_main_collection = true;
5231 #region Public Constructor
5232 public ListViewItemCollection (ListView owner)
5234 list = new ArrayList (0);
5237 #endregion // Public Constructor
5240 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
5243 is_main_collection = false;
5247 #region Public Properties
5252 if (owner != null && owner.VirtualMode)
5253 return owner.VirtualListSize;
5260 public bool IsReadOnly {
5261 get { return false; }
5265 public virtual ListViewItem this [int index] {
5267 public virtual ListViewItem this [int displayIndex] {
5271 int index = displayIndex;
5274 if (index < 0 || index >= Count)
5275 throw new ArgumentOutOfRangeException ("index");
5278 if (owner != null && owner.VirtualMode)
5279 return RetrieveVirtualItemFromOwner (index);
5281 return (ListViewItem) list [index];
5286 int index = displayIndex;
5289 if (index < 0 || index >= Count)
5290 throw new ArgumentOutOfRangeException ("index");
5293 if (owner != null && owner.VirtualMode)
5294 throw new InvalidOperationException ();
5297 if (list.Contains (value))
5298 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5300 if (value.ListView != null && value.ListView != owner)
5301 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");
5303 if (is_main_collection)
5304 value.Owner = owner;
5307 if (value.Group != null)
5308 value.Group.Items.Remove (value);
5310 value.SetGroup (group);
5315 //UIA Framework event: Item Replaced
5316 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5319 list [index] = value;
5321 CollectionChanged (true);
5324 //UIA Framework event: Item Replaced
5325 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5332 public virtual ListViewItem this [string key] {
5334 int idx = IndexOfKey (key);
5343 bool ICollection.IsSynchronized {
5344 get { return true; }
5347 object ICollection.SyncRoot {
5348 get { return this; }
5351 bool IList.IsFixedSize {
5352 get { return list.IsFixedSize; }
5355 object IList.this [int index] {
5356 get { return this [index]; }
5359 //UIA Framework event: Item Replaced
5360 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5363 if (value is ListViewItem)
5364 this [index] = (ListViewItem) value;
5366 this [index] = new ListViewItem (value.ToString ());
5370 //UIA Framework event: Item Replaced
5371 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5375 #endregion // Public Properties
5377 #region Public Methods
5378 public virtual ListViewItem Add (ListViewItem value)
5381 if (owner != null && owner.VirtualMode)
5382 throw new InvalidOperationException ();
5387 // Item is ignored until it has been added to the ListView
5388 if (is_main_collection || value.ListView != null)
5389 CollectionChanged (true);
5392 //UIA Framework event: Item Added
5393 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5399 public virtual ListViewItem Add (string text)
5401 ListViewItem item = new ListViewItem (text);
5402 return this.Add (item);
5405 public virtual ListViewItem Add (string text, int imageIndex)
5407 ListViewItem item = new ListViewItem (text, imageIndex);
5408 return this.Add (item);
5412 public virtual ListViewItem Add (string text, string imageKey)
5414 ListViewItem item = new ListViewItem (text, imageKey);
5415 return this.Add (item);
5418 public virtual ListViewItem Add (string key, string text, int imageIndex)
5420 ListViewItem item = new ListViewItem (text, imageIndex);
5422 return this.Add (item);
5425 public virtual ListViewItem Add (string key, string text, string imageKey)
5427 ListViewItem item = new ListViewItem (text, imageKey);
5429 return this.Add (item);
5434 public void AddRange (ListViewItem [] items)
5437 public void AddRange (ListViewItem [] values)
5439 ListViewItem [] items = values;
5442 throw new ArgumentNullException ("Argument cannot be null!", "items");
5444 if (owner != null && owner.VirtualMode)
5445 throw new InvalidOperationException ();
5448 owner.BeginUpdate ();
5450 foreach (ListViewItem item in items) {
5454 //UIA Framework event: Item Added
5455 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5461 CollectionChanged (true);
5465 public void AddRange (ListViewItemCollection items)
5468 throw new ArgumentNullException ("Argument cannot be null!", "items");
5470 ListViewItem[] itemArray = new ListViewItem[items.Count];
5471 items.CopyTo (itemArray,0);
5472 this.AddRange (itemArray);
5476 public virtual void Clear ()
5479 if (owner != null && owner.VirtualMode)
5480 throw new InvalidOperationException ();
5482 if (is_main_collection && owner != null) {
5483 owner.SetFocusedItem (-1);
5484 owner.h_scroll.Value = owner.v_scroll.Value = 0;
5487 // first remove any item in the groups that *are* part of this LV too
5488 foreach (ListViewGroup group in owner.groups)
5489 group.Items.ClearItemsWithSameListView ();
5492 foreach (ListViewItem item in list) {
5493 owner.item_control.CancelEdit (item);
5499 foreach (ListViewItem item in list)
5500 item.SetGroup (null);
5504 CollectionChanged (false);
5507 //UIA Framework event: Items Removed
5508 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5514 // This method is intended to be used from ListViewGroup.Items, not from ListView.Items,
5515 // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items)
5516 void ClearItemsWithSameListView ()
5518 if (is_main_collection)
5521 int counter = list.Count - 1;
5522 while (counter >= 0) {
5523 ListViewItem item = list [counter] as ListViewItem;
5525 // remove only if the items in group have being added to the ListView too
5526 if (item.ListView == group.ListView) {
5527 list.RemoveAt (counter);
5528 item.SetGroup (null);
5536 public bool Contains (ListViewItem item)
5538 return IndexOf (item) != -1;
5542 public virtual bool ContainsKey (string key)
5544 return IndexOfKey (key) != -1;
5548 public void CopyTo (Array dest, int index)
5550 list.CopyTo (dest, index);
5554 public ListViewItem [] Find (string key, bool searchAllSubItems)
5557 return new ListViewItem [0];
5559 List<ListViewItem> temp_list = new List<ListViewItem> ();
5561 for (int i = 0; i < list.Count; i++) {
5562 ListViewItem lvi = (ListViewItem) list [i];
5563 if (String.Compare (key, lvi.Name, true) == 0)
5564 temp_list.Add (lvi);
5567 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5568 temp_list.CopyTo (retval);
5574 public IEnumerator GetEnumerator ()
5577 if (owner != null && owner.VirtualMode)
5578 throw new InvalidOperationException ();
5581 // This enumerator makes a copy of the collection so
5582 // it can be deleted from in a foreach
5583 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5586 int IList.Add (object item)
5592 if (owner != null && owner.VirtualMode)
5593 throw new InvalidOperationException ();
5596 if (item is ListViewItem) {
5597 li = (ListViewItem) item;
5598 if (list.Contains (li))
5599 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5601 if (li.ListView != null && li.ListView != owner)
5602 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");
5605 li = new ListViewItem (item.ToString ());
5610 result = list.Add (li);
5611 CollectionChanged (true);
5614 //UIA Framework event: Item Added
5615 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5621 bool IList.Contains (object item)
5623 return Contains ((ListViewItem) item);
5626 int IList.IndexOf (object item)
5628 return IndexOf ((ListViewItem) item);
5631 void IList.Insert (int index, object item)
5633 if (item is ListViewItem)
5634 this.Insert (index, (ListViewItem) item);
5636 this.Insert (index, item.ToString ());
5639 //UIA Framework event: Item Added
5640 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5644 void IList.Remove (object item)
5646 Remove ((ListViewItem) item);
5649 public int IndexOf (ListViewItem item)
5652 if (owner != null && owner.VirtualMode) {
5653 for (int i = 0; i < Count; i++)
5654 if (RetrieveVirtualItemFromOwner (i) == item)
5661 return list.IndexOf (item);
5665 public virtual int IndexOfKey (string key)
5667 if (key == null || key.Length == 0)
5670 for (int i = 0; i < Count; i++) {
5671 ListViewItem lvi = this [i];
5672 if (String.Compare (key, lvi.Name, true) == 0)
5680 public ListViewItem Insert (int index, ListViewItem item)
5682 if (index < 0 || index > list.Count)
5683 throw new ArgumentOutOfRangeException ("index");
5686 if (owner != null && owner.VirtualMode)
5687 throw new InvalidOperationException ();
5690 if (list.Contains (item))
5691 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5693 if (item.ListView != null && item.ListView != owner)
5694 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");
5696 if (is_main_collection)
5700 if (item.Group != null)
5701 item.Group.Items.Remove (item);
5703 item.SetGroup (group);
5707 list.Insert (index, item);
5709 if (is_main_collection || item.ListView != null)
5710 CollectionChanged (true);
5712 // force an update of the selected info if the new item is selected.
5714 item.SetSelectedCore (true);
5716 //UIA Framework event: Item Added
5717 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5723 public ListViewItem Insert (int index, string text)
5725 return this.Insert (index, new ListViewItem (text));
5728 public ListViewItem Insert (int index, string text, int imageIndex)
5730 return this.Insert (index, new ListViewItem (text, imageIndex));
5734 public ListViewItem Insert (int index, string text, string imageKey)
5736 ListViewItem lvi = new ListViewItem (text, imageKey);
5737 return Insert (index, lvi);
5740 public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5742 ListViewItem lvi = new ListViewItem (text, imageIndex);
5744 return Insert (index, lvi);
5747 public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5749 ListViewItem lvi = new ListViewItem (text, imageKey);
5751 return Insert (index, lvi);
5755 public virtual void Remove (ListViewItem item)
5758 if (owner != null && owner.VirtualMode)
5759 throw new InvalidOperationException ();
5762 int idx = list.IndexOf (item);
5767 public virtual void RemoveAt (int index)
5769 if (index < 0 || index >= Count)
5770 throw new ArgumentOutOfRangeException ("index");
5773 if (owner != null && owner.VirtualMode)
5774 throw new InvalidOperationException ();
5777 ListViewItem item = (ListViewItem) list [index];
5779 bool selection_changed = false;
5780 if (is_main_collection && owner != null) {
5782 int display_index = item.DisplayIndex;
5783 if (item.Focused && display_index + 1 == Count) // Last item
5784 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5786 selection_changed = owner.SelectedIndices.Contains (index);
5787 owner.item_control.CancelEdit (item);
5790 list.RemoveAt (index);
5793 if (is_main_collection) {
5795 if (item.Group != null)
5796 item.Group.Items.Remove (item);
5798 item.SetGroup (null);
5803 CollectionChanged (false);
5804 if (selection_changed && owner != null)
5805 owner.OnSelectedIndexChanged (EventArgs.Empty);
5809 //UIA Framework event: Item Removed
5810 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5815 public virtual void RemoveByKey (string key)
5817 int idx = IndexOfKey (key);
5823 #endregion // Public Methods
5825 internal ListView Owner {
5835 internal ListViewGroup Group {
5845 void AddItem (ListViewItem value)
5847 if (list.Contains (value))
5848 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5850 if (value.ListView != null && value.ListView != owner)
5851 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");
5852 if (is_main_collection)
5853 value.Owner = owner;
5856 if (value.Group != null)
5857 value.Group.Items.Remove (value);
5859 value.SetGroup (group);
5865 // force an update of the selected info if the new item is selected.
5867 value.SetSelectedCore (true);
5870 void CollectionChanged (bool sort)
5872 if (owner != null) {
5877 owner.Redraw (true);
5882 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5884 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5886 owner.OnRetrieveVirtualItem (args);
5887 ListViewItem retval = args.Item;
5888 retval.Owner = owner;
5889 retval.DisplayIndex = displayIndex;
5896 internal event CollectionChangedHandler Changed;
5898 internal void Sort (IComparer comparer)
5900 list.Sort (comparer);
5904 internal void OnChange ()
5906 if (Changed != null)
5909 } // ListViewItemCollection
5912 // In normal mode, the selection information resides in the Items,
5913 // making SelectedIndexCollection.List read-only
5915 // In virtual mode, SelectedIndexCollection directly saves the selection
5916 // information, instead of getting it from Items, making List read-and-write
5918 [ListBindable (false)]
5920 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5922 private readonly ListView owner;
5923 private ArrayList list;
5925 #region Public Constructor
5926 public SelectedIndexCollection (ListView owner)
5929 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5931 #endregion // Public Constructor
5933 #region Public Properties
5937 if (!owner.is_selection_available)
5944 public bool IsReadOnly {
5954 public int this [int index] {
5956 if (!owner.is_selection_available || index < 0 || index >= List.Count)
5957 throw new ArgumentOutOfRangeException ("index");
5959 return (int) List [index];
5963 bool ICollection.IsSynchronized {
5964 get { return false; }
5967 object ICollection.SyncRoot {
5968 get { return this; }
5971 bool IList.IsFixedSize {
5981 object IList.this [int index] {
5982 get { return this [index]; }
5983 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5985 #endregion // Public Properties
5987 #region Public Methods
5989 public int Add (int itemIndex)
5991 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5992 throw new ArgumentOutOfRangeException ("index");
5994 if (owner.virtual_mode && !owner.is_selection_available)
5997 owner.Items [itemIndex].Selected = true;
5999 if (!owner.is_selection_available)
6013 if (!owner.is_selection_available)
6016 int [] indexes = (int []) List.ToArray (typeof (int));
6017 foreach (int index in indexes)
6018 owner.Items [index].Selected = false;
6021 public bool Contains (int selectedIndex)
6023 return IndexOf (selectedIndex) != -1;
6026 public void CopyTo (Array dest, int index)
6028 List.CopyTo (dest, index);
6031 public IEnumerator GetEnumerator ()
6033 return List.GetEnumerator ();
6036 int IList.Add (object value)
6038 throw new NotSupportedException ("Add operation is not supported.");
6046 bool IList.Contains (object selectedIndex)
6048 if (!(selectedIndex is int))
6050 return Contains ((int) selectedIndex);
6053 int IList.IndexOf (object selectedIndex)
6055 if (!(selectedIndex is int))
6057 return IndexOf ((int) selectedIndex);
6060 void IList.Insert (int index, object value)
6062 throw new NotSupportedException ("Insert operation is not supported.");
6065 void IList.Remove (object value)
6067 throw new NotSupportedException ("Remove operation is not supported.");
6070 void IList.RemoveAt (int index)
6072 throw new NotSupportedException ("RemoveAt operation is not supported.");
6075 public int IndexOf (int selectedIndex)
6077 if (!owner.is_selection_available)
6080 return List.IndexOf (selectedIndex);
6084 public void Remove (int itemIndex)
6086 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
6087 throw new ArgumentOutOfRangeException ("itemIndex");
6089 owner.Items [itemIndex].Selected = false;
6092 #endregion // Public Methods
6094 internal ArrayList List {
6097 list = new ArrayList ();
6099 if (!owner.VirtualMode)
6101 for (int i = 0; i < owner.Items.Count; i++) {
6102 if (owner.Items [i].Selected)
6110 internal void Reset ()
6112 // force re-population of list
6116 private void ItemsCollection_Changed ()
6122 internal void RemoveIndex (int index)
6124 int idx = List.BinarySearch (index);
6126 List.RemoveAt (idx);
6129 // actually store index in the collection
6130 // also, keep the collection sorted, as .Net does
6131 internal void InsertIndex (int index)
6134 int iMax = List.Count - 1;
6135 while (iMin <= iMax) {
6136 int iMid = (iMin + iMax) / 2;
6137 int current_index = (int) List [iMid];
6139 if (current_index == index)
6140 return; // Already added
6141 if (current_index > index)
6147 List.Insert (iMin, index);
6151 } // SelectedIndexCollection
6154 [ListBindable (false)]
6156 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
6158 private readonly ListView owner;
6160 #region Public Constructor
6161 public SelectedListViewItemCollection (ListView owner)
6165 #endregion // Public Constructor
6167 #region Public Properties
6171 return owner.SelectedIndices.Count;
6175 public bool IsReadOnly {
6176 get { return true; }
6179 public ListViewItem this [int index] {
6181 if (!owner.is_selection_available || index < 0 || index >= Count)
6182 throw new ArgumentOutOfRangeException ("index");
6184 int item_index = owner.SelectedIndices [index];
6185 return owner.Items [item_index];
6190 public virtual ListViewItem this [string key] {
6192 int idx = IndexOfKey (key);
6201 bool ICollection.IsSynchronized {
6202 get { return false; }
6205 object ICollection.SyncRoot {
6206 get { return this; }
6209 bool IList.IsFixedSize {
6210 get { return true; }
6213 object IList.this [int index] {
6214 get { return this [index]; }
6215 set { throw new NotSupportedException ("SetItem operation is not supported."); }
6217 #endregion // Public Properties
6219 #region Public Methods
6220 public void Clear ()
6222 owner.SelectedIndices.Clear ();
6225 public bool Contains (ListViewItem item)
6227 return IndexOf (item) != -1;
6231 public virtual bool ContainsKey (string key)
6233 return IndexOfKey (key) != -1;
6237 public void CopyTo (Array dest, int index)
6239 if (!owner.is_selection_available)
6241 if (index > Count) // Throws ArgumentException instead of IOOR exception
6242 throw new ArgumentException ("index");
6244 for (int i = 0; i < Count; i++)
6245 dest.SetValue (this [i], index++);
6248 public IEnumerator GetEnumerator ()
6250 if (!owner.is_selection_available)
6251 return (new ListViewItem [0]).GetEnumerator ();
6253 ListViewItem [] items = new ListViewItem [Count];
6254 for (int i = 0; i < Count; i++)
6255 items [i] = this [i];
6257 return items.GetEnumerator ();
6260 int IList.Add (object value)
6262 throw new NotSupportedException ("Add operation is not supported.");
6265 bool IList.Contains (object item)
6267 if (!(item is ListViewItem))
6269 return Contains ((ListViewItem) item);
6272 int IList.IndexOf (object item)
6274 if (!(item is ListViewItem))
6276 return IndexOf ((ListViewItem) item);
6279 void IList.Insert (int index, object value)
6281 throw new NotSupportedException ("Insert operation is not supported.");
6284 void IList.Remove (object value)
6286 throw new NotSupportedException ("Remove operation is not supported.");
6289 void IList.RemoveAt (int index)
6291 throw new NotSupportedException ("RemoveAt operation is not supported.");
6294 public int IndexOf (ListViewItem item)
6296 if (!owner.is_selection_available)
6299 for (int i = 0; i < Count; i++)
6300 if (this [i] == item)
6307 public virtual int IndexOfKey (string key)
6309 if (!owner.is_selection_available || key == null || key.Length == 0)
6312 for (int i = 0; i < Count; i++) {
6313 ListViewItem item = this [i];
6314 if (String.Compare (item.Name, key, true) == 0)
6321 #endregion // Public Methods
6323 } // SelectedListViewItemCollection
6325 internal delegate void CollectionChangedHandler ();
6327 struct ItemMatrixLocation
6332 public ItemMatrixLocation (int row, int col)
6359 #endregion // Subclasses
6361 protected override void OnResize (EventArgs e)
6366 protected override void OnMouseLeave (EventArgs e)
6368 base.OnMouseLeave (e);
6372 // ColumnReorder event
6374 static object ColumnReorderedEvent = new object ();
6375 public event ColumnReorderedEventHandler ColumnReordered {
6376 add { Events.AddHandler (ColumnReorderedEvent, value); }
6377 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
6380 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
6382 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
6389 // ColumnWidthChanged
6391 static object ColumnWidthChangedEvent = new object ();
6392 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
6393 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
6394 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
6397 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
6399 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
6404 void RaiseColumnWidthChanged (int resize_column)
6406 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
6408 OnColumnWidthChanged (n);
6412 // ColumnWidthChanging
6414 static object ColumnWidthChangingEvent = new object ();
6415 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
6416 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
6417 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
6420 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6422 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6428 // 2.0 profile based implementation
6430 bool CanProceedWithResize (ColumnHeader col, int width)
6432 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6436 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6437 cwceh (this, changing);
6438 return !changing.Cancel;
6442 // 1.0 profile based implementation
6444 bool CanProceedWithResize (ColumnHeader col, int width)
6449 void RaiseColumnWidthChanged (int resize_column)
6454 internal void RaiseColumnWidthChanged (ColumnHeader column)
6456 int index = Columns.IndexOf (column);
6457 RaiseColumnWidthChanged (index);
6462 #region UIA Framework: Methods, Properties and Events
6464 static object UIALabelEditChangedEvent = new object ();
6465 static object UIAShowGroupsChangedEvent = new object ();
6466 static object UIAMultiSelectChangedEvent = new object ();
6467 static object UIAViewChangedEvent = new object ();
6468 static object UIACheckBoxesChangedEvent = new object ();
6469 static object UIAFocusedItemChangedEvent = new object ();
6471 internal Rectangle UIAHeaderControl {
6472 get { return header_control.Bounds; }
6475 internal int UIAColumns {
6476 get { return cols; }
6479 internal int UIARows {
6480 get { return rows; }
6483 internal ListViewGroup UIADefaultListViewGroup
6485 get { return groups.DefaultGroup; }
6488 internal ScrollBar UIAHScrollBar {
6489 get { return h_scroll; }
6492 internal ScrollBar UIAVScrollBar {
6493 get { return v_scroll; }
6496 internal event EventHandler UIAShowGroupsChanged {
6497 add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6498 remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6501 internal event EventHandler UIACheckBoxesChanged {
6502 add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6503 remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6506 internal event EventHandler UIAMultiSelectChanged {
6507 add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6508 remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6511 internal event EventHandler UIALabelEditChanged {
6512 add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6513 remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6516 internal event EventHandler UIAViewChanged {
6517 add { Events.AddHandler (UIAViewChangedEvent, value); }
6518 remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6521 internal event EventHandler UIAFocusedItemChanged {
6522 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6523 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6526 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6528 return group.HeaderBounds;
6531 internal int UIAItemsLocationLength
6533 get { return items_location.Length; }
6536 private void OnUIACheckBoxesChanged ()
6538 EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6540 eh (this, EventArgs.Empty);
6543 private void OnUIAShowGroupsChanged ()
6545 EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6547 eh (this, EventArgs.Empty);
6550 private void OnUIAMultiSelectChanged ()
6552 EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6554 eh (this, EventArgs.Empty);
6557 private void OnUIALabelEditChanged ()
6559 EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6561 eh (this, EventArgs.Empty);
6564 private void OnUIAViewChanged ()
6566 EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6568 eh (this, EventArgs.Empty);
6571 internal void OnUIAFocusedItemChanged ()
6573 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6575 eh (this, EventArgs.Empty);
6578 #endregion // UIA Framework: Methods, Properties and Events