1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
23 // Ravindra Kumar (rkumar@novell.com)
24 // Jordi Mas i Hernandez, jordi@ximian.com
25 // Mike Kestner (mkestner@novell.com)
26 // Daniel Nauck (dna(at)mono-project(dot)de)
27 // Carlos Alberto Cortez <calberto.cortez@gmail.com>
34 using System.Collections;
35 using System.ComponentModel;
36 using System.ComponentModel.Design;
38 using System.Runtime.InteropServices;
39 using System.Globalization;
40 using System.Collections.Generic;
42 namespace System.Windows.Forms
44 [DefaultEvent ("SelectedIndexChanged")]
45 [DefaultProperty ("Items")]
46 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
47 [ClassInterface (ClassInterfaceType.AutoDispatch)]
49 [Docking (DockingBehavior.Ask)]
50 public class ListView : Control
52 private ItemActivation activation = ItemActivation.Standard;
53 private ListViewAlignment alignment = ListViewAlignment.Top;
54 private bool allow_column_reorder;
55 private bool auto_arrange = true;
56 private bool check_boxes;
57 private readonly CheckedIndexCollection checked_indices;
58 private readonly CheckedListViewItemCollection checked_items;
59 private readonly ColumnHeaderCollection columns;
60 internal int focused_item_index = -1;
61 private bool full_row_select;
62 private bool grid_lines;
63 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
64 private bool hide_selection = true;
65 private bool hover_selection;
66 private IComparer item_sorter;
67 private readonly ListViewItemCollection items;
68 private readonly ListViewGroupCollection groups;
69 private bool owner_draw;
70 private bool show_groups = true;
71 private bool label_edit;
72 private bool label_wrap = true;
73 private bool multiselect = true;
74 private bool scrollable = true;
75 private bool hover_pending;
76 private readonly SelectedIndexCollection selected_indices;
77 private readonly SelectedListViewItemCollection selected_items;
78 private SortOrder sort_order = SortOrder.None;
79 private ImageList state_image_list;
80 internal bool updating;
81 private View view = View.LargeIcon;
82 private int layout_wd; // We might draw more than our client area
83 private int layout_ht; // therefore we need to have these two.
84 internal HeaderControl header_control;
85 internal ItemControl item_control;
86 internal ScrollBar h_scroll; // used for scrolling horizontally
87 internal ScrollBar v_scroll; // used for scrolling vertically
88 internal int h_marker; // Position markers for scrolling
89 internal int v_marker;
90 private int keysearch_tickcnt;
91 private string keysearch_text;
92 static private readonly int keysearch_keydelay = 1000;
93 private int[] reordered_column_indices;
94 private int[] reordered_items_indices;
95 private Point [] items_location;
96 private ItemMatrixLocation [] items_matrix_location;
97 private Size item_size; // used for caching item size
98 private int custom_column_width; // used when using Columns with SmallIcon/List views
99 private int hot_item_index = -1;
100 private bool hot_tracking;
101 private ListViewInsertionMark insertion_mark;
102 private bool show_item_tooltips;
103 private ToolTip item_tooltip;
104 private Size tile_size;
105 private bool virtual_mode;
106 private int virtual_list_size;
107 private bool right_to_left_layout;
108 // selection is available after the first time the handle is created, *even* if later
109 // the handle is either recreated or destroyed - so keep this info around.
110 private bool is_selection_available;
112 // internal variables
113 internal ImageList large_image_list;
114 internal ImageList small_image_list;
115 internal Size text_size = Size.Empty;
118 static object AfterLabelEditEvent = new object ();
119 static object BeforeLabelEditEvent = new object ();
120 static object ColumnClickEvent = new object ();
121 static object ItemActivateEvent = new object ();
122 static object ItemCheckEvent = new object ();
123 static object ItemDragEvent = new object ();
124 static object SelectedIndexChangedEvent = new object ();
125 static object DrawColumnHeaderEvent = new object();
126 static object DrawItemEvent = new object();
127 static object DrawSubItemEvent = new object();
128 static object ItemCheckedEvent = new object ();
129 static object ItemMouseHoverEvent = new object ();
130 static object ItemSelectionChangedEvent = new object ();
131 static object CacheVirtualItemsEvent = new object ();
132 static object RetrieveVirtualItemEvent = new object ();
133 static object RightToLeftLayoutChangedEvent = new object ();
134 static object SearchForVirtualItemEvent = new object ();
135 static object VirtualItemsSelectionRangeChangedEvent = new object ();
137 public event LabelEditEventHandler AfterLabelEdit {
138 add { Events.AddHandler (AfterLabelEditEvent, value); }
139 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
144 [EditorBrowsable (EditorBrowsableState.Never)]
145 public new event EventHandler BackgroundImageLayoutChanged {
146 add { base.BackgroundImageLayoutChanged += value; }
147 remove { base.BackgroundImageLayoutChanged -= value; }
150 public event LabelEditEventHandler BeforeLabelEdit {
151 add { Events.AddHandler (BeforeLabelEditEvent, value); }
152 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
155 public event ColumnClickEventHandler ColumnClick {
156 add { Events.AddHandler (ColumnClickEvent, value); }
157 remove { Events.RemoveHandler (ColumnClickEvent, value); }
160 public event DrawListViewColumnHeaderEventHandler DrawColumnHeader {
161 add { Events.AddHandler(DrawColumnHeaderEvent, value); }
162 remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); }
165 public event DrawListViewItemEventHandler DrawItem {
166 add { Events.AddHandler(DrawItemEvent, value); }
167 remove { Events.RemoveHandler(DrawItemEvent, value); }
170 public event DrawListViewSubItemEventHandler DrawSubItem {
171 add { Events.AddHandler(DrawSubItemEvent, value); }
172 remove { Events.RemoveHandler(DrawSubItemEvent, value); }
175 public event EventHandler ItemActivate {
176 add { Events.AddHandler (ItemActivateEvent, value); }
177 remove { Events.RemoveHandler (ItemActivateEvent, value); }
180 public event ItemCheckEventHandler ItemCheck {
181 add { Events.AddHandler (ItemCheckEvent, value); }
182 remove { Events.RemoveHandler (ItemCheckEvent, value); }
185 public event ItemCheckedEventHandler ItemChecked {
186 add { Events.AddHandler (ItemCheckedEvent, value); }
187 remove { Events.RemoveHandler (ItemCheckedEvent, value); }
190 public event ItemDragEventHandler ItemDrag {
191 add { Events.AddHandler (ItemDragEvent, value); }
192 remove { Events.RemoveHandler (ItemDragEvent, value); }
195 public event ListViewItemMouseHoverEventHandler ItemMouseHover {
196 add { Events.AddHandler (ItemMouseHoverEvent, value); }
197 remove { Events.RemoveHandler (ItemMouseHoverEvent, value); }
200 public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged {
201 add { Events.AddHandler (ItemSelectionChangedEvent, value); }
202 remove { Events.RemoveHandler (ItemSelectionChangedEvent, value); }
206 [EditorBrowsable (EditorBrowsableState.Never)]
207 public new event EventHandler PaddingChanged {
208 add { base.PaddingChanged += value; }
209 remove { base.PaddingChanged -= value; }
213 [EditorBrowsable (EditorBrowsableState.Never)]
214 public new event PaintEventHandler Paint {
215 add { base.Paint += value; }
216 remove { base.Paint -= value; }
219 public event EventHandler SelectedIndexChanged {
220 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
221 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
225 [EditorBrowsable (EditorBrowsableState.Never)]
226 public new event EventHandler TextChanged {
227 add { base.TextChanged += value; }
228 remove { base.TextChanged -= value; }
231 public event CacheVirtualItemsEventHandler CacheVirtualItems {
232 add { Events.AddHandler (CacheVirtualItemsEvent, value); }
233 remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); }
236 public event RetrieveVirtualItemEventHandler RetrieveVirtualItem {
237 add { Events.AddHandler (RetrieveVirtualItemEvent, value); }
238 remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); }
241 public event EventHandler RightToLeftLayoutChanged {
242 add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
243 remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
246 public event SearchForVirtualItemEventHandler SearchForVirtualItem {
247 add { Events.AddHandler (SearchForVirtualItemEvent, value); }
248 remove { Events.AddHandler (SearchForVirtualItemEvent, value); }
251 public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged {
252 add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); }
253 remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); }
258 #region Public Constructors
261 background_color = ThemeEngine.Current.ColorWindow;
262 groups = new ListViewGroupCollection (this);
263 items = new ListViewItemCollection (this);
264 items.Changed += new CollectionChangedHandler (OnItemsChanged);
265 checked_indices = new CheckedIndexCollection (this);
266 checked_items = new CheckedListViewItemCollection (this);
267 columns = new ColumnHeaderCollection (this);
268 foreground_color = SystemColors.WindowText;
269 selected_indices = new SelectedIndexCollection (this);
270 selected_items = new SelectedListViewItemCollection (this);
271 items_location = new Point [16];
272 items_matrix_location = new ItemMatrixLocation [16];
273 reordered_items_indices = new int [16];
274 item_tooltip = new ToolTip ();
275 item_tooltip.Active = false;
276 insertion_mark = new ListViewInsertionMark (this);
278 InternalBorderStyle = BorderStyle.Fixed3D;
280 header_control = new HeaderControl (this);
281 header_control.Visible = false;
282 Controls.AddImplicit (header_control);
284 item_control = new ItemControl (this);
285 Controls.AddImplicit (item_control);
287 h_scroll = new ImplicitHScrollBar ();
288 Controls.AddImplicit (this.h_scroll);
290 v_scroll = new ImplicitVScrollBar ();
291 Controls.AddImplicit (this.v_scroll);
293 h_marker = v_marker = 0;
294 keysearch_tickcnt = 0;
296 // scroll bars are disabled initially
297 h_scroll.Visible = false;
298 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
299 v_scroll.Visible = false;
300 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
303 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
304 SizeChanged += new EventHandler (ListView_SizeChanged);
305 GotFocus += new EventHandler (FocusChanged);
306 LostFocus += new EventHandler (FocusChanged);
307 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
308 MouseEnter += new EventHandler (ListView_MouseEnter);
309 Invalidated += new InvalidateEventHandler (ListView_Invalidated);
311 BackgroundImageTiled = false;
313 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
314 | ControlStyles.UseTextForAccessibility
317 #endregion // Public Constructors
319 #region Private Internal Properties
320 internal Size CheckBoxSize {
322 if (this.check_boxes) {
323 if (this.state_image_list != null)
324 return this.state_image_list.ImageSize;
326 return ThemeEngine.Current.ListViewCheckBoxSize;
332 internal Size ItemSize {
334 if (view != View.Details)
337 Size size = new Size ();
338 size.Height = item_size.Height;
339 for (int i = 0; i < columns.Count; i++)
340 size.Width += columns [i].Wd;
349 internal int HotItemIndex {
351 return hot_item_index;
354 hot_item_index = value;
358 internal bool UsingGroups {
360 return show_groups && groups.Count > 0 && view != View.List &&
361 Application.VisualStylesEnabled;
365 internal override bool ScaleChildrenInternal {
366 get { return false; }
369 internal bool UseCustomColumnWidth {
371 return (view == View.List || view == View.SmallIcon) && columns.Count > 0;
375 internal ColumnHeader EnteredColumnHeader {
377 return header_control.EnteredColumnHeader;
380 #endregion // Private Internal Properties
382 #region Protected Properties
383 protected override CreateParams CreateParams {
384 get { return base.CreateParams; }
387 protected override Size DefaultSize {
388 get { return ThemeEngine.Current.ListViewDefaultSize; }
390 protected override bool DoubleBuffered {
392 return base.DoubleBuffered;
395 base.DoubleBuffered = value;
398 #endregion // Protected Properties
400 #region Public Instance Properties
401 [DefaultValue (ItemActivation.Standard)]
402 public ItemActivation Activation {
403 get { return activation; }
405 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
406 value != ItemActivation.TwoClick) {
407 throw new InvalidEnumArgumentException (string.Format
408 ("Enum argument value '{0}' is not valid for Activation", value));
410 if (hot_tracking && value != ItemActivation.OneClick)
411 throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick");
417 [DefaultValue (ListViewAlignment.Top)]
419 public ListViewAlignment Alignment {
420 get { return alignment; }
422 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
423 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
424 throw new InvalidEnumArgumentException (string.Format
425 ("Enum argument value '{0}' is not valid for Alignment", value));
428 if (this.alignment != value) {
430 // alignment does not matter in Details/List views
431 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
437 [DefaultValue (false)]
438 public bool AllowColumnReorder {
439 get { return allow_column_reorder; }
440 set { allow_column_reorder = value; }
443 [DefaultValue (true)]
444 public bool AutoArrange {
445 get { return auto_arrange; }
447 if (auto_arrange != value) {
448 auto_arrange = value;
449 // autoarrange does not matter in Details/List views
450 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
456 public override Color BackColor {
458 if (background_color.IsEmpty)
459 return ThemeEngine.Current.ColorWindow;
461 return background_color;
464 background_color = value;
465 item_control.BackColor = value;
470 [EditorBrowsable (EditorBrowsableState.Never)]
471 public override ImageLayout BackgroundImageLayout {
473 return base.BackgroundImageLayout;
476 base.BackgroundImageLayout = value;
480 [DefaultValue (false)]
481 public bool BackgroundImageTiled {
483 return item_control.BackgroundImageLayout == ImageLayout.Tile;
486 ImageLayout new_image_layout = value ? ImageLayout.Tile : ImageLayout.None;
487 if (new_image_layout == item_control.BackgroundImageLayout)
490 item_control.BackgroundImageLayout = new_image_layout;
494 [DefaultValue (BorderStyle.Fixed3D)]
496 public BorderStyle BorderStyle {
497 get { return InternalBorderStyle; }
498 set { InternalBorderStyle = value; }
501 [DefaultValue (false)]
502 public bool CheckBoxes {
503 get { return check_boxes; }
505 if (check_boxes != value) {
506 if (value && View == View.Tile)
507 throw new NotSupportedException ("CheckBoxes are not"
508 + " supported in Tile view. Choose a different"
509 + " view or set CheckBoxes to false.");
514 //UIA Framework: Event used by ListView to set/unset Toggle Pattern
515 OnUIACheckBoxesChanged ();
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 public CheckedIndexCollection CheckedIndices {
523 get { return checked_indices; }
527 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
528 public CheckedListViewItemCollection CheckedItems {
529 get { return checked_items; }
532 [Editor ("System.Windows.Forms.Design.ColumnHeaderCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
533 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
535 [MergableProperty (false)]
536 public ColumnHeaderCollection Columns {
537 get { return columns; }
541 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
542 public ListViewItem FocusedItem {
544 if (focused_item_index == -1)
547 return GetItemAtDisplayIndex (focused_item_index);
550 if (value == null || value.ListView != this ||
554 SetFocusedItem (value.DisplayIndex);
558 public override Color ForeColor {
560 if (foreground_color.IsEmpty)
561 return ThemeEngine.Current.ColorWindowText;
563 return foreground_color;
565 set { foreground_color = value; }
568 [DefaultValue (false)]
569 public bool FullRowSelect {
570 get { return full_row_select; }
572 if (full_row_select != value) {
573 full_row_select = value;
574 InvalidateSelection ();
579 [DefaultValue (false)]
580 public bool GridLines {
581 get { return grid_lines; }
583 if (grid_lines != value) {
590 [DefaultValue (ColumnHeaderStyle.Clickable)]
591 public ColumnHeaderStyle HeaderStyle {
592 get { return header_style; }
594 if (header_style == value)
598 case ColumnHeaderStyle.Clickable:
599 case ColumnHeaderStyle.Nonclickable:
600 case ColumnHeaderStyle.None:
603 throw new InvalidEnumArgumentException (string.Format
604 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
607 header_style = value;
608 if (view == View.Details)
613 [DefaultValue (true)]
614 public bool HideSelection {
615 get { return hide_selection; }
617 if (hide_selection != value) {
618 hide_selection = value;
619 InvalidateSelection ();
624 [DefaultValue (false)]
625 public bool HotTracking {
630 if (hot_tracking == value)
633 hot_tracking = value;
635 hover_selection = true;
636 activation = ItemActivation.OneClick;
641 [DefaultValue (false)]
642 public bool HoverSelection {
643 get { return hover_selection; }
645 if (hot_tracking && value == false)
646 throw new ArgumentException ("When HotTracking is on, hover selection must be true");
647 hover_selection = value;
651 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
653 public ListViewInsertionMark InsertionMark {
655 return insertion_mark;
659 [Editor ("System.Windows.Forms.Design.ListViewItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
660 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
662 [MergableProperty (false)]
663 public ListViewItemCollection Items {
664 get { return items; }
667 [DefaultValue (false)]
668 public bool LabelEdit {
669 get { return label_edit; }
671 if (value != label_edit) {
674 // UIA Framework: Event used by Value Pattern in ListView.ListItem provider
675 OnUIALabelEditChanged ();
681 [DefaultValue (true)]
683 public bool LabelWrap {
684 get { return label_wrap; }
686 if (label_wrap != value) {
693 [DefaultValue (null)]
694 public ImageList LargeImageList {
695 get { return large_image_list; }
697 large_image_list = value;
703 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
704 public IComparer ListViewItemSorter {
706 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
711 if (item_sorter != value) {
718 [DefaultValue (true)]
719 public bool MultiSelect {
720 get { return multiselect; }
722 if (value != multiselect) {
725 // UIA Framework: Event used by Selection Pattern in ListView.ListItem provider
726 OnUIAMultiSelectChanged ();
732 [DefaultValue(false)]
733 public bool OwnerDraw {
734 get { return owner_draw; }
742 [EditorBrowsable (EditorBrowsableState.Never)]
743 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
744 public new Padding Padding {
749 base.Padding = value;
753 [MonoTODO ("RTL not supported")]
755 [DefaultValue (false)]
756 public virtual bool RightToLeftLayout {
757 get { return right_to_left_layout; }
759 if (right_to_left_layout != value) {
760 right_to_left_layout = value;
761 OnRightToLeftLayoutChanged (EventArgs.Empty);
766 [DefaultValue (true)]
767 public bool Scrollable {
768 get { return scrollable; }
770 if (scrollable != value) {
778 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
779 public SelectedIndexCollection SelectedIndices {
780 get { return selected_indices; }
784 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
785 public SelectedListViewItemCollection SelectedItems {
786 get { return selected_items; }
790 public bool ShowGroups {
791 get { return show_groups; }
793 if (show_groups != value) {
797 // UIA Framework: Used to update a11y Tree
798 OnUIAShowGroupsChanged ();
803 [LocalizableAttribute (true)]
804 [MergableProperty (false)]
805 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
806 [Editor ("System.Windows.Forms.Design.ListViewGroupCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
807 public ListViewGroupCollection Groups {
808 get { return groups; }
811 [DefaultValue (false)]
812 public bool ShowItemToolTips {
814 return show_item_tooltips;
817 show_item_tooltips = value;
818 item_tooltip.Active = false;
822 [DefaultValue (null)]
823 public ImageList SmallImageList {
824 get { return small_image_list; }
826 small_image_list = value;
831 [DefaultValue (SortOrder.None)]
832 public SortOrder Sorting {
833 get { return sort_order; }
835 if (!Enum.IsDefined (typeof (SortOrder), value)) {
836 throw new InvalidEnumArgumentException ("value", (int) value,
840 if (sort_order == value)
845 if (virtual_mode) // Sorting is not allowed in virtual mode
848 if (value == SortOrder.None) {
849 if (item_sorter != null) {
850 // ListViewItemSorter should never be reset for SmallIcon
851 // and LargeIcon view
852 if (View != View.SmallIcon && View != View.LargeIcon)
857 if (item_sorter == null)
858 item_sorter = new ItemComparer (value);
859 if (item_sorter is ItemComparer) {
860 item_sorter = new ItemComparer (value);
867 private void OnImageListChanged (object sender, EventArgs args)
869 item_control.Invalidate ();
872 [DefaultValue (null)]
873 public ImageList StateImageList {
874 get { return state_image_list; }
876 if (state_image_list == value)
879 if (state_image_list != null)
880 state_image_list.Images.Changed -= new EventHandler (OnImageListChanged);
882 state_image_list = value;
884 if (state_image_list != null)
885 state_image_list.Images.Changed += new EventHandler (OnImageListChanged);
893 [EditorBrowsable (EditorBrowsableState.Never)]
894 public override string Text {
895 get { return base.Text; }
897 if (value == base.Text)
906 public Size TileSize {
911 if (value.Width <= 0 || value.Height <= 0)
912 throw new ArgumentOutOfRangeException ("value");
915 if (view == View.Tile)
921 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
922 public ListViewItem TopItem {
924 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
925 throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view.");
927 if (this.items.Count == 0)
929 // if contents are not scrolled
930 // it is the first item
931 else if (h_marker == 0 && v_marker == 0)
932 return this.items [0];
933 // do a hit test for the scrolled position
935 int header_offset = header_control.Height;
936 for (int i = 0; i < items.Count; i++) {
937 Point item_loc = GetItemLocation (i);
938 if (item_loc.X >= 0 && item_loc.Y - header_offset >= 0)
945 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
946 throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view.");
948 // .Net doesn't throw any exception in the cases below
949 if (value == null || value.ListView != this)
952 // Take advantage this property is only valid for Details view.
953 SetScrollValue (v_scroll, item_size.Height * value.Index);
957 [EditorBrowsable (EditorBrowsableState.Advanced)]
958 [DefaultValue (true)]
960 [MonoInternalNote ("Stub, not implemented")]
961 public bool UseCompatibleStateImageBehavior {
969 [DefaultValue (View.LargeIcon)]
973 if (!Enum.IsDefined (typeof (View), value))
974 throw new InvalidEnumArgumentException ("value", (int) value,
978 if (CheckBoxes && value == View.Tile)
979 throw new NotSupportedException ("CheckBoxes are not"
980 + " supported in Tile view. Choose a different"
981 + " view or set CheckBoxes to false.");
982 if (VirtualMode && value == View.Tile)
983 throw new NotSupportedException ("VirtualMode is"
984 + " not supported in Tile view. Choose a different"
985 + " view or set ViewMode to false.");
987 h_scroll.Value = v_scroll.Value = 0;
991 // UIA Framework: Event used to update UIA Tree.
997 [DefaultValue (false)]
998 [RefreshProperties (RefreshProperties.Repaint)]
999 public bool VirtualMode {
1001 return virtual_mode;
1004 if (virtual_mode == value)
1007 if (!virtual_mode && items.Count > 0)
1008 throw new InvalidOperationException ();
1009 if (value && view == View.Tile)
1010 throw new NotSupportedException ("VirtualMode is"
1011 + " not supported in Tile view. Choose a different"
1012 + " view or set ViewMode to false.");
1014 virtual_mode = value;
1020 [RefreshProperties (RefreshProperties.Repaint)]
1021 public int VirtualListSize {
1023 return virtual_list_size;
1027 throw new ArgumentException ("value");
1029 if (virtual_list_size == value)
1032 virtual_list_size = value;
1034 focused_item_index = -1;
1035 selected_indices.Reset ();
1040 #endregion // Public Instance Properties
1042 #region Internal Methods Properties
1044 internal int FirstVisibleIndex {
1047 if (this.items.Count == 0)
1050 if (h_marker == 0 && v_marker == 0)
1053 Size item_size = ItemSize;
1054 // In virtual mode we always have fixed positions, and we can infer the positon easily
1059 first = v_marker / item_size.Height;
1061 case View.LargeIcon:
1062 case View.SmallIcon:
1063 first = (v_marker / (item_size.Height + y_spacing)) * cols;
1066 first = (h_marker / (item_size.Width * x_spacing)) * rows;
1070 if (first >= items.Count)
1071 first = items.Count;
1075 for (int i = 0; i < items.Count; i++) {
1076 Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size);
1077 if (item_rect.Right >= 0 && item_rect.Bottom >= 0)
1086 internal int LastVisibleIndex {
1088 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
1089 if (View == View.List || Alignment == ListViewAlignment.Left) {
1090 if (GetItemLocation (i).X > item_control.ClientRectangle.Right)
1093 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
1098 return Items.Count - 1;
1102 internal void OnSelectedIndexChanged ()
1104 if (is_selection_available)
1105 OnSelectedIndexChanged (EventArgs.Empty);
1108 internal int TotalWidth {
1109 get { return Math.Max (this.Width, this.layout_wd); }
1112 internal int TotalHeight {
1113 get { return Math.Max (this.Height, this.layout_ht); }
1116 internal void Redraw (bool recalculate)
1118 // Avoid calculations when control is being updated
1121 // VirtualMode doesn't do any calculations until handle is created
1122 if (virtual_mode && !IsHandleCreated)
1127 CalculateListView (this.alignment);
1132 void InvalidateSelection ()
1134 foreach (int selected_index in SelectedIndices)
1135 items [selected_index].Invalidate ();
1138 const int text_padding = 15;
1140 internal Size GetChildColumnSize (int index)
1142 Size ret_size = Size.Empty;
1143 ColumnHeader col = this.columns [index];
1145 if (col.Width == -2) { // autosize = max(items, columnheader)
1146 Size size = Size.Ceiling (TextRenderer.MeasureString
1147 (col.Text, this.Font));
1148 size.Width += text_padding;
1149 ret_size = BiggestItem (index);
1150 if (size.Width > ret_size.Width)
1153 else { // -1 and all the values < -2 are put under one category
1154 ret_size = BiggestItem (index);
1155 // fall back to empty columns' width if no subitem is available for a column
1156 if (ret_size.IsEmpty) {
1157 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
1158 if (col.Text.Length > 0)
1159 ret_size.Height = Size.Ceiling (TextRenderer.MeasureString
1160 (col.Text, this.Font)).Height;
1162 ret_size.Height = this.Font.Height;
1166 ret_size.Height += text_padding;
1168 // adjust the size for icon and checkbox for 0th column
1170 ret_size.Width += (this.CheckBoxSize.Width + 4);
1171 if (this.small_image_list != null)
1172 ret_size.Width += this.small_image_list.ImageSize.Width;
1177 // Returns the size of biggest item text in a column
1178 // or the sum of the text and indent count if we are on 2.0
1179 private Size BiggestItem (int col)
1181 Size temp = Size.Empty;
1182 Size ret_size = Size.Empty;
1183 bool use_indent_count = small_image_list != null;
1185 // VirtualMode uses the first item text size
1186 if (virtual_mode && items.Count > 0) {
1187 ListViewItem item = items [0];
1188 ret_size = Size.Ceiling (TextRenderer.MeasureString (item.SubItems[col].Text,
1191 if (use_indent_count)
1192 ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width;
1194 // 0th column holds the item text, we check the size of
1195 // the various subitems falling in that column and get
1196 // the biggest one's size.
1197 foreach (ListViewItem item in items) {
1198 if (col >= item.SubItems.Count)
1201 temp = Size.Ceiling (TextRenderer.MeasureString
1202 (item.SubItems [col].Text, Font));
1204 if (use_indent_count)
1205 temp.Width += item.IndentCount * small_image_list.ImageSize.Width;
1207 if (temp.Width > ret_size.Width)
1212 // adjustment for space in Details view
1213 if (!ret_size.IsEmpty && view == View.Details)
1214 ret_size.Width += ThemeEngine.Current.ListViewItemPaddingWidth;
1219 const int max_wrap_padding = 30;
1221 // Sets the size of the biggest item text as per the view
1222 private void CalcTextSize ()
1224 // clear the old value
1225 text_size = Size.Empty;
1227 if (items.Count == 0)
1230 text_size = BiggestItem (0);
1232 if (view == View.LargeIcon && this.label_wrap) {
1233 Size temp = Size.Empty;
1234 if (this.check_boxes)
1235 temp.Width += 2 * this.CheckBoxSize.Width;
1236 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1237 temp.Width += icon_w + max_wrap_padding;
1238 // wrapping is done for two lines only
1239 if (text_size.Width > temp.Width) {
1240 text_size.Width = temp.Width;
1241 text_size.Height *= 2;
1244 else if (view == View.List) {
1245 // in list view max text shown in determined by the
1246 // control width, even if scolling is enabled.
1247 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
1248 if (this.small_image_list != null)
1249 max_wd -= this.small_image_list.ImageSize.Width;
1251 if (text_size.Width > max_wd)
1252 text_size.Width = max_wd;
1255 // we do the default settings, if we have got 0's
1256 if (text_size.Height <= 0)
1257 text_size.Height = this.Font.Height;
1258 if (text_size.Width <= 0)
1259 text_size.Width = this.Width;
1261 // little adjustment
1262 text_size.Width += 2;
1263 text_size.Height += 2;
1266 private void SetScrollValue (ScrollBar scrollbar, int val)
1269 if (scrollbar == h_scroll)
1270 max = h_scroll.Maximum - h_scroll.LargeChange + 1;
1272 max = v_scroll.Maximum - v_scroll.LargeChange + 1;
1276 else if (val < scrollbar.Minimum)
1277 val = scrollbar.Minimum;
1279 scrollbar.Value = val;
1282 private void Scroll (ScrollBar scrollbar, int delta)
1284 if (delta == 0 || !scrollbar.Visible)
1287 SetScrollValue (scrollbar, scrollbar.Value + delta);
1290 private void CalculateScrollBars ()
1292 Rectangle client_area = ClientRectangle;
1293 int height = client_area.Height;
1294 int width = client_area.Width;
1298 h_scroll.Visible = false;
1299 v_scroll.Visible = false;
1300 item_control.Size = new Size (width, height);
1301 header_control.Width = width;
1305 // Don't calculate if the view is not displayable
1306 if (client_area.Height < 0 || client_area.Width < 0)
1309 // making a scroll bar visible might make
1310 // other scroll bar visible
1311 if (layout_wd > client_area.Right) {
1312 h_scroll.Visible = true;
1313 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1314 v_scroll.Visible = true;
1316 v_scroll.Visible = false;
1317 } else if (layout_ht > client_area.Bottom) {
1318 v_scroll.Visible = true;
1319 if ((layout_wd + v_scroll.Width) > client_area.Right)
1320 h_scroll.Visible = true;
1322 h_scroll.Visible = false;
1324 h_scroll.Visible = false;
1325 v_scroll.Visible = false;
1329 item_size = ItemSize;
1331 if (h_scroll.is_visible) {
1332 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1333 h_scroll.Minimum = 0;
1335 // if v_scroll is visible, adjust the maximum of the
1336 // h_scroll to account for the width of v_scroll
1337 if (v_scroll.Visible) {
1338 h_scroll.Maximum = layout_wd + v_scroll.Width;
1339 h_scroll.Width = client_area.Width - v_scroll.Width;
1342 h_scroll.Maximum = layout_wd;
1343 h_scroll.Width = client_area.Width;
1346 if (view == View.List)
1347 h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing;
1349 h_scroll.SmallChange = Font.Height;
1351 h_scroll.LargeChange = client_area.Width;
1352 height -= h_scroll.Height;
1355 if (v_scroll.is_visible) {
1356 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1357 v_scroll.Minimum = 0;
1359 // if h_scroll is visible, adjust the height of
1360 // v_scroll to account for the height of h_scroll
1361 if (h_scroll.Visible) {
1362 v_scroll.Maximum = layout_ht + h_scroll.Height;
1363 v_scroll.Height = client_area.Height > h_scroll.Height ? client_area.Height - h_scroll.Height : 0;
1365 v_scroll.Maximum = layout_ht;
1366 v_scroll.Height = client_area.Height;
1369 if (view == View.Details) {
1370 // Need to update Maximum if using LargeChange with value other than the visible area
1371 int headerPlusOneItem = header_control.Height + item_size.Height;
1372 v_scroll.LargeChange = v_scroll.Height > headerPlusOneItem ? v_scroll.Height - headerPlusOneItem : 0;
1373 v_scroll.Maximum = v_scroll.Maximum > headerPlusOneItem ? v_scroll.Maximum - headerPlusOneItem : 0;
1375 v_scroll.LargeChange = v_scroll.Height;
1377 v_scroll.SmallChange = item_size.Height;
1378 width -= v_scroll.Width;
1381 item_control.Size = new Size (width, height);
1383 if (header_control.is_visible)
1384 header_control.Width = width;
1387 internal int GetReorderedColumnIndex (ColumnHeader column)
1389 if (reordered_column_indices == null)
1390 return column.Index;
1392 for (int i = 0; i < Columns.Count; i++)
1393 if (reordered_column_indices [i] == column.Index)
1399 internal ColumnHeader GetReorderedColumn (int index)
1401 if (reordered_column_indices == null)
1402 return Columns [index];
1404 return Columns [reordered_column_indices [index]];
1407 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1410 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1412 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1416 header_control.Invalidate ();
1417 item_control.Invalidate ();
1422 int column_count = Columns.Count;
1424 if (reordered_column_indices == null) {
1425 reordered_column_indices = new int [column_count];
1426 for (int i = 0; i < column_count; i++)
1427 reordered_column_indices [i] = i;
1430 if (reordered_column_indices [index] == col.Index)
1433 int[] curr = reordered_column_indices;
1434 int [] result = new int [column_count];
1436 for (int i = 0; i < column_count; i++) {
1437 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1441 result [i] = col.Index;
1443 result [i] = curr [curr_idx++];
1446 ReorderColumns (result, true);
1449 internal void ReorderColumns (int [] display_indices, bool redraw)
1451 reordered_column_indices = display_indices;
1452 for (int i = 0; i < Columns.Count; i++) {
1453 ColumnHeader col = Columns [i];
1454 col.InternalDisplayIndex = reordered_column_indices [i];
1456 if (redraw && view == View.Details && IsHandleCreated) {
1458 header_control.Invalidate ();
1459 item_control.Invalidate ();
1463 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1465 int column_count = Columns.Count;
1466 newCol.SetListView (this);
1468 int [] display_indices = new int [column_count];
1469 for (int i = 0; i < column_count; i++) {
1470 ColumnHeader col = Columns [i];
1472 display_indices [i] = index;
1474 int display_index = col.InternalDisplayIndex;
1475 if (display_index < index) {
1476 display_indices [i] = display_index;
1478 display_indices [i] = (display_index + 1);
1483 ReorderColumns (display_indices, redraw);
1487 Size LargeIconItemSize
1490 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1491 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1492 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1493 int w = Math.Max (text_size.Width, image_w);
1496 w += 2 + CheckBoxSize.Width;
1498 return new Size (w, h);
1502 Size SmallIconItemSize {
1504 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1505 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1506 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1507 int w = text_size.Width + image_w;
1510 w += 2 + CheckBoxSize.Width;
1512 return new Size (w, h);
1518 // Calculate tile size if needed
1519 // It appears that using Font.Size instead of a SizeF value can give us
1520 // a slightly better approach to the proportions defined in .Net
1521 if (tile_size == Size.Empty) {
1522 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1523 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1524 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1525 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1527 tile_size = new Size (w, h);
1534 int GetDetailsItemHeight ()
1537 int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1538 int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1539 item_height = Math.Max (checkbox_height, text_size.Height);
1540 item_height = Math.Max (item_height, small_image_height);
1544 void SetItemLocation (int index, int x, int y, int row, int col)
1546 Point old_location = items_location [index];
1547 if (old_location.X == x && old_location.Y == y)
1550 items_location [index] = new Point (x, y);
1551 items_matrix_location [index] = new ItemMatrixLocation (row, col);
1554 // Initial position matches item's position in ListViewItemCollection
1556 reordered_items_indices [index] = index;
1560 void ShiftItemsPositions (int from, int to, bool forward)
1563 for (int i = to + 1; i > from; i--) {
1564 reordered_items_indices [i] = reordered_items_indices [i - 1];
1566 ListViewItem item = items [reordered_items_indices [i]];
1568 item.DisplayIndex = i;
1572 for (int i = from - 1; i < to; i++) {
1573 reordered_items_indices [i] = reordered_items_indices [i + 1];
1575 ListViewItem item = items [reordered_items_indices [i]];
1577 item.DisplayIndex = i;
1583 internal void ChangeItemLocation (int display_index, Point new_pos)
1585 int new_display_index = GetDisplayIndexFromLocation (new_pos);
1586 if (new_display_index == display_index)
1589 int item_index = reordered_items_indices [display_index];
1590 ListViewItem item = items [item_index];
1592 bool forward = new_display_index < display_index;
1593 int index_from, index_to;
1595 index_from = new_display_index;
1596 index_to = display_index - 1;
1598 index_from = display_index + 1;
1599 index_to = new_display_index;
1602 ShiftItemsPositions (index_from, index_to, forward);
1604 reordered_items_indices [new_display_index] = item_index;
1607 item.DisplayIndex = new_display_index;
1611 int GetDisplayIndexFromLocation (Point loc)
1613 int display_index = -1;
1614 Rectangle item_area;
1617 if (loc.X < 0 || loc.Y < 0)
1620 // Adjustment to put in the next position refered by 'loc'
1621 loc.X -= item_size.Width / 2;
1625 for (int i = 0; i < items.Count; i++) {
1626 item_area = new Rectangle (GetItemLocation (i), item_size);
1627 item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing,
1628 ThemeEngine.Current.ListViewVerticalSpacing);
1630 if (item_area.Contains (loc)) {
1636 // Put in in last position
1637 if (display_index == -1)
1638 display_index = items.Count - 1;
1640 return display_index;
1643 // When using groups, the items with no group assigned
1644 // belong to the DefaultGroup
1645 int GetDefaultGroupItems ()
1648 foreach (ListViewItem item in items)
1649 if (item.Group == null)
1655 // cache the spacing to let virtualmode compute the positions on the fly
1660 int[,] item_index_matrix;
1662 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1664 Rectangle area = ClientRectangle;
1666 if (UseCustomColumnWidth)
1667 CalculateCustomColumnWidth ();
1669 // When groups are used the alignment is always top-aligned
1674 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1675 for (int i = 0; i < groups.InternalCount; i++) {
1676 ListViewGroup group = groups.GetInternalGroup (i);
1677 int items_in_group = group.GetActualItemCount ();
1679 if (items_in_group == 0)
1682 int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1683 if (group_cols <= 0)
1685 int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols);
1687 group.starting_row = rows;
1688 group.rows = group_rows;
1689 group.starting_item = items;
1690 group.current_item = 0; // Reset layout
1692 cols = Math.Max (group_cols, cols);
1694 items += items_in_group;
1698 // Simple matrix if no groups are used
1700 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1703 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1705 if (UseCustomColumnWidth)
1706 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width));
1708 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1713 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1717 item_index_matrix = new int [rows, cols];
1720 // When using custom column width, we look for the minimum one
1721 void CalculateCustomColumnWidth ()
1723 int min_width = Int32.MaxValue;
1724 for (int i = 0; i < columns.Count; i++) {
1725 int col_width = columns [i].Width;
1727 if (col_width < min_width)
1728 min_width = col_width;
1731 custom_column_width = min_width;
1734 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1736 header_control.Visible = false;
1737 header_control.Size = Size.Empty;
1738 item_control.Visible = true;
1739 item_control.Location = Point.Empty;
1740 ItemSize = item_size; // Cache item size
1741 this.x_spacing = x_spacing;
1742 this.y_spacing = y_spacing;
1744 if (items.Count == 0)
1747 Size sz = item_size;
1749 CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing);
1751 layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing;
1752 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1754 if (virtual_mode) { // no actual assignment is needed on items for virtual mode
1755 item_control.Size = new Size (layout_wd, layout_ht);
1759 bool using_groups = UsingGroups;
1760 if (using_groups) // the groups layout will override layout_ht
1761 CalculateGroupsLayout (sz, y_spacing, 0);
1763 int row = 0, col = 0;
1765 int display_index = 0;
1767 for (int i = 0; i < items.Count; i++) {
1768 ListViewItem item = items [i];
1770 ListViewGroup group = item.Group;
1772 group = groups.DefaultGroup;
1774 Point group_items_loc = group.items_area_location;
1775 int current_item = group.current_item++;
1776 int starting_row = group.starting_row;
1778 display_index = group.starting_item + current_item;
1779 row = (current_item / cols);
1780 col = current_item % cols;
1782 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1783 y = row * (item_size.Height + y_spacing) + group_items_loc.Y;
1785 SetItemLocation (display_index, x, y, row + starting_row, col);
1786 SetItemAtDisplayIndex (display_index, i);
1787 item_index_matrix [row + starting_row, col] = i;
1791 x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1792 y = row * (item_size.Height + y_spacing);
1793 display_index = i; // Same as item index in Items
1795 SetItemLocation (i, x, y, row, col);
1796 item_index_matrix [row, col] = i;
1805 if (++col == cols) {
1813 item.DisplayIndex = display_index;
1814 item.SetPosition (new Point (x, y));
1817 item_control.Size = new Size (layout_wd, layout_ht);
1820 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin)
1823 bool details = view == View.Details;
1825 for (int i = 0; i < groups.InternalCount; i++) {
1826 ListViewGroup group = groups.GetInternalGroup (i);
1827 if (group.ItemCount == 0)
1830 y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows);
1833 layout_ht = y; // Update height taking into account Groups' headers heights
1836 int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows)
1838 Rectangle client_area = ClientRectangle;
1839 int header_height = Font.Height + 15; // one line height + some padding
1841 group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height);
1842 group.items_area_location = new Point (0, y_origin + header_height);
1844 int items_area_height = ((item_height + y_spacing) * rows);
1845 return header_height + items_area_height + 10; // Add a small bottom margin
1848 void CalculateDetailsGroupItemsCount ()
1852 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1853 for (int i = 0; i < groups.InternalCount; i++) {
1854 ListViewGroup group = groups.GetInternalGroup (i);
1855 int items_in_group = group.GetActualItemCount ();
1857 if (items_in_group == 0)
1860 group.starting_item = items;
1861 group.current_item = 0; // Reset layout.
1862 items += items_in_group;
1866 void LayoutHeader ()
1869 for (int i = 0; i < Columns.Count; i++) {
1870 ColumnHeader col = GetReorderedColumn (i);
1873 col.CalcColumnHeader ();
1879 if (x < ClientRectangle.Width)
1880 x = ClientRectangle.Width;
1882 if (header_style == ColumnHeaderStyle.None) {
1883 header_control.Visible = false;
1884 header_control.Size = Size.Empty;
1885 layout_wd = ClientRectangle.Width;
1887 header_control.Width = x;
1888 header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font);
1889 header_control.Visible = true;
1893 void LayoutDetails ()
1897 if (columns.Count == 0) {
1898 item_control.Visible = false;
1899 layout_wd = ClientRectangle.Width;
1900 layout_ht = ClientRectangle.Height;
1904 item_control.Visible = true;
1905 item_control.Location = Point.Empty;
1906 item_control.Width = ClientRectangle.Width;
1907 AdjustChildrenZOrder ();
1909 int item_height = GetDetailsItemHeight ();
1910 ItemSize = new Size (0, item_height); // We only cache Height for details view
1911 int y = header_control.Height;
1912 layout_ht = y + (item_height * items.Count);
1913 if (items.Count > 0 && grid_lines) // some space for bottom gridline
1916 bool using_groups = UsingGroups;
1918 // Observe that this routines will override our layout_ht value
1919 CalculateDetailsGroupItemsCount ();
1920 CalculateGroupsLayout (ItemSize, 2, y);
1923 if (virtual_mode) // no assgination on items is needed
1926 for (int i = 0; i < items.Count; i++) {
1927 ListViewItem item = items [i];
1933 ListViewGroup group = item.Group;
1935 group = groups.DefaultGroup;
1937 int current_item = group.current_item++;
1938 Point group_items_loc = group.items_area_location;
1939 display_index = group.starting_item + current_item;
1941 y = item_y = current_item * (item_height + 2) + group_items_loc.Y;
1942 SetItemLocation (display_index, 0, item_y, 0, 0);
1943 SetItemAtDisplayIndex (display_index, i);
1948 SetItemLocation (i, 0, item_y, 0, 0);
1953 item.DisplayIndex = display_index;
1954 item.SetPosition (new Point (0, item_y));
1958 // Need to make sure HeaderControl is on top, and we can't simply use BringToFront since
1959 // these controls are implicit, so we need to re-populate our collection.
1960 void AdjustChildrenZOrder ()
1963 Controls.ClearImplicit ();
1964 Controls.AddImplicit (header_control);
1965 Controls.AddImplicit (item_control);
1966 Controls.AddImplicit (h_scroll);
1967 Controls.AddImplicit (v_scroll);
1971 private void AdjustItemsPositionArray (int count)
1973 // In virtual mode we compute the positions on the fly.
1976 if (items_location.Length >= count)
1979 // items_location, items_matrix_location and reordered_items_indices must keep the same length
1980 count = Math.Max (count, items_location.Length * 2);
1981 items_location = new Point [count];
1982 items_matrix_location = new ItemMatrixLocation [count];
1983 reordered_items_indices = new int [count];
1986 private void CalculateListView (ListViewAlignment align)
1990 AdjustItemsPositionArray (items.Count);
1997 case View.SmallIcon:
1998 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
1999 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2002 case View.LargeIcon:
2003 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
2004 ThemeEngine.Current.ListViewHorizontalSpacing,
2005 ThemeEngine.Current.ListViewVerticalSpacing);
2009 LayoutIcons (SmallIconItemSize, true,
2010 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2013 if (!Application.VisualStylesEnabled)
2014 goto case View.LargeIcon;
2016 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
2017 ThemeEngine.Current.ListViewHorizontalSpacing,
2018 ThemeEngine.Current.ListViewVerticalSpacing);
2022 CalculateScrollBars ();
2025 internal Point GetItemLocation (int index)
2027 Point loc = Point.Empty;
2029 loc = GetFixedItemLocation (index);
2031 loc = items_location [index];
2033 loc.X -= h_marker; // Adjust to scroll
2039 Point GetFixedItemLocation (int index)
2041 Point loc = Point.Empty;
2044 case View.LargeIcon:
2045 case View.SmallIcon:
2046 loc.X = index % cols * (item_size.Width + x_spacing);
2047 loc.Y = index / cols * (item_size.Height + y_spacing);
2050 loc.X = index / rows * (item_size.Width + x_spacing);
2051 loc.Y = index % rows * (item_size.Height + y_spacing);
2054 loc.Y = header_control.Height + (index * item_size.Height);
2061 internal int GetItemIndex (int display_index)
2064 return display_index; // no reordering in virtual mode.
2065 return reordered_items_indices [display_index];
2068 internal ListViewItem GetItemAtDisplayIndex (int display_index)
2070 // in virtual mode there's no reordering at all.
2072 return items [display_index];
2073 return items [reordered_items_indices [display_index]];
2076 internal void SetItemAtDisplayIndex (int display_index, int index)
2078 reordered_items_indices [display_index] = index;
2081 private bool KeySearchString (KeyEventArgs ke)
2083 int current_tickcnt = Environment.TickCount;
2084 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2085 keysearch_text = string.Empty;
2088 if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2091 keysearch_text += (char)ke.KeyCode;
2092 keysearch_tickcnt = current_tickcnt;
2094 int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex;
2095 int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0;
2097 ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true);
2098 if (item != null && prev_focused != item.DisplayIndex) {
2099 selected_indices.Clear ();
2101 SetFocusedItem (item.DisplayIndex);
2102 item.Selected = true;
2103 EnsureVisible (GetItemIndex (item.DisplayIndex));
2109 private void OnItemsChanged ()
2111 ResetSearchString ();
2114 private void ResetSearchString ()
2116 keysearch_text = String.Empty;
2119 int GetAdjustedIndex (Keys key)
2123 if (View == View.Details) {
2126 result = FocusedItem.DisplayIndex - 1;
2129 result = FocusedItem.DisplayIndex + 1;
2130 if (result == items.Count)
2134 int last_index = LastVisibleIndex;
2135 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2136 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2138 if (FocusedItem.DisplayIndex == last_index) {
2139 if (FocusedItem.DisplayIndex < Items.Count - 1) {
2140 int page_size = item_control.Height / ItemSize.Height - 1;
2141 result = FocusedItem.DisplayIndex + page_size - 1;
2142 if (result >= Items.Count)
2143 result = Items.Count - 1;
2146 result = last_index;
2149 int first_index = FirstVisibleIndex;
2150 if (GetItemLocation (first_index).Y < 0)
2152 if (FocusedItem.DisplayIndex == first_index) {
2153 if (first_index > 0) {
2154 int page_size = item_control.Height / ItemSize.Height - 1;
2155 result = first_index - page_size + 1;
2160 result = first_index;
2167 return GetFixedAdjustedIndex (key);
2169 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex];
2170 int row = item_matrix_location.Row;
2171 int col = item_matrix_location.Col;
2173 int adjusted_index = -1;
2179 adjusted_index = item_index_matrix [row, col - 1];
2183 if (col == (cols - 1))
2185 while (item_index_matrix [row, col + 1] == 0) {
2190 adjusted_index = item_index_matrix [row, col + 1];
2196 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2201 adjusted_index = item_index_matrix [row - 1, col];
2205 if (row == (rows - 1) || row == Items.Count - 1)
2207 while (item_index_matrix [row + 1, col] == 0) {
2212 adjusted_index = item_index_matrix [row + 1, col];
2219 return items [adjusted_index].DisplayIndex;
2222 // Used for virtual mode, where items *cannot* be re-arranged
2223 int GetFixedAdjustedIndex (Keys key)
2229 if (view == View.List)
2230 result = focused_item_index - rows;
2232 result = focused_item_index - 1;
2235 if (view == View.List)
2236 result = focused_item_index + rows;
2238 result = focused_item_index + 1;
2241 if (view != View.List)
2242 result = focused_item_index - cols;
2244 result = focused_item_index - 1;
2247 if (view != View.List)
2248 result = focused_item_index + cols;
2250 result = focused_item_index + 1;
2257 if (result < 0 || result >= items.Count)
2258 result = focused_item_index;
2263 ListViewItem selection_start;
2265 private bool SelectItems (ArrayList sel_items)
2267 bool changed = false;
2268 foreach (ListViewItem item in SelectedItems)
2269 if (!sel_items.Contains (item)) {
2270 item.Selected = false;
2273 foreach (ListViewItem item in sel_items)
2274 if (!item.Selected) {
2275 item.Selected = true;
2281 private void UpdateMultiSelection (int index, bool reselect)
2283 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2284 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2285 ListViewItem item = GetItemAtDisplayIndex (index);
2287 if (shift_pressed && selection_start != null) {
2288 ArrayList list = new ArrayList ();
2289 int start_index = selection_start.DisplayIndex;
2290 int start = Math.Min (start_index, index);
2291 int end = Math.Max (start_index, index);
2292 if (View == View.Details) {
2293 for (int i = start; i <= end; i++)
2294 list.Add (GetItemAtDisplayIndex (i));
2296 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2297 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2298 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2299 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2300 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2301 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2303 for (int i = 0; i < items.Count; i++) {
2304 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2306 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2307 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2308 list.Add (GetItemAtDisplayIndex (i));
2312 } else if (ctrl_pressed) {
2313 item.Selected = !item.Selected;
2314 selection_start = item;
2317 // do not unselect, and reselect the item
2318 foreach (int itemIndex in SelectedIndices) {
2319 if (index == itemIndex)
2321 items [itemIndex].Selected = false;
2324 SelectedItems.Clear ();
2325 item.Selected = true;
2327 selection_start = item;
2331 internal override bool InternalPreProcessMessage (ref Message msg)
2333 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2334 Keys key_data = (Keys)msg.WParam.ToInt32();
2336 HandleNavKeys (key_data);
2339 return base.InternalPreProcessMessage (ref msg);
2342 bool HandleNavKeys (Keys key_data)
2344 if (Items.Count == 0 || !item_control.Visible)
2347 if (FocusedItem == null)
2352 SelectIndex (Items.Count - 1);
2365 SelectIndex (GetAdjustedIndex (key_data));
2369 SelectIndex (focused_item_index);
2370 ToggleItemsCheckState ();
2373 if (selected_indices.Count > 0)
2374 OnItemActivate (EventArgs.Empty);
2384 void ToggleItemsCheckState ()
2389 // Don't modify check state if StateImageList has less than 2 elements
2390 if (StateImageList != null && StateImageList.Images.Count < 2)
2393 if (SelectedIndices.Count > 0) {
2394 for (int i = 0; i < SelectedIndices.Count; i++) {
2395 ListViewItem item = Items [SelectedIndices [i]];
2396 item.Checked = !item.Checked;
2401 if (FocusedItem != null) {
2402 FocusedItem.Checked = !FocusedItem.Checked;
2403 SelectIndex (FocusedItem.Index);
2407 void SelectIndex (int display_index)
2409 if (display_index == -1)
2413 UpdateMultiSelection (display_index, true);
2414 else if (!GetItemAtDisplayIndex (display_index).Selected)
2415 GetItemAtDisplayIndex (display_index).Selected = true;
2417 SetFocusedItem (display_index);
2418 EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index
2421 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2423 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2426 if (ke.Alt || ke.Control)
2429 ke.Handled = KeySearchString (ke);
2432 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2434 Point loc = PointToClient (Control.MousePosition);
2435 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2438 internal class ItemControl : Control {
2441 ListViewItem clicked_item;
2442 ListViewItem last_clicked_item;
2443 bool hover_processed = false;
2444 bool checking = false;
2445 ListViewItem prev_hovered_item;
2446 ListViewItem prev_tooltip_item;
2448 Point drag_begin = new Point (-1, -1);
2449 internal int dragged_item_index = -1;
2451 ListViewLabelEditTextBox edit_text_box;
2452 internal ListViewItem edit_item;
2453 LabelEditEventArgs edit_args;
2455 public ItemControl (ListView owner)
2458 this.SetStyle (ControlStyles.DoubleBuffer, true);
2459 DoubleClick += new EventHandler(ItemsDoubleClick);
2460 MouseDown += new MouseEventHandler(ItemsMouseDown);
2461 MouseMove += new MouseEventHandler(ItemsMouseMove);
2462 MouseHover += new EventHandler(ItemsMouseHover);
2463 MouseUp += new MouseEventHandler(ItemsMouseUp);
2466 void ItemsDoubleClick (object sender, EventArgs e)
2468 if (owner.activation == ItemActivation.Standard)
2469 owner.OnItemActivate (EventArgs.Empty);
2479 BoxSelect box_select_mode = BoxSelect.None;
2480 IList prev_selection;
2481 Point box_select_start;
2483 Rectangle box_select_rect;
2484 internal Rectangle BoxSelectRectangle {
2485 get { return box_select_rect; }
2487 if (box_select_rect == value)
2490 InvalidateBoxSelectRect ();
2491 box_select_rect = value;
2492 InvalidateBoxSelectRect ();
2496 void InvalidateBoxSelectRect ()
2498 if (BoxSelectRectangle.Size.IsEmpty)
2501 Rectangle edge = BoxSelectRectangle;
2507 edge.Y = BoxSelectRectangle.Bottom - 1;
2509 edge.Y = BoxSelectRectangle.Y - 1;
2511 edge.Height = BoxSelectRectangle.Height + 2;
2513 edge.X = BoxSelectRectangle.Right - 1;
2517 private Rectangle CalculateBoxSelectRectangle (Point pt)
2519 int left = Math.Min (box_select_start.X, pt.X);
2520 int right = Math.Max (box_select_start.X, pt.X);
2521 int top = Math.Min (box_select_start.Y, pt.Y);
2522 int bottom = Math.Max (box_select_start.Y, pt.Y);
2523 return Rectangle.FromLTRB (left, top, right, bottom);
2526 bool BoxIntersectsItem (int index)
2528 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2529 if (owner.View != View.Details) {
2531 r.Y += r.Height / 4;
2535 return BoxSelectRectangle.IntersectsWith (r);
2538 bool BoxIntersectsText (int index)
2540 Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds;
2541 return BoxSelectRectangle.IntersectsWith (r);
2544 ArrayList BoxSelectedItems {
2546 ArrayList result = new ArrayList ();
2547 for (int i = 0; i < owner.Items.Count; i++) {
2549 // Can't iterate over specific items properties in virtualmode
2550 if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode)
2551 intersects = BoxIntersectsText (i);
2553 intersects = BoxIntersectsItem (i);
2556 result.Add (owner.GetItemAtDisplayIndex (i));
2562 private bool PerformBoxSelection (Point pt)
2564 if (box_select_mode == BoxSelect.None)
2567 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2569 ArrayList box_items = BoxSelectedItems;
2573 switch (box_select_mode) {
2575 case BoxSelect.Normal:
2579 case BoxSelect.Control:
2580 items = new ArrayList ();
2581 foreach (int index in prev_selection)
2582 if (!box_items.Contains (owner.Items [index]))
2583 items.Add (owner.Items [index]);
2584 foreach (ListViewItem item in box_items)
2585 if (!prev_selection.Contains (item.Index))
2589 case BoxSelect.Shift:
2591 foreach (ListViewItem item in box_items)
2592 prev_selection.Remove (item.Index);
2593 foreach (int index in prev_selection)
2594 items.Add (owner.Items [index]);
2598 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2602 owner.SelectItems (items);
2608 private void ItemsMouseDown (object sender, MouseEventArgs me)
2610 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2611 if (owner.items.Count == 0)
2614 bool box_selecting = false;
2615 Size item_size = owner.ItemSize;
2616 Point pt = new Point (me.X, me.Y);
2617 for (int i = 0; i < owner.items.Count; i++) {
2618 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2619 if (!item_rect.Contains (pt))
2622 // Actual item in 'i' position
2623 ListViewItem item = owner.GetItemAtDisplayIndex (i);
2625 if (item.CheckRectReal.Contains (pt)) {
2626 // Don't modify check state if we have only one image
2627 // and if we are in 1.1 profile only take into account
2629 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2633 // Generate an extra ItemCheck event when we got two clicks
2634 // (Match weird .Net behaviour)
2636 item.Checked = !item.Checked;
2638 item.Checked = !item.Checked;
2643 if (owner.View == View.Details) {
2644 bool over_text = item.TextBounds.Contains (pt);
2645 if (owner.FullRowSelect) {
2646 clicked_item = item;
2647 bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2648 if (!over_text && over_item_column && owner.MultiSelect)
2649 box_selecting = true;
2650 } else if (over_text)
2651 clicked_item = item;
2653 owner.SetFocusedItem (i);
2655 clicked_item = item;
2661 if (clicked_item != null) {
2662 bool changed = !clicked_item.Selected;
2663 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2664 owner.SetFocusedItem (clicked_item.DisplayIndex);
2666 if (owner.MultiSelect) {
2667 bool reselect = (!owner.LabelEdit || changed);
2668 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2669 owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect);
2671 clicked_item.Selected = true;
2674 if (owner.VirtualMode && changed) {
2675 // Broken event - It's not fired from Item.Selected also
2676 ListViewVirtualItemsSelectionRangeChangedEventArgs args =
2677 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2679 owner.OnVirtualItemsSelectionRangeChanged (args);
2681 // Report clicks only if the item was clicked. On MS the
2682 // clicks are only raised if you click an item
2684 if (me.Clicks > 1) {
2685 if (owner.CheckBoxes)
2686 clicked_item.Checked = !clicked_item.Checked;
2687 } else if (me.Clicks == 1) {
2688 if (owner.LabelEdit && !changed)
2689 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2692 drag_begin = me.Location;
2693 dragged_item_index = clicked_item.Index;
2695 if (owner.MultiSelect)
2696 box_selecting = true;
2697 else if (owner.SelectedItems.Count > 0)
2698 owner.SelectedItems.Clear ();
2701 if (box_selecting) {
2702 Keys mods = XplatUI.State.ModifierKeys;
2703 if ((mods & Keys.Shift) != 0)
2704 box_select_mode = BoxSelect.Shift;
2705 else if ((mods & Keys.Control) != 0)
2706 box_select_mode = BoxSelect.Control;
2708 box_select_mode = BoxSelect.Normal;
2709 box_select_start = pt;
2710 prev_selection = owner.SelectedIndices.List.Clone () as IList;
2714 private void ItemsMouseMove (object sender, MouseEventArgs me)
2716 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2718 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2722 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2723 !hover_processed && owner.Activation != ItemActivation.OneClick
2724 && !owner.ShowItemToolTips
2728 Point pt = PointToClient (Control.MousePosition);
2729 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2731 if (hover_processed && item != null && item != prev_hovered_item) {
2732 hover_processed = false;
2733 XplatUI.ResetMouseHover (Handle);
2736 // Need to invalidate the item in HotTracking to show/hide the underline style
2737 if (owner.Activation == ItemActivation.OneClick) {
2738 if (item == null && owner.HotItemIndex != -1) {
2739 if (owner.HotTracking)
2740 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2742 Cursor = Cursors.Default;
2743 owner.HotItemIndex = -1;
2744 } else if (item != null && owner.HotItemIndex == -1) {
2745 if (owner.HotTracking)
2746 Invalidate (item.Bounds);
2748 Cursor = Cursors.Hand;
2749 owner.HotItemIndex = item.Index;
2753 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2754 if (drag_begin != new Point (-1, -1)) {
2755 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2756 if (!r.Contains (me.X, me.Y)) {
2757 ListViewItem dragged_item = owner.items [dragged_item_index];
2758 owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2760 drag_begin = new Point (-1, -1);
2761 dragged_item_index = -1;
2766 if (owner.ShowItemToolTips) {
2768 owner.item_tooltip.Active = false;
2769 prev_tooltip_item = null;
2770 } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2771 owner.item_tooltip.Active = true;
2772 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2773 prev_tooltip_item = item;
2779 private void ItemsMouseHover (object sender, EventArgs e)
2781 if (owner.hover_pending) {
2782 owner.OnMouseHover (e);
2783 owner.hover_pending = false;
2789 hover_processed = true;
2790 Point pt = PointToClient (Control.MousePosition);
2791 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2795 prev_hovered_item = item;
2797 if (owner.HoverSelection) {
2798 if (owner.MultiSelect)
2799 owner.UpdateMultiSelection (item.Index, true);
2801 item.Selected = true;
2803 owner.SetFocusedItem (item.DisplayIndex);
2804 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2807 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2810 void HandleClicks (MouseEventArgs me)
2812 // if the click is not on an item,
2813 // clicks remains as 0
2815 owner.OnDoubleClick (EventArgs.Empty);
2816 owner.OnMouseDoubleClick (me);
2817 } else if (clicks == 1) {
2818 owner.OnClick (EventArgs.Empty);
2819 owner.OnMouseClick (me);
2825 private void ItemsMouseUp (object sender, MouseEventArgs me)
2827 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
2828 HandleClicks (owner_me);
2831 if (owner.Items.Count == 0) {
2833 owner.OnMouseUp (owner_me);
2837 Point pt = new Point (me.X, me.Y);
2839 Rectangle rect = Rectangle.Empty;
2840 if (clicked_item != null) {
2841 if (owner.view == View.Details && !owner.full_row_select)
2842 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
2844 rect = clicked_item.Bounds;
2846 if (rect.Contains (pt)) {
2847 switch (owner.activation) {
2848 case ItemActivation.OneClick:
2849 owner.OnItemActivate (EventArgs.Empty);
2852 case ItemActivation.TwoClick:
2853 if (last_clicked_item == clicked_item) {
2854 owner.OnItemActivate (EventArgs.Empty);
2855 last_clicked_item = null;
2857 last_clicked_item = clicked_item;
2860 // DoubleClick activation is handled in another handler
2864 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
2865 // Need this to clean up background clicks
2866 owner.SelectedItems.Clear ();
2870 owner.OnMouseUp (owner_me);
2873 private void ResetMouseState ()
2875 clicked_item = null;
2876 box_select_start = Point.Empty;
2877 BoxSelectRectangle = Rectangle.Empty;
2878 prev_selection = null;
2879 box_select_mode = BoxSelect.None;
2882 // Clean these bits in case the mouse buttons were
2883 // released before firing ItemDrag
2884 dragged_item_index = -1;
2885 drag_begin = new Point (-1, -1);
2888 private void LabelEditFinished (object sender, EventArgs e)
2890 EndEdit (edit_item);
2893 private void LabelEditCancelled (object sender, EventArgs e)
2895 edit_args.SetLabel (null);
2896 EndEdit (edit_item);
2899 private void LabelTextChanged (object sender, EventArgs e)
2901 if (edit_args != null)
2902 edit_args.SetLabel (edit_text_box.Text);
2905 internal void BeginEdit (ListViewItem item)
2907 if (edit_item != null)
2908 EndEdit (edit_item);
2910 if (edit_text_box == null) {
2911 edit_text_box = new ListViewLabelEditTextBox ();
2912 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
2913 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
2914 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
2915 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
2916 edit_text_box.Visible = false;
2917 Controls.Add (edit_text_box);
2920 item.EnsureVisible();
2922 edit_text_box.Reset ();
2924 switch (owner.view) {
2926 case View.SmallIcon:
2928 edit_text_box.TextAlign = HorizontalAlignment.Left;
2929 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2930 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
2931 edit_text_box.Width = (int)sizef.Width + 4;
2932 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
2933 edit_text_box.WordWrap = false;
2934 edit_text_box.Multiline = false;
2936 case View.LargeIcon:
2937 edit_text_box.TextAlign = HorizontalAlignment.Center;
2938 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2939 sizef = TextRenderer.MeasureString (item.Text, item.Font);
2940 edit_text_box.Width = (int)sizef.Width + 4;
2941 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
2942 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
2943 edit_text_box.WordWrap = true;
2944 edit_text_box.Multiline = true;
2950 edit_text_box.Text = item.Text;
2951 edit_text_box.Font = item.Font;
2952 edit_text_box.Visible = true;
2953 edit_text_box.Focus ();
2954 edit_text_box.SelectAll ();
2956 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
2957 owner.OnBeforeLabelEdit (edit_args);
2959 if (edit_args.CancelEdit)
2963 internal void CancelEdit (ListViewItem item)
2965 // do nothing if there's no item being edited, or if the
2966 // item being edited is not the one passed in
2967 if (edit_item == null || edit_item != item)
2970 edit_args.SetLabel (null);
2974 internal void EndEdit (ListViewItem item)
2976 // do nothing if there's no item being edited, or if the
2977 // item being edited is not the one passed in
2978 if (edit_item == null || edit_item != item)
2981 if (edit_text_box != null) {
2982 if (edit_text_box.Visible)
2983 edit_text_box.Visible = false;
2984 // ensure listview gets focus
2988 // Same as TreeView.EndEdit: need to have focus in synch
2989 Application.DoEvents ();
2992 // Create a new instance, since we could get a call to BeginEdit
2993 // from the handler and have fields out of synch
2995 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
2998 owner.OnAfterLabelEdit (args);
2999 if (!args.CancelEdit && args.Label != null)
3000 item.Text = args.Label;
3003 internal override void OnPaintInternal (PaintEventArgs pe)
3005 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
3008 protected override void WndProc (ref Message m)
3010 switch ((Msg)m.Msg) {
3011 case Msg.WM_KILLFOCUS:
3012 owner.Select (false, true);
3014 case Msg.WM_SETFOCUS:
3015 owner.Select (false, true);
3017 case Msg.WM_LBUTTONDOWN:
3019 owner.Select (false, true);
3021 case Msg.WM_RBUTTONDOWN:
3023 owner.Select (false, true);
3028 base.WndProc (ref m);
3032 internal class ListViewLabelEditTextBox : TextBox
3037 int max_height = -1;
3038 int min_height = -1;
3040 int old_number_lines = 1;
3042 SizeF text_size_one_char;
3044 public ListViewLabelEditTextBox ()
3046 min_height = DefaultSize.Height;
3047 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3050 public int MaxWidth {
3052 if (value < min_width)
3053 max_width = min_width;
3059 public int MaxHeight {
3061 if (value < min_height)
3062 max_height = min_height;
3068 public new int Width {
3078 public override Font Font {
3084 text_size_one_char = TextRenderer.MeasureString ("B", Font);
3088 protected override void OnTextChanged (EventArgs e)
3090 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3092 int new_width = (int)text_size.Width + 8;
3095 ResizeTextBoxWidth (new_width);
3097 if (Width != max_width)
3098 ResizeTextBoxWidth (new_width);
3100 int number_lines = Lines.Length;
3102 if (number_lines != old_number_lines) {
3103 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3104 old_number_lines = number_lines;
3106 ResizeTextBoxHeight (new_height);
3110 base.OnTextChanged (e);
3113 protected override bool IsInputKey (Keys key_data)
3115 if ((key_data & Keys.Alt) == 0) {
3116 switch (key_data & Keys.KeyCode) {
3123 return base.IsInputKey (key_data);
3126 protected override void OnKeyDown (KeyEventArgs e)
3131 switch (e.KeyCode) {
3135 OnEditingFinished (e);
3140 OnEditingCancelled (e);
3145 protected override void OnLostFocus (EventArgs e)
3148 OnEditingFinished (e);
3152 protected void OnEditingCancelled (EventArgs e)
3154 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3159 protected void OnEditingFinished (EventArgs e)
3161 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3166 private void ResizeTextBoxWidth (int new_width)
3168 if (new_width > max_width)
3169 base.Width = max_width;
3171 if (new_width >= min_width)
3172 base.Width = new_width;
3174 base.Width = min_width;
3177 private void ResizeTextBoxHeight (int new_height)
3179 if (new_height > max_height)
3180 base.Height = max_height;
3182 if (new_height >= min_height)
3183 base.Height = new_height;
3185 base.Height = min_height;
3188 public void Reset ()
3195 old_number_lines = 1;
3197 Text = String.Empty;
3202 static object EditingCancelledEvent = new object ();
3203 public event EventHandler EditingCancelled {
3204 add { Events.AddHandler (EditingCancelledEvent, value); }
3205 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3208 static object EditingFinishedEvent = new object ();
3209 public event EventHandler EditingFinished {
3210 add { Events.AddHandler (EditingFinishedEvent, value); }
3211 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3215 internal override void OnPaintInternal (PaintEventArgs pe)
3220 CalculateScrollBars ();
3223 void FocusChanged (object o, EventArgs args)
3225 if (Items.Count == 0)
3228 if (FocusedItem == null)
3231 ListViewItem focused_item = FocusedItem;
3233 if (focused_item.ListView != null) {
3234 focused_item.Invalidate ();
3235 focused_item.Layout ();
3236 focused_item.Invalidate ();
3240 private void ListView_Invalidated (object sender, InvalidateEventArgs e)
3242 // When the ListView is invalidated, we need to invalidate
3243 // the child controls.
3244 header_control.Invalidate ();
3245 item_control.Invalidate ();
3248 private void ListView_MouseEnter (object sender, EventArgs args)
3250 hover_pending = true; // Need a hover event for every Enter/Leave cycle
3253 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3255 if (Items.Count == 0)
3258 int lines = me.Delta / 120;
3265 case View.SmallIcon:
3266 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3268 case View.LargeIcon:
3269 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
3272 Scroll (h_scroll, -ItemSize.Width * lines);
3275 if (!Application.VisualStylesEnabled)
3276 goto case View.LargeIcon;
3278 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3283 private void ListView_SizeChanged (object sender, EventArgs e)
3288 private void SetFocusedItem (int display_index)
3290 if (display_index != -1)
3291 GetItemAtDisplayIndex (display_index).Focused = true;
3292 else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3293 GetItemAtDisplayIndex (focused_item_index).Focused = false;
3294 focused_item_index = display_index;
3295 if (display_index == -1)
3296 OnUIAFocusedItemChanged ();
3297 // otherwise the event will have been fired
3298 // when the ListViewItem's Focused was set
3301 private void HorizontalScroller (object sender, EventArgs e)
3303 item_control.EndEdit (item_control.edit_item);
3305 // Avoid unnecessary flickering, when button is
3306 // kept pressed at the end
3307 if (h_marker != h_scroll.Value) {
3309 int pixels = h_marker - h_scroll.Value;
3311 h_marker = h_scroll.Value;
3312 if (header_control.Visible)
3313 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3315 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3319 private void VerticalScroller (object sender, EventArgs e)
3321 item_control.EndEdit (item_control.edit_item);
3323 // Avoid unnecessary flickering, when button is
3324 // kept pressed at the end
3325 if (v_marker != v_scroll.Value) {
3326 int pixels = v_marker - v_scroll.Value;
3327 Rectangle area = item_control.ClientRectangle;
3328 if (header_control.Visible) {
3329 area.Y += header_control.Height;
3330 area.Height -= header_control.Height;
3333 v_marker = v_scroll.Value;
3334 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3338 internal override bool IsInputCharInternal (char charCode)
3342 #endregion // Internal Methods Properties
3344 #region Protected Methods
3345 protected override void CreateHandle ()
3347 base.CreateHandle ();
3348 is_selection_available = true;
3349 for (int i = 0; i < SelectedItems.Count; i++)
3350 OnSelectedIndexChanged (EventArgs.Empty);
3353 protected override void Dispose (bool disposing)
3356 large_image_list = null;
3357 small_image_list = null;
3358 state_image_list = null;
3360 foreach (ColumnHeader col in columns)
3361 col.SetListView (null);
3363 if (!virtual_mode) // In virtual mode we don't save the items
3364 foreach (ListViewItem item in items)
3368 base.Dispose (disposing);
3371 protected override bool IsInputKey (Keys keyData)
3388 return base.IsInputKey (keyData);
3391 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3393 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3398 protected override void OnBackgroundImageChanged (EventArgs e)
3400 item_control.BackgroundImage = BackgroundImage;
3401 base.OnBackgroundImageChanged (e);
3404 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3406 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3411 protected internal virtual void OnColumnClick (ColumnClickEventArgs e)
3413 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3418 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3420 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3425 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3427 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3432 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3434 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3439 protected override void OnFontChanged (EventArgs e)
3441 base.OnFontChanged (e);
3445 protected override void OnHandleCreated (EventArgs e)
3447 base.OnHandleCreated (e);
3448 CalculateListView (alignment);
3449 if (!virtual_mode) // Sorting is not allowed in virtual mode
3453 protected override void OnHandleDestroyed (EventArgs e)
3455 base.OnHandleDestroyed (e);
3458 protected virtual void OnItemActivate (EventArgs e)
3460 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3465 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3467 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3472 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3474 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3479 protected virtual void OnItemDrag (ItemDragEventArgs e)
3481 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3486 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3488 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3493 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3495 ListViewItemSelectionChangedEventHandler eh =
3496 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3501 protected override void OnMouseHover (EventArgs e)
3503 base.OnMouseHover (e);
3506 protected override void OnParentChanged (EventArgs e)
3508 base.OnParentChanged (e);
3511 protected virtual void OnSelectedIndexChanged (EventArgs e)
3513 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3518 protected override void OnSystemColorsChanged (EventArgs e)
3520 base.OnSystemColorsChanged (e);
3523 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3525 CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3530 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3532 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3537 [EditorBrowsable (EditorBrowsableState.Advanced)]
3538 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3540 EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3545 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3547 SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3552 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3554 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3555 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3560 protected void RealizeProperties ()
3565 protected void UpdateExtendedStyles ()
3570 bool refocusing = false;
3572 protected override void WndProc (ref Message m)
3574 switch ((Msg)m.Msg) {
3575 case Msg.WM_KILLFOCUS:
3576 Control receiver = Control.FromHandle (m.WParam);
3577 if (receiver == item_control) {
3583 case Msg.WM_SETFOCUS:
3593 base.WndProc (ref m);
3595 #endregion // Protected Methods
3597 #region Public Instance Methods
3598 public void ArrangeIcons ()
3600 ArrangeIcons (this.alignment);
3603 public void ArrangeIcons (ListViewAlignment value)
3605 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3606 if (view == View.LargeIcon || view == View.SmallIcon)
3610 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3612 if (columnIndex < 0 || columnIndex >= columns.Count)
3613 throw new ArgumentOutOfRangeException ("columnIndex");
3615 columns [columnIndex].AutoResize (headerAutoResize);
3618 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3621 foreach (ColumnHeader col in columns)
3622 col.AutoResize (headerAutoResize);
3626 public void BeginUpdate ()
3628 // flag to avoid painting
3632 public void Clear ()
3635 items.Clear (); // Redraw (true) called here
3638 public void EndUpdate ()
3640 // flag to avoid painting
3643 // probably, now we need a redraw with recalculations
3647 public void EnsureVisible (int index)
3649 if (index < 0 || index >= items.Count || scrollable == false || updating)
3652 Rectangle view_rect = item_control.ClientRectangle;
3653 // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items
3654 Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds;
3656 if (view == View.Details && header_style != ColumnHeaderStyle.None) {
3657 view_rect.Y += header_control.Height;
3658 view_rect.Height -= header_control.Height;
3661 if (view_rect.Contains (bounds))
3664 if (View != View.Details) {
3665 if (bounds.Left < 0)
3666 h_scroll.Value += bounds.Left;
3667 // Don't shift right unless right-to-left layout is active. (Xamarin bug 22483)
3668 else if (this.RightToLeftLayout && bounds.Right > view_rect.Right)
3669 h_scroll.Value += (bounds.Right - view_rect.Right);
3672 if (bounds.Top < view_rect.Y)
3673 v_scroll.Value += bounds.Top - view_rect.Y;
3674 else if (bounds.Bottom > view_rect.Bottom)
3675 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3678 public ListViewItem FindItemWithText (string text)
3680 if (items.Count == 0)
3683 return FindItemWithText (text, true, 0, true);
3686 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3688 return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3691 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3693 return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3696 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3698 if (startIndex < 0 || startIndex >= items.Count)
3699 throw new ArgumentOutOfRangeException ("startIndex");
3702 throw new ArgumentNullException ("text");
3705 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3706 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty,
3707 SearchDirectionHint.Down, startIndex);
3709 OnSearchForVirtualItem (args);
3710 int idx = args.Index;
3711 if (idx >= 0 && idx < virtual_list_size)
3719 ListViewItem lvi = items [i];
3721 if (isPrefixSearch) { // prefix search
3722 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3724 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3727 if (i + 1 >= items.Count) {
3735 if (i == startIndex)
3739 // Subitems have a minor priority, so we have to do a second linear search
3740 // Also, we don't need to to a roundtrip search for them by now
3741 if (includeSubItemsInSearch) {
3742 for (i = startIndex; i < items.Count; i++) {
3743 ListViewItem lvi = items [i];
3744 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3745 if (isPrefixSearch) {
3746 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text,
3747 text, CompareOptions.IgnoreCase))
3749 } else if (String.Compare (sub_item.Text, text, true) == 0)
3757 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3759 return FindNearestItem (searchDirection, new Point (x, y));
3762 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3764 if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3765 throw new ArgumentOutOfRangeException ("searchDirection");
3767 if (view != View.LargeIcon && view != View.SmallIcon)
3768 throw new InvalidOperationException ();
3771 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3772 false, false, String.Empty, point,
3775 OnSearchForVirtualItem (args);
3776 int idx = args.Index;
3777 if (idx >= 0 && idx < virtual_list_size)
3783 ListViewItem item = null;
3784 int min_dist = Int32.MaxValue;
3787 // It looks like .Net does a previous adjustment
3790 case SearchDirectionHint.Up:
3791 point.Y -= item_size.Height;
3793 case SearchDirectionHint.Down:
3794 point.Y += item_size.Height;
3796 case SearchDirectionHint.Left:
3797 point.X -= item_size.Width;
3799 case SearchDirectionHint.Right:
3800 point.X += item_size.Width;
3804 for (int i = 0; i < items.Count; i++) {
3805 Point item_loc = GetItemLocation (i);
3807 if (dir == SearchDirectionHint.Up) {
3808 if (point.Y < item_loc.Y)
3810 } else if (dir == SearchDirectionHint.Down) {
3811 if (point.Y > item_loc.Y)
3813 } else if (dir == SearchDirectionHint.Left) {
3814 if (point.X < item_loc.X)
3816 } else if (dir == SearchDirectionHint.Right) {
3817 if (point.X > item_loc.X)
3821 int x_dist = point.X - item_loc.X;
3822 int y_dist = point.Y - item_loc.Y;
3824 int dist = x_dist * x_dist + y_dist * y_dist;
3825 if (dist < min_dist) {
3834 public ListViewItem GetItemAt (int x, int y)
3836 Size item_size = ItemSize;
3837 for (int i = 0; i < items.Count; i++) {
3838 Rectangle item_rect = items [i].Bounds;
3839 if (item_rect.Contains (x, y))
3846 public Rectangle GetItemRect (int index)
3848 return GetItemRect (index, ItemBoundsPortion.Entire);
3851 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
3853 if (index < 0 || index >= items.Count)
3854 throw new IndexOutOfRangeException ("index");
3856 return items [index].GetBounds (portion);
3859 public ListViewHitTestInfo HitTest (Point point)
3861 return HitTest (point.X, point.Y);
3864 public ListViewHitTestInfo HitTest (int x, int y)
3867 throw new ArgumentOutOfRangeException ("x");
3869 throw new ArgumentOutOfRangeException ("y");
3871 ListViewItem item = GetItemAt (x, y);
3873 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
3875 ListViewHitTestLocations locations = 0;
3876 if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
3877 locations |= ListViewHitTestLocations.Label;
3878 else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
3879 locations |= ListViewHitTestLocations.Image;
3880 else if (item.CheckRectReal.Contains (x, y))
3881 locations |= ListViewHitTestLocations.StateImage;
3883 ListViewItem.ListViewSubItem subitem = null;
3884 if (view == View.Details)
3885 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
3886 if (si.Bounds.Contains (x, y)) {
3891 return new ListViewHitTestInfo (item, subitem, locations);
3894 [EditorBrowsable (EditorBrowsableState.Advanced)]
3895 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
3897 if (startIndex < 0 || startIndex >= items.Count)
3898 throw new ArgumentOutOfRangeException ("startIndex");
3899 if (endIndex < 0 || endIndex >= items.Count)
3900 throw new ArgumentOutOfRangeException ("endIndex");
3901 if (startIndex > endIndex)
3902 throw new ArgumentException ("startIndex");
3907 for (int i = startIndex; i <= endIndex; i++)
3908 items [i].Invalidate ();
3910 if (!invalidateOnly)
3917 throw new InvalidOperationException ();
3922 // we need this overload to reuse the logic for sorting, while allowing
3923 // redrawing to be done by caller or have it done by this method when
3924 // sorting is really performed
3926 // ListViewItemCollection's Add and AddRange methods call this overload
3927 // with redraw set to false, as they take care of redrawing themselves
3928 // (they even want to redraw the listview if no sort is performed, as
3929 // an item was added), while ListView.Sort () only wants to redraw if
3930 // sorting was actually performed
3931 private void Sort (bool redraw)
3933 if (!IsHandleCreated || item_sorter == null) {
3937 items.Sort (item_sorter);
3942 public override string ToString ()
3944 int count = this.Items.Count;
3947 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
3949 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
3951 #endregion // Public Instance Methods
3956 internal class HeaderControl : Control {
3959 bool column_resize_active = false;
3960 ColumnHeader resize_column;
3961 ColumnHeader clicked_column;
3962 ColumnHeader drag_column;
3964 int drag_to_index = -1;
3965 ColumnHeader entered_column_header;
3967 public HeaderControl (ListView owner)
3970 this.SetStyle (ControlStyles.DoubleBuffer, true);
3971 MouseDown += new MouseEventHandler (HeaderMouseDown);
3972 MouseMove += new MouseEventHandler (HeaderMouseMove);
3973 MouseUp += new MouseEventHandler (HeaderMouseUp);
3974 MouseLeave += new EventHandler (OnMouseLeave);
3977 internal ColumnHeader EnteredColumnHeader {
3978 get { return entered_column_header; }
3980 if (entered_column_header == value)
3982 if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
3983 Region region_to_invalidate = new Region ();
3984 region_to_invalidate.MakeEmpty ();
3985 if (entered_column_header != null)
3986 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
3987 entered_column_header = value;
3988 if (entered_column_header != null)
3989 region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
3990 Invalidate (region_to_invalidate);
3991 region_to_invalidate.Dispose ();
3993 entered_column_header = value;
3997 void OnMouseLeave (object sender, EventArgs e)
3999 EnteredColumnHeader = null;
4002 private ColumnHeader ColumnAtX (int x)
4004 Point pt = new Point (x, 0);
4005 ColumnHeader result = null;
4006 foreach (ColumnHeader col in owner.Columns) {
4007 if (col.Rect.Contains (pt)) {
4015 private int GetReorderedIndex (ColumnHeader col)
4017 if (owner.reordered_column_indices == null)
4020 for (int i = 0; i < owner.Columns.Count; i++)
4021 if (owner.reordered_column_indices [i] == col.Index)
4023 throw new Exception ("Column index missing from reordered array");
4026 private void HeaderMouseDown (object sender, MouseEventArgs me)
4028 if (resize_column != null) {
4029 column_resize_active = true;
4034 clicked_column = ColumnAtX (me.X + owner.h_marker);
4036 if (clicked_column != null) {
4038 if (owner.AllowColumnReorder) {
4040 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4041 drag_column.Rect = clicked_column.Rect;
4042 drag_to_index = GetReorderedIndex (clicked_column);
4044 clicked_column.Pressed = true;
4045 Invalidate (clicked_column);
4050 void Invalidate (ColumnHeader columnHeader)
4052 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4055 Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4057 Rectangle bounds = columnHeader.Rect;
4058 bounds.X -= owner.h_marker;
4064 column_resize_active = false;
4065 resize_column = null;
4067 Cursor = Cursors.Default;
4070 private void HeaderMouseMove (object sender, MouseEventArgs me)
4072 Point pt = new Point (me.X + owner.h_marker, me.Y);
4074 if (column_resize_active) {
4075 int width = pt.X - resize_column.X;
4079 if (!owner.CanProceedWithResize (resize_column, width)){
4083 resize_column.Width = width;
4087 resize_column = null;
4089 if (clicked_column != null) {
4090 if (owner.AllowColumnReorder) {
4093 r = drag_column.Rect;
4094 r.X = clicked_column.Rect.X + me.X - drag_x;
4095 drag_column.Rect = r;
4097 int x = me.X + owner.h_marker;
4098 ColumnHeader over = ColumnAtX (x);
4100 drag_to_index = owner.Columns.Count;
4101 else if (x < over.X + over.Width / 2)
4102 drag_to_index = GetReorderedIndex (over);
4104 drag_to_index = GetReorderedIndex (over) + 1;
4107 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4108 bool pressed = clicked_column.Pressed;
4109 clicked_column.Pressed = over == clicked_column;
4110 if (clicked_column.Pressed ^ pressed)
4111 Invalidate (clicked_column);
4116 for (int i = 0; i < owner.Columns.Count; i++) {
4117 Rectangle zone = owner.Columns [i].Rect;
4118 if (zone.Contains (pt))
4119 EnteredColumnHeader = owner.Columns [i];
4120 zone.X = zone.Right - 5;
4122 if (zone.Contains (pt)) {
4123 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4125 resize_column = owner.Columns [i];
4130 if (resize_column == null)
4131 Cursor = Cursors.Default;
4133 Cursor = Cursors.VSplit;
4136 void HeaderMouseUp (object sender, MouseEventArgs me)
4140 if (column_resize_active) {
4141 int column_idx = resize_column.Index;
4143 owner.RaiseColumnWidthChanged (column_idx);
4147 if (clicked_column != null && clicked_column.Pressed) {
4148 clicked_column.Pressed = false;
4149 Invalidate (clicked_column);
4150 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4153 if (drag_column != null && owner.AllowColumnReorder) {
4155 if (drag_to_index > GetReorderedIndex (clicked_column))
4157 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4158 owner.ReorderColumn (clicked_column, drag_to_index, true);
4163 clicked_column = null;
4166 internal override void OnPaintInternal (PaintEventArgs pe)
4171 Theme theme = ThemeEngine.Current;
4172 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4174 if (drag_column == null)
4178 if (drag_to_index == owner.Columns.Count)
4179 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4181 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4182 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4185 protected override void WndProc (ref Message m)
4187 switch ((Msg)m.Msg) {
4188 case Msg.WM_SETFOCUS:
4192 base.WndProc (ref m);
4198 private class ItemComparer : IComparer {
4199 readonly SortOrder sort_order;
4201 public ItemComparer (SortOrder sortOrder)
4203 sort_order = sortOrder;
4206 public int Compare (object x, object y)
4208 ListViewItem item_x = x as ListViewItem;
4209 ListViewItem item_y = y as ListViewItem;
4210 if (sort_order == SortOrder.Ascending)
4211 return String.Compare (item_x.Text, item_y.Text);
4213 return String.Compare (item_y.Text, item_x.Text);
4217 [ListBindable (false)]
4218 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4220 private readonly ListView owner;
4222 #region Public Constructor
4223 public CheckedIndexCollection (ListView owner)
4227 #endregion // Public Constructor
4229 #region Public Properties
4232 get { return owner.CheckedItems.Count; }
4235 public bool IsReadOnly {
4236 get { return true; }
4239 public int this [int index] {
4241 int [] indices = GetIndices ();
4242 if (index < 0 || index >= indices.Length)
4243 throw new ArgumentOutOfRangeException ("index");
4244 return indices [index];
4248 bool ICollection.IsSynchronized {
4249 get { return false; }
4252 object ICollection.SyncRoot {
4253 get { return this; }
4256 bool IList.IsFixedSize {
4257 get { return true; }
4260 object IList.this [int index] {
4261 get { return this [index]; }
4262 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4264 #endregion // Public Properties
4266 #region Public Methods
4267 public bool Contains (int checkedIndex)
4269 int [] indices = GetIndices ();
4270 for (int i = 0; i < indices.Length; i++) {
4271 if (indices [i] == checkedIndex)
4277 public IEnumerator GetEnumerator ()
4279 int [] indices = GetIndices ();
4280 return indices.GetEnumerator ();
4283 void ICollection.CopyTo (Array dest, int index)
4285 int [] indices = GetIndices ();
4286 Array.Copy (indices, 0, dest, index, indices.Length);
4289 int IList.Add (object value)
4291 throw new NotSupportedException ("Add operation is not supported.");
4296 throw new NotSupportedException ("Clear operation is not supported.");
4299 bool IList.Contains (object checkedIndex)
4301 if (!(checkedIndex is int))
4303 return Contains ((int) checkedIndex);
4306 int IList.IndexOf (object checkedIndex)
4308 if (!(checkedIndex is int))
4310 return IndexOf ((int) checkedIndex);
4313 void IList.Insert (int index, object value)
4315 throw new NotSupportedException ("Insert operation is not supported.");
4318 void IList.Remove (object value)
4320 throw new NotSupportedException ("Remove operation is not supported.");
4323 void IList.RemoveAt (int index)
4325 throw new NotSupportedException ("RemoveAt operation is not supported.");
4328 public int IndexOf (int checkedIndex)
4330 int [] indices = GetIndices ();
4331 for (int i = 0; i < indices.Length; i++) {
4332 if (indices [i] == checkedIndex)
4337 #endregion // Public Methods
4339 private int [] GetIndices ()
4341 ArrayList checked_items = owner.CheckedItems.List;
4342 int [] indices = new int [checked_items.Count];
4343 for (int i = 0; i < checked_items.Count; i++) {
4344 ListViewItem item = (ListViewItem) checked_items [i];
4345 indices [i] = item.Index;
4349 } // CheckedIndexCollection
4351 [ListBindable (false)]
4352 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4354 private readonly ListView owner;
4355 private ArrayList list;
4357 #region Public Constructor
4358 public CheckedListViewItemCollection (ListView owner)
4361 this.owner.Items.Changed += new CollectionChangedHandler (
4362 ItemsCollection_Changed);
4364 #endregion // Public Constructor
4366 #region Public Properties
4370 if (!owner.CheckBoxes)
4376 public bool IsReadOnly {
4377 get { return true; }
4380 public ListViewItem this [int index] {
4382 if (owner.VirtualMode)
4383 throw new InvalidOperationException ();
4384 ArrayList checked_items = List;
4385 if (index < 0 || index >= checked_items.Count)
4386 throw new ArgumentOutOfRangeException ("index");
4387 return (ListViewItem) checked_items [index];
4391 public virtual ListViewItem this [string key] {
4393 int idx = IndexOfKey (key);
4394 return idx == -1 ? null : (ListViewItem) List [idx];
4398 bool ICollection.IsSynchronized {
4399 get { return false; }
4402 object ICollection.SyncRoot {
4403 get { return this; }
4406 bool IList.IsFixedSize {
4407 get { return true; }
4410 object IList.this [int index] {
4411 get { return this [index]; }
4412 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4414 #endregion // Public Properties
4416 #region Public Methods
4417 public bool Contains (ListViewItem item)
4419 if (!owner.CheckBoxes)
4421 return List.Contains (item);
4424 public virtual bool ContainsKey (string key)
4426 return IndexOfKey (key) != -1;
4429 public void CopyTo (Array dest, int index)
4431 if (owner.VirtualMode)
4432 throw new InvalidOperationException ();
4433 if (!owner.CheckBoxes)
4435 List.CopyTo (dest, index);
4438 public IEnumerator GetEnumerator ()
4440 if (owner.VirtualMode)
4441 throw new InvalidOperationException ();
4442 if (!owner.CheckBoxes)
4443 return (new ListViewItem [0]).GetEnumerator ();
4444 return List.GetEnumerator ();
4447 int IList.Add (object value)
4449 throw new NotSupportedException ("Add operation is not supported.");
4454 throw new NotSupportedException ("Clear operation is not supported.");
4457 bool IList.Contains (object item)
4459 if (!(item is ListViewItem))
4461 return Contains ((ListViewItem) item);
4464 int IList.IndexOf (object item)
4466 if (!(item is ListViewItem))
4468 return IndexOf ((ListViewItem) item);
4471 void IList.Insert (int index, object value)
4473 throw new NotSupportedException ("Insert operation is not supported.");
4476 void IList.Remove (object value)
4478 throw new NotSupportedException ("Remove operation is not supported.");
4481 void IList.RemoveAt (int index)
4483 throw new NotSupportedException ("RemoveAt operation is not supported.");
4486 public int IndexOf (ListViewItem item)
4488 if (owner.VirtualMode)
4489 throw new InvalidOperationException ();
4490 if (!owner.CheckBoxes)
4492 return List.IndexOf (item);
4495 public virtual int IndexOfKey (string key)
4497 if (owner.VirtualMode)
4498 throw new InvalidOperationException ();
4499 if (key == null || key.Length == 0)
4502 ArrayList checked_items = List;
4503 for (int i = 0; i < checked_items.Count; i++) {
4504 ListViewItem item = (ListViewItem) checked_items [i];
4505 if (String.Compare (key, item.Name, true) == 0)
4511 #endregion // Public Methods
4513 internal ArrayList List {
4516 list = new ArrayList ();
4517 foreach (ListViewItem item in owner.Items) {
4526 internal void Reset ()
4528 // force re-population of list
4532 private void ItemsCollection_Changed ()
4536 } // CheckedListViewItemCollection
4538 [ListBindable (false)]
4539 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4541 internal ArrayList list;
4542 private ListView owner;
4544 #region UIA Framework Events
4546 // We are using Reflection to add/remove internal events.
4547 // Class ListViewProvider uses the events when View is Details.
4549 //Event used to generate UIA StructureChangedEvent
4550 static object UIACollectionChangedEvent = new object ();
4552 internal event CollectionChangeEventHandler UIACollectionChanged {
4555 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4559 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4563 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4568 CollectionChangeEventHandler eh
4569 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4574 #endregion UIA Framework Events
4576 #region Public Constructor
4577 public ColumnHeaderCollection (ListView owner)
4579 list = new ArrayList ();
4582 #endregion // Public Constructor
4584 #region Public Properties
4587 get { return list.Count; }
4590 public bool IsReadOnly {
4591 get { return false; }
4594 public virtual ColumnHeader this [int index] {
4596 if (index < 0 || index >= list.Count)
4597 throw new ArgumentOutOfRangeException ("index");
4598 return (ColumnHeader) list [index];
4602 public virtual ColumnHeader this [string key] {
4604 int idx = IndexOfKey (key);
4608 return (ColumnHeader) list [idx];
4612 bool ICollection.IsSynchronized {
4613 get { return true; }
4616 object ICollection.SyncRoot {
4617 get { return this; }
4620 bool IList.IsFixedSize {
4621 get { return list.IsFixedSize; }
4624 object IList.this [int index] {
4625 get { return this [index]; }
4626 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4628 #endregion // Public Properties
4630 #region Public Methods
4631 public virtual int Add (ColumnHeader value)
4633 int idx = list.Add (value);
4634 owner.AddColumn (value, idx, true);
4636 //UIA Framework event: Item Added
4637 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4642 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4645 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4646 this.Add (colHeader);
4650 public virtual ColumnHeader Add (string text)
4652 return Add (String.Empty, text);
4655 public virtual ColumnHeader Add (string text, int width)
4657 return Add (String.Empty, text, width);
4660 public virtual ColumnHeader Add (string key, string text)
4662 ColumnHeader colHeader = new ColumnHeader ();
4663 colHeader.Name = key;
4664 colHeader.Text = text;
4669 public virtual ColumnHeader Add (string key, string text, int width)
4671 return Add (key, text, width, HorizontalAlignment.Left, -1);
4674 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4676 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4677 colHeader.ImageIndex = imageIndex;
4682 public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4684 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4685 colHeader.ImageKey = imageKey;
4690 public virtual void AddRange (ColumnHeader [] values)
4692 foreach (ColumnHeader colHeader in values) {
4693 int idx = list.Add (colHeader);
4694 owner.AddColumn (colHeader, idx, false);
4697 owner.Redraw (true);
4700 public virtual void Clear ()
4702 foreach (ColumnHeader col in list)
4703 col.SetListView (null);
4705 owner.ReorderColumns (new int [0], true);
4707 //UIA Framework event: Items cleared
4708 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4712 public bool Contains (ColumnHeader value)
4714 return list.Contains (value);
4717 public virtual bool ContainsKey (string key)
4719 return IndexOfKey (key) != -1;
4722 public IEnumerator GetEnumerator ()
4724 return list.GetEnumerator ();
4727 void ICollection.CopyTo (Array dest, int index)
4729 list.CopyTo (dest, index);
4732 int IList.Add (object value)
4734 if (! (value is ColumnHeader)) {
4735 throw new ArgumentException ("Not of type ColumnHeader", "value");
4738 return this.Add ((ColumnHeader) value);
4741 bool IList.Contains (object value)
4743 if (! (value is ColumnHeader)) {
4744 throw new ArgumentException ("Not of type ColumnHeader", "value");
4747 return this.Contains ((ColumnHeader) value);
4750 int IList.IndexOf (object value)
4752 if (! (value is ColumnHeader)) {
4753 throw new ArgumentException ("Not of type ColumnHeader", "value");
4756 return this.IndexOf ((ColumnHeader) value);
4759 void IList.Insert (int index, object value)
4761 if (! (value is ColumnHeader)) {
4762 throw new ArgumentException ("Not of type ColumnHeader", "value");
4765 this.Insert (index, (ColumnHeader) value);
4768 void IList.Remove (object value)
4770 if (! (value is ColumnHeader)) {
4771 throw new ArgumentException ("Not of type ColumnHeader", "value");
4774 this.Remove ((ColumnHeader) value);
4777 public int IndexOf (ColumnHeader value)
4779 return list.IndexOf (value);
4782 public virtual int IndexOfKey (string key)
4784 if (key == null || key.Length == 0)
4787 for (int i = 0; i < list.Count; i++) {
4788 ColumnHeader col = (ColumnHeader) list [i];
4789 if (String.Compare (key, col.Name, true) == 0)
4796 public void Insert (int index, ColumnHeader value)
4798 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
4799 // but it's really only greater.
4800 if (index < 0 || index > list.Count)
4801 throw new ArgumentOutOfRangeException ("index");
4803 list.Insert (index, value);
4804 owner.AddColumn (value, index, true);
4806 //UIA Framework event: Item added
4807 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4810 public void Insert (int index, string text)
4812 Insert (index, String.Empty, text);
4815 public void Insert (int index, string text, int width)
4817 Insert (index, String.Empty, text, width);
4820 public void Insert (int index, string key, string text)
4822 ColumnHeader colHeader = new ColumnHeader ();
4823 colHeader.Name = key;
4824 colHeader.Text = text;
4825 Insert (index, colHeader);
4828 public void Insert (int index, string key, string text, int width)
4830 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
4831 Insert (index, colHeader);
4834 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4836 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4837 colHeader.ImageIndex = imageIndex;
4838 Insert (index, colHeader);
4841 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4843 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4844 colHeader.ImageKey = imageKey;
4845 Insert (index, colHeader);
4848 public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
4851 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4852 this.Insert (index, colHeader);
4855 public virtual void Remove (ColumnHeader column)
4857 if (!Contains (column))
4860 list.Remove (column);
4861 column.SetListView (null);
4863 int rem_display_index = column.InternalDisplayIndex;
4864 int [] display_indices = new int [list.Count];
4865 for (int i = 0; i < display_indices.Length; i++) {
4866 ColumnHeader col = (ColumnHeader) list [i];
4867 int display_index = col.InternalDisplayIndex;
4868 if (display_index < rem_display_index) {
4869 display_indices [i] = display_index;
4871 display_indices [i] = (display_index - 1);
4875 column.InternalDisplayIndex = -1;
4876 owner.ReorderColumns (display_indices, true);
4878 //UIA Framework event: Item Removed
4879 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
4882 public virtual void RemoveByKey (string key)
4884 int idx = IndexOfKey (key);
4889 public virtual void RemoveAt (int index)
4891 if (index < 0 || index >= list.Count)
4892 throw new ArgumentOutOfRangeException ("index");
4894 ColumnHeader col = (ColumnHeader) list [index];
4897 #endregion // Public Methods
4900 } // ColumnHeaderCollection
4902 [ListBindable (false)]
4903 public class ListViewItemCollection : IList, ICollection, IEnumerable
4905 private readonly ArrayList list;
4906 private ListView owner;
4907 private ListViewGroup group;
4909 #region UIA Framework Events
4911 // We are using Reflection to add/remove internal events.
4912 // Class ListViewProvider uses the events.
4914 //Event used to generate UIA StructureChangedEvent
4915 static object UIACollectionChangedEvent = new object ();
4917 internal event CollectionChangeEventHandler UIACollectionChanged {
4920 owner.Events.AddHandler (UIACollectionChangedEvent, value);
4924 owner.Events.RemoveHandler (UIACollectionChangedEvent, value);
4928 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4933 CollectionChangeEventHandler eh
4934 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4939 #endregion UIA Framework Events
4941 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
4942 // In the later case ListViewItem.ListView never gets modified
4943 private bool is_main_collection = true;
4945 #region Public Constructor
4946 public ListViewItemCollection (ListView owner)
4948 list = new ArrayList (0);
4951 #endregion // Public Constructor
4953 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
4956 is_main_collection = false;
4959 #region Public Properties
4963 if (owner != null && owner.VirtualMode)
4964 return owner.VirtualListSize;
4970 public bool IsReadOnly {
4971 get { return false; }
4974 public virtual ListViewItem this [int index] {
4976 if (index < 0 || index >= Count)
4977 throw new ArgumentOutOfRangeException ("index");
4979 if (owner != null && owner.VirtualMode)
4980 return RetrieveVirtualItemFromOwner (index);
4981 return (ListViewItem) list [index];
4985 if (index < 0 || index >= Count)
4986 throw new ArgumentOutOfRangeException ("index");
4988 if (owner != null && owner.VirtualMode)
4989 throw new InvalidOperationException ();
4991 if (list.Contains (value))
4992 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4994 if (value.ListView != null && value.ListView != owner)
4995 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");
4997 if (is_main_collection)
4998 value.Owner = owner;
5000 if (value.Group != null)
5001 value.Group.Items.Remove (value);
5003 value.SetGroup (group);
5006 //UIA Framework event: Item Replaced
5007 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5009 list [index] = value;
5011 CollectionChanged (true);
5013 //UIA Framework event: Item Replaced
5014 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5019 public virtual ListViewItem this [string key] {
5021 int idx = IndexOfKey (key);
5029 bool ICollection.IsSynchronized {
5030 get { return true; }
5033 object ICollection.SyncRoot {
5034 get { return this; }
5037 bool IList.IsFixedSize {
5038 get { return list.IsFixedSize; }
5041 object IList.this [int index] {
5042 get { return this [index]; }
5044 //UIA Framework event: Item Replaced
5045 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5047 if (value is ListViewItem)
5048 this [index] = (ListViewItem) value;
5050 this [index] = new ListViewItem (value.ToString ());
5053 //UIA Framework event: Item Replaced
5054 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5057 #endregion // Public Properties
5059 #region Public Methods
5060 public virtual ListViewItem Add (ListViewItem value)
5062 if (owner != null && owner.VirtualMode)
5063 throw new InvalidOperationException ();
5067 // Item is ignored until it has been added to the ListView
5068 if (is_main_collection || value.ListView != null)
5069 CollectionChanged (true);
5071 //UIA Framework event: Item Added
5072 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5077 public virtual ListViewItem Add (string text)
5079 ListViewItem item = new ListViewItem (text);
5080 return this.Add (item);
5083 public virtual ListViewItem Add (string text, int imageIndex)
5085 ListViewItem item = new ListViewItem (text, imageIndex);
5086 return this.Add (item);
5089 public virtual ListViewItem Add (string text, string imageKey)
5091 ListViewItem item = new ListViewItem (text, imageKey);
5092 return this.Add (item);
5095 public virtual ListViewItem Add (string key, string text, int imageIndex)
5097 ListViewItem item = new ListViewItem (text, imageIndex);
5099 return this.Add (item);
5102 public virtual ListViewItem Add (string key, string text, string imageKey)
5104 ListViewItem item = new ListViewItem (text, imageKey);
5106 return this.Add (item);
5109 public void AddRange (ListViewItem [] items)
5112 throw new ArgumentNullException ("Argument cannot be null!", "items");
5113 if (owner != null && owner.VirtualMode)
5114 throw new InvalidOperationException ();
5116 owner.BeginUpdate ();
5118 foreach (ListViewItem item in items) {
5121 //UIA Framework event: Item Added
5122 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5127 CollectionChanged (true);
5130 public void AddRange (ListViewItemCollection items)
5133 throw new ArgumentNullException ("Argument cannot be null!", "items");
5135 ListViewItem[] itemArray = new ListViewItem[items.Count];
5136 items.CopyTo (itemArray,0);
5137 this.AddRange (itemArray);
5140 public virtual void Clear ()
5142 if (owner != null && owner.VirtualMode)
5143 throw new InvalidOperationException ();
5144 if (is_main_collection && owner != null) {
5145 owner.SetFocusedItem (-1);
5146 owner.h_scroll.Value = owner.v_scroll.Value = 0;
5148 // first remove any item in the groups that *are* part of this LV too
5149 foreach (ListViewGroup group in owner.groups)
5150 group.Items.ClearItemsWithSameListView ();
5152 foreach (ListViewItem item in list) {
5153 owner.item_control.CancelEdit (item);
5158 foreach (ListViewItem item in list)
5159 item.SetGroup (null);
5162 CollectionChanged (false);
5164 //UIA Framework event: Items Removed
5165 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5169 // This method is intended to be used from ListViewGroup.Items, not from ListView.Items,
5170 // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items)
5171 void ClearItemsWithSameListView ()
5173 if (is_main_collection)
5176 int counter = list.Count - 1;
5177 while (counter >= 0) {
5178 ListViewItem item = list [counter] as ListViewItem;
5180 // remove only if the items in group have being added to the ListView too
5181 if (item.ListView == group.ListView) {
5182 list.RemoveAt (counter);
5183 item.SetGroup (null);
5190 public bool Contains (ListViewItem item)
5192 return IndexOf (item) != -1;
5195 public virtual bool ContainsKey (string key)
5197 return IndexOfKey (key) != -1;
5200 public void CopyTo (Array dest, int index)
5202 list.CopyTo (dest, index);
5205 public ListViewItem [] Find (string key, bool searchAllSubItems)
5208 return new ListViewItem [0];
5210 List<ListViewItem> temp_list = new List<ListViewItem> ();
5212 for (int i = 0; i < list.Count; i++) {
5213 ListViewItem lvi = (ListViewItem) list [i];
5214 if (String.Compare (key, lvi.Name, true) == 0)
5215 temp_list.Add (lvi);
5218 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5219 temp_list.CopyTo (retval);
5224 public IEnumerator GetEnumerator ()
5226 if (owner != null && owner.VirtualMode)
5227 throw new InvalidOperationException ();
5229 // This enumerator makes a copy of the collection so
5230 // it can be deleted from in a foreach
5231 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5234 int IList.Add (object item)
5239 if (owner != null && owner.VirtualMode)
5240 throw new InvalidOperationException ();
5242 if (item is ListViewItem) {
5243 li = (ListViewItem) item;
5244 if (list.Contains (li))
5245 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5247 if (li.ListView != null && li.ListView != owner)
5248 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");
5251 li = new ListViewItem (item.ToString ());
5256 result = list.Add (li);
5257 CollectionChanged (true);
5259 //UIA Framework event: Item Added
5260 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5265 bool IList.Contains (object item)
5267 return Contains ((ListViewItem) item);
5270 int IList.IndexOf (object item)
5272 return IndexOf ((ListViewItem) item);
5275 void IList.Insert (int index, object item)
5277 if (item is ListViewItem)
5278 this.Insert (index, (ListViewItem) item);
5280 this.Insert (index, item.ToString ());
5282 //UIA Framework event: Item Added
5283 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5286 void IList.Remove (object item)
5288 Remove ((ListViewItem) item);
5291 public int IndexOf (ListViewItem item)
5293 if (owner != null && owner.VirtualMode) {
5294 for (int i = 0; i < Count; i++)
5295 if (RetrieveVirtualItemFromOwner (i) == item)
5301 return list.IndexOf (item);
5304 public virtual int IndexOfKey (string key)
5306 if (key == null || key.Length == 0)
5309 for (int i = 0; i < Count; i++) {
5310 ListViewItem lvi = this [i];
5311 if (String.Compare (key, lvi.Name, true) == 0)
5318 public ListViewItem Insert (int index, ListViewItem item)
5320 if (index < 0 || index > list.Count)
5321 throw new ArgumentOutOfRangeException ("index");
5323 if (owner != null && owner.VirtualMode)
5324 throw new InvalidOperationException ();
5326 if (list.Contains (item))
5327 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5329 if (item.ListView != null && item.ListView != owner)
5330 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");
5332 if (is_main_collection)
5335 if (item.Group != null)
5336 item.Group.Items.Remove (item);
5338 item.SetGroup (group);
5341 list.Insert (index, item);
5343 if (is_main_collection || item.ListView != null)
5344 CollectionChanged (true);
5346 // force an update of the selected info if the new item is selected.
5348 item.SetSelectedCore (true);
5349 //UIA Framework event: Item Added
5350 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5355 public ListViewItem Insert (int index, string text)
5357 return this.Insert (index, new ListViewItem (text));
5360 public ListViewItem Insert (int index, string text, int imageIndex)
5362 return this.Insert (index, new ListViewItem (text, imageIndex));
5365 public ListViewItem Insert (int index, string text, string imageKey)
5367 ListViewItem lvi = new ListViewItem (text, imageKey);
5368 return Insert (index, lvi);
5371 public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5373 ListViewItem lvi = new ListViewItem (text, imageIndex);
5375 return Insert (index, lvi);
5378 public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5380 ListViewItem lvi = new ListViewItem (text, imageKey);
5382 return Insert (index, lvi);
5385 public virtual void Remove (ListViewItem item)
5387 if (owner != null && owner.VirtualMode)
5388 throw new InvalidOperationException ();
5390 int idx = list.IndexOf (item);
5395 public virtual void RemoveAt (int index)
5397 if (index < 0 || index >= Count)
5398 throw new ArgumentOutOfRangeException ("index");
5400 if (owner != null && owner.VirtualMode)
5401 throw new InvalidOperationException ();
5403 ListViewItem item = (ListViewItem) list [index];
5405 bool selection_changed = false;
5406 if (is_main_collection && owner != null) {
5408 int display_index = item.DisplayIndex;
5409 if (item.Focused && display_index + 1 == Count) // Last item
5410 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5412 selection_changed = owner.SelectedIndices.Contains (index);
5413 owner.item_control.CancelEdit (item);
5416 list.RemoveAt (index);
5418 if (is_main_collection) {
5420 if (item.Group != null)
5421 item.Group.Items.Remove (item);
5423 item.SetGroup (null);
5425 CollectionChanged (false);
5426 if (selection_changed && owner != null)
5427 owner.OnSelectedIndexChanged (EventArgs.Empty);
5430 //UIA Framework event: Item Removed
5431 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5434 public virtual void RemoveByKey (string key)
5436 int idx = IndexOfKey (key);
5441 #endregion // Public Methods
5443 internal ListView Owner {
5452 internal ListViewGroup Group {
5461 void AddItem (ListViewItem value)
5463 if (list.Contains (value))
5464 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5466 if (value.ListView != null && value.ListView != owner)
5467 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");
5468 if (is_main_collection)
5469 value.Owner = owner;
5471 if (value.Group != null)
5472 value.Group.Items.Remove (value);
5474 value.SetGroup (group);
5479 // force an update of the selected info if the new item is selected.
5481 value.SetSelectedCore (true);
5484 void CollectionChanged (bool sort)
5486 if (owner != null) {
5491 owner.Redraw (true);
5495 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5497 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5499 owner.OnRetrieveVirtualItem (args);
5500 ListViewItem retval = args.Item;
5501 retval.Owner = owner;
5502 retval.DisplayIndex = displayIndex;
5508 internal event CollectionChangedHandler Changed;
5510 internal void Sort (IComparer comparer)
5512 list.Sort (comparer);
5516 internal void OnChange ()
5518 if (Changed != null)
5521 } // ListViewItemCollection
5524 // In normal mode, the selection information resides in the Items,
5525 // making SelectedIndexCollection.List read-only
5527 // In virtual mode, SelectedIndexCollection directly saves the selection
5528 // information, instead of getting it from Items, making List read-and-write
5529 [ListBindable (false)]
5530 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5532 private readonly ListView owner;
5533 private ArrayList list;
5535 #region Public Constructor
5536 public SelectedIndexCollection (ListView owner)
5539 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5541 #endregion // Public Constructor
5543 #region Public Properties
5547 if (!owner.is_selection_available)
5554 public bool IsReadOnly {
5560 public int this [int index] {
5562 if (!owner.is_selection_available || index < 0 || index >= List.Count)
5563 throw new ArgumentOutOfRangeException ("index");
5565 return (int) List [index];
5569 bool ICollection.IsSynchronized {
5570 get { return false; }
5573 object ICollection.SyncRoot {
5574 get { return this; }
5577 bool IList.IsFixedSize {
5583 object IList.this [int index] {
5584 get { return this [index]; }
5585 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5587 #endregion // Public Properties
5589 #region Public Methods
5590 public int Add (int itemIndex)
5592 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5593 throw new ArgumentOutOfRangeException ("index");
5595 if (owner.virtual_mode && !owner.is_selection_available)
5598 owner.Items [itemIndex].Selected = true;
5600 if (!owner.is_selection_available)
5606 public void Clear ()
5608 if (!owner.is_selection_available)
5611 int [] indexes = (int []) List.ToArray (typeof (int));
5612 foreach (int index in indexes)
5613 owner.Items [index].Selected = false;
5616 public bool Contains (int selectedIndex)
5618 return IndexOf (selectedIndex) != -1;
5621 public void CopyTo (Array dest, int index)
5623 List.CopyTo (dest, index);
5626 public IEnumerator GetEnumerator ()
5628 return List.GetEnumerator ();
5631 int IList.Add (object value)
5633 throw new NotSupportedException ("Add operation is not supported.");
5641 bool IList.Contains (object selectedIndex)
5643 if (!(selectedIndex is int))
5645 return Contains ((int) selectedIndex);
5648 int IList.IndexOf (object selectedIndex)
5650 if (!(selectedIndex is int))
5652 return IndexOf ((int) selectedIndex);
5655 void IList.Insert (int index, object value)
5657 throw new NotSupportedException ("Insert operation is not supported.");
5660 void IList.Remove (object value)
5662 throw new NotSupportedException ("Remove operation is not supported.");
5665 void IList.RemoveAt (int index)
5667 throw new NotSupportedException ("RemoveAt operation is not supported.");
5670 public int IndexOf (int selectedIndex)
5672 if (!owner.is_selection_available)
5675 return List.IndexOf (selectedIndex);
5678 public void Remove (int itemIndex)
5680 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5681 throw new ArgumentOutOfRangeException ("itemIndex");
5683 owner.Items [itemIndex].Selected = false;
5685 #endregion // Public Methods
5687 internal ArrayList List {
5690 list = new ArrayList ();
5691 if (!owner.VirtualMode)
5692 for (int i = 0; i < owner.Items.Count; i++) {
5693 if (owner.Items [i].Selected)
5701 internal void Reset ()
5703 // force re-population of list
5707 private void ItemsCollection_Changed ()
5712 internal void RemoveIndex (int index)
5714 int idx = List.BinarySearch (index);
5716 List.RemoveAt (idx);
5719 // actually store index in the collection
5720 // also, keep the collection sorted, as .Net does
5721 internal void InsertIndex (int index)
5724 int iMax = List.Count - 1;
5725 while (iMin <= iMax) {
5726 int iMid = (iMin + iMax) / 2;
5727 int current_index = (int) List [iMid];
5729 if (current_index == index)
5730 return; // Already added
5731 if (current_index > index)
5737 List.Insert (iMin, index);
5740 } // SelectedIndexCollection
5742 [ListBindable (false)]
5743 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
5745 private readonly ListView owner;
5747 #region Public Constructor
5748 public SelectedListViewItemCollection (ListView owner)
5752 #endregion // Public Constructor
5754 #region Public Properties
5758 return owner.SelectedIndices.Count;
5762 public bool IsReadOnly {
5763 get { return true; }
5766 public ListViewItem this [int index] {
5768 if (!owner.is_selection_available || index < 0 || index >= Count)
5769 throw new ArgumentOutOfRangeException ("index");
5771 int item_index = owner.SelectedIndices [index];
5772 return owner.Items [item_index];
5776 public virtual ListViewItem this [string key] {
5778 int idx = IndexOfKey (key);
5786 bool ICollection.IsSynchronized {
5787 get { return false; }
5790 object ICollection.SyncRoot {
5791 get { return this; }
5794 bool IList.IsFixedSize {
5795 get { return true; }
5798 object IList.this [int index] {
5799 get { return this [index]; }
5800 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5802 #endregion // Public Properties
5804 #region Public Methods
5805 public void Clear ()
5807 owner.SelectedIndices.Clear ();
5810 public bool Contains (ListViewItem item)
5812 return IndexOf (item) != -1;
5815 public virtual bool ContainsKey (string key)
5817 return IndexOfKey (key) != -1;
5820 public void CopyTo (Array dest, int index)
5822 if (!owner.is_selection_available)
5824 if (index > Count) // Throws ArgumentException instead of IOOR exception
5825 throw new ArgumentException ("index");
5827 for (int i = 0; i < Count; i++)
5828 dest.SetValue (this [i], index++);
5831 public IEnumerator GetEnumerator ()
5833 if (!owner.is_selection_available)
5834 return (new ListViewItem [0]).GetEnumerator ();
5836 ListViewItem [] items = new ListViewItem [Count];
5837 for (int i = 0; i < Count; i++)
5838 items [i] = this [i];
5840 return items.GetEnumerator ();
5843 int IList.Add (object value)
5845 throw new NotSupportedException ("Add operation is not supported.");
5848 bool IList.Contains (object item)
5850 if (!(item is ListViewItem))
5852 return Contains ((ListViewItem) item);
5855 int IList.IndexOf (object item)
5857 if (!(item is ListViewItem))
5859 return IndexOf ((ListViewItem) item);
5862 void IList.Insert (int index, object value)
5864 throw new NotSupportedException ("Insert operation is not supported.");
5867 void IList.Remove (object value)
5869 throw new NotSupportedException ("Remove operation is not supported.");
5872 void IList.RemoveAt (int index)
5874 throw new NotSupportedException ("RemoveAt operation is not supported.");
5877 public int IndexOf (ListViewItem item)
5879 if (!owner.is_selection_available)
5882 for (int i = 0; i < Count; i++)
5883 if (this [i] == item)
5889 public virtual int IndexOfKey (string key)
5891 if (!owner.is_selection_available || key == null || key.Length == 0)
5894 for (int i = 0; i < Count; i++) {
5895 ListViewItem item = this [i];
5896 if (String.Compare (item.Name, key, true) == 0)
5902 #endregion // Public Methods
5904 } // SelectedListViewItemCollection
5906 internal delegate void CollectionChangedHandler ();
5908 struct ItemMatrixLocation
5913 public ItemMatrixLocation (int row, int col)
5940 #endregion // Subclasses
5941 protected override void OnResize (EventArgs e)
5946 protected override void OnMouseLeave (EventArgs e)
5948 base.OnMouseLeave (e);
5952 // ColumnReorder event
5954 static object ColumnReorderedEvent = new object ();
5955 public event ColumnReorderedEventHandler ColumnReordered {
5956 add { Events.AddHandler (ColumnReorderedEvent, value); }
5957 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
5960 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
5962 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
5969 // ColumnWidthChanged
5971 static object ColumnWidthChangedEvent = new object ();
5972 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
5973 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
5974 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
5977 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
5979 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
5984 void RaiseColumnWidthChanged (int resize_column)
5986 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
5988 OnColumnWidthChanged (n);
5992 // ColumnWidthChanging
5994 static object ColumnWidthChangingEvent = new object ();
5995 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
5996 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
5997 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
6000 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6002 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6008 // 2.0 profile based implementation
6010 bool CanProceedWithResize (ColumnHeader col, int width)
6012 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6016 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6017 cwceh (this, changing);
6018 return !changing.Cancel;
6021 internal void RaiseColumnWidthChanged (ColumnHeader column)
6023 int index = Columns.IndexOf (column);
6024 RaiseColumnWidthChanged (index);
6028 #region UIA Framework: Methods, Properties and Events
6030 static object UIALabelEditChangedEvent = new object ();
6031 static object UIAShowGroupsChangedEvent = new object ();
6032 static object UIAMultiSelectChangedEvent = new object ();
6033 static object UIAViewChangedEvent = new object ();
6034 static object UIACheckBoxesChangedEvent = new object ();
6035 static object UIAFocusedItemChangedEvent = new object ();
6037 internal Rectangle UIAHeaderControl {
6038 get { return header_control.Bounds; }
6041 internal int UIAColumns {
6042 get { return cols; }
6045 internal int UIARows {
6046 get { return rows; }
6049 internal ListViewGroup UIADefaultListViewGroup
6051 get { return groups.DefaultGroup; }
6054 internal ScrollBar UIAHScrollBar {
6055 get { return h_scroll; }
6058 internal ScrollBar UIAVScrollBar {
6059 get { return v_scroll; }
6062 internal event EventHandler UIAShowGroupsChanged {
6063 add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6064 remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6067 internal event EventHandler UIACheckBoxesChanged {
6068 add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6069 remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6072 internal event EventHandler UIAMultiSelectChanged {
6073 add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6074 remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6077 internal event EventHandler UIALabelEditChanged {
6078 add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6079 remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6082 internal event EventHandler UIAViewChanged {
6083 add { Events.AddHandler (UIAViewChangedEvent, value); }
6084 remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6087 internal event EventHandler UIAFocusedItemChanged {
6088 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6089 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6092 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6094 return group.HeaderBounds;
6097 internal int UIAItemsLocationLength
6099 get { return items_location.Length; }
6102 private void OnUIACheckBoxesChanged ()
6104 EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6106 eh (this, EventArgs.Empty);
6109 private void OnUIAShowGroupsChanged ()
6111 EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6113 eh (this, EventArgs.Empty);
6116 private void OnUIAMultiSelectChanged ()
6118 EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6120 eh (this, EventArgs.Empty);
6123 private void OnUIALabelEditChanged ()
6125 EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6127 eh (this, EventArgs.Empty);
6130 private void OnUIAViewChanged ()
6132 EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6134 eh (this, EventArgs.Empty);
6137 internal void OnUIAFocusedItemChanged ()
6139 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6141 eh (this, EventArgs.Empty);
6144 #endregion // UIA Framework: Methods, Properties and Events