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 - item_control.Width;
1389 max = v_scroll.Maximum - item_control.Height;
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;
1414 h_scroll.Visible = false;
1415 v_scroll.Visible = false;
1416 item_control.Size = new Size (width, height);
1417 header_control.Width = width;
1421 // Don't calculate if the view is not displayable
1422 if (client_area.Height < 0 || client_area.Width < 0)
1425 // making a scroll bar visible might make
1426 // other scroll bar visible
1427 if (layout_wd > client_area.Right) {
1428 h_scroll.Visible = true;
1429 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1430 v_scroll.Visible = true;
1432 v_scroll.Visible = false;
1433 } else if (layout_ht > client_area.Bottom) {
1434 v_scroll.Visible = true;
1435 if ((layout_wd + v_scroll.Width) > client_area.Right)
1436 h_scroll.Visible = true;
1438 h_scroll.Visible = false;
1440 h_scroll.Visible = false;
1441 v_scroll.Visible = false;
1445 if (h_scroll.is_visible) {
1446 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1447 h_scroll.Minimum = 0;
1449 // if v_scroll is visible, adjust the maximum of the
1450 // h_scroll to account for the width of v_scroll
1451 if (v_scroll.Visible) {
1452 h_scroll.Maximum = layout_wd + v_scroll.Width;
1453 h_scroll.Width = client_area.Width - v_scroll.Width;
1456 h_scroll.Maximum = layout_wd;
1457 h_scroll.Width = client_area.Width;
1460 h_scroll.LargeChange = client_area.Width;
1461 h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing;
1462 height -= h_scroll.Height;
1465 if (v_scroll.is_visible) {
1466 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1467 v_scroll.Minimum = 0;
1468 v_scroll.Maximum = layout_ht;
1470 // if h_scroll is visible, adjust the height of
1471 // v_scroll to account for the height of h_scroll
1472 if (h_scroll.Visible)
1473 v_scroll.Height = client_area.Height - h_scroll.Height;
1475 v_scroll.Height = client_area.Height;
1477 v_scroll.LargeChange = client_area.Height;
1478 v_scroll.SmallChange = Font.Height;
1479 width -= v_scroll.Width;
1482 item_control.Size = new Size (width, height);
1484 if (header_control.is_visible)
1485 header_control.Width = width;
1489 internal int GetReorderedColumnIndex (ColumnHeader column)
1491 if (reordered_column_indices == null)
1492 return column.Index;
1494 for (int i = 0; i < Columns.Count; i++)
1495 if (reordered_column_indices [i] == column.Index)
1502 internal ColumnHeader GetReorderedColumn (int index)
1504 if (reordered_column_indices == null)
1505 return Columns [index];
1507 return Columns [reordered_column_indices [index]];
1510 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1514 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1516 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1520 header_control.Invalidate ();
1521 item_control.Invalidate ();
1527 int column_count = Columns.Count;
1529 if (reordered_column_indices == null) {
1530 reordered_column_indices = new int [column_count];
1531 for (int i = 0; i < column_count; i++)
1532 reordered_column_indices [i] = i;
1535 if (reordered_column_indices [index] == col.Index)
1538 int[] curr = reordered_column_indices;
1539 int [] result = new int [column_count];
1541 for (int i = 0; i < column_count; i++) {
1542 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1546 result [i] = col.Index;
1548 result [i] = curr [curr_idx++];
1551 ReorderColumns (result, true);
1554 internal void ReorderColumns (int [] display_indices, bool redraw)
1556 reordered_column_indices = display_indices;
1557 for (int i = 0; i < Columns.Count; i++) {
1558 ColumnHeader col = Columns [i];
1559 col.InternalDisplayIndex = reordered_column_indices [i];
1561 if (redraw && view == View.Details && IsHandleCreated) {
1563 header_control.Invalidate ();
1564 item_control.Invalidate ();
1568 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1570 int column_count = Columns.Count;
1571 newCol.SetListView (this);
1573 int [] display_indices = new int [column_count];
1574 for (int i = 0; i < column_count; i++) {
1575 ColumnHeader col = Columns [i];
1577 display_indices [i] = index;
1579 int display_index = col.InternalDisplayIndex;
1580 if (display_index < index) {
1581 display_indices [i] = display_index;
1583 display_indices [i] = (display_index + 1);
1588 ReorderColumns (display_indices, redraw);
1592 Size LargeIconItemSize
1595 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1596 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1597 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1598 int w = Math.Max (text_size.Width, image_w);
1601 w += 2 + CheckBoxSize.Width;
1603 return new Size (w, h);
1607 Size SmallIconItemSize {
1609 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1610 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1611 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1612 int w = text_size.Width + image_w;
1615 w += 2 + CheckBoxSize.Width;
1617 return new Size (w, h);
1624 // Calculate tile size if needed
1625 // It appears that using Font.Size instead of a SizeF value can give us
1626 // a slightly better approach to the proportions defined in .Net
1627 if (tile_size == Size.Empty) {
1628 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1629 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1630 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1631 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1633 tile_size = new Size (w, h);
1641 int GetDetailsItemHeight ()
1644 int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1645 int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1646 item_height = Math.Max (checkbox_height, text_size.Height);
1647 item_height = Math.Max (item_height, small_image_height);
1651 void SetItemLocation (int index, int x, int y, int row, int col)
1653 Point old_location = items_location [index];
1654 if (old_location.X == x && old_location.Y == y)
1657 items_location [index] = new Point (x, y);
1658 items_matrix_location [index] = new ItemMatrixLocation (row, col);
1661 // Initial position matches item's position in ListViewItemCollection
1663 reordered_items_indices [index] = index;
1667 void ShiftItemsPositions (int from, int to, bool forward)
1670 for (int i = to + 1; i > from; i--) {
1671 reordered_items_indices [i] = reordered_items_indices [i - 1];
1673 ListViewItem item = items [reordered_items_indices [i]];
1675 item.DisplayIndex = i;
1679 for (int i = from - 1; i < to; i++) {
1680 reordered_items_indices [i] = reordered_items_indices [i + 1];
1682 ListViewItem item = items [reordered_items_indices [i]];
1684 item.DisplayIndex = i;
1690 internal void ChangeItemLocation (int display_index, Point new_pos)
1692 int new_display_index = GetDisplayIndexFromLocation (new_pos);
1693 if (new_display_index == display_index)
1696 int item_index = reordered_items_indices [display_index];
1697 ListViewItem item = items [item_index];
1699 bool forward = new_display_index < display_index;
1700 int index_from, index_to;
1702 index_from = new_display_index;
1703 index_to = display_index - 1;
1705 index_from = display_index + 1;
1706 index_to = new_display_index;
1709 ShiftItemsPositions (index_from, index_to, forward);
1711 reordered_items_indices [new_display_index] = item_index;
1714 item.DisplayIndex = new_display_index;
1718 int GetDisplayIndexFromLocation (Point loc)
1720 int display_index = -1;
1721 Rectangle item_area;
1724 if (loc.X < 0 || loc.Y < 0)
1727 // Adjustment to put in the next position refered by 'loc'
1728 loc.X -= item_size.Width / 2;
1732 for (int i = 0; i < items.Count; i++) {
1733 item_area = new Rectangle (GetItemLocation (i), item_size);
1734 item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing,
1735 ThemeEngine.Current.ListViewVerticalSpacing);
1737 if (item_area.Contains (loc)) {
1743 // Put in in last position
1744 if (display_index == -1)
1745 display_index = items.Count - 1;
1747 return display_index;
1750 // When using groups, the items with no group assigned
1751 // belong to the DefaultGroup
1752 int GetDefaultGroupItems ()
1755 foreach (ListViewItem item in items)
1756 if (item.Group == null)
1764 // cache the spacing to let virtualmode compute the positions on the fly
1770 int[,] item_index_matrix;
1772 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1774 Rectangle area = ClientRectangle;
1776 if (UseCustomColumnWidth)
1777 CalculateCustomColumnWidth ();
1780 // When groups are used the alignment is always top-aligned
1785 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1786 for (int i = 0; i < groups.InternalCount; i++) {
1787 ListViewGroup group = groups.GetInternalGroup (i);
1788 int items_in_group = group.GetActualItemCount ();
1790 if (items_in_group == 0)
1793 int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1794 if (group_cols <= 0)
1796 int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols);
1798 group.starting_row = rows;
1799 group.rows = group_rows;
1800 group.starting_item = items;
1801 group.current_item = 0; // Reset layout
1803 cols = Math.Max (group_cols, cols);
1805 items += items_in_group;
1810 // Simple matrix if no groups are used
1812 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1815 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1817 if (UseCustomColumnWidth)
1818 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width));
1820 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1825 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1829 item_index_matrix = new int [rows, cols];
1832 // When using custom column width, we look for the minimum one
1833 void CalculateCustomColumnWidth ()
1835 int min_width = Int32.MaxValue;
1836 for (int i = 0; i < columns.Count; i++) {
1837 int col_width = columns [i].Width;
1839 if (col_width < min_width)
1840 min_width = col_width;
1843 custom_column_width = min_width;
1846 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1848 header_control.Visible = false;
1849 header_control.Size = Size.Empty;
1850 item_control.Visible = true;
1851 item_control.Location = Point.Empty;
1852 ItemSize = item_size; // Cache item size
1854 this.x_spacing = x_spacing;
1855 this.y_spacing = y_spacing;
1858 if (items.Count == 0)
1861 Size sz = item_size;
1863 CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing);
1865 layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing;
1866 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1869 if (virtual_mode) { // no actual assignment is needed on items for virtual mode
1870 item_control.Size = new Size (layout_wd, layout_ht);
1874 bool using_groups = UsingGroups;
1875 if (using_groups) // the groups layout will override layout_ht
1876 CalculateGroupsLayout (sz, y_spacing, 0);
1879 int row = 0, col = 0;
1881 int display_index = 0;
1883 for (int i = 0; i < items.Count; i++) {
1884 ListViewItem item = items [i];
1887 ListViewGroup group = item.Group;
1889 group = groups.DefaultGroup;
1891 Point group_items_loc = group.items_area_location;
1892 int current_item = group.current_item++;
1893 int starting_row = group.starting_row;
1895 display_index = group.starting_item + current_item;
1896 row = (current_item / cols);
1897 col = current_item % cols;
1899 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1900 y = row * (item_size.Height + y_spacing) + group_items_loc.Y;
1902 SetItemLocation (display_index, x, y, row + starting_row, col);
1903 SetItemAtDisplayIndex (display_index, i);
1904 item_index_matrix [row + starting_row, col] = i;
1909 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1910 y = row * (item_size.Height + y_spacing);
1911 display_index = i; // Same as item index in Items
1913 SetItemLocation (i, x, y, row, col);
1914 item_index_matrix [row, col] = i;
1923 if (++col == cols) {
1931 item.DisplayIndex = display_index;
1933 item.SetPosition (new Point (x, y));
1937 item_control.Size = new Size (layout_wd, layout_ht);
1941 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin)
1944 bool details = view == View.Details;
1946 for (int i = 0; i < groups.InternalCount; i++) {
1947 ListViewGroup group = groups.GetInternalGroup (i);
1948 if (group.ItemCount == 0)
1951 y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows);
1954 layout_ht = y; // Update height taking into account Groups' headers heights
1957 int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows)
1959 Rectangle client_area = ClientRectangle;
1960 int header_height = Font.Height + 15; // one line height + some padding
1962 group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height);
1963 group.items_area_location = new Point (0, y_origin + header_height);
1965 int items_area_height = ((item_height + y_spacing) * rows);
1966 return header_height + items_area_height + 10; // Add a small bottom margin
1969 void CalculateDetailsGroupItemsCount ()
1973 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1974 for (int i = 0; i < groups.InternalCount; i++) {
1975 ListViewGroup group = groups.GetInternalGroup (i);
1976 int items_in_group = group.GetActualItemCount ();
1978 if (items_in_group == 0)
1981 group.starting_item = items;
1982 group.current_item = 0; // Reset layout.
1983 items += items_in_group;
1988 void LayoutHeader ()
1991 for (int i = 0; i < Columns.Count; i++) {
1992 ColumnHeader col = GetReorderedColumn (i);
1995 col.CalcColumnHeader ();
2001 if (x < ClientRectangle.Width)
2002 x = ClientRectangle.Width;
2004 if (header_style == ColumnHeaderStyle.None) {
2005 header_control.Visible = false;
2006 header_control.Size = Size.Empty;
2007 layout_wd = ClientRectangle.Width;
2009 header_control.Width = x;
2010 header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font);
2011 header_control.Visible = true;
2015 void LayoutDetails ()
2019 if (columns.Count == 0) {
2020 item_control.Visible = false;
2021 layout_wd = ClientRectangle.Width;
2022 layout_ht = ClientRectangle.Height;
2026 item_control.Visible = true;
2027 item_control.Location = Point.Empty;
2028 item_control.Width = ClientRectangle.Width;
2030 int item_height = GetDetailsItemHeight ();
2031 ItemSize = new Size (0, item_height); // We only cache Height for details view
2032 int y = header_control.Height;
2033 layout_ht = y + (item_height * items.Count);
2034 if (items.Count > 0 && grid_lines) // some space for bottom gridline
2038 bool using_groups = UsingGroups;
2040 // Observe that this routines will override our layout_ht value
2041 CalculateDetailsGroupItemsCount ();
2042 CalculateGroupsLayout (ItemSize, 2, y);
2045 if (virtual_mode) // no assgination on items is needed
2049 for (int i = 0; i < items.Count; i++) {
2050 ListViewItem item = items [i];
2057 ListViewGroup group = item.Group;
2059 group = groups.DefaultGroup;
2061 int current_item = group.current_item++;
2062 Point group_items_loc = group.items_area_location;
2063 display_index = group.starting_item + current_item;
2065 y = item_y = current_item * (item_height + 2) + group_items_loc.Y;
2066 SetItemLocation (display_index, 0, item_y, 0, 0);
2067 SetItemAtDisplayIndex (display_index, i);
2073 SetItemLocation (i, 0, item_y, 0, 0);
2078 item.DisplayIndex = display_index;
2080 item.SetPosition (new Point (0, item_y));
2085 private void AdjustItemsPositionArray (int count)
2088 // In virtual mode we compute the positions on the fly.
2092 if (items_location.Length >= count)
2095 // items_location, items_matrix_location and reordered_items_indices must keep the same length
2096 count = Math.Max (count, items_location.Length * 2);
2097 items_location = new Point [count];
2098 items_matrix_location = new ItemMatrixLocation [count];
2099 reordered_items_indices = new int [count];
2102 private void CalculateListView (ListViewAlignment align)
2106 AdjustItemsPositionArray (items.Count);
2113 case View.SmallIcon:
2114 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
2115 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2118 case View.LargeIcon:
2119 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
2120 ThemeEngine.Current.ListViewHorizontalSpacing,
2121 ThemeEngine.Current.ListViewVerticalSpacing);
2125 LayoutIcons (SmallIconItemSize, true,
2126 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2130 if (!Application.VisualStylesEnabled)
2131 goto case View.LargeIcon;
2133 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
2134 ThemeEngine.Current.ListViewHorizontalSpacing,
2135 ThemeEngine.Current.ListViewVerticalSpacing);
2140 CalculateScrollBars ();
2143 internal Point GetItemLocation (int index)
2145 Point loc = Point.Empty;
2148 loc = GetFixedItemLocation (index);
2151 loc = items_location [index];
2153 loc.X -= h_marker; // Adjust to scroll
2160 Point GetFixedItemLocation (int index)
2162 Point loc = Point.Empty;
2165 case View.LargeIcon:
2166 case View.SmallIcon:
2167 loc.X = index % cols * (item_size.Width + x_spacing);
2168 loc.Y = index / cols * (item_size.Height + y_spacing);
2171 loc.X = index / rows * (item_size.Width + x_spacing);
2172 loc.Y = index % rows * (item_size.Height + y_spacing);
2175 loc.Y = header_control.Height + (index * item_size.Height);
2183 internal int GetItemIndex (int display_index)
2187 return display_index; // no reordering in virtual mode.
2189 return reordered_items_indices [display_index];
2192 internal ListViewItem GetItemAtDisplayIndex (int display_index)
2195 // in virtual mode there's no reordering at all.
2197 return items [display_index];
2199 return items [reordered_items_indices [display_index]];
2202 internal void SetItemAtDisplayIndex (int display_index, int index)
2204 reordered_items_indices [display_index] = index;
2207 private bool KeySearchString (KeyEventArgs ke)
2209 int current_tickcnt = Environment.TickCount;
2210 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2211 keysearch_text = string.Empty;
2214 if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2217 keysearch_text += (char)ke.KeyCode;
2218 keysearch_tickcnt = current_tickcnt;
2220 int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex;
2221 int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0;
2223 ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true);
2224 if (item != null && prev_focused != item.DisplayIndex) {
2225 selected_indices.Clear ();
2227 SetFocusedItem (item.DisplayIndex);
2228 item.Selected = true;
2229 EnsureVisible (GetItemIndex (item.DisplayIndex));
2235 private void OnItemsChanged ()
2237 ResetSearchString ();
2240 private void ResetSearchString ()
2242 keysearch_text = String.Empty;
2245 int GetAdjustedIndex (Keys key)
2249 if (View == View.Details) {
2252 result = FocusedItem.DisplayIndex - 1;
2255 result = FocusedItem.DisplayIndex + 1;
2256 if (result == items.Count)
2260 int last_index = LastVisibleIndex;
2261 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2262 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2264 if (FocusedItem.DisplayIndex == last_index) {
2265 if (FocusedItem.DisplayIndex < Items.Count - 1) {
2266 int page_size = item_control.Height / ItemSize.Height - 1;
2267 result = FocusedItem.DisplayIndex + page_size - 1;
2268 if (result >= Items.Count)
2269 result = Items.Count - 1;
2272 result = last_index;
2275 int first_index = FirstVisibleIndex;
2276 if (GetItemLocation (first_index).Y < 0)
2278 if (FocusedItem.DisplayIndex == first_index) {
2279 if (first_index > 0) {
2280 int page_size = item_control.Height / ItemSize.Height - 1;
2281 result = first_index - page_size + 1;
2286 result = first_index;
2294 return GetFixedAdjustedIndex (key);
2297 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex];
2298 int row = item_matrix_location.Row;
2299 int col = item_matrix_location.Col;
2301 int adjusted_index = -1;
2307 adjusted_index = item_index_matrix [row, col - 1];
2311 if (col == (cols - 1))
2313 while (item_index_matrix [row, col + 1] == 0) {
2318 adjusted_index = item_index_matrix [row, col + 1];
2324 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2329 adjusted_index = item_index_matrix [row - 1, col];
2333 if (row == (rows - 1) || row == Items.Count - 1)
2335 while (item_index_matrix [row + 1, col] == 0) {
2340 adjusted_index = item_index_matrix [row + 1, col];
2347 return items [adjusted_index].DisplayIndex;
2351 // Used for virtual mode, where items *cannot* be re-arranged
2352 int GetFixedAdjustedIndex (Keys key)
2358 if (view == View.List)
2359 result = focused_item_index - rows;
2361 result = focused_item_index - 1;
2364 if (view == View.List)
2365 result = focused_item_index + rows;
2367 result = focused_item_index + 1;
2370 if (view != View.List)
2371 result = focused_item_index - cols;
2373 result = focused_item_index - 1;
2376 if (view != View.List)
2377 result = focused_item_index + cols;
2379 result = focused_item_index + 1;
2386 if (result < 0 || result >= items.Count)
2387 result = focused_item_index;
2393 ListViewItem selection_start;
2395 private bool SelectItems (ArrayList sel_items)
2397 bool changed = false;
2398 foreach (ListViewItem item in SelectedItems)
2399 if (!sel_items.Contains (item)) {
2400 item.Selected = false;
2403 foreach (ListViewItem item in sel_items)
2404 if (!item.Selected) {
2405 item.Selected = true;
2411 private void UpdateMultiSelection (int index, bool reselect)
2413 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2414 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2415 ListViewItem item = GetItemAtDisplayIndex (index);
2417 if (shift_pressed && selection_start != null) {
2418 ArrayList list = new ArrayList ();
2419 int start_index = selection_start.DisplayIndex;
2420 int start = Math.Min (start_index, index);
2421 int end = Math.Max (start_index, index);
2422 if (View == View.Details) {
2423 for (int i = start; i <= end; i++)
2424 list.Add (GetItemAtDisplayIndex (i));
2426 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2427 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2428 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2429 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2430 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2431 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2433 for (int i = 0; i < items.Count; i++) {
2434 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2436 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2437 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2438 list.Add (GetItemAtDisplayIndex (i));
2442 } else if (ctrl_pressed) {
2443 item.Selected = !item.Selected;
2444 selection_start = item;
2447 // do not unselect, and reselect the item
2448 foreach (int itemIndex in SelectedIndices) {
2449 if (index == itemIndex)
2451 items [itemIndex].Selected = false;
2454 SelectedItems.Clear ();
2455 item.Selected = true;
2457 selection_start = item;
2461 internal override bool InternalPreProcessMessage (ref Message msg)
2463 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2464 Keys key_data = (Keys)msg.WParam.ToInt32();
2466 HandleNavKeys (key_data);
2469 return base.InternalPreProcessMessage (ref msg);
2472 bool HandleNavKeys (Keys key_data)
2474 if (Items.Count == 0 || !item_control.Visible)
2477 if (FocusedItem == null)
2482 SelectIndex (Items.Count - 1);
2495 SelectIndex (GetAdjustedIndex (key_data));
2499 SelectIndex (focused_item_index);
2500 ToggleItemsCheckState ();
2503 if (selected_indices.Count > 0)
2504 OnItemActivate (EventArgs.Empty);
2514 void ToggleItemsCheckState ()
2519 // Don't modify check state if StateImageList has less than 2 elements
2520 if (StateImageList != null && StateImageList.Images.Count < 2)
2523 if (SelectedIndices.Count > 0) {
2524 for (int i = 0; i < SelectedIndices.Count; i++) {
2525 ListViewItem item = Items [SelectedIndices [i]];
2526 item.Checked = !item.Checked;
2531 if (FocusedItem != null) {
2532 FocusedItem.Checked = !FocusedItem.Checked;
2533 SelectIndex (FocusedItem.Index);
2537 void SelectIndex (int display_index)
2539 if (display_index == -1)
2543 UpdateMultiSelection (display_index, true);
2544 else if (!GetItemAtDisplayIndex (display_index).Selected)
2545 GetItemAtDisplayIndex (display_index).Selected = true;
2547 SetFocusedItem (display_index);
2548 EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index
2551 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2553 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2556 if (ke.Alt || ke.Control)
2559 ke.Handled = KeySearchString (ke);
2562 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2564 Point loc = PointToClient (Control.MousePosition);
2565 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2568 internal class ItemControl : Control {
2571 ListViewItem clicked_item;
2572 ListViewItem last_clicked_item;
2573 bool hover_processed = false;
2574 bool checking = false;
2575 ListViewItem prev_hovered_item;
2577 ListViewItem prev_tooltip_item;
2580 Point drag_begin = new Point (-1, -1);
2581 internal int dragged_item_index = -1;
2583 ListViewLabelEditTextBox edit_text_box;
2584 internal ListViewItem edit_item;
2585 LabelEditEventArgs edit_args;
2587 public ItemControl (ListView owner)
2590 this.SetStyle (ControlStyles.DoubleBuffer, true);
2591 DoubleClick += new EventHandler(ItemsDoubleClick);
2592 MouseDown += new MouseEventHandler(ItemsMouseDown);
2593 MouseMove += new MouseEventHandler(ItemsMouseMove);
2594 MouseHover += new EventHandler(ItemsMouseHover);
2595 MouseUp += new MouseEventHandler(ItemsMouseUp);
2598 void ItemsDoubleClick (object sender, EventArgs e)
2600 if (owner.activation == ItemActivation.Standard)
2601 owner.OnItemActivate (EventArgs.Empty);
2611 BoxSelect box_select_mode = BoxSelect.None;
2612 IList prev_selection;
2613 Point box_select_start;
2615 Rectangle box_select_rect;
2616 internal Rectangle BoxSelectRectangle {
2617 get { return box_select_rect; }
2619 if (box_select_rect == value)
2622 InvalidateBoxSelectRect ();
2623 box_select_rect = value;
2624 InvalidateBoxSelectRect ();
2628 void InvalidateBoxSelectRect ()
2630 if (BoxSelectRectangle.Size.IsEmpty)
2633 Rectangle edge = BoxSelectRectangle;
2639 edge.Y = BoxSelectRectangle.Bottom - 1;
2641 edge.Y = BoxSelectRectangle.Y - 1;
2643 edge.Height = BoxSelectRectangle.Height + 2;
2645 edge.X = BoxSelectRectangle.Right - 1;
2649 private Rectangle CalculateBoxSelectRectangle (Point pt)
2651 int left = Math.Min (box_select_start.X, pt.X);
2652 int right = Math.Max (box_select_start.X, pt.X);
2653 int top = Math.Min (box_select_start.Y, pt.Y);
2654 int bottom = Math.Max (box_select_start.Y, pt.Y);
2655 return Rectangle.FromLTRB (left, top, right, bottom);
2658 bool BoxIntersectsItem (int index)
2660 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2661 if (owner.View != View.Details) {
2663 r.Y += r.Height / 4;
2667 return BoxSelectRectangle.IntersectsWith (r);
2670 bool BoxIntersectsText (int index)
2672 Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds;
2673 return BoxSelectRectangle.IntersectsWith (r);
2676 ArrayList BoxSelectedItems {
2678 ArrayList result = new ArrayList ();
2679 for (int i = 0; i < owner.Items.Count; i++) {
2682 // Can't iterate over specific items properties in virtualmode
2683 if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode)
2685 if (owner.View == View.Details && !owner.FullRowSelect)
2687 intersects = BoxIntersectsText (i);
2689 intersects = BoxIntersectsItem (i);
2692 result.Add (owner.GetItemAtDisplayIndex (i));
2698 private bool PerformBoxSelection (Point pt)
2700 if (box_select_mode == BoxSelect.None)
2703 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2705 ArrayList box_items = BoxSelectedItems;
2709 switch (box_select_mode) {
2711 case BoxSelect.Normal:
2715 case BoxSelect.Control:
2716 items = new ArrayList ();
2717 foreach (int index in prev_selection)
2718 if (!box_items.Contains (owner.Items [index]))
2719 items.Add (owner.Items [index]);
2720 foreach (ListViewItem item in box_items)
2721 if (!prev_selection.Contains (item.Index))
2725 case BoxSelect.Shift:
2727 foreach (ListViewItem item in box_items)
2728 prev_selection.Remove (item.Index);
2729 foreach (int index in prev_selection)
2730 items.Add (owner.Items [index]);
2734 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2738 owner.SelectItems (items);
2744 private void ItemsMouseDown (object sender, MouseEventArgs me)
2746 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2747 if (owner.items.Count == 0)
2750 bool box_selecting = false;
2751 Size item_size = owner.ItemSize;
2752 Point pt = new Point (me.X, me.Y);
2753 for (int i = 0; i < owner.items.Count; i++) {
2754 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2755 if (!item_rect.Contains (pt))
2758 // Actual item in 'i' position
2759 ListViewItem item = owner.GetItemAtDisplayIndex (i);
2761 if (item.CheckRectReal.Contains (pt)) {
2762 // Don't modify check state if we have only one image
2763 // and if we are in 1.1 profile only take into account
2765 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2772 // Generate an extra ItemCheck event when we got two clicks
2773 // (Match weird .Net behaviour)
2775 item.Checked = !item.Checked;
2777 item.Checked = !item.Checked;
2782 if (owner.View == View.Details) {
2783 bool over_text = item.TextBounds.Contains (pt);
2784 if (owner.FullRowSelect) {
2785 clicked_item = item;
2786 bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2787 if (!over_text && over_item_column && owner.MultiSelect)
2788 box_selecting = true;
2789 } else if (over_text)
2790 clicked_item = item;
2792 owner.SetFocusedItem (i);
2794 clicked_item = item;
2800 if (clicked_item != null) {
2801 bool changed = !clicked_item.Selected;
2802 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2803 owner.SetFocusedItem (clicked_item.DisplayIndex);
2805 if (owner.MultiSelect) {
2806 bool reselect = (!owner.LabelEdit || changed);
2807 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2808 owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect);
2810 clicked_item.Selected = true;
2814 if (owner.VirtualMode && changed) {
2815 // Broken event - It's not fired from Item.Selected also
2816 ListViewVirtualItemsSelectionRangeChangedEventArgs args =
2817 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2819 owner.OnVirtualItemsSelectionRangeChanged (args);
2822 // Report clicks only if the item was clicked. On MS the
2823 // clicks are only raised if you click an item
2825 if (me.Clicks > 1) {
2826 if (owner.CheckBoxes)
2827 clicked_item.Checked = !clicked_item.Checked;
2828 } else if (me.Clicks == 1) {
2829 if (owner.LabelEdit && !changed)
2830 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2833 if (owner.MultiSelect)
2834 box_selecting = true;
2835 else if (owner.SelectedItems.Count > 0)
2836 owner.SelectedItems.Clear ();
2839 if (box_selecting) {
2840 Keys mods = XplatUI.State.ModifierKeys;
2841 if ((mods & Keys.Shift) != 0)
2842 box_select_mode = BoxSelect.Shift;
2843 else if ((mods & Keys.Control) != 0)
2844 box_select_mode = BoxSelect.Control;
2846 box_select_mode = BoxSelect.Normal;
2847 box_select_start = pt;
2848 prev_selection = owner.SelectedIndices.List.Clone () as IList;
2852 private void ItemsMouseMove (object sender, MouseEventArgs me)
2854 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2856 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2860 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2861 !hover_processed && owner.Activation != ItemActivation.OneClick
2863 && !owner.ShowItemToolTips
2868 Point pt = PointToClient (Control.MousePosition);
2869 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2871 if (hover_processed && item != null && item != prev_hovered_item) {
2872 hover_processed = false;
2873 XplatUI.ResetMouseHover (Handle);
2876 // Need to invalidate the item in HotTracking to show/hide the underline style
2877 if (owner.Activation == ItemActivation.OneClick) {
2878 if (item == null && owner.HotItemIndex != -1) {
2880 if (owner.HotTracking)
2881 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2884 Cursor = Cursors.Default;
2885 owner.HotItemIndex = -1;
2886 } else if (item != null && owner.HotItemIndex == -1) {
2888 if (owner.HotTracking)
2889 Invalidate (item.Bounds);
2892 Cursor = Cursors.Hand;
2893 owner.HotItemIndex = item.Index;
2897 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2898 if (drag_begin.X == -1 && drag_begin.Y == -1) {
2900 drag_begin = new Point (me.X, me.Y);
2901 dragged_item_index = item.Index;
2905 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2906 if (!r.Contains (me.X, me.Y)) {
2907 ListViewItem dragged_item = owner.items [dragged_item_index];
2908 owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2910 drag_begin = new Point (-1, -1);
2911 dragged_item_index = -1;
2917 if (owner.ShowItemToolTips) {
2919 owner.item_tooltip.Active = false;
2920 prev_tooltip_item = null;
2921 } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2922 owner.item_tooltip.Active = true;
2923 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2924 prev_tooltip_item = item;
2931 private void ItemsMouseHover (object sender, EventArgs e)
2933 if (owner.hover_pending) {
2934 owner.OnMouseHover (e);
2935 owner.hover_pending = false;
2941 hover_processed = true;
2942 Point pt = PointToClient (Control.MousePosition);
2943 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2947 prev_hovered_item = item;
2949 if (owner.HoverSelection) {
2950 if (owner.MultiSelect)
2951 owner.UpdateMultiSelection (item.Index, true);
2953 item.Selected = true;
2955 owner.SetFocusedItem (item.DisplayIndex);
2956 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2960 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2964 void HandleClicks (MouseEventArgs me)
2966 // if the click is not on an item,
2967 // clicks remains as 0
2970 owner.OnDoubleClick (EventArgs.Empty);
2971 } else if (clicks == 1) {
2972 owner.OnClick (EventArgs.Empty);
2974 owner.OnDoubleClick (EventArgs.Empty);
2975 owner.OnMouseDoubleClick (me);
2976 } else if (clicks == 1) {
2977 owner.OnClick (EventArgs.Empty);
2978 owner.OnMouseClick (me);
2985 private void ItemsMouseUp (object sender, MouseEventArgs me)
2987 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
2988 HandleClicks (owner_me);
2991 if (owner.Items.Count == 0) {
2993 owner.OnMouseUp (owner_me);
2997 Point pt = new Point (me.X, me.Y);
2999 Rectangle rect = Rectangle.Empty;
3000 if (clicked_item != null) {
3001 if (owner.view == View.Details && !owner.full_row_select)
3002 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
3004 rect = clicked_item.Bounds;
3006 if (rect.Contains (pt)) {
3007 switch (owner.activation) {
3008 case ItemActivation.OneClick:
3009 owner.OnItemActivate (EventArgs.Empty);
3012 case ItemActivation.TwoClick:
3013 if (last_clicked_item == clicked_item) {
3014 owner.OnItemActivate (EventArgs.Empty);
3015 last_clicked_item = null;
3017 last_clicked_item = clicked_item;
3020 // DoubleClick activation is handled in another handler
3024 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
3025 // Need this to clean up background clicks
3026 owner.SelectedItems.Clear ();
3030 owner.OnMouseUp (owner_me);
3033 private void ResetMouseState ()
3035 clicked_item = null;
3036 box_select_start = Point.Empty;
3037 BoxSelectRectangle = Rectangle.Empty;
3038 prev_selection = null;
3039 box_select_mode = BoxSelect.None;
3042 // Clean these bits in case the mouse buttons were
3043 // released before firing ItemDrag
3044 dragged_item_index = -1;
3045 drag_begin = new Point (-1, -1);
3048 private void LabelEditFinished (object sender, EventArgs e)
3050 EndEdit (edit_item);
3053 private void LabelEditCancelled (object sender, EventArgs e)
3055 edit_args.SetLabel (null);
3056 EndEdit (edit_item);
3059 private void LabelTextChanged (object sender, EventArgs e)
3061 if (edit_args != null)
3062 edit_args.SetLabel (edit_text_box.Text);
3065 internal void BeginEdit (ListViewItem item)
3067 if (edit_item != null)
3068 EndEdit (edit_item);
3070 if (edit_text_box == null) {
3071 edit_text_box = new ListViewLabelEditTextBox ();
3072 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
3073 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
3074 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
3075 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
3076 edit_text_box.Visible = false;
3077 Controls.Add (edit_text_box);
3080 item.EnsureVisible();
3082 edit_text_box.Reset ();
3084 switch (owner.view) {
3086 case View.SmallIcon:
3088 edit_text_box.TextAlign = HorizontalAlignment.Left;
3089 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
3090 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
3091 edit_text_box.Width = (int)sizef.Width + 4;
3092 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
3093 edit_text_box.WordWrap = false;
3094 edit_text_box.Multiline = false;
3096 case View.LargeIcon:
3097 edit_text_box.TextAlign = HorizontalAlignment.Center;
3098 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
3099 sizef = TextRenderer.MeasureString (item.Text, item.Font);
3100 edit_text_box.Width = (int)sizef.Width + 4;
3101 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
3102 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
3103 edit_text_box.WordWrap = true;
3104 edit_text_box.Multiline = true;
3110 edit_text_box.Text = item.Text;
3111 edit_text_box.Font = item.Font;
3112 edit_text_box.Visible = true;
3113 edit_text_box.Focus ();
3114 edit_text_box.SelectAll ();
3116 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
3117 owner.OnBeforeLabelEdit (edit_args);
3119 if (edit_args.CancelEdit)
3123 internal void CancelEdit (ListViewItem item)
3125 // do nothing if there's no item being edited, or if the
3126 // item being edited is not the one passed in
3127 if (edit_item == null || edit_item != item)
3130 edit_args.SetLabel (null);
3134 internal void EndEdit (ListViewItem item)
3136 // do nothing if there's no item being edited, or if the
3137 // item being edited is not the one passed in
3138 if (edit_item == null || edit_item != item)
3141 if (edit_text_box != null) {
3142 if (edit_text_box.Visible)
3143 edit_text_box.Visible = false;
3144 // ensure listview gets focus
3148 // Same as TreeView.EndEdit: need to have focus in synch
3149 Application.DoEvents ();
3152 // Create a new instance, since we could get a call to BeginEdit
3153 // from the handler and have fields out of synch
3155 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
3158 owner.OnAfterLabelEdit (args);
3159 if (!args.CancelEdit && args.Label != null)
3160 item.Text = args.Label;
3163 internal override void OnPaintInternal (PaintEventArgs pe)
3165 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
3168 protected override void WndProc (ref Message m)
3170 switch ((Msg)m.Msg) {
3171 case Msg.WM_KILLFOCUS:
3172 owner.Select (false, true);
3174 case Msg.WM_SETFOCUS:
3175 owner.Select (false, true);
3177 case Msg.WM_LBUTTONDOWN:
3179 owner.Select (false, true);
3181 case Msg.WM_RBUTTONDOWN:
3183 owner.Select (false, true);
3188 base.WndProc (ref m);
3192 internal class ListViewLabelEditTextBox : TextBox
3197 int max_height = -1;
3198 int min_height = -1;
3200 int old_number_lines = 1;
3202 SizeF text_size_one_char;
3204 public ListViewLabelEditTextBox ()
3206 min_height = DefaultSize.Height;
3207 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3210 public int MaxWidth {
3212 if (value < min_width)
3213 max_width = min_width;
3219 public int MaxHeight {
3221 if (value < min_height)
3222 max_height = min_height;
3228 public new int Width {
3238 public override Font Font {
3244 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3248 protected override void OnTextChanged (EventArgs e)
3250 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3252 int new_width = (int)text_size.Width + 8;
3255 ResizeTextBoxWidth (new_width);
3257 if (Width != max_width)
3258 ResizeTextBoxWidth (new_width);
3260 int number_lines = Lines.Length;
3262 if (number_lines != old_number_lines) {
3263 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3264 old_number_lines = number_lines;
3266 ResizeTextBoxHeight (new_height);
3270 base.OnTextChanged (e);
3273 protected override bool IsInputKey (Keys key_data)
3275 if ((key_data & Keys.Alt) == 0) {
3276 switch (key_data & Keys.KeyCode) {
3283 return base.IsInputKey (key_data);
3286 protected override void OnKeyDown (KeyEventArgs e)
3291 switch (e.KeyCode) {
3295 OnEditingFinished (e);
3300 OnEditingCancelled (e);
3305 protected override void OnLostFocus (EventArgs e)
3308 OnEditingFinished (e);
3312 protected void OnEditingCancelled (EventArgs e)
3314 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3319 protected void OnEditingFinished (EventArgs e)
3321 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3326 private void ResizeTextBoxWidth (int new_width)
3328 if (new_width > max_width)
3329 base.Width = max_width;
3331 if (new_width >= min_width)
3332 base.Width = new_width;
3334 base.Width = min_width;
3337 private void ResizeTextBoxHeight (int new_height)
3339 if (new_height > max_height)
3340 base.Height = max_height;
3342 if (new_height >= min_height)
3343 base.Height = new_height;
3345 base.Height = min_height;
3348 public void Reset ()
3355 old_number_lines = 1;
3357 Text = String.Empty;
3362 static object EditingCancelledEvent = new object ();
3363 public event EventHandler EditingCancelled {
3364 add { Events.AddHandler (EditingCancelledEvent, value); }
3365 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3368 static object EditingFinishedEvent = new object ();
3369 public event EventHandler EditingFinished {
3370 add { Events.AddHandler (EditingFinishedEvent, value); }
3371 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3375 internal override void OnPaintInternal (PaintEventArgs pe)
3380 CalculateScrollBars ();
3383 void FocusChanged (object o, EventArgs args)
3385 if (Items.Count == 0)
3388 if (FocusedItem == null)
3391 ListViewItem focused_item = FocusedItem;
3393 if (focused_item.ListView != null) {
3394 focused_item.Invalidate ();
3395 focused_item.Layout ();
3396 focused_item.Invalidate ();
3400 private void ListView_Invalidated (object sender, InvalidateEventArgs e)
3402 // When the ListView is invalidated, we need to invalidate
3403 // the child controls.
3404 header_control.Invalidate ();
3405 item_control.Invalidate ();
3408 private void ListView_MouseEnter (object sender, EventArgs args)
3410 hover_pending = true; // Need a hover event for every Enter/Leave cycle
3413 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3415 if (Items.Count == 0)
3418 int lines = me.Delta / 120;
3425 case View.SmallIcon:
3426 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3428 case View.LargeIcon:
3429 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
3432 Scroll (h_scroll, -ItemSize.Width * lines);
3436 if (!Application.VisualStylesEnabled)
3437 goto case View.LargeIcon;
3439 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3445 private void ListView_SizeChanged (object sender, EventArgs e)
3450 private void SetFocusedItem (int display_index)
3452 if (display_index != -1)
3453 GetItemAtDisplayIndex (display_index).Focused = true;
3454 else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3455 GetItemAtDisplayIndex (focused_item_index).Focused = false;
3456 focused_item_index = display_index;
3458 if (display_index == -1)
3459 OnUIAFocusedItemChanged ();
3460 // otherwise the event will have been fired
3461 // when the ListViewItem's Focused was set
3465 private void HorizontalScroller (object sender, EventArgs e)
3467 item_control.EndEdit (item_control.edit_item);
3469 // Avoid unnecessary flickering, when button is
3470 // kept pressed at the end
3471 if (h_marker != h_scroll.Value) {
3473 int pixels = h_marker - h_scroll.Value;
3475 h_marker = h_scroll.Value;
3476 if (header_control.Visible)
3477 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3479 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3483 private void VerticalScroller (object sender, EventArgs e)
3485 item_control.EndEdit (item_control.edit_item);
3487 // Avoid unnecessary flickering, when button is
3488 // kept pressed at the end
3489 if (v_marker != v_scroll.Value) {
3490 int pixels = v_marker - v_scroll.Value;
3491 Rectangle area = item_control.ClientRectangle;
3492 if (header_control.Visible) {
3493 area.Y += header_control.Height;
3494 area.Height -= header_control.Height;
3497 v_marker = v_scroll.Value;
3498 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3502 internal override bool IsInputCharInternal (char charCode)
3506 #endregion // Internal Methods Properties
3508 #region Protected Methods
3509 protected override void CreateHandle ()
3511 base.CreateHandle ();
3512 is_selection_available = true;
3513 for (int i = 0; i < SelectedItems.Count; i++)
3514 OnSelectedIndexChanged (EventArgs.Empty);
3517 protected override void Dispose (bool disposing)
3520 h_scroll.Dispose ();
3521 v_scroll.Dispose ();
3523 large_image_list = null;
3524 small_image_list = null;
3525 state_image_list = null;
3527 foreach (ColumnHeader col in columns)
3528 col.SetListView (null);
3531 if (!virtual_mode) // In virtual mode we don't save the items
3533 foreach (ListViewItem item in items)
3537 base.Dispose (disposing);
3540 protected override bool IsInputKey (Keys keyData)
3557 return base.IsInputKey (keyData);
3560 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3562 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3568 protected override void OnBackgroundImageChanged (EventArgs e)
3570 item_control.BackgroundImage = BackgroundImage;
3571 base.OnBackgroundImageChanged (e);
3575 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3577 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3582 protected internal virtual void OnColumnClick (ColumnClickEventArgs e)
3584 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3590 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3592 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3597 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3599 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3604 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3606 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3612 protected override void OnEnabledChanged (EventArgs e)
3614 base.OnEnabledChanged (e);
3618 protected override void OnFontChanged (EventArgs e)
3620 base.OnFontChanged (e);
3624 protected override void OnHandleCreated (EventArgs e)
3626 base.OnHandleCreated (e);
3627 CalculateListView (alignment);
3629 if (!virtual_mode) // Sorting is not allowed in virtual mode
3634 protected override void OnHandleDestroyed (EventArgs e)
3636 base.OnHandleDestroyed (e);
3639 protected virtual void OnItemActivate (EventArgs e)
3641 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3646 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3648 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3654 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3656 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3662 protected virtual void OnItemDrag (ItemDragEventArgs e)
3664 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3670 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3672 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3677 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3679 ListViewItemSelectionChangedEventHandler eh =
3680 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3685 protected override void OnMouseHover (EventArgs e)
3687 base.OnMouseHover (e);
3690 protected override void OnParentChanged (EventArgs e)
3692 base.OnParentChanged (e);
3696 protected virtual void OnSelectedIndexChanged (EventArgs e)
3698 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3703 protected override void OnSystemColorsChanged (EventArgs e)
3705 base.OnSystemColorsChanged (e);
3709 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3711 CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3716 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3718 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3723 [EditorBrowsable (EditorBrowsableState.Advanced)]
3724 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3726 EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3731 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3733 SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3738 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3740 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3741 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3747 protected void RealizeProperties ()
3752 protected void UpdateExtendedStyles ()
3757 bool refocusing = false;
3759 protected override void WndProc (ref Message m)
3761 switch ((Msg)m.Msg) {
3762 case Msg.WM_KILLFOCUS:
3763 Control receiver = Control.FromHandle (m.WParam);
3764 if (receiver == item_control) {
3770 case Msg.WM_SETFOCUS:
3780 base.WndProc (ref m);
3782 #endregion // Protected Methods
3784 #region Public Instance Methods
3785 public void ArrangeIcons ()
3787 ArrangeIcons (this.alignment);
3790 public void ArrangeIcons (ListViewAlignment value)
3792 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3793 if (view == View.LargeIcon || view == View.SmallIcon)
3798 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3800 if (columnIndex < 0 || columnIndex >= columns.Count)
3801 throw new ArgumentOutOfRangeException ("columnIndex");
3803 columns [columnIndex].AutoResize (headerAutoResize);
3806 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3809 foreach (ColumnHeader col in columns)
3810 col.AutoResize (headerAutoResize);
3815 public void BeginUpdate ()
3817 // flag to avoid painting
3821 public void Clear ()
3824 items.Clear (); // Redraw (true) called here
3827 public void EndUpdate ()
3829 // flag to avoid painting
3832 // probably, now we need a redraw with recalculations
3836 public void EnsureVisible (int index)
3838 if (index < 0 || index >= items.Count || scrollable == false || updating)
3841 Rectangle view_rect = item_control.ClientRectangle;
3843 // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items
3844 Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds;
3846 Rectangle bounds = items [index].Bounds;
3849 if (view == View.Details && header_style != ColumnHeaderStyle.None) {
3850 view_rect.Y += header_control.Height;
3851 view_rect.Height -= header_control.Height;
3854 if (view_rect.Contains (bounds))
3857 if (View != View.Details) {
3858 if (bounds.Left < 0)
3859 h_scroll.Value += bounds.Left;
3860 else if (bounds.Right > view_rect.Right)
3861 h_scroll.Value += (bounds.Right - view_rect.Right);
3864 if (bounds.Top < view_rect.Y)
3865 v_scroll.Value += bounds.Top - view_rect.Y;
3866 else if (bounds.Bottom > view_rect.Bottom)
3867 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3871 public ListViewItem FindItemWithText (string text)
3873 if (items.Count == 0)
3876 return FindItemWithText (text, true, 0, true);
3879 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3881 return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3884 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3886 return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3890 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3892 if (startIndex < 0 || startIndex >= items.Count)
3893 throw new ArgumentOutOfRangeException ("startIndex");
3896 throw new ArgumentNullException ("text");
3900 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3901 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty,
3902 SearchDirectionHint.Down, startIndex);
3904 OnSearchForVirtualItem (args);
3905 int idx = args.Index;
3906 if (idx >= 0 && idx < virtual_list_size)
3915 ListViewItem lvi = items [i];
3917 if (isPrefixSearch) { // prefix search
3918 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3920 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3923 if (i + 1 >= items.Count) {
3931 if (i == startIndex)
3935 // Subitems have a minor priority, so we have to do a second linear search
3936 // Also, we don't need to to a roundtrip search for them by now
3937 if (includeSubItemsInSearch) {
3938 for (i = startIndex; i < items.Count; i++) {
3939 ListViewItem lvi = items [i];
3940 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3941 if (isPrefixSearch) {
3942 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text,
3943 text, CompareOptions.IgnoreCase))
3945 } else if (String.Compare (sub_item.Text, text, true) == 0)
3954 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3956 return FindNearestItem (searchDirection, new Point (x, y));
3959 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3961 if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3962 throw new ArgumentOutOfRangeException ("searchDirection");
3964 if (view != View.LargeIcon && view != View.SmallIcon)
3965 throw new InvalidOperationException ();
3968 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3969 false, false, String.Empty, point,
3972 OnSearchForVirtualItem (args);
3973 int idx = args.Index;
3974 if (idx >= 0 && idx < virtual_list_size)
3980 ListViewItem item = null;
3981 int min_dist = Int32.MaxValue;
3984 // It looks like .Net does a previous adjustment
3987 case SearchDirectionHint.Up:
3988 point.Y -= item_size.Height;
3990 case SearchDirectionHint.Down:
3991 point.Y += item_size.Height;
3993 case SearchDirectionHint.Left:
3994 point.X -= item_size.Width;
3996 case SearchDirectionHint.Right:
3997 point.X += item_size.Width;
4001 for (int i = 0; i < items.Count; i++) {
4002 Point item_loc = GetItemLocation (i);
4004 if (dir == SearchDirectionHint.Up) {
4005 if (point.Y < item_loc.Y)
4007 } else if (dir == SearchDirectionHint.Down) {
4008 if (point.Y > item_loc.Y)
4010 } else if (dir == SearchDirectionHint.Left) {
4011 if (point.X < item_loc.X)
4013 } else if (dir == SearchDirectionHint.Right) {
4014 if (point.X > item_loc.X)
4018 int x_dist = point.X - item_loc.X;
4019 int y_dist = point.Y - item_loc.Y;
4021 int dist = x_dist * x_dist + y_dist * y_dist;
4022 if (dist < min_dist) {
4032 public ListViewItem GetItemAt (int x, int y)
4034 Size item_size = ItemSize;
4035 for (int i = 0; i < items.Count; i++) {
4036 Point item_location = GetItemLocation (i);
4037 Rectangle item_rect = new Rectangle (item_location, item_size);
4038 if (item_rect.Contains (x, y))
4045 public Rectangle GetItemRect (int index)
4047 return GetItemRect (index, ItemBoundsPortion.Entire);
4050 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
4052 if (index < 0 || index >= items.Count)
4053 throw new IndexOutOfRangeException ("index");
4055 return items [index].GetBounds (portion);
4059 public ListViewHitTestInfo HitTest (Point point)
4061 return HitTest (point.X, point.Y);
4064 public ListViewHitTestInfo HitTest (int x, int y)
4067 throw new ArgumentOutOfRangeException ("x");
4069 throw new ArgumentOutOfRangeException ("y");
4071 ListViewItem item = GetItemAt (x, y);
4073 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
4075 ListViewHitTestLocations locations = 0;
4076 if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
4077 locations |= ListViewHitTestLocations.Label;
4078 else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
4079 locations |= ListViewHitTestLocations.Image;
4080 else if (item.CheckRectReal.Contains (x, y))
4081 locations |= ListViewHitTestLocations.StateImage;
4083 ListViewItem.ListViewSubItem subitem = null;
4084 if (view == View.Details)
4085 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
4086 if (si.Bounds.Contains (x, y)) {
4091 return new ListViewHitTestInfo (item, subitem, locations);
4094 [EditorBrowsable (EditorBrowsableState.Advanced)]
4095 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
4097 if (startIndex < 0 || startIndex >= items.Count)
4098 throw new ArgumentOutOfRangeException ("startIndex");
4099 if (endIndex < 0 || endIndex >= items.Count)
4100 throw new ArgumentOutOfRangeException ("endIndex");
4101 if (startIndex > endIndex)
4102 throw new ArgumentException ("startIndex");
4107 for (int i = startIndex; i <= endIndex; i++)
4108 items [i].Invalidate ();
4110 if (!invalidateOnly)
4119 throw new InvalidOperationException ();
4125 // we need this overload to reuse the logic for sorting, while allowing
4126 // redrawing to be done by caller or have it done by this method when
4127 // sorting is really performed
4129 // ListViewItemCollection's Add and AddRange methods call this overload
4130 // with redraw set to false, as they take care of redrawing themselves
4131 // (they even want to redraw the listview if no sort is performed, as
4132 // an item was added), while ListView.Sort () only wants to redraw if
4133 // sorting was actually performed
4134 private void Sort (bool redraw)
4136 if (!IsHandleCreated || item_sorter == null) {
4140 items.Sort (item_sorter);
4145 public override string ToString ()
4147 int count = this.Items.Count;
4150 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
4152 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
4154 #endregion // Public Instance Methods
4159 internal class HeaderControl : Control {
4162 bool column_resize_active = false;
4163 ColumnHeader resize_column;
4164 ColumnHeader clicked_column;
4165 ColumnHeader drag_column;
4167 int drag_to_index = -1;
4168 ColumnHeader entered_column_header;
4170 public HeaderControl (ListView owner)
4173 this.SetStyle (ControlStyles.DoubleBuffer, true);
4174 MouseDown += new MouseEventHandler (HeaderMouseDown);
4175 MouseMove += new MouseEventHandler (HeaderMouseMove);
4176 MouseUp += new MouseEventHandler (HeaderMouseUp);
4177 MouseLeave += new EventHandler (OnMouseLeave);
4180 internal ColumnHeader EnteredColumnHeader {
4181 get { return entered_column_header; }
4183 if (entered_column_header == value)
4185 if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
4186 Region region_to_invalidate = new Region ();
4187 region_to_invalidate.MakeEmpty ();
4188 if (entered_column_header != null)
4189 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4190 entered_column_header = value;
4191 if (entered_column_header != null)
4192 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4193 Invalidate (region_to_invalidate);
4194 region_to_invalidate.Dispose ();
4196 entered_column_header = value;
4200 void OnMouseLeave (object sender, EventArgs e)
4202 EnteredColumnHeader = null;
4205 private ColumnHeader ColumnAtX (int x)
4207 Point pt = new Point (x, 0);
4208 ColumnHeader result = null;
4209 foreach (ColumnHeader col in owner.Columns) {
4210 if (col.Rect.Contains (pt)) {
4218 private int GetReorderedIndex (ColumnHeader col)
4220 if (owner.reordered_column_indices == null)
4223 for (int i = 0; i < owner.Columns.Count; i++)
4224 if (owner.reordered_column_indices [i] == col.Index)
4226 throw new Exception ("Column index missing from reordered array");
4229 private void HeaderMouseDown (object sender, MouseEventArgs me)
4231 if (resize_column != null) {
4232 column_resize_active = true;
4237 clicked_column = ColumnAtX (me.X + owner.h_marker);
4239 if (clicked_column != null) {
4241 if (owner.AllowColumnReorder) {
4243 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4244 drag_column.Rect = clicked_column.Rect;
4245 drag_to_index = GetReorderedIndex (clicked_column);
4247 clicked_column.Pressed = true;
4248 Invalidate (clicked_column);
4253 void Invalidate (ColumnHeader columnHeader)
4255 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4258 Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4260 Rectangle bounds = columnHeader.Rect;
4261 bounds.X -= owner.h_marker;
4267 column_resize_active = false;
4268 resize_column = null;
4270 Cursor = Cursors.Default;
4273 private void HeaderMouseMove (object sender, MouseEventArgs me)
4275 Point pt = new Point (me.X + owner.h_marker, me.Y);
4277 if (column_resize_active) {
4278 int width = pt.X - resize_column.X;
4282 if (!owner.CanProceedWithResize (resize_column, width)){
4286 resize_column.Width = width;
4290 resize_column = null;
4292 if (clicked_column != null) {
4293 if (owner.AllowColumnReorder) {
4296 r = drag_column.Rect;
4297 r.X = clicked_column.Rect.X + me.X - drag_x;
4298 drag_column.Rect = r;
4300 int x = me.X + owner.h_marker;
4301 ColumnHeader over = ColumnAtX (x);
4303 drag_to_index = owner.Columns.Count;
4304 else if (x < over.X + over.Width / 2)
4305 drag_to_index = GetReorderedIndex (over);
4307 drag_to_index = GetReorderedIndex (over) + 1;
4310 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4311 bool pressed = clicked_column.Pressed;
4312 clicked_column.Pressed = over == clicked_column;
4313 if (clicked_column.Pressed ^ pressed)
4314 Invalidate (clicked_column);
4319 for (int i = 0; i < owner.Columns.Count; i++) {
4320 Rectangle zone = owner.Columns [i].Rect;
4321 if (zone.Contains (pt))
4322 EnteredColumnHeader = owner.Columns [i];
4323 zone.X = zone.Right - 5;
4325 if (zone.Contains (pt)) {
4326 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4328 resize_column = owner.Columns [i];
4333 if (resize_column == null)
4334 Cursor = Cursors.Default;
4336 Cursor = Cursors.VSplit;
4339 void HeaderMouseUp (object sender, MouseEventArgs me)
4343 if (column_resize_active) {
4344 int column_idx = resize_column.Index;
4346 owner.RaiseColumnWidthChanged (column_idx);
4350 if (clicked_column != null && clicked_column.Pressed) {
4351 clicked_column.Pressed = false;
4352 Invalidate (clicked_column);
4353 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4356 if (drag_column != null && owner.AllowColumnReorder) {
4358 if (drag_to_index > GetReorderedIndex (clicked_column))
4360 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4361 owner.ReorderColumn (clicked_column, drag_to_index, true);
4366 clicked_column = null;
4369 internal override void OnPaintInternal (PaintEventArgs pe)
4374 Theme theme = ThemeEngine.Current;
4375 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4377 if (drag_column == null)
4381 if (drag_to_index == owner.Columns.Count)
4382 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4384 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4385 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4388 protected override void WndProc (ref Message m)
4390 switch ((Msg)m.Msg) {
4391 case Msg.WM_SETFOCUS:
4395 base.WndProc (ref m);
4401 private class ItemComparer : IComparer {
4402 readonly SortOrder sort_order;
4404 public ItemComparer (SortOrder sortOrder)
4406 sort_order = sortOrder;
4409 public int Compare (object x, object y)
4411 ListViewItem item_x = x as ListViewItem;
4412 ListViewItem item_y = y as ListViewItem;
4413 if (sort_order == SortOrder.Ascending)
4414 return String.Compare (item_x.Text, item_y.Text);
4416 return String.Compare (item_y.Text, item_x.Text);
4421 [ListBindable (false)]
4423 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4425 private readonly ListView owner;
4427 #region Public Constructor
4428 public CheckedIndexCollection (ListView owner)
4432 #endregion // Public Constructor
4434 #region Public Properties
4437 get { return owner.CheckedItems.Count; }
4440 public bool IsReadOnly {
4441 get { return true; }
4444 public int this [int index] {
4446 int [] indices = GetIndices ();
4447 if (index < 0 || index >= indices.Length)
4448 throw new ArgumentOutOfRangeException ("index");
4449 return indices [index];
4453 bool ICollection.IsSynchronized {
4454 get { return false; }
4457 object ICollection.SyncRoot {
4458 get { return this; }
4461 bool IList.IsFixedSize {
4462 get { return true; }
4465 object IList.this [int index] {
4466 get { return this [index]; }
4467 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4469 #endregion // Public Properties
4471 #region Public Methods
4472 public bool Contains (int checkedIndex)
4474 int [] indices = GetIndices ();
4475 for (int i = 0; i < indices.Length; i++) {
4476 if (indices [i] == checkedIndex)
4482 public IEnumerator GetEnumerator ()
4484 int [] indices = GetIndices ();
4485 return indices.GetEnumerator ();
4488 void ICollection.CopyTo (Array dest, int index)
4490 int [] indices = GetIndices ();
4491 Array.Copy (indices, 0, dest, index, indices.Length);
4494 int IList.Add (object value)
4496 throw new NotSupportedException ("Add operation is not supported.");
4501 throw new NotSupportedException ("Clear operation is not supported.");
4504 bool IList.Contains (object checkedIndex)
4506 if (!(checkedIndex is int))
4508 return Contains ((int) checkedIndex);
4511 int IList.IndexOf (object checkedIndex)
4513 if (!(checkedIndex is int))
4515 return IndexOf ((int) checkedIndex);
4518 void IList.Insert (int index, object value)
4520 throw new NotSupportedException ("Insert operation is not supported.");
4523 void IList.Remove (object value)
4525 throw new NotSupportedException ("Remove operation is not supported.");
4528 void IList.RemoveAt (int index)
4530 throw new NotSupportedException ("RemoveAt operation is not supported.");
4533 public int IndexOf (int checkedIndex)
4535 int [] indices = GetIndices ();
4536 for (int i = 0; i < indices.Length; i++) {
4537 if (indices [i] == checkedIndex)
4542 #endregion // Public Methods
4544 private int [] GetIndices ()
4546 ArrayList checked_items = owner.CheckedItems.List;
4547 int [] indices = new int [checked_items.Count];
4548 for (int i = 0; i < checked_items.Count; i++) {
4549 ListViewItem item = (ListViewItem) checked_items [i];
4550 indices [i] = item.Index;
4554 } // CheckedIndexCollection
4557 [ListBindable (false)]
4559 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4561 private readonly ListView owner;
4562 private ArrayList list;
4564 #region Public Constructor
4565 public CheckedListViewItemCollection (ListView owner)
4568 this.owner.Items.Changed += new CollectionChangedHandler (
4569 ItemsCollection_Changed);
4571 #endregion // Public Constructor
4573 #region Public Properties
4577 if (!owner.CheckBoxes)
4583 public bool IsReadOnly {
4584 get { return true; }
4587 public ListViewItem this [int index] {
4590 if (owner.VirtualMode)
4591 throw new InvalidOperationException ();
4593 ArrayList checked_items = List;
4594 if (index < 0 || index >= checked_items.Count)
4595 throw new ArgumentOutOfRangeException ("index");
4596 return (ListViewItem) checked_items [index];
4601 public virtual ListViewItem this [string key] {
4603 int idx = IndexOfKey (key);
4604 return idx == -1 ? null : (ListViewItem) List [idx];
4609 bool ICollection.IsSynchronized {
4610 get { return false; }
4613 object ICollection.SyncRoot {
4614 get { return this; }
4617 bool IList.IsFixedSize {
4618 get { return true; }
4621 object IList.this [int index] {
4622 get { return this [index]; }
4623 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4625 #endregion // Public Properties
4627 #region Public Methods
4628 public bool Contains (ListViewItem item)
4630 if (!owner.CheckBoxes)
4632 return List.Contains (item);
4636 public virtual bool ContainsKey (string key)
4638 return IndexOfKey (key) != -1;
4642 public void CopyTo (Array dest, int index)
4645 if (owner.VirtualMode)
4646 throw new InvalidOperationException ();
4648 if (!owner.CheckBoxes)
4650 List.CopyTo (dest, index);
4653 public IEnumerator GetEnumerator ()
4656 if (owner.VirtualMode)
4657 throw new InvalidOperationException ();
4659 if (!owner.CheckBoxes)
4660 return (new ListViewItem [0]).GetEnumerator ();
4661 return List.GetEnumerator ();
4664 int IList.Add (object value)
4666 throw new NotSupportedException ("Add operation is not supported.");
4671 throw new NotSupportedException ("Clear operation is not supported.");
4674 bool IList.Contains (object item)
4676 if (!(item is ListViewItem))
4678 return Contains ((ListViewItem) item);
4681 int IList.IndexOf (object item)
4683 if (!(item is ListViewItem))
4685 return IndexOf ((ListViewItem) item);
4688 void IList.Insert (int index, object value)
4690 throw new NotSupportedException ("Insert operation is not supported.");
4693 void IList.Remove (object value)
4695 throw new NotSupportedException ("Remove operation is not supported.");
4698 void IList.RemoveAt (int index)
4700 throw new NotSupportedException ("RemoveAt operation is not supported.");
4703 public int IndexOf (ListViewItem item)
4706 if (owner.VirtualMode)
4707 throw new InvalidOperationException ();
4709 if (!owner.CheckBoxes)
4711 return List.IndexOf (item);
4715 public virtual int IndexOfKey (string key)
4718 if (owner.VirtualMode)
4719 throw new InvalidOperationException ();
4721 if (key == null || key.Length == 0)
4724 ArrayList checked_items = List;
4725 for (int i = 0; i < checked_items.Count; i++) {
4726 ListViewItem item = (ListViewItem) checked_items [i];
4727 if (String.Compare (key, item.Name, true) == 0)
4734 #endregion // Public Methods
4736 internal ArrayList List {
4739 list = new ArrayList ();
4740 foreach (ListViewItem item in owner.Items) {
4749 internal void Reset ()
4751 // force re-population of list
4755 private void ItemsCollection_Changed ()
4759 } // CheckedListViewItemCollection
4762 [ListBindable (false)]
4764 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4766 internal ArrayList list;
4767 private ListView owner;
4769 #region UIA Framework Events
4772 // We are using Reflection to add/remove internal events.
4773 // Class ListViewProvider uses the events when View is Details.
4775 //Event used to generate UIA StructureChangedEvent
4776 static object UIACollectionChangedEvent = new object ();
4778 internal event CollectionChangeEventHandler UIACollectionChanged {
4781 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4785 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4789 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4794 CollectionChangeEventHandler eh
4795 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4801 #endregion UIA Framework Events
4803 #region Public Constructor
4804 public ColumnHeaderCollection (ListView owner)
4806 list = new ArrayList ();
4809 #endregion // Public Constructor
4811 #region Public Properties
4814 get { return list.Count; }
4817 public bool IsReadOnly {
4818 get { return false; }
4821 public virtual ColumnHeader this [int index] {
4823 if (index < 0 || index >= list.Count)
4824 throw new ArgumentOutOfRangeException ("index");
4825 return (ColumnHeader) list [index];
4830 public virtual ColumnHeader this [string key] {
4832 int idx = IndexOfKey (key);
4836 return (ColumnHeader) list [idx];
4841 bool ICollection.IsSynchronized {
4842 get { return true; }
4845 object ICollection.SyncRoot {
4846 get { return this; }
4849 bool IList.IsFixedSize {
4850 get { return list.IsFixedSize; }
4853 object IList.this [int index] {
4854 get { return this [index]; }
4855 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4857 #endregion // Public Properties
4859 #region Public Methods
4860 public virtual int Add (ColumnHeader value)
4862 int idx = list.Add (value);
4863 owner.AddColumn (value, idx, true);
4866 //UIA Framework event: Item Added
4867 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4874 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4878 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
4881 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4882 this.Add (colHeader);
4887 public virtual ColumnHeader Add (string text)
4889 return Add (String.Empty, text);
4892 public virtual ColumnHeader Add (string text, int width)
4894 return Add (String.Empty, text, width);
4897 public virtual ColumnHeader Add (string key, string text)
4899 ColumnHeader colHeader = new ColumnHeader ();
4900 colHeader.Name = key;
4901 colHeader.Text = text;
4906 public virtual ColumnHeader Add (string key, string text, int width)
4908 return Add (key, text, width, HorizontalAlignment.Left, -1);
4911 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4913 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4914 colHeader.ImageIndex = imageIndex;
4919 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4921 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4922 colHeader.ImageKey = imageKey;
4928 public virtual void AddRange (ColumnHeader [] values)
4930 foreach (ColumnHeader colHeader in values) {
4931 int idx = list.Add (colHeader);
4932 owner.AddColumn (colHeader, idx, false);
4935 owner.Redraw (true);
4938 public virtual void Clear ()
4940 foreach (ColumnHeader col in list)
4941 col.SetListView (null);
4943 owner.ReorderColumns (new int [0], true);
4946 //UIA Framework event: Items cleared
4947 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4952 public bool Contains (ColumnHeader value)
4954 return list.Contains (value);
4958 public virtual bool ContainsKey (string key)
4960 return IndexOfKey (key) != -1;
4964 public IEnumerator GetEnumerator ()
4966 return list.GetEnumerator ();
4969 void ICollection.CopyTo (Array dest, int index)
4971 list.CopyTo (dest, index);
4974 int IList.Add (object value)
4976 if (! (value is ColumnHeader)) {
4977 throw new ArgumentException ("Not of type ColumnHeader", "value");
4980 return this.Add ((ColumnHeader) value);
4983 bool IList.Contains (object value)
4985 if (! (value is ColumnHeader)) {
4986 throw new ArgumentException ("Not of type ColumnHeader", "value");
4989 return this.Contains ((ColumnHeader) value);
4992 int IList.IndexOf (object value)
4994 if (! (value is ColumnHeader)) {
4995 throw new ArgumentException ("Not of type ColumnHeader", "value");
4998 return this.IndexOf ((ColumnHeader) value);
5001 void IList.Insert (int index, object value)
5003 if (! (value is ColumnHeader)) {
5004 throw new ArgumentException ("Not of type ColumnHeader", "value");
5007 this.Insert (index, (ColumnHeader) value);
5010 void IList.Remove (object value)
5012 if (! (value is ColumnHeader)) {
5013 throw new ArgumentException ("Not of type ColumnHeader", "value");
5016 this.Remove ((ColumnHeader) value);
5019 public int IndexOf (ColumnHeader value)
5021 return list.IndexOf (value);
5025 public virtual int IndexOfKey (string key)
5027 if (key == null || key.Length == 0)
5030 for (int i = 0; i < list.Count; i++) {
5031 ColumnHeader col = (ColumnHeader) list [i];
5032 if (String.Compare (key, col.Name, true) == 0)
5040 public void Insert (int index, ColumnHeader value)
5042 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
5043 // but it's really only greater.
5044 if (index < 0 || index > list.Count)
5045 throw new ArgumentOutOfRangeException ("index");
5047 list.Insert (index, value);
5048 owner.AddColumn (value, index, true);
5051 //UIA Framework event: Item added
5052 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5057 public void Insert (int index, string text)
5059 Insert (index, String.Empty, text);
5062 public void Insert (int index, string text, int width)
5064 Insert (index, String.Empty, text, width);
5067 public void Insert (int index, string key, string text)
5069 ColumnHeader colHeader = new ColumnHeader ();
5070 colHeader.Name = key;
5071 colHeader.Text = text;
5072 Insert (index, colHeader);
5075 public void Insert (int index, string key, string text, int width)
5077 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
5078 Insert (index, colHeader);
5081 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
5083 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
5084 colHeader.ImageIndex = imageIndex;
5085 Insert (index, colHeader);
5088 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
5090 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
5091 colHeader.ImageKey = imageKey;
5092 Insert (index, colHeader);
5097 public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
5101 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
5104 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
5105 this.Insert (index, colHeader);
5108 public virtual void Remove (ColumnHeader column)
5110 if (!Contains (column))
5113 list.Remove (column);
5114 column.SetListView (null);
5116 int rem_display_index = column.InternalDisplayIndex;
5117 int [] display_indices = new int [list.Count];
5118 for (int i = 0; i < display_indices.Length; i++) {
5119 ColumnHeader col = (ColumnHeader) list [i];
5120 int display_index = col.InternalDisplayIndex;
5121 if (display_index < rem_display_index) {
5122 display_indices [i] = display_index;
5124 display_indices [i] = (display_index - 1);
5128 column.InternalDisplayIndex = -1;
5129 owner.ReorderColumns (display_indices, true);
5132 //UIA Framework event: Item Removed
5133 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
5138 public virtual void RemoveByKey (string key)
5140 int idx = IndexOfKey (key);
5146 public virtual void RemoveAt (int index)
5148 if (index < 0 || index >= list.Count)
5149 throw new ArgumentOutOfRangeException ("index");
5151 ColumnHeader col = (ColumnHeader) list [index];
5154 #endregion // Public Methods
5157 } // ColumnHeaderCollection
5160 [ListBindable (false)]
5162 public class ListViewItemCollection : IList, ICollection, IEnumerable
5164 private readonly ArrayList list;
5165 private ListView owner;
5167 private ListViewGroup group;
5170 #region UIA Framework Events
5173 // We are using Reflection to add/remove internal events.
5174 // Class ListViewProvider uses the events.
5176 //Event used to generate UIA StructureChangedEvent
5177 static object UIACollectionChangedEvent = new object ();
5179 internal event CollectionChangeEventHandler UIACollectionChanged {
5182 owner.Events.AddHandler (UIACollectionChangedEvent, value);
5186 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
5190 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
5195 CollectionChangeEventHandler eh
5196 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
5202 #endregion UIA Framework Events
5204 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
5205 // In the later case ListViewItem.ListView never gets modified
5206 private bool is_main_collection = true;
5208 #region Public Constructor
5209 public ListViewItemCollection (ListView owner)
5211 list = new ArrayList (0);
5214 #endregion // Public Constructor
5217 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
5220 is_main_collection = false;
5224 #region Public Properties
5229 if (owner != null && owner.VirtualMode)
5230 return owner.VirtualListSize;
5237 public bool IsReadOnly {
5238 get { return false; }
5242 public virtual ListViewItem this [int index] {
5244 public virtual ListViewItem this [int displayIndex] {
5248 int index = displayIndex;
5251 if (index < 0 || index >= Count)
5252 throw new ArgumentOutOfRangeException ("index");
5255 if (owner != null && owner.VirtualMode)
5256 return RetrieveVirtualItemFromOwner (index);
5258 return (ListViewItem) list [index];
5263 int index = displayIndex;
5266 if (index < 0 || index >= Count)
5267 throw new ArgumentOutOfRangeException ("index");
5270 if (owner != null && owner.VirtualMode)
5271 throw new InvalidOperationException ();
5274 if (list.Contains (value))
5275 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5277 if (value.ListView != null && value.ListView != owner)
5278 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");
5280 if (is_main_collection)
5281 value.Owner = owner;
5284 if (value.Group != null)
5285 value.Group.Items.Remove (value);
5287 value.SetGroup (group);
5292 //UIA Framework event: Item Replaced
5293 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5296 list [index] = value;
5298 CollectionChanged (true);
5301 //UIA Framework event: Item Replaced
5302 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5309 public virtual ListViewItem this [string key] {
5311 int idx = IndexOfKey (key);
5320 bool ICollection.IsSynchronized {
5321 get { return true; }
5324 object ICollection.SyncRoot {
5325 get { return this; }
5328 bool IList.IsFixedSize {
5329 get { return list.IsFixedSize; }
5332 object IList.this [int index] {
5333 get { return this [index]; }
5336 //UIA Framework event: Item Replaced
5337 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5340 if (value is ListViewItem)
5341 this [index] = (ListViewItem) value;
5343 this [index] = new ListViewItem (value.ToString ());
5347 //UIA Framework event: Item Replaced
5348 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5352 #endregion // Public Properties
5354 #region Public Methods
5355 public virtual ListViewItem Add (ListViewItem value)
5358 if (owner != null && owner.VirtualMode)
5359 throw new InvalidOperationException ();
5364 // Item is ignored until it has been added to the ListView
5365 if (is_main_collection || value.ListView != null)
5366 CollectionChanged (true);
5369 //UIA Framework event: Item Added
5370 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5376 public virtual ListViewItem Add (string text)
5378 ListViewItem item = new ListViewItem (text);
5379 return this.Add (item);
5382 public virtual ListViewItem Add (string text, int imageIndex)
5384 ListViewItem item = new ListViewItem (text, imageIndex);
5385 return this.Add (item);
5389 public virtual ListViewItem Add (string text, string imageKey)
5391 ListViewItem item = new ListViewItem (text, imageKey);
5392 return this.Add (item);
5395 public virtual ListViewItem Add (string key, string text, int imageIndex)
5397 ListViewItem item = new ListViewItem (text, imageIndex);
5399 return this.Add (item);
5402 public virtual ListViewItem Add (string key, string text, string imageKey)
5404 ListViewItem item = new ListViewItem (text, imageKey);
5406 return this.Add (item);
5411 public void AddRange (ListViewItem [] items)
5414 public void AddRange (ListViewItem [] values)
5416 ListViewItem [] items = values;
5419 throw new ArgumentNullException ("Argument cannot be null!", "items");
5421 if (owner != null && owner.VirtualMode)
5422 throw new InvalidOperationException ();
5425 owner.BeginUpdate ();
5427 foreach (ListViewItem item in items) {
5431 //UIA Framework event: Item Added
5432 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5438 CollectionChanged (true);
5442 public void AddRange (ListViewItemCollection items)
5445 throw new ArgumentNullException ("Argument cannot be null!", "items");
5447 ListViewItem[] itemArray = new ListViewItem[items.Count];
5448 items.CopyTo (itemArray,0);
5449 this.AddRange (itemArray);
5453 public virtual void Clear ()
5456 if (owner != null && owner.VirtualMode)
5457 throw new InvalidOperationException ();
5459 if (is_main_collection && owner != null) {
5460 owner.SetFocusedItem (-1);
5461 owner.h_scroll.Value = owner.v_scroll.Value = 0;
5464 // first remove any item in the groups that *are* part of this LV too
5465 foreach (ListViewGroup group in owner.groups)
5466 group.Items.ClearItemsWithSameListView ();
5469 foreach (ListViewItem item in list) {
5470 owner.item_control.CancelEdit (item);
5476 foreach (ListViewItem item in list)
5477 item.SetGroup (null);
5481 CollectionChanged (false);
5484 //UIA Framework event: Items Removed
5485 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5491 // This method is intended to be used from ListViewGroup.Items, not from ListView.Items,
5492 // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items)
5493 void ClearItemsWithSameListView ()
5495 if (is_main_collection)
5498 int counter = list.Count - 1;
5499 while (counter >= 0) {
5500 ListViewItem item = list [counter] as ListViewItem;
5502 // remove only if the items in group have being added to the ListView too
5503 if (item.ListView == group.ListView) {
5504 list.RemoveAt (counter);
5505 item.SetGroup (null);
5513 public bool Contains (ListViewItem item)
5515 return IndexOf (item) != -1;
5519 public virtual bool ContainsKey (string key)
5521 return IndexOfKey (key) != -1;
5525 public void CopyTo (Array dest, int index)
5527 list.CopyTo (dest, index);
5531 public ListViewItem [] Find (string key, bool searchAllSubItems)
5534 return new ListViewItem [0];
5536 List<ListViewItem> temp_list = new List<ListViewItem> ();
5538 for (int i = 0; i < list.Count; i++) {
5539 ListViewItem lvi = (ListViewItem) list [i];
5540 if (String.Compare (key, lvi.Name, true) == 0)
5541 temp_list.Add (lvi);
5544 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5545 temp_list.CopyTo (retval);
5551 public IEnumerator GetEnumerator ()
5554 if (owner != null && owner.VirtualMode)
5555 throw new InvalidOperationException ();
5558 // This enumerator makes a copy of the collection so
5559 // it can be deleted from in a foreach
5560 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5563 int IList.Add (object item)
5569 if (owner != null && owner.VirtualMode)
5570 throw new InvalidOperationException ();
5573 if (item is ListViewItem) {
5574 li = (ListViewItem) item;
5575 if (list.Contains (li))
5576 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5578 if (li.ListView != null && li.ListView != owner)
5579 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");
5582 li = new ListViewItem (item.ToString ());
5587 result = list.Add (li);
5588 CollectionChanged (true);
5591 //UIA Framework event: Item Added
5592 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5598 bool IList.Contains (object item)
5600 return Contains ((ListViewItem) item);
5603 int IList.IndexOf (object item)
5605 return IndexOf ((ListViewItem) item);
5608 void IList.Insert (int index, object item)
5610 if (item is ListViewItem)
5611 this.Insert (index, (ListViewItem) item);
5613 this.Insert (index, item.ToString ());
5616 //UIA Framework event: Item Added
5617 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5621 void IList.Remove (object item)
5623 Remove ((ListViewItem) item);
5626 public int IndexOf (ListViewItem item)
5629 if (owner != null && owner.VirtualMode) {
5630 for (int i = 0; i < Count; i++)
5631 if (RetrieveVirtualItemFromOwner (i) == item)
5638 return list.IndexOf (item);
5642 public virtual int IndexOfKey (string key)
5644 if (key == null || key.Length == 0)
5647 for (int i = 0; i < Count; i++) {
5648 ListViewItem lvi = this [i];
5649 if (String.Compare (key, lvi.Name, true) == 0)
5657 public ListViewItem Insert (int index, ListViewItem item)
5659 if (index < 0 || index > list.Count)
5660 throw new ArgumentOutOfRangeException ("index");
5663 if (owner != null && owner.VirtualMode)
5664 throw new InvalidOperationException ();
5667 if (list.Contains (item))
5668 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5670 if (item.ListView != null && item.ListView != owner)
5671 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");
5673 if (is_main_collection)
5677 if (item.Group != null)
5678 item.Group.Items.Remove (item);
5680 item.SetGroup (group);
5684 list.Insert (index, item);
5686 if (is_main_collection || item.ListView != null)
5687 CollectionChanged (true);
5690 //UIA Framework event: Item Added
5691 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5697 public ListViewItem Insert (int index, string text)
5699 return this.Insert (index, new ListViewItem (text));
5702 public ListViewItem Insert (int index, string text, int imageIndex)
5704 return this.Insert (index, new ListViewItem (text, imageIndex));
5708 public ListViewItem Insert (int index, string text, string imageKey)
5710 ListViewItem lvi = new ListViewItem (text, imageKey);
5711 return Insert (index, lvi);
5714 public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5716 ListViewItem lvi = new ListViewItem (text, imageIndex);
5718 return Insert (index, lvi);
5721 public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5723 ListViewItem lvi = new ListViewItem (text, imageKey);
5725 return Insert (index, lvi);
5729 public virtual void Remove (ListViewItem item)
5732 if (owner != null && owner.VirtualMode)
5733 throw new InvalidOperationException ();
5736 int idx = list.IndexOf (item);
5741 public virtual void RemoveAt (int index)
5743 if (index < 0 || index >= Count)
5744 throw new ArgumentOutOfRangeException ("index");
5747 if (owner != null && owner.VirtualMode)
5748 throw new InvalidOperationException ();
5751 ListViewItem item = (ListViewItem) list [index];
5753 bool selection_changed = false;
5754 if (is_main_collection && owner != null) {
5756 int display_index = item.DisplayIndex;
5757 if (item.Focused && display_index + 1 == Count) // Last item
5758 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5760 selection_changed = owner.SelectedIndices.Contains (index);
5761 owner.item_control.CancelEdit (item);
5764 list.RemoveAt (index);
5767 if (is_main_collection) {
5769 if (item.Group != null)
5770 item.Group.Items.Remove (item);
5772 item.SetGroup (null);
5777 CollectionChanged (false);
5778 if (selection_changed && owner != null)
5779 owner.OnSelectedIndexChanged (EventArgs.Empty);
5783 //UIA Framework event: Item Removed
5784 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5789 public virtual void RemoveByKey (string key)
5791 int idx = IndexOfKey (key);
5797 #endregion // Public Methods
5799 internal ListView Owner {
5809 internal ListViewGroup Group {
5819 void AddItem (ListViewItem value)
5821 if (list.Contains (value))
5822 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5824 if (value.ListView != null && value.ListView != owner)
5825 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");
5826 if (is_main_collection)
5827 value.Owner = owner;
5830 if (value.Group != null)
5831 value.Group.Items.Remove (value);
5833 value.SetGroup (group);
5841 void CollectionChanged (bool sort)
5843 if (owner != null) {
5848 owner.Redraw (true);
5853 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5855 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5857 owner.OnRetrieveVirtualItem (args);
5858 ListViewItem retval = args.Item;
5859 retval.Owner = owner;
5860 retval.DisplayIndex = displayIndex;
5867 internal event CollectionChangedHandler Changed;
5869 internal void Sort (IComparer comparer)
5871 list.Sort (comparer);
5875 internal void OnChange ()
5877 if (Changed != null)
5880 } // ListViewItemCollection
5883 // In normal mode, the selection information resides in the Items,
5884 // making SelectedIndexCollection.List read-only
5886 // In virtual mode, SelectedIndexCollection directly saves the selection
5887 // information, instead of getting it from Items, making List read-and-write
5889 [ListBindable (false)]
5891 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5893 private readonly ListView owner;
5894 private ArrayList list;
5896 #region Public Constructor
5897 public SelectedIndexCollection (ListView owner)
5900 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5902 #endregion // Public Constructor
5904 #region Public Properties
5908 if (!owner.is_selection_available)
5915 public bool IsReadOnly {
5925 public int this [int index] {
5927 if (!owner.is_selection_available || index < 0 || index >= List.Count)
5928 throw new ArgumentOutOfRangeException ("index");
5930 return (int) List [index];
5934 bool ICollection.IsSynchronized {
5935 get { return false; }
5938 object ICollection.SyncRoot {
5939 get { return this; }
5942 bool IList.IsFixedSize {
5952 object IList.this [int index] {
5953 get { return this [index]; }
5954 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5956 #endregion // Public Properties
5958 #region Public Methods
5960 public int Add (int itemIndex)
5962 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5963 throw new ArgumentOutOfRangeException ("index");
5965 if (owner.virtual_mode && !owner.is_selection_available)
5968 owner.Items [itemIndex].Selected = true;
5970 if (!owner.is_selection_available)
5984 if (!owner.is_selection_available)
5987 int [] indexes = (int []) List.ToArray (typeof (int));
5988 foreach (int index in indexes)
5989 owner.Items [index].Selected = false;
5992 public bool Contains (int selectedIndex)
5994 return IndexOf (selectedIndex) != -1;
5997 public void CopyTo (Array dest, int index)
5999 List.CopyTo (dest, index);
6002 public IEnumerator GetEnumerator ()
6004 return List.GetEnumerator ();
6007 int IList.Add (object value)
6009 throw new NotSupportedException ("Add operation is not supported.");
6017 bool IList.Contains (object selectedIndex)
6019 if (!(selectedIndex is int))
6021 return Contains ((int) selectedIndex);
6024 int IList.IndexOf (object selectedIndex)
6026 if (!(selectedIndex is int))
6028 return IndexOf ((int) selectedIndex);
6031 void IList.Insert (int index, object value)
6033 throw new NotSupportedException ("Insert operation is not supported.");
6036 void IList.Remove (object value)
6038 throw new NotSupportedException ("Remove operation is not supported.");
6041 void IList.RemoveAt (int index)
6043 throw new NotSupportedException ("RemoveAt operation is not supported.");
6046 public int IndexOf (int selectedIndex)
6048 if (!owner.is_selection_available)
6051 return List.IndexOf (selectedIndex);
6055 public void Remove (int itemIndex)
6057 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
6058 throw new ArgumentOutOfRangeException ("itemIndex");
6060 owner.Items [itemIndex].Selected = false;
6063 #endregion // Public Methods
6065 internal ArrayList List {
6068 list = new ArrayList ();
6070 if (!owner.VirtualMode)
6072 for (int i = 0; i < owner.Items.Count; i++) {
6073 if (owner.Items [i].Selected)
6081 internal void Reset ()
6083 // force re-population of list
6087 private void ItemsCollection_Changed ()
6093 internal void RemoveIndex (int index)
6095 int idx = List.BinarySearch (index);
6097 List.RemoveAt (idx);
6100 // actually store index in the collection
6101 // also, keep the collection sorted, as .Net does
6102 internal void InsertIndex (int index)
6105 int iMax = List.Count - 1;
6106 while (iMin <= iMax) {
6107 int iMid = (iMin + iMax) / 2;
6108 int current_index = (int) List [iMid];
6110 if (current_index == index)
6111 return; // Already added
6112 if (current_index > index)
6118 List.Insert (iMin, index);
6122 } // SelectedIndexCollection
6125 [ListBindable (false)]
6127 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
6129 private readonly ListView owner;
6131 #region Public Constructor
6132 public SelectedListViewItemCollection (ListView owner)
6136 #endregion // Public Constructor
6138 #region Public Properties
6142 return owner.SelectedIndices.Count;
6146 public bool IsReadOnly {
6147 get { return true; }
6150 public ListViewItem this [int index] {
6152 if (!owner.is_selection_available || index < 0 || index >= Count)
6153 throw new ArgumentOutOfRangeException ("index");
6155 int item_index = owner.SelectedIndices [index];
6156 return owner.Items [item_index];
6161 public virtual ListViewItem this [string key] {
6163 int idx = IndexOfKey (key);
6172 bool ICollection.IsSynchronized {
6173 get { return false; }
6176 object ICollection.SyncRoot {
6177 get { return this; }
6180 bool IList.IsFixedSize {
6181 get { return true; }
6184 object IList.this [int index] {
6185 get { return this [index]; }
6186 set { throw new NotSupportedException ("SetItem operation is not supported."); }
6188 #endregion // Public Properties
6190 #region Public Methods
6191 public void Clear ()
6193 owner.SelectedIndices.Clear ();
6196 public bool Contains (ListViewItem item)
6198 return IndexOf (item) != -1;
6202 public virtual bool ContainsKey (string key)
6204 return IndexOfKey (key) != -1;
6208 public void CopyTo (Array dest, int index)
6210 if (!owner.is_selection_available)
6212 if (index > Count) // Throws ArgumentException instead of IOOR exception
6213 throw new ArgumentException ("index");
6215 for (int i = 0; i < Count; i++)
6216 dest.SetValue (this [i], index++);
6219 public IEnumerator GetEnumerator ()
6221 if (!owner.is_selection_available)
6222 return (new ListViewItem [0]).GetEnumerator ();
6224 ListViewItem [] items = new ListViewItem [Count];
6225 for (int i = 0; i < Count; i++)
6226 items [i] = this [i];
6228 return items.GetEnumerator ();
6231 int IList.Add (object value)
6233 throw new NotSupportedException ("Add operation is not supported.");
6236 bool IList.Contains (object item)
6238 if (!(item is ListViewItem))
6240 return Contains ((ListViewItem) item);
6243 int IList.IndexOf (object item)
6245 if (!(item is ListViewItem))
6247 return IndexOf ((ListViewItem) item);
6250 void IList.Insert (int index, object value)
6252 throw new NotSupportedException ("Insert operation is not supported.");
6255 void IList.Remove (object value)
6257 throw new NotSupportedException ("Remove operation is not supported.");
6260 void IList.RemoveAt (int index)
6262 throw new NotSupportedException ("RemoveAt operation is not supported.");
6265 public int IndexOf (ListViewItem item)
6267 if (!owner.is_selection_available)
6270 for (int i = 0; i < Count; i++)
6271 if (this [i] == item)
6278 public virtual int IndexOfKey (string key)
6280 if (!owner.is_selection_available || key == null || key.Length == 0)
6283 for (int i = 0; i < Count; i++) {
6284 ListViewItem item = this [i];
6285 if (String.Compare (item.Name, key, true) == 0)
6292 #endregion // Public Methods
6294 } // SelectedListViewItemCollection
6296 internal delegate void CollectionChangedHandler ();
6298 struct ItemMatrixLocation
6303 public ItemMatrixLocation (int row, int col)
6330 #endregion // Subclasses
6332 protected override void OnResize (EventArgs e)
6337 protected override void OnMouseLeave (EventArgs e)
6339 base.OnMouseLeave (e);
6343 // ColumnReorder event
6345 static object ColumnReorderedEvent = new object ();
6346 public event ColumnReorderedEventHandler ColumnReordered {
6347 add { Events.AddHandler (ColumnReorderedEvent, value); }
6348 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
6351 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
6353 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
6360 // ColumnWidthChanged
6362 static object ColumnWidthChangedEvent = new object ();
6363 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
6364 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
6365 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
6368 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
6370 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
6375 void RaiseColumnWidthChanged (int resize_column)
6377 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
6379 OnColumnWidthChanged (n);
6383 // ColumnWidthChanging
6385 static object ColumnWidthChangingEvent = new object ();
6386 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
6387 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
6388 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
6391 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6393 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6399 // 2.0 profile based implementation
6401 bool CanProceedWithResize (ColumnHeader col, int width)
6403 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6407 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6408 cwceh (this, changing);
6409 return !changing.Cancel;
6413 // 1.0 profile based implementation
6415 bool CanProceedWithResize (ColumnHeader col, int width)
6420 void RaiseColumnWidthChanged (int resize_column)
6425 internal void RaiseColumnWidthChanged (ColumnHeader column)
6427 int index = Columns.IndexOf (column);
6428 RaiseColumnWidthChanged (index);
6433 #region UIA Framework: Methods, Properties and Events
6435 static object UIALabelEditChangedEvent = new object ();
6436 static object UIAShowGroupsChangedEvent = new object ();
6437 static object UIAMultiSelectChangedEvent = new object ();
6438 static object UIAViewChangedEvent = new object ();
6439 static object UIACheckBoxesChangedEvent = new object ();
6440 static object UIAFocusedItemChangedEvent = new object ();
6442 internal Rectangle UIAHeaderControl {
6443 get { return header_control.Bounds; }
6446 internal int UIAColumns {
6447 get { return cols; }
6450 internal int UIARows {
6451 get { return rows; }
6454 internal ListViewGroup UIADefaultListViewGroup
6456 get { return groups.DefaultGroup; }
6459 internal ScrollBar UIAHScrollBar {
6460 get { return h_scroll; }
6463 internal ScrollBar UIAVScrollBar {
6464 get { return v_scroll; }
6467 internal event EventHandler UIAShowGroupsChanged {
6468 add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6469 remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6472 internal event EventHandler UIACheckBoxesChanged {
6473 add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6474 remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6477 internal event EventHandler UIAMultiSelectChanged {
6478 add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6479 remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6482 internal event EventHandler UIALabelEditChanged {
6483 add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6484 remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6487 internal event EventHandler UIAViewChanged {
6488 add { Events.AddHandler (UIAViewChangedEvent, value); }
6489 remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6492 internal event EventHandler UIAFocusedItemChanged {
6493 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6494 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6497 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6499 return group.HeaderBounds;
6502 internal int UIAItemsLocationLength
6504 get { return items_location.Length; }
6507 private void OnUIACheckBoxesChanged ()
6509 EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6511 eh (this, EventArgs.Empty);
6514 private void OnUIAShowGroupsChanged ()
6516 EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6518 eh (this, EventArgs.Empty);
6521 private void OnUIAMultiSelectChanged ()
6523 EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6525 eh (this, EventArgs.Empty);
6528 private void OnUIALabelEditChanged ()
6530 EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6532 eh (this, EventArgs.Empty);
6535 private void OnUIAViewChanged ()
6537 EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6539 eh (this, EventArgs.Empty);
6542 internal void OnUIAFocusedItemChanged ()
6544 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6546 eh (this, EventArgs.Empty);
6549 #endregion // UIA Framework: Methods, Properties and Events