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)
35 using System
.Collections
;
36 using System
.ComponentModel
;
37 using System
.ComponentModel
.Design
;
39 using System
.Runtime
.InteropServices
;
40 using System
.Globalization
;
42 using System
.Collections
.Generic
;
45 namespace System
.Windows
.Forms
47 [DefaultEvent ("SelectedIndexChanged")]
48 [DefaultProperty ("Items")]
49 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts
.AssemblySystem_Design
, "System.ComponentModel.Design.IDesigner")]
51 [ClassInterface (ClassInterfaceType
.AutoDispatch
)]
53 [Docking (DockingBehavior
.Ask
)]
55 public class ListView
: Control
57 private ItemActivation activation
= ItemActivation
.Standard
;
58 private ListViewAlignment alignment
= ListViewAlignment
.Top
;
59 private bool allow_column_reorder
;
60 private bool auto_arrange
= true;
61 private bool check_boxes
;
62 private readonly CheckedIndexCollection checked_indices
;
63 private readonly CheckedListViewItemCollection checked_items
;
64 private readonly ColumnHeaderCollection columns
;
65 internal int focused_item_index
= -1;
66 private bool full_row_select
;
67 private bool grid_lines
;
68 private ColumnHeaderStyle header_style
= ColumnHeaderStyle
.Clickable
;
69 private bool hide_selection
= true;
70 private bool hover_selection
;
71 private IComparer item_sorter
;
72 private readonly ListViewItemCollection items
;
74 private readonly ListViewGroupCollection groups
;
75 private bool owner_draw
;
76 private bool show_groups
= true;
78 private bool label_edit
;
79 private bool label_wrap
= true;
80 private bool multiselect
= true;
81 private bool scrollable
= true;
82 private bool hover_pending
;
83 private readonly SelectedIndexCollection selected_indices
;
84 private readonly SelectedListViewItemCollection selected_items
;
85 private SortOrder sort_order
= SortOrder
.None
;
86 private ImageList state_image_list
;
87 private bool updating
;
88 private View view
= View
.LargeIcon
;
89 private int layout_wd
; // We might draw more than our client area
90 private int layout_ht
; // therefore we need to have these two.
91 HeaderControl header_control
;
92 internal ItemControl item_control
;
93 internal ScrollBar h_scroll
; // used for scrolling horizontally
94 internal ScrollBar v_scroll
; // used for scrolling vertically
95 internal int h_marker
; // Position markers for scrolling
96 internal int v_marker
;
97 private int keysearch_tickcnt
;
98 private string keysearch_text
;
99 static private readonly int keysearch_keydelay
= 1000;
100 private int[] reordered_column_indices
;
101 private Point
[] items_location
;
102 private ItemMatrixLocation
[] items_matrix_location
;
103 private Size item_size
; // used for caching item size
104 private int hot_item_index
= -1;
106 private bool hot_tracking
;
107 private bool show_item_tooltips
;
108 private ToolTip item_tooltip
;
109 private Size tile_size
;
110 private bool virtual_mode
;
111 private int virtual_list_size
;
114 // internal variables
115 internal ImageList large_image_list
;
116 internal ImageList small_image_list
;
117 internal Size text_size
= Size
.Empty
;
120 static object AfterLabelEditEvent
= new object ();
121 static object BeforeLabelEditEvent
= new object ();
122 static object ColumnClickEvent
= new object ();
123 static object ItemActivateEvent
= new object ();
124 static object ItemCheckEvent
= new object ();
125 static object ItemDragEvent
= new object ();
126 static object SelectedIndexChangedEvent
= new object ();
128 static object DrawColumnHeaderEvent
= new object();
129 static object DrawItemEvent
= new object();
130 static object DrawSubItemEvent
= new object();
131 static object ItemCheckedEvent
= new object ();
132 static object ItemMouseHoverEvent
= new object ();
133 static object ItemSelectionChangedEvent
= new object ();
134 static object CacheVirtualItemsEvent
= new object ();
135 static object RetrieveVirtualItemEvent
= new object ();
136 static object VirtualItemsSelectionRangeChangedEvent
= new object ();
139 public event LabelEditEventHandler AfterLabelEdit
{
140 add { Events.AddHandler (AfterLabelEditEvent, value); }
141 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
145 [EditorBrowsable (EditorBrowsableState
.Never
)]
146 public new event EventHandler BackgroundImageChanged
{
147 add { base.BackgroundImageChanged += value; }
148 remove { base.BackgroundImageChanged -= value; }
151 public event LabelEditEventHandler BeforeLabelEdit
{
152 add { Events.AddHandler (BeforeLabelEditEvent, value); }
153 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
156 public event ColumnClickEventHandler ColumnClick
{
157 add { Events.AddHandler (ColumnClickEvent, value); }
158 remove { Events.RemoveHandler (ColumnClickEvent, value); }
162 public event DrawListViewColumnHeaderEventHandler DrawColumnHeader
{
163 add { Events.AddHandler(DrawColumnHeaderEvent, value); }
164 remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); }
167 public event DrawListViewItemEventHandler DrawItem
{
168 add { Events.AddHandler(DrawItemEvent, value); }
169 remove { Events.RemoveHandler(DrawItemEvent, value); }
172 public event DrawListViewSubItemEventHandler DrawSubItem
{
173 add { Events.AddHandler(DrawSubItemEvent, value); }
174 remove { Events.RemoveHandler(DrawSubItemEvent, value); }
178 public event EventHandler ItemActivate
{
179 add { Events.AddHandler (ItemActivateEvent, value); }
180 remove { Events.RemoveHandler (ItemActivateEvent, value); }
183 public event ItemCheckEventHandler ItemCheck
{
184 add { Events.AddHandler (ItemCheckEvent, value); }
185 remove { Events.RemoveHandler (ItemCheckEvent, value); }
189 public event ItemCheckedEventHandler ItemChecked
{
190 add { Events.AddHandler (ItemCheckedEvent, value); }
191 remove { Events.RemoveHandler (ItemCheckedEvent, value); }
195 public event ItemDragEventHandler ItemDrag
{
196 add { Events.AddHandler (ItemDragEvent, value); }
197 remove { Events.RemoveHandler (ItemDragEvent, value); }
201 public event ListViewItemMouseHoverEventHandler ItemMouseHover
{
202 add { Events.AddHandler (ItemMouseHoverEvent, value); }
203 remove { Events.RemoveHandler (ItemMouseHoverEvent, value); }
206 public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged
{
207 add { Events.AddHandler (ItemSelectionChangedEvent, value); }
208 remove { Events.RemoveHandler (ItemSelectionChangedEvent, 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; }
232 public event CacheVirtualItemsEventHandler CacheVirtualItems
{
233 add { Events.AddHandler (CacheVirtualItemsEvent, value); }
234 remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); }
237 public event RetrieveVirtualItemEventHandler RetrieveVirtualItem
{
238 add { Events.AddHandler (RetrieveVirtualItemEvent, value); }
239 remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); }
242 public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged
{
243 add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); }
244 remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); }
250 #region Public Constructors
253 background_color
= ThemeEngine
.Current
.ColorWindow
;
254 items
= new ListViewItemCollection (this);
256 groups
= new ListViewGroupCollection (this);
258 checked_indices
= new CheckedIndexCollection (this);
259 checked_items
= new CheckedListViewItemCollection (this);
260 columns
= new ColumnHeaderCollection (this);
261 foreground_color
= SystemColors
.WindowText
;
262 selected_indices
= new SelectedIndexCollection (this);
263 selected_items
= new SelectedListViewItemCollection (this);
264 items_location
= new Point
[16];
265 items_matrix_location
= new ItemMatrixLocation
[16];
267 item_tooltip
= new ToolTip ();
268 item_tooltip
.Active
= false;
271 InternalBorderStyle
= BorderStyle
.Fixed3D
;
273 header_control
= new HeaderControl (this);
274 header_control
.Visible
= false;
275 Controls
.AddImplicit (header_control
);
277 item_control
= new ItemControl (this);
278 Controls
.AddImplicit (item_control
);
280 h_scroll
= new ImplicitHScrollBar ();
281 Controls
.AddImplicit (this.h_scroll
);
283 v_scroll
= new ImplicitVScrollBar ();
284 Controls
.AddImplicit (this.v_scroll
);
286 h_marker
= v_marker
= 0;
287 keysearch_tickcnt
= 0;
289 // scroll bars are disabled initially
290 h_scroll
.Visible
= false;
291 h_scroll
.ValueChanged
+= new EventHandler(HorizontalScroller
);
292 v_scroll
.Visible
= false;
293 v_scroll
.ValueChanged
+= new EventHandler(VerticalScroller
);
296 base.KeyDown
+= new KeyEventHandler(ListView_KeyDown
);
297 SizeChanged
+= new EventHandler (ListView_SizeChanged
);
298 GotFocus
+= new EventHandler (FocusChanged
);
299 LostFocus
+= new EventHandler (FocusChanged
);
300 MouseWheel
+= new MouseEventHandler(ListView_MouseWheel
);
301 MouseEnter
+= new EventHandler (ListView_MouseEnter
);
303 this.SetStyle (ControlStyles
.UserPaint
| ControlStyles
.StandardClick
305 | ControlStyles
.UseTextForAccessibility
309 #endregion // Public Constructors
311 #region Private Internal Properties
312 internal Size CheckBoxSize
{
314 if (this.check_boxes
) {
315 if (this.state_image_list
!= null)
316 return this.state_image_list
.ImageSize
;
318 return ThemeEngine
.Current
.ListViewCheckBoxSize
;
324 internal Size ItemSize
{
326 if (view
!= View
.Details
)
329 Size size
= new Size ();
330 size
.Height
= item_size
.Height
;
331 for (int i
= 0; i
< columns
.Count
; i
++)
332 size
.Width
+= columns
[i
].Wd
;
341 internal int HotItemIndex
{
343 return hot_item_index
;
346 hot_item_index
= value;
350 #endregion // Private Internal Properties
352 #region Protected Properties
353 protected override CreateParams CreateParams
{
354 get { return base.CreateParams; }
357 protected override Size DefaultSize
{
358 get { return ThemeEngine.Current.ListViewDefaultSize; }
360 #endregion // Protected Properties
362 #region Public Instance Properties
363 [DefaultValue (ItemActivation
.Standard
)]
364 public ItemActivation Activation
{
365 get { return activation; }
367 if (value != ItemActivation
.Standard
&& value != ItemActivation
.OneClick
&&
368 value != ItemActivation
.TwoClick
) {
369 throw new InvalidEnumArgumentException (string.Format
370 ("Enum argument value '{0}' is not valid for Activation", value));
373 if (hot_tracking
&& value != ItemActivation
.OneClick
)
374 throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick");
381 [DefaultValue (ListViewAlignment
.Top
)]
383 public ListViewAlignment Alignment
{
384 get { return alignment; }
386 if (value != ListViewAlignment
.Default
&& value != ListViewAlignment
.Left
&&
387 value != ListViewAlignment
.SnapToGrid
&& value != ListViewAlignment
.Top
) {
388 throw new InvalidEnumArgumentException (string.Format
389 ("Enum argument value '{0}' is not valid for Alignment", value));
392 if (this.alignment
!= value) {
394 // alignment does not matter in Details/List views
395 if (this.view
== View
.LargeIcon
|| this.View
== View
.SmallIcon
)
401 [DefaultValue (false)]
402 public bool AllowColumnReorder
{
403 get { return allow_column_reorder; }
404 set { allow_column_reorder = value; }
407 [DefaultValue (true)]
408 public bool AutoArrange
{
409 get { return auto_arrange; }
411 if (auto_arrange
!= value) {
412 auto_arrange
= value;
413 // autoarrange does not matter in Details/List views
414 if (this.view
== View
.LargeIcon
|| this.View
== View
.SmallIcon
)
420 public override Color BackColor
{
422 if (background_color
.IsEmpty
)
423 return ThemeEngine
.Current
.ColorWindow
;
425 return background_color
;
427 set { background_color = value; }
431 [EditorBrowsable (EditorBrowsableState
.Never
)]
432 public override Image BackgroundImage
{
433 get { return base.BackgroundImage; }
434 set { base.BackgroundImage = value; }
437 [DefaultValue (BorderStyle
.Fixed3D
)]
439 public BorderStyle BorderStyle
{
440 get { return InternalBorderStyle; }
441 set { InternalBorderStyle = value; }
444 [DefaultValue (false)]
445 public bool CheckBoxes
{
446 get { return check_boxes; }
448 if (check_boxes
!= value) {
450 if (value && View
== View
.Tile
)
451 throw new NotSupportedException ("CheckBoxes are not"
452 + " supported in Tile view. Choose a different"
453 + " view or set CheckBoxes to false.");
463 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
464 public CheckedIndexCollection CheckedIndices
{
465 get { return checked_indices; }
469 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
470 public CheckedListViewItemCollection CheckedItems
{
471 get { return checked_items; }
474 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
476 [MergableProperty (false)]
477 public ColumnHeaderCollection Columns
{
478 get { return columns; }
482 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
483 public ListViewItem FocusedItem
{
485 if (focused_item_index
== -1)
488 return items
[focused_item_index
];
492 if (value == null || value.ListView
!= this ||
496 SetFocusedItem (value.Index
);
501 public override Color ForeColor
{
503 if (foreground_color
.IsEmpty
)
504 return ThemeEngine
.Current
.ColorWindowText
;
506 return foreground_color
;
508 set { foreground_color = value; }
511 [DefaultValue (false)]
512 public bool FullRowSelect
{
513 get { return full_row_select; }
515 if (full_row_select
!= value) {
516 full_row_select
= value;
517 InvalidateSelection ();
522 [DefaultValue (false)]
523 public bool GridLines
{
524 get { return grid_lines; }
526 if (grid_lines
!= value) {
533 [DefaultValue (ColumnHeaderStyle
.Clickable
)]
534 public ColumnHeaderStyle HeaderStyle
{
535 get { return header_style; }
537 if (header_style
== value)
541 case ColumnHeaderStyle
.Clickable
:
542 case ColumnHeaderStyle
.Nonclickable
:
543 case ColumnHeaderStyle
.None
:
546 throw new InvalidEnumArgumentException (string.Format
547 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
550 header_style
= value;
551 if (view
== View
.Details
)
556 [DefaultValue (true)]
557 public bool HideSelection
{
558 get { return hide_selection; }
560 if (hide_selection
!= value) {
561 hide_selection
= value;
562 InvalidateSelection ();
568 [DefaultValue (false)]
569 public bool HotTracking
{
574 if (hot_tracking
== value)
577 hot_tracking
= value;
579 hover_selection
= true;
580 activation
= ItemActivation
.OneClick
;
586 [DefaultValue (false)]
587 public bool HoverSelection
{
588 get { return hover_selection; }
591 if (hot_tracking
&& value == false)
592 throw new ArgumentException ("When HotTracking is on, hover selection must be true");
594 hover_selection
= value;
598 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
600 [MergableProperty (false)]
601 public ListViewItemCollection Items
{
602 get { return items; }
605 [DefaultValue (false)]
606 public bool LabelEdit
{
607 get { return label_edit; }
608 set { label_edit = value; }
611 [DefaultValue (true)]
613 public bool LabelWrap
{
614 get { return label_wrap; }
616 if (label_wrap
!= value) {
623 [DefaultValue (null)]
624 public ImageList LargeImageList
{
625 get { return large_image_list; }
627 large_image_list
= value;
633 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
634 public IComparer ListViewItemSorter
{
636 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
&& item_sorter
is ItemComparer
)
641 if (item_sorter
!= value) {
648 [DefaultValue (true)]
649 public bool MultiSelect
{
650 get { return multiselect; }
651 set { multiselect = value; }
656 [DefaultValue(false)]
657 public bool OwnerDraw
{
658 get { return owner_draw; }
666 [DefaultValue (true)]
667 public bool Scrollable
{
668 get { return scrollable; }
670 if (scrollable
!= value) {
678 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
679 public SelectedIndexCollection SelectedIndices
{
680 get { return selected_indices; }
684 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
685 public SelectedListViewItemCollection SelectedItems
{
686 get { return selected_items; }
691 public bool ShowGroups
{
692 get { return show_groups; }
694 if (show_groups
!= value) {
701 [LocalizableAttribute (true)]
702 [MergableProperty (false)]
703 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
704 public ListViewGroupCollection Groups
{
705 get { return groups; }
708 [DefaultValue (false)]
709 public bool ShowItemToolTips
{
711 return show_item_tooltips
;
714 show_item_tooltips
= value;
715 item_tooltip
.Active
= false;
720 [DefaultValue (null)]
721 public ImageList SmallImageList
{
722 get { return small_image_list; }
724 small_image_list
= value;
729 [DefaultValue (SortOrder
.None
)]
730 public SortOrder Sorting
{
731 get { return sort_order; }
733 if (!Enum
.IsDefined (typeof (SortOrder
), value)) {
734 throw new InvalidEnumArgumentException ("value", (int) value,
738 if (sort_order
== value)
744 if (virtual_mode
) // Sorting is not allowed in virtual mode
748 if (value == SortOrder
.None
) {
749 if (item_sorter
!= null) {
750 // ListViewItemSorter should never be reset for SmallIcon
751 // and LargeIcon view
752 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
)
756 // in .NET 1.1, only internal IComparer would be
758 if (item_sorter
is ItemComparer
)
764 if (item_sorter
== null)
765 item_sorter
= new ItemComparer (value);
766 if (item_sorter
is ItemComparer
) {
768 item_sorter
= new ItemComparer (value);
770 // in .NET 1.1, the sort order is not updated for
771 // SmallIcon and LargeIcon views if no custom IComparer
773 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
)
774 item_sorter
= new ItemComparer (value);
782 private void OnImageListChanged (object sender
, EventArgs args
)
784 item_control
.Invalidate ();
787 [DefaultValue (null)]
788 public ImageList StateImageList
{
789 get { return state_image_list; }
791 if (state_image_list
== value)
794 if (state_image_list
!= null)
795 state_image_list
.Images
.Changed
-= new EventHandler (OnImageListChanged
);
797 state_image_list
= value;
799 if (state_image_list
!= null)
800 state_image_list
.Images
.Changed
+= new EventHandler (OnImageListChanged
);
808 [EditorBrowsable (EditorBrowsableState
.Never
)]
809 public override string Text
{
810 get { return base.Text; }
812 if (value == base.Text
)
822 public Size TileSize
{
827 if (value.Width
<= 0 || value.Height
<= 0)
828 throw new ArgumentOutOfRangeException ("value");
837 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
838 public ListViewItem TopItem
{
841 if (view
== View
.LargeIcon
|| view
== View
.SmallIcon
|| view
== View
.Tile
)
842 throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view.");
845 if (this.items
.Count
== 0)
847 // if contents are not scrolled
848 // it is the first item
849 else if (h_marker
== 0 && v_marker
== 0)
850 return this.items
[0];
851 // do a hit test for the scrolled position
853 for (int i
= 0; i
< items
.Count
; i
++) {
854 Point item_loc
= GetItemLocation (i
);
855 if (item_loc
.X
>= 0 && item_loc
.Y
>= 0)
863 if (view
== View
.LargeIcon
|| view
== View
.SmallIcon
|| view
== View
.Tile
)
864 throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view.");
866 // .Net doesn't throw any exception in the cases below
867 if (value == null || value.ListView
!= this)
870 EnsureVisible (value.Index
);
876 [EditorBrowsable (EditorBrowsableState
.Advanced
)]
877 [DefaultValue (true)]
879 [MonoInternalNote ("Stub, not implemented")]
880 public bool UseCompatibleStateImageBehavior
{
889 [DefaultValue (View
.LargeIcon
)]
893 if (!Enum
.IsDefined (typeof (View
), value))
894 throw new InvalidEnumArgumentException ("value", (int) value,
899 if (CheckBoxes
&& value == View
.Tile
)
900 throw new NotSupportedException ("CheckBoxes are not"
901 + " supported in Tile view. Choose a different"
902 + " view or set CheckBoxes to false.");
905 h_scroll
.Value
= v_scroll
.Value
= 0;
913 [DefaultValue (false)]
914 [RefreshProperties (RefreshProperties
.Repaint
)]
915 public bool VirtualMode
{
920 if (virtual_mode
== value)
923 if (!virtual_mode
&& items
.Count
> 0)
924 throw new InvalidOperationException ();
926 virtual_mode
= value;
932 [RefreshProperties (RefreshProperties
.Repaint
)]
933 public int VirtualListSize
{
935 return virtual_list_size
;
939 throw new ArgumentException ("value");
941 if (virtual_list_size
== value)
944 virtual_list_size
= value;
950 #endregion // Public Instance Properties
952 #region Internal Methods Properties
954 internal int FirstVisibleIndex
{
957 if (this.items
.Count
== 0)
960 if (h_marker
== 0 && v_marker
== 0)
963 Size item_size
= ItemSize
;
964 for (int i
= 0; i
< items
.Count
; i
++) {
965 Rectangle item_rect
= new Rectangle (GetItemLocation (i
), item_size
);
966 if (item_rect
.Right
>= 0 && item_rect
.Bottom
>= 0)
975 internal int LastVisibleIndex
{
977 for (int i
= FirstVisibleIndex
; i
< Items
.Count
; i
++) {
978 if (View
== View
.List
|| Alignment
== ListViewAlignment
.Left
) {
979 if (GetItemLocation (i
).X
> item_control
.ClientRectangle
.Right
)
982 if (GetItemLocation (i
).Y
> item_control
.ClientRectangle
.Bottom
)
987 return Items
.Count
- 1;
991 internal void OnSelectedIndexChanged ()
994 OnSelectedIndexChanged (EventArgs
.Empty
);
997 internal int TotalWidth
{
998 get { return Math.Max (this.Width, this.layout_wd); }
1001 internal int TotalHeight
{
1002 get { return Math.Max (this.Height, this.layout_ht); }
1005 internal void Redraw (bool recalculate
)
1007 // Avoid calculations when control is being updated
1011 // VirtualMode doesn't do any calculations until handle is created
1012 if (virtual_mode
&& !IsHandleCreated
)
1018 CalculateListView (this.alignment
);
1023 void InvalidateSelection ()
1025 foreach (int selected_index
in SelectedIndices
)
1026 items
[selected_index
].Invalidate ();
1029 const int text_padding
= 15;
1031 internal Size
GetChildColumnSize (int index
)
1033 Size ret_size
= Size
.Empty
;
1034 ColumnHeader col
= this.columns
[index
];
1036 if (col
.Width
== -2) { // autosize = max(items, columnheader)
1037 Size size
= Size
.Ceiling (TextRenderer
.MeasureString
1038 (col
.Text
, this.Font
));
1039 size
.Width
+= text_padding
;
1040 ret_size
= BiggestItem (index
);
1041 if (size
.Width
> ret_size
.Width
)
1044 else { // -1 and all the values < -2 are put under one category
1045 ret_size
= BiggestItem (index
);
1046 // fall back to empty columns' width if no subitem is available for a column
1047 if (ret_size
.IsEmpty
) {
1048 ret_size
.Width
= ThemeEngine
.Current
.ListViewEmptyColumnWidth
;
1049 if (col
.Text
.Length
> 0)
1050 ret_size
.Height
= Size
.Ceiling (TextRenderer
.MeasureString
1051 (col
.Text
, this.Font
)).Height
;
1053 ret_size
.Height
= this.Font
.Height
;
1057 ret_size
.Height
+= text_padding
;
1059 // adjust the size for icon and checkbox for 0th column
1061 ret_size
.Width
+= (this.CheckBoxSize
.Width
+ 4);
1062 if (this.small_image_list
!= null)
1063 ret_size
.Width
+= this.small_image_list
.ImageSize
.Width
;
1068 // Returns the size of biggest item text in a column.
1069 private Size
BiggestItem (int col
)
1071 Size temp
= Size
.Empty
;
1072 Size ret_size
= Size
.Empty
;
1075 // VirtualMode uses the first item text size
1076 if (virtual_mode
&& items
.Count
> 0) {
1077 ListViewItem item
= items
[0];
1078 ret_size
= Size
.Ceiling (TextRenderer
.MeasureString (item
.SubItems
[col
].Text
,
1082 // 0th column holds the item text, we check the size of
1083 // the various subitems falling in that column and get
1084 // the biggest one's size.
1085 foreach (ListViewItem item
in items
) {
1086 if (col
>= item
.SubItems
.Count
)
1089 temp
= Size
.Ceiling (TextRenderer
.MeasureString
1090 (item
.SubItems
[col
].Text
, Font
));
1091 if (temp
.Width
> ret_size
.Width
)
1098 // adjustment for space
1099 if (!ret_size
.IsEmpty
)
1100 ret_size
.Width
+= 4;
1105 const int max_wrap_padding
= 38;
1107 // Sets the size of the biggest item text as per the view
1108 private void CalcTextSize ()
1110 // clear the old value
1111 text_size
= Size
.Empty
;
1113 if (items
.Count
== 0)
1116 text_size
= BiggestItem (0);
1118 if (view
== View
.LargeIcon
&& this.label_wrap
) {
1119 Size temp
= Size
.Empty
;
1120 if (this.check_boxes
)
1121 temp
.Width
+= 2 * this.CheckBoxSize
.Width
;
1122 int icon_w
= LargeImageList
== null ? 12 : LargeImageList
.ImageSize
.Width
;
1123 temp
.Width
+= icon_w
+ max_wrap_padding
;
1124 // wrapping is done for two lines only
1125 if (text_size
.Width
> temp
.Width
) {
1126 text_size
.Width
= temp
.Width
;
1127 text_size
.Height
*= 2;
1130 else if (view
== View
.List
) {
1131 // in list view max text shown in determined by the
1132 // control width, even if scolling is enabled.
1133 int max_wd
= this.Width
- (this.CheckBoxSize
.Width
- 2);
1134 if (this.small_image_list
!= null)
1135 max_wd
-= this.small_image_list
.ImageSize
.Width
;
1137 if (text_size
.Width
> max_wd
)
1138 text_size
.Width
= max_wd
;
1141 // we do the default settings, if we have got 0's
1142 if (text_size
.Height
<= 0)
1143 text_size
.Height
= this.Font
.Height
;
1144 if (text_size
.Width
<= 0)
1145 text_size
.Width
= this.Width
;
1147 // little adjustment
1148 text_size
.Width
+= 4;
1149 text_size
.Height
+= 2;
1152 private void Scroll (ScrollBar scrollbar
, int delta
)
1154 if (delta
== 0 || !scrollbar
.Visible
)
1158 if (scrollbar
== h_scroll
)
1159 max
= h_scroll
.Maximum
- item_control
.Width
;
1161 max
= v_scroll
.Maximum
- item_control
.Height
;
1163 int val
= scrollbar
.Value
+ delta
;
1166 else if (val
< scrollbar
.Minimum
)
1167 val
= scrollbar
.Minimum
;
1168 scrollbar
.Value
= val
;
1171 private void CalculateScrollBars ()
1173 if (!IsHandleCreated
)
1176 Rectangle client_area
= ClientRectangle
;
1179 h_scroll
.Visible
= false;
1180 v_scroll
.Visible
= false;
1181 item_control
.Height
= client_area
.Height
;
1182 item_control
.Width
= client_area
.Width
;
1183 header_control
.Width
= client_area
.Width
;
1187 // Don't calculate if the view is not displayable
1188 if (client_area
.Height
< 0 || client_area
.Width
< 0)
1191 // making a scroll bar visible might make
1192 // other scroll bar visible
1193 if (layout_wd
> client_area
.Right
) {
1194 h_scroll
.Visible
= true;
1195 if ((layout_ht
+ h_scroll
.Height
) > client_area
.Bottom
)
1196 v_scroll
.Visible
= true;
1198 v_scroll
.Visible
= false;
1199 } else if (layout_ht
> client_area
.Bottom
) {
1200 v_scroll
.Visible
= true;
1201 if ((layout_wd
+ v_scroll
.Width
) > client_area
.Right
)
1202 h_scroll
.Visible
= true;
1204 h_scroll
.Visible
= false;
1206 h_scroll
.Visible
= false;
1207 v_scroll
.Visible
= false;
1210 item_control
.Height
= client_area
.Height
;
1212 if (h_scroll
.is_visible
) {
1213 h_scroll
.Location
= new Point (client_area
.X
, client_area
.Bottom
- h_scroll
.Height
);
1214 h_scroll
.Minimum
= 0;
1216 // if v_scroll is visible, adjust the maximum of the
1217 // h_scroll to account for the width of v_scroll
1218 if (v_scroll
.Visible
) {
1219 h_scroll
.Maximum
= layout_wd
+ v_scroll
.Width
;
1220 h_scroll
.Width
= client_area
.Width
- v_scroll
.Width
;
1223 h_scroll
.Maximum
= layout_wd
;
1224 h_scroll
.Width
= client_area
.Width
;
1227 h_scroll
.LargeChange
= client_area
.Width
;
1228 h_scroll
.SmallChange
= Font
.Height
;
1229 item_control
.Height
-= h_scroll
.Height
;
1232 if (header_control
.is_visible
)
1233 header_control
.Width
= client_area
.Width
;
1234 item_control
.Width
= client_area
.Width
;
1236 if (v_scroll
.is_visible
) {
1237 v_scroll
.Location
= new Point (client_area
.Right
- v_scroll
.Width
, client_area
.Y
);
1238 v_scroll
.Minimum
= 0;
1240 // if h_scroll is visible, adjust the maximum of the
1241 // v_scroll to account for the height of h_scroll
1242 if (h_scroll
.Visible
) {
1243 v_scroll
.Maximum
= layout_ht
+ h_scroll
.Height
;
1244 v_scroll
.Height
= client_area
.Height
; // - h_scroll.Height already done
1246 v_scroll
.Maximum
= layout_ht
;
1247 v_scroll
.Height
= client_area
.Height
;
1250 v_scroll
.LargeChange
= client_area
.Height
;
1251 v_scroll
.SmallChange
= Font
.Height
;
1252 if (header_control
.Visible
)
1253 header_control
.Width
-= v_scroll
.Width
;
1254 item_control
.Width
-= v_scroll
.Width
;
1259 internal int GetReorderedColumnIndex (ColumnHeader column
)
1261 if (reordered_column_indices
== null)
1262 return column
.Index
;
1264 for (int i
= 0; i
< Columns
.Count
; i
++)
1265 if (reordered_column_indices
[i
] == column
.Index
)
1272 internal ColumnHeader
GetReorderedColumn (int index
)
1274 if (reordered_column_indices
== null)
1275 return Columns
[index
];
1277 return Columns
[reordered_column_indices
[index
]];
1280 internal void ReorderColumn (ColumnHeader col
, int index
, bool fireEvent
)
1284 ColumnReorderedEventHandler eh
= (ColumnReorderedEventHandler
) (Events
[ColumnReorderedEvent
]);
1286 ColumnReorderedEventArgs args
= new ColumnReorderedEventArgs (col
.Index
, index
, col
);
1290 header_control
.Invalidate ();
1291 item_control
.Invalidate ();
1297 int column_count
= Columns
.Count
;
1299 if (reordered_column_indices
== null) {
1300 reordered_column_indices
= new int [column_count
];
1301 for (int i
= 0; i
< column_count
; i
++)
1302 reordered_column_indices
[i
] = i
;
1305 if (reordered_column_indices
[index
] == col
.Index
)
1308 int[] curr
= reordered_column_indices
;
1309 int [] result
= new int [column_count
];
1311 for (int i
= 0; i
< column_count
; i
++) {
1312 if (curr_idx
< column_count
&& curr
[curr_idx
] == col
.Index
)
1316 result
[i
] = col
.Index
;
1318 result
[i
] = curr
[curr_idx
++];
1321 ReorderColumns (result
, true);
1324 internal void ReorderColumns (int [] display_indices
, bool redraw
)
1326 reordered_column_indices
= display_indices
;
1327 for (int i
= 0; i
< Columns
.Count
; i
++) {
1328 ColumnHeader col
= Columns
[i
];
1329 col
.InternalDisplayIndex
= reordered_column_indices
[i
];
1331 if (redraw
&& view
== View
.Details
&& IsHandleCreated
) {
1333 header_control
.Invalidate ();
1334 item_control
.Invalidate ();
1338 internal void AddColumn (ColumnHeader newCol
, int index
, bool redraw
)
1340 int column_count
= Columns
.Count
;
1341 newCol
.SetListView (this);
1343 int [] display_indices
= new int [column_count
];
1344 for (int i
= 0; i
< column_count
; i
++) {
1345 ColumnHeader col
= Columns
[i
];
1347 display_indices
[i
] = index
;
1349 int display_index
= col
.InternalDisplayIndex
;
1350 if (display_index
< index
) {
1351 display_indices
[i
] = display_index
;
1353 display_indices
[i
] = (display_index
+ 1);
1358 ReorderColumns (display_indices
, redraw
);
1362 Size LargeIconItemSize
1365 int image_w
= LargeImageList
== null ? 12 : LargeImageList
.ImageSize
.Width
;
1366 int image_h
= LargeImageList
== null ? 2 : LargeImageList
.ImageSize
.Height
;
1367 int w
= CheckBoxSize
.Width
+ 2 + Math
.Max (text_size
.Width
, image_w
);
1368 int h
= text_size
.Height
+ 2 + Math
.Max (CheckBoxSize
.Height
, image_h
);
1369 return new Size (w
, h
);
1373 Size SmallIconItemSize
{
1375 int image_w
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Width
;
1376 int image_h
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Height
;
1377 int w
= text_size
.Width
+ 2 + CheckBoxSize
.Width
+ image_w
;
1378 int h
= Math
.Max (text_size
.Height
, Math
.Max (CheckBoxSize
.Height
, image_h
));
1379 return new Size (w
, h
);
1386 // Calculate tile size if needed
1387 // It appears that using Font.Size instead of a SizeF value can give us
1388 // a slightly better approach to the proportions defined in .Net
1389 if (tile_size
== Size
.Empty
) {
1390 int image_w
= LargeImageList
== null ? 0 : LargeImageList
.ImageSize
.Width
;
1391 int image_h
= LargeImageList
== null ? 0 : LargeImageList
.ImageSize
.Height
;
1392 int w
= (int)Font
.Size
* ThemeEngine
.Current
.ListViewTileWidthFactor
+ image_w
+ 4;
1393 int h
= Math
.Max ((int)Font
.Size
* ThemeEngine
.Current
.ListViewTileHeightFactor
, image_h
);
1395 tile_size
= new Size (w
, h
);
1403 int GetDetailsItemHeight ()
1406 int checkbox_height
= CheckBoxes
? CheckBoxSize
.Height
: 0;
1407 int small_image_height
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Height
;
1408 item_height
= Math
.Max (checkbox_height
, text_size
.Height
);
1409 item_height
= Math
.Max (item_height
, small_image_height
);
1414 void SetItemLocation (int index
, int x
, int y
, int row
, int col
)
1416 Point old_location
= items_location
[index
];
1417 if (old_location
.X
== x
&& old_location
.Y
== y
)
1420 Size item_size
= ItemSize
;
1421 Rectangle old_rect
= new Rectangle (GetItemLocation (index
), item_size
);
1423 items_location
[index
] = new Point (x
, y
);
1424 items_matrix_location
[index
] = new ItemMatrixLocation (row
, col
);
1426 // Invalidate both previous and new bounds
1427 item_control
.Invalidate (old_rect
);
1428 item_control
.Invalidate (new Rectangle (GetItemLocation (index
), item_size
));
1433 int[,] item_index_matrix
;
1435 void CalculateRowsAndCols (Size item_size
, bool left_aligned
, int x_spacing
, int y_spacing
)
1437 Rectangle area
= ClientRectangle
;
1439 if (show_groups
&& groups
.Count
> 0 && view
!= View
.List
) {
1440 // When groups are used the alignment is always top-aligned
1444 for (int i
= 0; i
< groups
.Count
; i
++) {
1445 ListViewGroup
group = groups
[i
];
1446 group.starting_row
= rows
;
1448 int group_cols
= (int) Math
.Floor ((double)(area
.Width
- v_scroll
.Width
+ x_spacing
) / (double)(item_size
.Width
+ x_spacing
));
1449 if (group_cols
<= 0)
1451 int group_rows
= (int) Math
.Ceiling ((double)group.Items
.Count
/ (double)group_cols
);
1453 cols
= Math
.Max (group_cols
, cols
);
1459 // Simple matrix if no groups are used
1461 rows
= (int) Math
.Floor ((double)(area
.Height
- h_scroll
.Height
+ y_spacing
) / (double)(item_size
.Height
+ y_spacing
));
1464 cols
= (int) Math
.Ceiling ((double)items
.Count
/ (double)rows
);
1466 cols
= (int) Math
.Floor ((double)(area
.Width
- v_scroll
.Width
+ x_spacing
) / (double)(item_size
.Width
+ x_spacing
));
1469 rows
= (int) Math
.Ceiling ((double)items
.Count
/ (double)cols
);
1475 item_index_matrix
= new int [rows
, cols
];
1478 void LayoutIcons (Size item_size
, bool left_aligned
, int x_spacing
, int y_spacing
)
1480 header_control
.Visible
= false;
1481 header_control
.Size
= Size
.Empty
;
1482 item_control
.Visible
= true;
1483 item_control
.Location
= Point
.Empty
;
1484 ItemSize
= item_size
; // Cache item size
1486 if (items
.Count
== 0)
1489 Size sz
= item_size
;
1491 CalculateRowsAndCols (sz
, left_aligned
, x_spacing
, y_spacing
);
1493 layout_ht
= rows
* (sz
.Height
+ y_spacing
) - y_spacing
;
1494 layout_wd
= cols
* (sz
.Width
+ x_spacing
) - x_spacing
;
1496 int current_item
= 0;
1499 if (show_groups
&& groups
.Count
> 0 && view
!= View
.List
)
1500 LayoutIconsGroups (left_aligned
, x_spacing
, y_spacing
);
1503 // Layout the entire ListView as a single section
1504 LayoutIconsSection (items
, left_aligned
, 0, ref current_y
, new Size (x_spacing
, y_spacing
), ref current_item
);
1506 item_control
.Size
= new Size (layout_wd
, layout_ht
);
1510 void LayoutIconsGroups (bool left_aligned
, int x_spacing
, int y_spacing
)
1512 int header_spacing
= 10;
1513 int header_height
= text_size
.Height
+ 10;
1514 Rectangle client_area
= ClientRectangle
;
1516 int current_item
= 0;
1519 for (int i
= 0; i
< groups
.Count
; i
++) {
1520 ListViewGroup
group = groups
[i
];
1521 if (group.Items
.Count
== 0)
1524 group.Bounds
= new Rectangle (0, current_y
, client_area
.Width
- v_scroll
.Width
, header_height
);
1525 current_y
+= header_height
;
1527 LayoutIconsSection (group.Items
, left_aligned
, group.starting_row
, ref current_y
, new Size (x_spacing
, y_spacing
),
1530 current_y
+= header_spacing
;
1533 layout_ht
= current_y
; // Adjust with the header heights
1537 void LayoutIconsSection (ListView
.ListViewItemCollection items_collection
, bool left_aligned
, int current_global_row
, ref int y_origin
,
1538 Size item_spacing
, ref int current_item
)
1540 // current_global_row is the global one, and
1541 // row is the local one for the current group
1543 int row
= 0, col
= 0;
1544 int x_spacing
= item_spacing
.Width
;
1545 int y_spacing
= item_spacing
.Height
;
1546 Size item_size
= ItemSize
;
1548 for (int i
= 0; i
< items_collection
.Count
; i
++) {
1549 ListViewItem item
= items_collection
[i
];
1550 x
= col
* (item_size
.Width
+ x_spacing
);
1551 y
= row
* (item_size
.Height
+ y_spacing
) + y_origin
;
1553 SetItemLocation (current_item
, x
, y
, current_global_row
, col
);
1554 item_index_matrix
[current_global_row
, col
] = current_item
;
1562 current_global_row
++;
1565 current_global_row
= row
= 0;
1569 if (++col
== cols
) {
1572 current_global_row
++;
1577 // Return the lower bounds of the icons section
1578 y_origin
= y
+ item_size
.Height
;
1581 void LayoutHeader ()
1584 for (int i
= 0; i
< Columns
.Count
; i
++) {
1585 ColumnHeader col
= GetReorderedColumn (i
);
1588 col
.CalcColumnHeader ();
1594 if (x
< ClientRectangle
.Width
)
1595 x
= ClientRectangle
.Width
;
1597 if (header_style
== ColumnHeaderStyle
.None
) {
1598 header_control
.Visible
= false;
1599 header_control
.Size
= Size
.Empty
;
1600 layout_wd
= ClientRectangle
.Width
;
1602 header_control
.Width
= x
;
1603 header_control
.Height
= columns
.Count
> 0 ? columns
[0].Ht
: Font
.Height
+ 5;
1604 header_control
.Visible
= true;
1608 void LayoutDetails ()
1612 if (columns
.Count
== 0) {
1613 item_control
.Visible
= false;
1614 layout_wd
= ClientRectangle
.Width
;
1615 layout_ht
= ClientRectangle
.Height
;
1619 item_control
.Visible
= true;
1620 item_control
.Location
= Point
.Empty
;
1621 item_control
.Width
= ClientRectangle
.Width
;
1623 int item_height
= GetDetailsItemHeight ();
1624 ItemSize
= new Size (0, item_height
); // We only cache Height for details view
1626 int y
= header_control
.Height
;
1627 if (items
.Count
> 0) {
1628 for (int i
= 0; i
< items
.Count
; i
++) {
1629 SetItemLocation (i
, 0, y
, 0, 0);
1631 if (!virtual_mode
) // Virtual mode sets Layout until draw time
1633 items
[i
].Layout ();
1635 y
+= item_height
+ 2;
1638 // some space for bottom gridline
1646 private void AdjustItemsPositionArray (int count
)
1648 if (items_location
.Length
>= count
)
1651 // items_location and items_matrix_location must keep the same length
1652 count
= Math
.Max (count
, items_location
.Length
* 2);
1653 items_location
= new Point
[count
];
1654 items_matrix_location
= new ItemMatrixLocation
[count
];
1657 private void CalculateListView (ListViewAlignment align
)
1661 AdjustItemsPositionArray (items
.Count
);
1668 case View
.SmallIcon
:
1669 LayoutIcons (SmallIconItemSize
, alignment
== ListViewAlignment
.Left
,
1670 ThemeEngine
.Current
.ListViewHorizontalSpacing
, 2);
1673 case View
.LargeIcon
:
1674 LayoutIcons (LargeIconItemSize
, alignment
== ListViewAlignment
.Left
,
1675 ThemeEngine
.Current
.ListViewHorizontalSpacing
,
1676 ThemeEngine
.Current
.ListViewVerticalSpacing
);
1680 LayoutIcons (SmallIconItemSize
, true,
1681 ThemeEngine
.Current
.ListViewHorizontalSpacing
, 2);
1685 LayoutIcons (TileItemSize
, alignment
== ListViewAlignment
.Left
,
1686 ThemeEngine
.Current
.ListViewHorizontalSpacing
,
1687 ThemeEngine
.Current
.ListViewVerticalSpacing
);
1692 CalculateScrollBars ();
1695 internal Point
GetItemLocation (int index
)
1697 Point loc
= items_location
[index
];
1698 loc
.X
-= h_marker
; // Adjust to scroll
1704 private bool KeySearchString (KeyEventArgs ke
)
1706 int current_tickcnt
= Environment
.TickCount
;
1707 if (keysearch_tickcnt
> 0 && current_tickcnt
- keysearch_tickcnt
> keysearch_keydelay
) {
1708 keysearch_text
= string.Empty
;
1711 if (!Char
.IsLetterOrDigit ((char)ke
.KeyCode
))
1714 keysearch_text
+= (char)ke
.KeyCode
;
1715 keysearch_tickcnt
= current_tickcnt
;
1717 int start
= FocusedItem
== null ? 0 : FocusedItem
.Index
;
1720 if (CultureInfo
.CurrentCulture
.CompareInfo
.IsPrefix (Items
[i
].Text
, keysearch_text
,
1721 CompareOptions
.IgnoreCase
)) {
1723 items
[i
].Selected
= true;
1727 i
= (i
+ 1 < Items
.Count
) ? i
+1 : 0;
1735 int GetAdjustedIndex (Keys key
)
1739 if (View
== View
.Details
) {
1742 result
= FocusedItem
.Index
- 1;
1745 result
= FocusedItem
.Index
+ 1;
1746 if (result
== items
.Count
)
1750 int last_index
= LastVisibleIndex
;
1751 Rectangle item_rect
= new Rectangle (GetItemLocation (last_index
), ItemSize
);
1752 if (item_rect
.Bottom
> item_control
.ClientRectangle
.Bottom
)
1754 if (FocusedItem
.Index
== last_index
) {
1755 if (FocusedItem
.Index
< Items
.Count
- 1) {
1756 int page_size
= item_control
.Height
/ ItemSize
.Height
- 1;
1757 result
= FocusedItem
.Index
+ page_size
- 1;
1758 if (result
>= Items
.Count
)
1759 result
= Items
.Count
- 1;
1762 result
= last_index
;
1765 int first_index
= FirstVisibleIndex
;
1766 if (GetItemLocation (first_index
).Y
< 0)
1768 if (FocusedItem
.Index
== first_index
) {
1769 if (first_index
> 0) {
1770 int page_size
= item_control
.Height
/ ItemSize
.Height
- 1;
1771 result
= first_index
- page_size
+ 1;
1776 result
= first_index
;
1782 ItemMatrixLocation item_matrix_location
= items_matrix_location
[FocusedItem
.Index
];
1783 int row
= item_matrix_location
.Row
;
1784 int col
= item_matrix_location
.Col
;
1790 return item_index_matrix
[row
, col
- 1];
1793 if (col
== (cols
- 1))
1795 while (item_index_matrix
[row
, col
+ 1] == 0) {
1800 return item_index_matrix
[row
, col
+ 1];
1805 while (item_index_matrix
[row
- 1, col
] == 0 && row
!= 1) {
1810 return item_index_matrix
[row
- 1, col
];
1813 if (row
== (rows
- 1) || row
== Items
.Count
- 1)
1815 while (item_index_matrix
[row
+ 1, col
] == 0) {
1820 return item_index_matrix
[row
+ 1, col
];
1827 ListViewItem selection_start
;
1829 private bool SelectItems (ArrayList sel_items
)
1831 bool changed
= false;
1832 foreach (ListViewItem item
in SelectedItems
)
1833 if (!sel_items
.Contains (item
)) {
1834 item
.Selected
= false;
1837 foreach (ListViewItem item
in sel_items
)
1838 if (!item
.Selected
) {
1839 item
.Selected
= true;
1845 private void UpdateMultiSelection (int index
, bool reselect
)
1847 bool shift_pressed
= (XplatUI
.State
.ModifierKeys
& Keys
.Shift
) != 0;
1848 bool ctrl_pressed
= (XplatUI
.State
.ModifierKeys
& Keys
.Control
) != 0;
1849 ListViewItem item
= items
[index
];
1851 if (shift_pressed
&& selection_start
!= null) {
1852 ArrayList list
= new ArrayList ();
1853 int start_index
= selection_start
.Index
;
1854 int start
= Math
.Min (start_index
, index
);
1855 int end
= Math
.Max (start_index
, index
);
1856 if (View
== View
.Details
) {
1857 for (int i
= start
; i
<= end
; i
++)
1858 list
.Add (items
[i
]);
1860 ItemMatrixLocation start_item_matrix_location
= items_matrix_location
[start
];
1861 ItemMatrixLocation end_item_matrix_location
= items_matrix_location
[end
];
1862 int left
= Math
.Min (start_item_matrix_location
.Col
, end_item_matrix_location
.Col
);
1863 int right
= Math
.Max (start_item_matrix_location
.Col
, end_item_matrix_location
.Col
);
1864 int top
= Math
.Min (start_item_matrix_location
.Row
, end_item_matrix_location
.Row
);
1865 int bottom
= Math
.Max (start_item_matrix_location
.Row
, end_item_matrix_location
.Row
);
1867 for (int i
= 0; i
< items
.Count
; i
++) {
1868 ItemMatrixLocation item_matrix_loc
= items_matrix_location
[i
];
1870 if (item_matrix_loc
.Row
>= top
&& item_matrix_loc
.Row
<= bottom
&&
1871 item_matrix_loc
.Col
>= left
&& item_matrix_loc
.Col
<= right
)
1872 list
.Add (items
[i
]);
1876 } else if (ctrl_pressed
) {
1877 item
.Selected
= !item
.Selected
;
1878 selection_start
= item
;
1881 // do not unselect, and reselect the item
1882 foreach (int itemIndex
in SelectedIndices
) {
1883 if (index
== itemIndex
)
1885 items
[itemIndex
].Selected
= false;
1888 SelectedItems
.Clear ();
1889 item
.Selected
= true;
1891 selection_start
= item
;
1895 internal override bool InternalPreProcessMessage (ref Message msg
)
1897 if (msg
.Msg
== (int)Msg
.WM_KEYDOWN
) {
1898 Keys key_data
= (Keys
)msg
.WParam
.ToInt32();
1900 HandleNavKeys (key_data
);
1903 return base.InternalPreProcessMessage (ref msg
);
1906 bool HandleNavKeys (Keys key_data
)
1908 if (Items
.Count
== 0 || !item_control
.Visible
)
1911 if (FocusedItem
== null)
1916 SelectIndex (Items
.Count
- 1);
1929 SelectIndex (GetAdjustedIndex (key_data
));
1933 ToggleItemsCheckState ();
1936 if (selected_indices
.Count
> 0)
1937 OnItemActivate (EventArgs
.Empty
);
1947 void ToggleItemsCheckState ()
1952 // Don't modify check state if StateImageList has less than 2 elements
1953 if (StateImageList
!= null && StateImageList
.Images
.Count
< 2)
1956 if (SelectedIndices
.Count
> 0) {
1957 for (int i
= 0; i
< SelectedIndices
.Count
; i
++) {
1958 ListViewItem item
= Items
[SelectedIndices
[i
]];
1959 item
.Checked
= !item
.Checked
;
1964 if (FocusedItem
!= null) {
1965 FocusedItem
.Checked
= !FocusedItem
.Checked
;
1966 SelectIndex (FocusedItem
.Index
);
1970 void SelectIndex (int index
)
1976 UpdateMultiSelection (index
, true);
1977 else if (!items
[index
].Selected
)
1978 items
[index
].Selected
= true;
1980 SetFocusedItem (index
);
1981 EnsureVisible (index
);
1984 private void ListView_KeyDown (object sender
, KeyEventArgs ke
)
1986 if (ke
.Handled
|| Items
.Count
== 0 || !item_control
.Visible
)
1989 if (ke
.Alt
|| ke
.Control
)
1992 ke
.Handled
= KeySearchString (ke
);
1995 private MouseEventArgs
TranslateMouseEventArgs (MouseEventArgs args
)
1997 Point loc
= PointToClient (Control
.MousePosition
);
1998 return new MouseEventArgs (args
.Button
, args
.Clicks
, loc
.X
, loc
.Y
, args
.Delta
);
2001 internal class ItemControl
: Control
{
2004 ListViewItem clicked_item
;
2005 ListViewItem last_clicked_item
;
2006 bool hover_processed
= false;
2007 bool checking
= false;
2008 ListViewItem prev_hovered_item
;
2010 ListViewItem prev_tooltip_item
;
2014 ListViewLabelEditTextBox edit_text_box
;
2015 internal ListViewItem edit_item
;
2016 LabelEditEventArgs edit_args
;
2018 public ItemControl (ListView owner
)
2021 DoubleClick
+= new EventHandler(ItemsDoubleClick
);
2022 MouseDown
+= new MouseEventHandler(ItemsMouseDown
);
2023 MouseMove
+= new MouseEventHandler(ItemsMouseMove
);
2024 MouseHover
+= new EventHandler(ItemsMouseHover
);
2025 MouseUp
+= new MouseEventHandler(ItemsMouseUp
);
2028 void ItemsDoubleClick (object sender
, EventArgs e
)
2030 if (owner
.activation
== ItemActivation
.Standard
)
2031 owner
.OnItemActivate (EventArgs
.Empty
);
2041 BoxSelect box_select_mode
= BoxSelect
.None
;
2042 IList prev_selection
;
2043 Point box_select_start
;
2045 Rectangle box_select_rect
;
2046 internal Rectangle BoxSelectRectangle
{
2047 get { return box_select_rect; }
2049 if (box_select_rect
== value)
2052 InvalidateBoxSelectRect ();
2053 box_select_rect
= value;
2054 InvalidateBoxSelectRect ();
2058 void InvalidateBoxSelectRect ()
2060 if (BoxSelectRectangle
.Size
.IsEmpty
)
2063 Rectangle edge
= BoxSelectRectangle
;
2069 edge
.Y
= BoxSelectRectangle
.Bottom
- 1;
2071 edge
.Y
= BoxSelectRectangle
.Y
- 1;
2073 edge
.Height
= BoxSelectRectangle
.Height
+ 2;
2075 edge
.X
= BoxSelectRectangle
.Right
- 1;
2079 private Rectangle
CalculateBoxSelectRectangle (Point pt
)
2081 int left
= Math
.Min (box_select_start
.X
, pt
.X
);
2082 int right
= Math
.Max (box_select_start
.X
, pt
.X
);
2083 int top
= Math
.Min (box_select_start
.Y
, pt
.Y
);
2084 int bottom
= Math
.Max (box_select_start
.Y
, pt
.Y
);
2085 return Rectangle
.FromLTRB (left
, top
, right
, bottom
);
2088 bool BoxIntersectsItem (int index
)
2090 Rectangle r
= new Rectangle (owner
.GetItemLocation (index
), owner
.ItemSize
);
2091 if (owner
.View
!= View
.Details
) {
2093 r
.Y
+= r
.Height
/ 4;
2097 return BoxSelectRectangle
.IntersectsWith (r
);
2100 bool BoxIntersectsText (int index
)
2102 Rectangle r
= owner
.Items
[index
].TextBounds
;
2103 return BoxSelectRectangle
.IntersectsWith (r
);
2106 ArrayList BoxSelectedItems
{
2108 ArrayList result
= new ArrayList ();
2109 for (int i
= 0; i
< owner
.Items
.Count
; i
++) {
2111 if (owner
.View
== View
.Details
&& !owner
.FullRowSelect
)
2112 intersects
= BoxIntersectsText (i
);
2114 intersects
= BoxIntersectsItem (i
);
2117 result
.Add (owner
.Items
[i
]);
2123 private bool PerformBoxSelection (Point pt
)
2125 if (box_select_mode
== BoxSelect
.None
)
2128 BoxSelectRectangle
= CalculateBoxSelectRectangle (pt
);
2130 ArrayList box_items
= BoxSelectedItems
;
2134 switch (box_select_mode
) {
2136 case BoxSelect
.Normal
:
2140 case BoxSelect
.Control
:
2141 items
= new ArrayList ();
2142 foreach (int index
in prev_selection
)
2143 if (!box_items
.Contains (owner
.Items
[index
]))
2144 items
.Add (owner
.Items
[index
]);
2145 foreach (ListViewItem item
in box_items
)
2146 if (!prev_selection
.Contains (item
.Index
))
2150 case BoxSelect
.Shift
:
2152 foreach (ListViewItem item
in box_items
)
2153 prev_selection
.Remove (item
.Index
);
2154 foreach (int index
in prev_selection
)
2155 items
.Add (owner
.Items
[index
]);
2159 throw new Exception ("Unexpected Selection mode: " + box_select_mode
);
2163 owner
.SelectItems (items
);
2169 private void ItemsMouseDown (object sender
, MouseEventArgs me
)
2171 owner
.OnMouseDown (owner
.TranslateMouseEventArgs (me
));
2172 if (owner
.items
.Count
== 0)
2175 bool box_selecting
= false;
2176 Size item_size
= owner
.ItemSize
;
2177 Point pt
= new Point (me
.X
, me
.Y
);
2178 for (int i
= 0; i
< owner
.items
.Count
; i
++) {
2179 Rectangle item_rect
= new Rectangle (owner
.GetItemLocation (i
), item_size
);
2180 if (!item_rect
.Contains (pt
))
2183 if (owner
.items
[i
].CheckRectReal
.Contains (pt
)) {
2184 ListViewItem item
= owner
.items
[i
];
2186 // Don't modify check state if we have only one image
2187 // and if we are in 1.1 profile only take into account
2189 if (owner
.StateImageList
!= null && owner
.StateImageList
.Images
.Count
< 2
2196 // Generate an extra ItemCheck event when we got two clicks
2197 // (Match weird .Net behaviour)
2199 item
.Checked
= !item
.Checked
;
2201 item
.Checked
= !item
.Checked
;
2206 if (owner
.View
== View
.Details
) {
2207 bool over_text
= owner
.items
[i
].TextBounds
.Contains (pt
);
2208 if (owner
.FullRowSelect
) {
2209 clicked_item
= owner
.items
[i
];
2210 bool over_item_column
= (me
.X
> owner
.Columns
[0].X
&& me
.X
< owner
.Columns
[0].X
+ owner
.Columns
[0].Width
);
2211 if (!over_text
&& over_item_column
&& owner
.MultiSelect
)
2212 box_selecting
= true;
2213 } else if (over_text
)
2214 clicked_item
= owner
.items
[i
];
2216 owner
.SetFocusedItem (i
);
2218 clicked_item
= owner
.items
[i
];
2224 if (clicked_item
!= null) {
2225 bool changed
= !clicked_item
.Selected
;
2226 if (me
.Button
== MouseButtons
.Left
|| (XplatUI
.State
.ModifierKeys
== Keys
.None
&& changed
))
2227 owner
.SetFocusedItem (clicked_item
.Index
);
2229 if (owner
.MultiSelect
) {
2230 bool reselect
= (!owner
.LabelEdit
|| changed
);
2231 if (me
.Button
== MouseButtons
.Left
|| (XplatUI
.State
.ModifierKeys
== Keys
.None
&& changed
))
2232 owner
.UpdateMultiSelection (clicked_item
.Index
, reselect
);
2234 clicked_item
.Selected
= true;
2238 if (owner
.VirtualMode
&& changed
) {
2239 // Broken event - It's not fired from Item.Selected also
2240 ListViewVirtualItemsSelectionRangeChangedEventArgs args
=
2241 new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner
.items
.Count
- 1, false);
2243 owner
.OnVirtualItemsSelectionRangeChanged (args
);
2246 // Report clicks only if the item was clicked. On MS the
2247 // clicks are only raised if you click an item
2249 if (me
.Clicks
> 1) {
2250 if (owner
.CheckBoxes
)
2251 clicked_item
.Checked
= !clicked_item
.Checked
;
2252 } else if (me
.Clicks
== 1) {
2253 if (owner
.LabelEdit
&& !changed
)
2254 BeginEdit (clicked_item
); // this is probably not the correct place to execute BeginEdit
2257 if (owner
.MultiSelect
)
2258 box_selecting
= true;
2259 else if (owner
.SelectedItems
.Count
> 0)
2260 owner
.SelectedItems
.Clear ();
2263 if (box_selecting
) {
2264 Keys mods
= XplatUI
.State
.ModifierKeys
;
2265 if ((mods
& Keys
.Shift
) != 0)
2266 box_select_mode
= BoxSelect
.Shift
;
2267 else if ((mods
& Keys
.Control
) != 0)
2268 box_select_mode
= BoxSelect
.Control
;
2270 box_select_mode
= BoxSelect
.Normal
;
2271 box_select_start
= pt
;
2272 prev_selection
= owner
.SelectedIndices
.List
.Clone () as IList
;
2276 private void ItemsMouseMove (object sender
, MouseEventArgs me
)
2278 bool done
= PerformBoxSelection (new Point (me
.X
, me
.Y
));
2280 owner
.OnMouseMove (owner
.TranslateMouseEventArgs (me
));
2284 if (!hover_processed
&& owner
.Activation
!= ItemActivation
.OneClick
2286 && !owner
.ShowItemToolTips
2291 Point pt
= PointToClient (Control
.MousePosition
);
2292 ListViewItem item
= owner
.GetItemAt (pt
.X
, pt
.Y
);
2294 if (hover_processed
&& item
!= null && item
!= prev_hovered_item
) {
2295 hover_processed
= false;
2296 XplatUI
.ResetMouseHover (Handle
);
2299 // Need to invalidate the item in HotTracking to show/hide the underline style
2300 if (owner
.Activation
== ItemActivation
.OneClick
) {
2301 if (item
== null && owner
.HotItemIndex
!= -1) {
2303 if (owner
.HotTracking
)
2304 Invalidate (owner
.Items
[owner
.HotItemIndex
].Bounds
); // Previous one
2307 Cursor
= Cursors
.Default
;
2308 owner
.HotItemIndex
= -1;
2309 } else if (item
!= null && owner
.HotItemIndex
== -1) {
2311 if (owner
.HotTracking
)
2312 Invalidate (item
.Bounds
);
2315 Cursor
= Cursors
.Hand
;
2316 owner
.HotItemIndex
= item
.Index
;
2321 if (owner
.ShowItemToolTips
) {
2323 owner
.item_tooltip
.Active
= false;
2324 prev_tooltip_item
= null;
2325 } else if (item
!= prev_tooltip_item
&& item
.ToolTipText
.Length
> 0) {
2326 owner
.item_tooltip
.Active
= true;
2327 owner
.item_tooltip
.SetToolTip (owner
, item
.ToolTipText
);
2328 prev_tooltip_item
= item
;
2336 private void ItemsMouseHover (object sender
, EventArgs e
)
2338 if (owner
.hover_pending
) {
2339 owner
.OnMouseHover (e
);
2340 owner
.hover_pending
= false;
2346 hover_processed
= true;
2347 Point pt
= PointToClient (Control
.MousePosition
);
2348 ListViewItem item
= owner
.GetItemAt (pt
.X
, pt
.Y
);
2352 prev_hovered_item
= item
;
2354 if (owner
.HoverSelection
) {
2355 if (owner
.MultiSelect
)
2356 owner
.UpdateMultiSelection (item
.Index
, true);
2358 item
.Selected
= true;
2360 owner
.SetFocusedItem (item
.Index
);
2361 Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2365 owner
.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item
));
2369 void HandleClicks (MouseEventArgs me
)
2371 // if the click is not on an item,
2372 // clicks remains as 0
2375 owner
.OnDoubleClick (EventArgs
.Empty
);
2376 } else if (clicks
== 1) {
2377 owner
.OnClick (EventArgs
.Empty
);
2379 owner
.OnDoubleClick (EventArgs
.Empty
);
2380 owner
.OnMouseDoubleClick (me
);
2381 } else if (clicks
== 1) {
2382 owner
.OnClick (EventArgs
.Empty
);
2383 owner
.OnMouseClick (me
);
2390 private void ItemsMouseUp (object sender
, MouseEventArgs me
)
2392 MouseEventArgs owner_me
= owner
.TranslateMouseEventArgs (me
);
2393 HandleClicks (owner_me
);
2396 if (owner
.Items
.Count
== 0) {
2397 owner
.OnMouseUp (owner_me
);
2401 Point pt
= new Point (me
.X
, me
.Y
);
2403 Rectangle rect
= Rectangle
.Empty
;
2404 if (clicked_item
!= null) {
2405 if (owner
.view
== View
.Details
&& !owner
.full_row_select
)
2406 rect
= clicked_item
.GetBounds (ItemBoundsPortion
.Label
);
2408 rect
= clicked_item
.Bounds
;
2410 if (rect
.Contains (pt
)) {
2411 switch (owner
.activation
) {
2412 case ItemActivation
.OneClick
:
2413 owner
.OnItemActivate (EventArgs
.Empty
);
2416 case ItemActivation
.TwoClick
:
2417 if (last_clicked_item
== clicked_item
) {
2418 owner
.OnItemActivate (EventArgs
.Empty
);
2419 last_clicked_item
= null;
2421 last_clicked_item
= clicked_item
;
2424 // DoubleClick activation is handled in another handler
2428 } else if (!checking
&& owner
.SelectedItems
.Count
> 0 && BoxSelectRectangle
.Size
.IsEmpty
) {
2429 // Need this to clean up background clicks
2430 owner
.SelectedItems
.Clear ();
2433 clicked_item
= null;
2434 box_select_start
= Point
.Empty
;
2435 BoxSelectRectangle
= Rectangle
.Empty
;
2436 prev_selection
= null;
2437 box_select_mode
= BoxSelect
.None
;
2439 owner
.OnMouseUp (owner_me
);
2442 private void LabelEditFinished (object sender
, EventArgs e
)
2444 EndEdit (edit_item
);
2447 private void LabelEditCancelled (object sender
, EventArgs e
)
2449 edit_args
.SetLabel (null);
2450 EndEdit (edit_item
);
2453 private void LabelTextChanged (object sender
, EventArgs e
)
2455 if (edit_args
!= null)
2456 edit_args
.SetLabel (edit_text_box
.Text
);
2459 internal void BeginEdit (ListViewItem item
)
2461 if (edit_item
!= null)
2462 EndEdit (edit_item
);
2464 if (edit_text_box
== null) {
2465 edit_text_box
= new ListViewLabelEditTextBox ();
2466 edit_text_box
.BorderStyle
= BorderStyle
.FixedSingle
;
2467 edit_text_box
.EditingCancelled
+= new EventHandler (LabelEditCancelled
);
2468 edit_text_box
.EditingFinished
+= new EventHandler (LabelEditFinished
);
2469 edit_text_box
.TextChanged
+= new EventHandler (LabelTextChanged
);
2470 edit_text_box
.Visible
= false;
2471 Controls
.Add (edit_text_box
);
2474 item
.EnsureVisible();
2476 edit_text_box
.Reset ();
2478 switch (owner
.view
) {
2480 case View
.SmallIcon
:
2482 edit_text_box
.TextAlign
= HorizontalAlignment
.Left
;
2483 edit_text_box
.Bounds
= item
.GetBounds (ItemBoundsPortion
.Label
);
2484 SizeF sizef
= TextRenderer
.MeasureString (item
.Text
, item
.Font
);
2485 edit_text_box
.Width
= (int)sizef
.Width
+ 4;
2486 edit_text_box
.MaxWidth
= owner
.ClientRectangle
.Width
- edit_text_box
.Bounds
.X
;
2487 edit_text_box
.WordWrap
= false;
2488 edit_text_box
.Multiline
= false;
2490 case View
.LargeIcon
:
2491 edit_text_box
.TextAlign
= HorizontalAlignment
.Center
;
2492 edit_text_box
.Bounds
= item
.GetBounds (ItemBoundsPortion
.Label
);
2493 sizef
= TextRenderer
.MeasureString (item
.Text
, item
.Font
);
2494 edit_text_box
.Width
= (int)sizef
.Width
+ 4;
2495 edit_text_box
.MaxWidth
= item
.GetBounds(ItemBoundsPortion
.Entire
).Width
;
2496 edit_text_box
.MaxHeight
= owner
.ClientRectangle
.Height
- edit_text_box
.Bounds
.Y
;
2497 edit_text_box
.WordWrap
= true;
2498 edit_text_box
.Multiline
= true;
2504 edit_text_box
.Text
= item
.Text
;
2505 edit_text_box
.Font
= item
.Font
;
2506 edit_text_box
.Visible
= true;
2507 edit_text_box
.Focus ();
2508 edit_text_box
.SelectAll ();
2510 edit_args
= new LabelEditEventArgs (owner
.Items
.IndexOf (edit_item
));
2511 owner
.OnBeforeLabelEdit (edit_args
);
2513 if (edit_args
.CancelEdit
)
2517 internal void CancelEdit (ListViewItem item
)
2519 // do nothing if there's no item being edited, or if the
2520 // item being edited is not the one passed in
2521 if (edit_item
== null || edit_item
!= item
)
2524 edit_args
.SetLabel (null);
2528 internal void EndEdit (ListViewItem item
)
2530 // do nothing if there's no item being edited, or if the
2531 // item being edited is not the one passed in
2532 if (edit_item
== null || edit_item
!= item
)
2535 owner
.OnAfterLabelEdit (edit_args
);
2536 if (!edit_args
.CancelEdit
&& edit_args
.Label
!= null)
2537 edit_item
.Text
= edit_text_box
.Text
;
2539 if (edit_text_box
!= null) {
2540 if (edit_text_box
.Visible
)
2541 edit_text_box
.Visible
= false;
2542 // ensure listview gets focus
2549 internal override void OnPaintInternal (PaintEventArgs pe
)
2551 ThemeEngine
.Current
.DrawListViewItems (pe
.Graphics
, pe
.ClipRectangle
, owner
);
2554 protected override void WndProc (ref Message m
)
2556 switch ((Msg
)m
.Msg
) {
2557 case Msg
.WM_KILLFOCUS
:
2558 owner
.Select (false, true);
2560 case Msg
.WM_SETFOCUS
:
2561 owner
.Select (false, true);
2563 case Msg
.WM_RBUTTONDOWN
:
2564 owner
.Select (false, true);
2569 base.WndProc (ref m
);
2573 internal class ListViewLabelEditTextBox
: TextBox
2578 int max_height
= -1;
2579 int min_height
= -1;
2581 int old_number_lines
= 1;
2583 SizeF text_size_one_char
;
2585 public ListViewLabelEditTextBox ()
2587 min_height
= DefaultSize
.Height
;
2588 text_size_one_char
= TextRenderer
.MeasureString ("B", Font
);
2591 public int MaxWidth
{
2593 if (value < min_width
)
2594 max_width
= min_width
;
2600 public int MaxHeight
{
2602 if (value < min_height
)
2603 max_height
= min_height
;
2609 public new int Width
{
2619 public override Font Font
{
2625 text_size_one_char
= TextRenderer
.MeasureString ("B", Font
);
2629 protected override void OnTextChanged (EventArgs e
)
2631 SizeF text_size
= TextRenderer
.MeasureString (Text
, Font
);
2633 int new_width
= (int)text_size
.Width
+ 8;
2636 ResizeTextBoxWidth (new_width
);
2638 if (Width
!= max_width
)
2639 ResizeTextBoxWidth (new_width
);
2641 int number_lines
= Lines
.Length
;
2643 if (number_lines
!= old_number_lines
) {
2644 int new_height
= number_lines
* (int)text_size_one_char
.Height
+ 4;
2645 old_number_lines
= number_lines
;
2647 ResizeTextBoxHeight (new_height
);
2651 base.OnTextChanged (e
);
2654 protected override bool IsInputKey (Keys key_data
)
2656 if ((key_data
& Keys
.Alt
) == 0) {
2657 switch (key_data
& Keys
.KeyCode
) {
2664 return base.IsInputKey (key_data
);
2667 protected override void OnKeyDown (KeyEventArgs e
)
2672 switch (e
.KeyCode
) {
2676 OnEditingFinished (e
);
2681 OnEditingCancelled (e
);
2686 protected override void OnLostFocus (EventArgs e
)
2689 OnEditingFinished (e
);
2693 protected void OnEditingCancelled (EventArgs e
)
2695 EventHandler eh
= (EventHandler
)(Events
[EditingCancelledEvent
]);
2700 protected void OnEditingFinished (EventArgs e
)
2702 EventHandler eh
= (EventHandler
)(Events
[EditingFinishedEvent
]);
2707 private void ResizeTextBoxWidth (int new_width
)
2709 if (new_width
> max_width
)
2710 base.Width
= max_width
;
2712 if (new_width
>= min_width
)
2713 base.Width
= new_width
;
2715 base.Width
= min_width
;
2718 private void ResizeTextBoxHeight (int new_height
)
2720 if (new_height
> max_height
)
2721 base.Height
= max_height
;
2723 if (new_height
>= min_height
)
2724 base.Height
= new_height
;
2726 base.Height
= min_height
;
2729 public void Reset ()
2736 old_number_lines
= 1;
2738 Text
= String
.Empty
;
2743 static object EditingCancelledEvent
= new object ();
2744 public event EventHandler EditingCancelled
{
2745 add { Events.AddHandler (EditingCancelledEvent, value); }
2746 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
2749 static object EditingFinishedEvent
= new object ();
2750 public event EventHandler EditingFinished
{
2751 add { Events.AddHandler (EditingFinishedEvent, value); }
2752 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
2756 internal override void OnPaintInternal (PaintEventArgs pe
)
2761 CalculateScrollBars ();
2764 void FocusChanged (object o
, EventArgs args
)
2766 if (Items
.Count
== 0)
2769 if (FocusedItem
== null)
2772 ListViewItem focused_item
= FocusedItem
;
2774 if (focused_item
.ListView
!= null) {
2775 item_control
.Invalidate (focused_item
.Bounds
);
2776 focused_item
.Layout ();
2777 item_control
.Invalidate (focused_item
.Bounds
);
2781 private void ListView_MouseEnter (object sender
, EventArgs args
)
2783 hover_pending
= true; // Need a hover event for every Enter/Leave cycle
2786 private void ListView_MouseWheel (object sender
, MouseEventArgs me
)
2788 if (Items
.Count
== 0)
2791 int lines
= me
.Delta
/ 120;
2798 case View
.SmallIcon
:
2799 Scroll (v_scroll
, -ItemSize
.Height
* SystemInformation
.MouseWheelScrollLines
* lines
);
2801 case View
.LargeIcon
:
2802 Scroll (v_scroll
, -(ItemSize
.Height
+ ThemeEngine
.Current
.ListViewVerticalSpacing
) * lines
);
2805 Scroll (h_scroll
, -ItemSize
.Width
* lines
);
2809 Scroll (v_scroll
, -(ItemSize
.Height
+ ThemeEngine
.Current
.ListViewVerticalSpacing
) * 2 * lines
);
2815 private void ListView_SizeChanged (object sender
, EventArgs e
)
2817 CalculateListView (alignment
);
2820 private void SetFocusedItem (int index
)
2823 items
[index
].Focused
= true;
2824 else if (focused_item_index
!= -1) // Previous focused item
2825 items
[focused_item_index
].Focused
= false;
2827 focused_item_index
= index
;
2830 private void HorizontalScroller (object sender
, EventArgs e
)
2832 item_control
.EndEdit (item_control
.edit_item
);
2834 // Avoid unnecessary flickering, when button is
2835 // kept pressed at the end
2836 if (h_marker
!= h_scroll
.Value
) {
2838 int pixels
= h_marker
- h_scroll
.Value
;
2840 h_marker
= h_scroll
.Value
;
2841 if (header_control
.Visible
)
2842 XplatUI
.ScrollWindow (header_control
.Handle
, pixels
, 0, false);
2844 XplatUI
.ScrollWindow (item_control
.Handle
, pixels
, 0, false);
2848 private void VerticalScroller (object sender
, EventArgs e
)
2850 item_control
.EndEdit (item_control
.edit_item
);
2852 // Avoid unnecessary flickering, when button is
2853 // kept pressed at the end
2854 if (v_marker
!= v_scroll
.Value
) {
2855 int pixels
= v_marker
- v_scroll
.Value
;
2856 Rectangle area
= item_control
.ClientRectangle
;
2857 if (header_control
.Visible
) {
2858 area
.Y
+= header_control
.Height
;
2859 area
.Height
-= header_control
.Height
;
2862 v_marker
= v_scroll
.Value
;
2863 XplatUI
.ScrollWindow (item_control
.Handle
, area
, 0, pixels
, false);
2866 #endregion // Internal Methods Properties
2868 #region Protected Methods
2869 protected override void CreateHandle ()
2871 base.CreateHandle ();
2872 for (int i
= 0; i
< SelectedItems
.Count
; i
++)
2873 OnSelectedIndexChanged (EventArgs
.Empty
);
2876 protected override void Dispose (bool disposing
)
2879 h_scroll
.Dispose ();
2880 v_scroll
.Dispose ();
2882 large_image_list
= null;
2883 small_image_list
= null;
2884 state_image_list
= null;
2886 foreach (ColumnHeader col
in columns
)
2887 col
.SetListView (null);
2890 if (!virtual_mode
) // In virtual mode we don't save the items
2892 foreach (ListViewItem item
in items
)
2896 base.Dispose (disposing
);
2899 protected override bool IsInputKey (Keys keyData
)
2916 return base.IsInputKey (keyData
);
2919 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e
)
2921 LabelEditEventHandler eh
= (LabelEditEventHandler
)(Events
[AfterLabelEditEvent
]);
2926 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e
)
2928 LabelEditEventHandler eh
= (LabelEditEventHandler
)(Events
[BeforeLabelEditEvent
]);
2933 protected virtual void OnColumnClick (ColumnClickEventArgs e
)
2935 ColumnClickEventHandler eh
= (ColumnClickEventHandler
)(Events
[ColumnClickEvent
]);
2941 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e
)
2943 DrawListViewColumnHeaderEventHandler eh
= (DrawListViewColumnHeaderEventHandler
)(Events
[DrawColumnHeaderEvent
]);
2948 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e
)
2950 DrawListViewItemEventHandler eh
= (DrawListViewItemEventHandler
)(Events
[DrawItemEvent
]);
2955 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e
)
2957 DrawListViewSubItemEventHandler eh
= (DrawListViewSubItemEventHandler
)(Events
[DrawSubItemEvent
]);
2963 protected override void OnEnabledChanged (EventArgs e
)
2965 base.OnEnabledChanged (e
);
2968 protected override void OnFontChanged (EventArgs e
)
2970 base.OnFontChanged (e
);
2974 protected override void OnHandleCreated (EventArgs e
)
2976 base.OnHandleCreated (e
);
2977 CalculateListView (alignment
);
2979 if (!virtual_mode
) // Sorting is not allowed in virtual mode
2984 protected override void OnHandleDestroyed (EventArgs e
)
2986 base.OnHandleDestroyed (e
);
2989 protected virtual void OnItemActivate (EventArgs e
)
2991 EventHandler eh
= (EventHandler
)(Events
[ItemActivateEvent
]);
2996 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice
)
2998 ItemCheckEventHandler eh
= (ItemCheckEventHandler
)(Events
[ItemCheckEvent
]);
3004 protected internal virtual void OnItemChecked (ItemCheckedEventArgs icea
)
3006 ItemCheckedEventHandler eh
= (ItemCheckedEventHandler
)(Events
[ItemCheckedEvent
]);
3012 protected virtual void OnItemDrag (ItemDragEventArgs e
)
3014 EventHandler eh
= (EventHandler
)(Events
[ItemDragEvent
]);
3020 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs args
)
3022 ListViewItemMouseHoverEventHandler eh
= (ListViewItemMouseHoverEventHandler
)(Events
[ItemMouseHoverEvent
]);
3027 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs args
)
3029 ListViewItemSelectionChangedEventHandler eh
=
3030 (ListViewItemSelectionChangedEventHandler
) Events
[ItemSelectionChangedEvent
];
3036 protected virtual void OnSelectedIndexChanged (EventArgs e
)
3038 EventHandler eh
= (EventHandler
)(Events
[SelectedIndexChangedEvent
]);
3043 protected override void OnSystemColorsChanged (EventArgs e
)
3045 base.OnSystemColorsChanged (e
);
3049 protected virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs args
)
3051 EventHandler eh
= (EventHandler
)Events
[CacheVirtualItemsEvent
];
3056 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs args
)
3058 RetrieveVirtualItemEventHandler eh
= (RetrieveVirtualItemEventHandler
)Events
[RetrieveVirtualItemEvent
];
3063 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs args
)
3065 ListViewVirtualItemsSelectionRangeChangedEventHandler eh
=
3066 (ListViewVirtualItemsSelectionRangeChangedEventHandler
) Events
[VirtualItemsSelectionRangeChangedEvent
];
3072 protected void RealizeProperties ()
3077 protected void UpdateExtendedStyles ()
3082 bool refocusing
= false;
3084 protected override void WndProc (ref Message m
)
3086 switch ((Msg
)m
.Msg
) {
3087 case Msg
.WM_KILLFOCUS
:
3088 Control receiver
= Control
.FromHandle (m
.WParam
);
3089 if (receiver
== item_control
) {
3095 case Msg
.WM_SETFOCUS
:
3105 base.WndProc (ref m
);
3107 #endregion // Protected Methods
3109 #region Public Instance Methods
3110 public void ArrangeIcons ()
3112 ArrangeIcons (this.alignment
);
3115 public void ArrangeIcons (ListViewAlignment alignment
)
3117 // Icons are arranged only if view is set to LargeIcon or SmallIcon
3118 if (view
== View
.LargeIcon
|| view
== View
.SmallIcon
) {
3119 this.CalculateListView (alignment
);
3120 // we have done the calculations already
3121 this.Redraw (false);
3126 public void AutoResizeColumn (int columnIndex
, ColumnHeaderAutoResizeStyle headerAutoResize
)
3128 if (columnIndex
< 0 || columnIndex
>= columns
.Count
)
3129 throw new ArgumentOutOfRangeException ("columnIndex");
3131 columns
[columnIndex
].AutoResize (headerAutoResize
);
3134 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize
)
3137 foreach (ColumnHeader col
in columns
)
3138 col
.AutoResize (headerAutoResize
);
3143 public void BeginUpdate ()
3145 // flag to avoid painting
3149 public void Clear ()
3152 items
.Clear (); // Redraw (true) called here
3155 public void EndUpdate ()
3157 // flag to avoid painting
3160 // probably, now we need a redraw with recalculations
3164 public void EnsureVisible (int index
)
3166 if (index
< 0 || index
>= items
.Count
|| scrollable
== false)
3169 Rectangle view_rect
= item_control
.ClientRectangle
;
3170 Rectangle bounds
= new Rectangle (GetItemLocation (index
), ItemSize
);
3172 if (view_rect
.Contains (bounds
))
3175 if (View
!= View
.Details
) {
3176 if (bounds
.Left
< 0)
3177 h_scroll
.Value
+= bounds
.Left
;
3178 else if (bounds
.Right
> view_rect
.Right
)
3179 h_scroll
.Value
+= (bounds
.Right
- view_rect
.Right
);
3183 v_scroll
.Value
+= bounds
.Top
;
3184 else if (bounds
.Bottom
> view_rect
.Bottom
)
3185 v_scroll
.Value
+= (bounds
.Bottom
- view_rect
.Bottom
);
3189 public ListViewItem
FindItemWithText (string text
)
3191 if (items
.Count
== 0)
3194 return FindItemWithText (text
, true, 0, true);
3197 public ListViewItem
FindItemWithText (string text
, bool includeSubItems
, int startIndex
)
3199 return FindItemWithText (text
, includeSubItems
, startIndex
, true);
3202 public ListViewItem
FindItemWithText (string text
, bool includeSubItems
, int startIndex
, bool prefixSearch
)
3204 if (startIndex
< 0 || startIndex
>= items
.Count
)
3205 throw new ArgumentOutOfRangeException ("startIndex");
3208 throw new ArgumentNullException ("text");
3210 for (int i
= startIndex
; i
< items
.Count
; i
++) {
3211 ListViewItem lvi
= items
[i
];
3213 if ((prefixSearch
&& lvi
.Text
.StartsWith (text
, true, CultureInfo
.CurrentCulture
)) // prefix search
3214 || String
.Compare (lvi
.Text
, text
, true) == 0) // match
3218 if (includeSubItems
) {
3219 for (int i
= startIndex
; i
< items
.Count
; i
++) {
3220 ListViewItem lvi
= items
[i
];
3221 foreach (ListViewItem
.ListViewSubItem sub_item
in lvi
.SubItems
)
3222 if ((prefixSearch
&& sub_item
.Text
.StartsWith (text
, true, CultureInfo
.CurrentCulture
))
3223 || String
.Compare (sub_item
.Text
, text
, true) == 0)
3232 public ListViewItem
GetItemAt (int x
, int y
)
3234 Size item_size
= ItemSize
;
3235 for (int i
= 0; i
< items
.Count
; i
++) {
3236 Point item_location
= GetItemLocation (i
);
3237 Rectangle item_rect
= new Rectangle (item_location
, item_size
);
3238 if (item_rect
.Contains (x
, y
))
3245 public Rectangle
GetItemRect (int index
)
3247 return GetItemRect (index
, ItemBoundsPortion
.Entire
);
3250 public Rectangle
GetItemRect (int index
, ItemBoundsPortion portion
)
3252 if (index
< 0 || index
>= items
.Count
)
3253 throw new IndexOutOfRangeException ("index");
3255 return items
[index
].GetBounds (portion
);
3259 public ListViewHitTestInfo
HitTest (Point pt
)
3261 return HitTest (pt
.X
, pt
.Y
);
3264 public ListViewHitTestInfo
HitTest (int x
, int y
)
3267 throw new ArgumentOutOfRangeException ("x");
3269 throw new ArgumentOutOfRangeException ("y");
3271 ListViewItem item
= GetItemAt (x
, y
);
3273 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations
.None
);
3275 ListViewHitTestLocations locations
= 0;
3276 if (item
.GetBounds (ItemBoundsPortion
.Label
).Contains (x
, y
))
3277 locations
|= ListViewHitTestLocations
.Label
;
3278 else if (item
.GetBounds (ItemBoundsPortion
.Icon
).Contains (x
, y
))
3279 locations
|= ListViewHitTestLocations
.Image
;
3280 else if (item
.CheckRectReal
.Contains (x
, y
))
3281 locations
|= ListViewHitTestLocations
.StateImage
;
3283 ListViewItem
.ListViewSubItem subitem
= null;
3284 if (view
== View
.Details
)
3285 foreach (ListViewItem
.ListViewSubItem si
in item
.SubItems
)
3286 if (si
.Bounds
.Contains (x
, y
)) {
3291 return new ListViewHitTestInfo (item
, subitem
, locations
);
3294 public void RedrawItems (int startIndex
, int endIndex
, bool invalidateOnly
)
3296 if (startIndex
< 0 || startIndex
>= items
.Count
)
3297 throw new ArgumentOutOfRangeException ("startIndex");
3298 if (endIndex
< 0 || endIndex
>= items
.Count
)
3299 throw new ArgumentOutOfRangeException ("endIndex");
3300 if (startIndex
> endIndex
)
3301 throw new ArgumentException ("startIndex");
3306 for (int i
= startIndex
; i
<= endIndex
; i
++)
3307 item_control
.Invalidate (items
[i
].Bounds
);
3309 if (!invalidateOnly
)
3318 throw new InvalidOperationException ();
3324 // we need this overload to reuse the logic for sorting, while allowing
3325 // redrawing to be done by caller or have it done by this method when
3326 // sorting is really performed
3328 // ListViewItemCollection's Add and AddRange methods call this overload
3329 // with redraw set to false, as they take care of redrawing themselves
3330 // (they even want to redraw the listview if no sort is performed, as
3331 // an item was added), while ListView.Sort () only wants to redraw if
3332 // sorting was actually performed
3333 private void Sort (bool redraw
)
3335 if (!IsHandleCreated
|| item_sorter
== null) {
3339 items
.Sort (item_sorter
);
3344 public override string ToString ()
3346 int count
= this.Items
.Count
;
3349 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
3351 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count
, this.Items
[0].ToString ());
3353 #endregion // Public Instance Methods
3358 class HeaderControl
: Control
{
3361 bool column_resize_active
= false;
3362 ColumnHeader resize_column
;
3363 ColumnHeader clicked_column
;
3364 ColumnHeader drag_column
;
3366 int drag_to_index
= -1;
3368 public HeaderControl (ListView owner
)
3371 MouseDown
+= new MouseEventHandler (HeaderMouseDown
);
3372 MouseMove
+= new MouseEventHandler (HeaderMouseMove
);
3373 MouseUp
+= new MouseEventHandler (HeaderMouseUp
);
3376 private ColumnHeader
ColumnAtX (int x
)
3378 Point pt
= new Point (x
, 0);
3379 ColumnHeader result
= null;
3380 foreach (ColumnHeader col
in owner
.Columns
) {
3381 if (col
.Rect
.Contains (pt
)) {
3389 private int GetReorderedIndex (ColumnHeader col
)
3391 if (owner
.reordered_column_indices
== null)
3394 for (int i
= 0; i
< owner
.Columns
.Count
; i
++)
3395 if (owner
.reordered_column_indices
[i
] == col
.Index
)
3397 throw new Exception ("Column index missing from reordered array");
3400 private void HeaderMouseDown (object sender
, MouseEventArgs me
)
3402 if (resize_column
!= null) {
3403 column_resize_active
= true;
3408 clicked_column
= ColumnAtX (me
.X
+ owner
.h_marker
);
3410 if (clicked_column
!= null) {
3412 if (owner
.AllowColumnReorder
) {
3414 drag_column
= (ColumnHeader
) (clicked_column
as ICloneable
).Clone ();
3415 drag_column
.Rect
= clicked_column
.Rect
;
3416 drag_to_index
= GetReorderedIndex (clicked_column
);
3418 clicked_column
.Pressed
= true;
3419 Rectangle bounds
= clicked_column
.Rect
;
3420 bounds
.X
-= owner
.h_marker
;
3421 Invalidate (bounds
);
3428 column_resize_active
= false;
3429 resize_column
= null;
3431 Cursor
= Cursors
.Default
;
3434 private void HeaderMouseMove (object sender
, MouseEventArgs me
)
3436 Point pt
= new Point (me
.X
+ owner
.h_marker
, me
.Y
);
3438 if (column_resize_active
) {
3439 int width
= pt
.X
- resize_column
.X
;
3443 if (!owner
.CanProceedWithResize (resize_column
, width
)){
3447 resize_column
.Width
= width
;
3451 resize_column
= null;
3453 if (clicked_column
!= null) {
3454 if (owner
.AllowColumnReorder
) {
3457 r
= drag_column
.Rect
;
3458 r
.X
= clicked_column
.Rect
.X
+ me
.X
- drag_x
;
3459 drag_column
.Rect
= r
;
3461 int x
= me
.X
+ owner
.h_marker
;
3462 ColumnHeader over
= ColumnAtX (x
);
3464 drag_to_index
= owner
.Columns
.Count
;
3465 else if (x
< over
.X
+ over
.Width
/ 2)
3466 drag_to_index
= GetReorderedIndex (over
);
3468 drag_to_index
= GetReorderedIndex (over
) + 1;
3471 ColumnHeader over
= ColumnAtX (me
.X
+ owner
.h_marker
);
3472 bool pressed
= clicked_column
.Pressed
;
3473 clicked_column
.Pressed
= over
== clicked_column
;
3474 if (clicked_column
.Pressed ^ pressed
) {
3475 Rectangle bounds
= clicked_column
.Rect
;
3476 bounds
.X
-= owner
.h_marker
;
3477 Invalidate (bounds
);
3483 for (int i
= 0; i
< owner
.Columns
.Count
; i
++) {
3484 Rectangle zone
= owner
.Columns
[i
].Rect
;
3485 zone
.X
= zone
.Right
- 5;
3487 if (zone
.Contains (pt
)) {
3488 if (i
< owner
.Columns
.Count
- 1 && owner
.Columns
[i
+ 1].Width
== 0)
3490 resize_column
= owner
.Columns
[i
];
3495 if (resize_column
== null)
3496 Cursor
= Cursors
.Default
;
3498 Cursor
= Cursors
.VSplit
;
3501 void HeaderMouseUp (object sender
, MouseEventArgs me
)
3505 if (column_resize_active
) {
3506 int column_idx
= resize_column
.Index
;
3508 owner
.RaiseColumnWidthChanged (column_idx
);
3512 if (clicked_column
!= null && clicked_column
.Pressed
) {
3513 clicked_column
.Pressed
= false;
3514 Rectangle bounds
= clicked_column
.Rect
;
3515 bounds
.X
-= owner
.h_marker
;
3516 Invalidate (bounds
);
3517 owner
.OnColumnClick (new ColumnClickEventArgs (clicked_column
.Index
));
3520 if (drag_column
!= null && owner
.AllowColumnReorder
) {
3522 if (drag_to_index
> GetReorderedIndex (clicked_column
))
3524 if (owner
.GetReorderedColumn (drag_to_index
) != clicked_column
)
3525 owner
.ReorderColumn (clicked_column
, drag_to_index
, true);
3530 clicked_column
= null;
3533 internal override void OnPaintInternal (PaintEventArgs pe
)
3538 Theme theme
= ThemeEngine
.Current
;
3539 theme
.DrawListViewHeader (pe
.Graphics
, pe
.ClipRectangle
, this.owner
);
3541 if (drag_column
== null)
3545 if (drag_to_index
== owner
.Columns
.Count
)
3546 target_x
= owner
.GetReorderedColumn (drag_to_index
- 1).Rect
.Right
- owner
.h_marker
;
3548 target_x
= owner
.GetReorderedColumn (drag_to_index
).Rect
.X
- owner
.h_marker
;
3549 theme
.DrawListViewHeaderDragDetails (pe
.Graphics
, owner
, drag_column
, target_x
);
3552 protected override void WndProc (ref Message m
)
3554 switch ((Msg
)m
.Msg
) {
3555 case Msg
.WM_SETFOCUS
:
3559 base.WndProc (ref m
);
3565 private class ItemComparer
: IComparer
{
3566 readonly SortOrder sort_order
;
3568 public ItemComparer (SortOrder sortOrder
)
3570 sort_order
= sortOrder
;
3573 public int Compare (object x
, object y
)
3575 ListViewItem item_x
= x
as ListViewItem
;
3576 ListViewItem item_y
= y
as ListViewItem
;
3577 if (sort_order
== SortOrder
.Ascending
)
3578 return String
.Compare (item_x
.Text
, item_y
.Text
);
3580 return String
.Compare (item_y
.Text
, item_x
.Text
);
3584 public class CheckedIndexCollection
: IList
, ICollection
, IEnumerable
3586 private readonly ListView owner
;
3588 #region Public Constructor
3589 public CheckedIndexCollection (ListView owner
)
3593 #endregion // Public Constructor
3595 #region Public Properties
3598 get { return owner.CheckedItems.Count; }
3601 public bool IsReadOnly
{
3602 get { return true; }
3605 public int this [int index
] {
3607 int [] indices
= GetIndices ();
3608 if (index
< 0 || index
>= indices
.Length
)
3609 throw new ArgumentOutOfRangeException ("index");
3610 return indices
[index
];
3614 bool ICollection
.IsSynchronized
{
3615 get { return false; }
3618 object ICollection
.SyncRoot
{
3619 get { return this; }
3622 bool IList
.IsFixedSize
{
3623 get { return true; }
3626 object IList
.this [int index
] {
3627 get { return this [index]; }
3628 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3630 #endregion // Public Properties
3632 #region Public Methods
3633 public bool Contains (int checkedIndex
)
3635 int [] indices
= GetIndices ();
3636 for (int i
= 0; i
< indices
.Length
; i
++) {
3637 if (indices
[i
] == checkedIndex
)
3643 public IEnumerator
GetEnumerator ()
3645 int [] indices
= GetIndices ();
3646 return indices
.GetEnumerator ();
3649 void ICollection
.CopyTo (Array dest
, int index
)
3651 int [] indices
= GetIndices ();
3652 Array
.Copy (indices
, 0, dest
, index
, indices
.Length
);
3655 int IList
.Add (object value)
3657 throw new NotSupportedException ("Add operation is not supported.");
3662 throw new NotSupportedException ("Clear operation is not supported.");
3665 bool IList
.Contains (object checkedIndex
)
3667 if (!(checkedIndex
is int))
3669 return Contains ((int) checkedIndex
);
3672 int IList
.IndexOf (object checkedIndex
)
3674 if (!(checkedIndex
is int))
3676 return IndexOf ((int) checkedIndex
);
3679 void IList
.Insert (int index
, object value)
3681 throw new NotSupportedException ("Insert operation is not supported.");
3684 void IList
.Remove (object value)
3686 throw new NotSupportedException ("Remove operation is not supported.");
3689 void IList
.RemoveAt (int index
)
3691 throw new NotSupportedException ("RemoveAt operation is not supported.");
3694 public int IndexOf (int checkedIndex
)
3696 int [] indices
= GetIndices ();
3697 for (int i
= 0; i
< indices
.Length
; i
++) {
3698 if (indices
[i
] == checkedIndex
)
3703 #endregion // Public Methods
3705 private int [] GetIndices ()
3707 ArrayList checked_items
= owner
.CheckedItems
.List
;
3708 int [] indices
= new int [checked_items
.Count
];
3709 for (int i
= 0; i
< checked_items
.Count
; i
++) {
3710 ListViewItem item
= (ListViewItem
) checked_items
[i
];
3711 indices
[i
] = item
.Index
;
3715 } // CheckedIndexCollection
3717 public class CheckedListViewItemCollection
: IList
, ICollection
, IEnumerable
3719 private readonly ListView owner
;
3720 private ArrayList list
;
3722 #region Public Constructor
3723 public CheckedListViewItemCollection (ListView owner
)
3726 this.owner
.Items
.Changed
+= new CollectionChangedHandler (
3727 ItemsCollection_Changed
);
3729 #endregion // Public Constructor
3731 #region Public Properties
3735 if (!owner
.CheckBoxes
)
3741 public bool IsReadOnly
{
3742 get { return true; }
3745 public ListViewItem
this [int index
] {
3748 if (owner
.VirtualMode
)
3749 throw new InvalidOperationException ();
3751 ArrayList checked_items
= List
;
3752 if (index
< 0 || index
>= checked_items
.Count
)
3753 throw new ArgumentOutOfRangeException ("index");
3754 return (ListViewItem
) checked_items
[index
];
3759 public virtual ListViewItem
this [string key
] {
3761 int idx
= IndexOfKey (key
);
3762 return idx
== -1 ? null : (ListViewItem
) List
[idx
];
3767 bool ICollection
.IsSynchronized
{
3768 get { return false; }
3771 object ICollection
.SyncRoot
{
3772 get { return this; }
3775 bool IList
.IsFixedSize
{
3776 get { return true; }
3779 object IList
.this [int index
] {
3780 get { return this [index]; }
3781 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3783 #endregion // Public Properties
3785 #region Public Methods
3786 public bool Contains (ListViewItem item
)
3788 if (!owner
.CheckBoxes
)
3790 return List
.Contains (item
);
3794 public virtual bool ContainsKey (string key
)
3796 return IndexOfKey (key
) != -1;
3800 public void CopyTo (Array dest
, int index
)
3803 if (owner
.VirtualMode
)
3804 throw new InvalidOperationException ();
3806 if (!owner
.CheckBoxes
)
3808 List
.CopyTo (dest
, index
);
3811 public IEnumerator
GetEnumerator ()
3814 if (owner
.VirtualMode
)
3815 throw new InvalidOperationException ();
3817 if (!owner
.CheckBoxes
)
3818 return (new ListViewItem
[0]).GetEnumerator ();
3819 return List
.GetEnumerator ();
3822 int IList
.Add (object value)
3824 throw new NotSupportedException ("Add operation is not supported.");
3829 throw new NotSupportedException ("Clear operation is not supported.");
3832 bool IList
.Contains (object item
)
3834 if (!(item
is ListViewItem
))
3836 return Contains ((ListViewItem
) item
);
3839 int IList
.IndexOf (object item
)
3841 if (!(item
is ListViewItem
))
3843 return IndexOf ((ListViewItem
) item
);
3846 void IList
.Insert (int index
, object value)
3848 throw new NotSupportedException ("Insert operation is not supported.");
3851 void IList
.Remove (object value)
3853 throw new NotSupportedException ("Remove operation is not supported.");
3856 void IList
.RemoveAt (int index
)
3858 throw new NotSupportedException ("RemoveAt operation is not supported.");
3861 public int IndexOf (ListViewItem item
)
3864 if (owner
.VirtualMode
)
3865 throw new InvalidOperationException ();
3867 if (!owner
.CheckBoxes
)
3869 return List
.IndexOf (item
);
3873 public virtual int IndexOfKey (string key
)
3876 if (owner
.VirtualMode
)
3877 throw new InvalidOperationException ();
3879 if (key
== null || key
.Length
== 0)
3882 ArrayList checked_items
= List
;
3883 for (int i
= 0; i
< checked_items
.Count
; i
++) {
3884 ListViewItem item
= (ListViewItem
) checked_items
[i
];
3885 if (String
.Compare (key
, item
.Name
, true) == 0)
3892 #endregion // Public Methods
3894 internal ArrayList List
{
3897 list
= new ArrayList ();
3898 foreach (ListViewItem item
in owner
.Items
) {
3907 internal void Reset ()
3909 // force re-population of list
3913 private void ItemsCollection_Changed ()
3917 } // CheckedListViewItemCollection
3919 public class ColumnHeaderCollection
: IList
, ICollection
, IEnumerable
3921 internal ArrayList list
;
3922 private ListView owner
;
3924 #region Public Constructor
3925 public ColumnHeaderCollection (ListView owner
)
3927 list
= new ArrayList ();
3930 #endregion // Public Constructor
3932 #region Public Properties
3935 get { return list.Count; }
3938 public bool IsReadOnly
{
3939 get { return false; }
3942 public virtual ColumnHeader
this [int index
] {
3944 if (index
< 0 || index
>= list
.Count
)
3945 throw new ArgumentOutOfRangeException ("index");
3946 return (ColumnHeader
) list
[index
];
3951 public virtual ColumnHeader
this [string key
] {
3953 int idx
= IndexOfKey (key
);
3957 return (ColumnHeader
) list
[idx
];
3962 bool ICollection
.IsSynchronized
{
3963 get { return true; }
3966 object ICollection
.SyncRoot
{
3967 get { return this; }
3970 bool IList
.IsFixedSize
{
3971 get { return list.IsFixedSize; }
3974 object IList
.this [int index
] {
3975 get { return this [index]; }
3976 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3978 #endregion // Public Properties
3980 #region Public Methods
3981 public virtual int Add (ColumnHeader
value)
3983 int idx
= list
.Add (value);
3984 owner
.AddColumn (value, idx
, true);
3988 public virtual ColumnHeader
Add (string str
, int width
, HorizontalAlignment textAlign
)
3990 ColumnHeader colHeader
= new ColumnHeader (this.owner
, str
, textAlign
, width
);
3991 this.Add (colHeader
);
3996 public virtual ColumnHeader
Add (string text
)
3998 return Add (String
.Empty
, text
);
4001 public virtual ColumnHeader
Add (string text
, int iwidth
)
4003 return Add (String
.Empty
, text
, iwidth
);
4006 public virtual ColumnHeader
Add (string key
, string text
)
4008 ColumnHeader colHeader
= new ColumnHeader ();
4009 colHeader
.Name
= key
;
4010 colHeader
.Text
= text
;
4015 public virtual ColumnHeader
Add (string key
, string text
, int iwidth
)
4017 return Add (key
, text
, iwidth
, HorizontalAlignment
.Left
, -1);
4020 public virtual ColumnHeader
Add (string key
, string text
, int iwidth
, HorizontalAlignment textAlign
, int imageIndex
)
4022 ColumnHeader colHeader
= new ColumnHeader (key
, text
, iwidth
, textAlign
);
4023 colHeader
.ImageIndex
= imageIndex
;
4028 public virtual ColumnHeader
Add (string key
, string text
, int iwidth
, HorizontalAlignment textAlign
, string imageKey
)
4030 ColumnHeader colHeader
= new ColumnHeader (key
, text
, iwidth
, textAlign
);
4031 colHeader
.ImageKey
= imageKey
;
4037 public virtual void AddRange (ColumnHeader
[] values
)
4039 foreach (ColumnHeader colHeader
in values
) {
4040 int idx
= list
.Add (colHeader
);
4041 owner
.AddColumn (colHeader
, idx
, false);
4044 owner
.Redraw (true);
4047 public virtual void Clear ()
4049 foreach (ColumnHeader col
in list
)
4050 col
.SetListView (null);
4052 owner
.ReorderColumns (new int [0], true);
4055 public bool Contains (ColumnHeader
value)
4057 return list
.Contains (value);
4061 public virtual bool ContainsKey (string key
)
4063 return IndexOfKey (key
) != -1;
4067 public IEnumerator
GetEnumerator ()
4069 return list
.GetEnumerator ();
4072 void ICollection
.CopyTo (Array dest
, int index
)
4074 list
.CopyTo (dest
, index
);
4077 int IList
.Add (object value)
4079 if (! (value is ColumnHeader
)) {
4080 throw new ArgumentException ("Not of type ColumnHeader", "value");
4083 return this.Add ((ColumnHeader
) value);
4086 bool IList
.Contains (object value)
4088 if (! (value is ColumnHeader
)) {
4089 throw new ArgumentException ("Not of type ColumnHeader", "value");
4092 return this.Contains ((ColumnHeader
) value);
4095 int IList
.IndexOf (object value)
4097 if (! (value is ColumnHeader
)) {
4098 throw new ArgumentException ("Not of type ColumnHeader", "value");
4101 return this.IndexOf ((ColumnHeader
) value);
4104 void IList
.Insert (int index
, object value)
4106 if (! (value is ColumnHeader
)) {
4107 throw new ArgumentException ("Not of type ColumnHeader", "value");
4110 this.Insert (index
, (ColumnHeader
) value);
4113 void IList
.Remove (object value)
4115 if (! (value is ColumnHeader
)) {
4116 throw new ArgumentException ("Not of type ColumnHeader", "value");
4119 this.Remove ((ColumnHeader
) value);
4122 public int IndexOf (ColumnHeader
value)
4124 return list
.IndexOf (value);
4128 public virtual int IndexOfKey (string key
)
4130 if (key
== null || key
.Length
== 0)
4133 for (int i
= 0; i
< list
.Count
; i
++) {
4134 ColumnHeader col
= (ColumnHeader
) list
[i
];
4135 if (String
.Compare (key
, col
.Name
, true) == 0)
4143 public void Insert (int index
, ColumnHeader
value)
4145 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
4146 // but it's really only greater.
4147 if (index
< 0 || index
> list
.Count
)
4148 throw new ArgumentOutOfRangeException ("index");
4150 list
.Insert (index
, value);
4151 owner
.AddColumn (value, index
, true);
4155 public void Insert (int index
, string text
)
4157 Insert (index
, String
.Empty
, text
);
4160 public void Insert (int index
, string text
, int width
)
4162 Insert (index
, String
.Empty
, text
, width
);
4165 public void Insert (int index
, string key
, string text
)
4167 ColumnHeader colHeader
= new ColumnHeader ();
4168 colHeader
.Name
= key
;
4169 colHeader
.Text
= text
;
4170 Insert (index
, colHeader
);
4173 public void Insert (int index
, string key
, string text
, int width
)
4175 ColumnHeader colHeader
= new ColumnHeader (key
, text
, width
, HorizontalAlignment
.Left
);
4176 Insert (index
, colHeader
);
4179 public void Insert (int index
, string key
, string text
, int width
, HorizontalAlignment textAlign
, int imageIndex
)
4181 ColumnHeader colHeader
= new ColumnHeader (key
, text
, width
, textAlign
);
4182 colHeader
.ImageIndex
= imageIndex
;
4183 Insert (index
, colHeader
);
4186 public void Insert (int index
, string key
, string text
, int width
, HorizontalAlignment textAlign
, string imageKey
)
4188 ColumnHeader colHeader
= new ColumnHeader (key
, text
, width
, textAlign
);
4189 colHeader
.ImageKey
= imageKey
;
4190 Insert (index
, colHeader
);
4194 public void Insert (int index
, string str
, int width
, HorizontalAlignment textAlign
)
4196 ColumnHeader colHeader
= new ColumnHeader (this.owner
, str
, textAlign
, width
);
4197 this.Insert (index
, colHeader
);
4200 public virtual void Remove (ColumnHeader column
)
4202 if (!Contains (column
))
4205 list
.Remove (column
);
4206 column
.SetListView (null);
4208 int rem_display_index
= column
.InternalDisplayIndex
;
4209 int [] display_indices
= new int [list
.Count
];
4210 for (int i
= 0; i
< display_indices
.Length
; i
++) {
4211 ColumnHeader col
= (ColumnHeader
) list
[i
];
4212 int display_index
= col
.InternalDisplayIndex
;
4213 if (display_index
< rem_display_index
) {
4214 display_indices
[i
] = display_index
;
4216 display_indices
[i
] = (display_index
- 1);
4220 column
.InternalDisplayIndex
= -1;
4221 owner
.ReorderColumns (display_indices
, true);
4225 public virtual void RemoveByKey (string key
)
4227 int idx
= IndexOfKey (key
);
4233 public virtual void RemoveAt (int index
)
4235 if (index
< 0 || index
>= list
.Count
)
4236 throw new ArgumentOutOfRangeException ("index");
4238 ColumnHeader col
= (ColumnHeader
) list
[index
];
4241 #endregion // Public Methods
4244 } // ColumnHeaderCollection
4246 public class ListViewItemCollection
: IList
, ICollection
, IEnumerable
4248 private readonly ArrayList list
;
4249 private ListView owner
;
4251 private ListViewGroup
group;
4254 // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
4255 // In the later case ListViewItem.ListView never gets modified
4256 private bool is_main_collection
= true;
4258 #region Public Constructor
4259 public ListViewItemCollection (ListView owner
)
4261 list
= new ArrayList (0);
4264 #endregion // Public Constructor
4267 internal ListViewItemCollection (ListView owner
, ListViewGroup
group) : this (owner
)
4270 is_main_collection
= false;
4274 #region Public Properties
4279 if (owner
!= null && owner
.VirtualMode
)
4280 return owner
.VirtualListSize
;
4287 public bool IsReadOnly
{
4288 get { return false; }
4291 public virtual ListViewItem
this [int displayIndex
] {
4293 if (displayIndex
< 0 || displayIndex
>= Count
)
4294 throw new ArgumentOutOfRangeException ("displayIndex");
4297 if (owner
!= null && owner
.VirtualMode
)
4298 return RetrieveVirtualItemFromOwner (displayIndex
);
4300 return (ListViewItem
) list
[displayIndex
];
4304 if (displayIndex
< 0 || displayIndex
>= Count
)
4305 throw new ArgumentOutOfRangeException ("displayIndex");
4308 if (owner
!= null && owner
.VirtualMode
)
4309 throw new InvalidOperationException ();
4312 if (list
.Contains (value))
4313 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4315 if (value.ListView
!= null && value.ListView
!= owner
)
4316 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");
4318 if (is_main_collection
)
4319 value.Owner
= owner
;
4322 if (value.Group
!= null)
4323 value.Group
.Items
.Remove (value);
4325 value.SetGroup (group);
4329 list
[displayIndex
] = value;
4330 CollectionChanged (true);
4335 public virtual ListViewItem
this [string key
] {
4337 int idx
= IndexOfKey (key
);
4346 bool ICollection
.IsSynchronized
{
4347 get { return true; }
4350 object ICollection
.SyncRoot
{
4351 get { return this; }
4354 bool IList
.IsFixedSize
{
4355 get { return list.IsFixedSize; }
4358 object IList
.this [int index
] {
4359 get { return this [index]; }
4361 if (value is ListViewItem
)
4362 this [index
] = (ListViewItem
) value;
4364 this [index
] = new ListViewItem (value.ToString ());
4368 #endregion // Public Properties
4370 #region Public Methods
4371 public virtual ListViewItem
Add (ListViewItem
value)
4374 if (owner
!= null && owner
.VirtualMode
)
4375 throw new InvalidOperationException ();
4379 CollectionChanged (true);
4384 public virtual ListViewItem
Add (string text
)
4386 ListViewItem item
= new ListViewItem (text
);
4387 return this.Add (item
);
4390 public virtual ListViewItem
Add (string text
, int imageIndex
)
4392 ListViewItem item
= new ListViewItem (text
, imageIndex
);
4393 return this.Add (item
);
4397 public virtual ListViewItem
Add (string text
, string imageKey
)
4399 ListViewItem item
= new ListViewItem (text
, imageKey
);
4400 return this.Add (item
);
4403 public virtual ListViewItem
Add (string key
, string text
, int imageIndex
)
4405 ListViewItem item
= new ListViewItem (text
, imageIndex
);
4407 return this.Add (item
);
4410 public virtual ListViewItem
Add (string key
, string text
, string imageKey
)
4412 ListViewItem item
= new ListViewItem (text
, imageKey
);
4414 return this.Add (item
);
4418 public void AddRange (ListViewItem
[] values
)
4421 throw new ArgumentNullException ("Argument cannot be null!", "values");
4423 if (owner
!= null && owner
.VirtualMode
)
4424 throw new InvalidOperationException ();
4427 foreach (ListViewItem item
in values
)
4430 CollectionChanged (true);
4434 public void AddRange (ListViewItemCollection items
)
4437 throw new ArgumentNullException ("Argument cannot be null!", "items");
4439 ListViewItem
[] itemArray
= new ListViewItem
[items
.Count
];
4440 items
.CopyTo (itemArray
,0);
4441 this.AddRange (itemArray
);
4445 public virtual void Clear ()
4448 if (owner
!= null && owner
.VirtualMode
)
4449 throw new InvalidOperationException ();
4451 if (is_main_collection
&& owner
!= null) {
4452 owner
.SetFocusedItem (-1);
4453 owner
.h_scroll
.Value
= owner
.v_scroll
.Value
= 0;
4455 foreach (ListViewItem item
in list
) {
4456 owner
.item_control
.CancelEdit (item
);
4463 foreach (ListViewItem item
in list
)
4464 item
.SetGroup (null);
4468 CollectionChanged (false);
4471 public bool Contains (ListViewItem item
)
4473 return IndexOf (item
) != -1;
4477 public virtual bool ContainsKey (string key
)
4479 return IndexOfKey (key
) != -1;
4483 public void CopyTo (Array dest
, int index
)
4485 list
.CopyTo (dest
, index
);
4489 public ListViewItem
[] Find (string key
, bool searchAllSubitems
)
4492 return new ListViewItem
[0];
4494 List
<ListViewItem
> temp_list
= new List
<ListViewItem
> ();
4496 for (int i
= 0; i
< list
.Count
; i
++) {
4497 ListViewItem lvi
= (ListViewItem
) list
[i
];
4498 if (String
.Compare (key
, lvi
.Name
, true) == 0)
4499 temp_list
.Add (lvi
);
4502 ListViewItem
[] retval
= new ListViewItem
[temp_list
.Count
];
4503 temp_list
.CopyTo (retval
);
4509 public IEnumerator
GetEnumerator ()
4512 if (owner
!= null && owner
.VirtualMode
)
4513 throw new InvalidOperationException ();
4516 return list
.GetEnumerator ();
4519 int IList
.Add (object item
)
4525 if (owner
!= null && owner
.VirtualMode
)
4526 throw new InvalidOperationException ();
4529 if (item
is ListViewItem
) {
4530 li
= (ListViewItem
) item
;
4531 if (list
.Contains (li
))
4532 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
4534 if (li
.ListView
!= null && li
.ListView
!= owner
)
4535 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");
4538 li
= new ListViewItem (item
.ToString ());
4541 result
= list
.Add (li
);
4542 CollectionChanged (true);
4547 bool IList
.Contains (object item
)
4549 return Contains ((ListViewItem
) item
);
4552 int IList
.IndexOf (object item
)
4554 return IndexOf ((ListViewItem
) item
);
4557 void IList
.Insert (int index
, object item
)
4559 if (item
is ListViewItem
)
4560 this.Insert (index
, (ListViewItem
) item
);
4562 this.Insert (index
, item
.ToString ());
4565 void IList
.Remove (object item
)
4567 Remove ((ListViewItem
) item
);
4570 public int IndexOf (ListViewItem item
)
4573 if (owner
!= null && owner
.VirtualMode
) {
4574 for (int i
= 0; i
< Count
; i
++)
4575 if (RetrieveVirtualItemFromOwner (i
) == item
)
4582 return list
.IndexOf (item
);
4586 public virtual int IndexOfKey (string key
)
4588 if (key
== null || key
.Length
== 0)
4591 for (int i
= 0; i
< Count
; i
++) {
4592 ListViewItem lvi
= this [i
];
4593 if (String
.Compare (key
, lvi
.Name
, true) == 0)
4601 public ListViewItem
Insert (int index
, ListViewItem item
)
4603 if (index
< 0 || index
> list
.Count
)
4604 throw new ArgumentOutOfRangeException ("index");
4607 if (owner
!= null && owner
.VirtualMode
)
4608 throw new InvalidOperationException ();
4611 if (list
.Contains (item
))
4612 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
4614 if (item
.ListView
!= null && item
.ListView
!= owner
)
4615 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");
4617 if (is_main_collection
)
4621 if (item
.Group
!= null)
4622 item
.Group
.Items
.Remove (item
);
4624 item
.SetGroup (group);
4628 list
.Insert (index
, item
);
4629 CollectionChanged (true);
4633 public ListViewItem
Insert (int index
, string text
)
4635 return this.Insert (index
, new ListViewItem (text
));
4638 public ListViewItem
Insert (int index
, string text
, int imageIndex
)
4640 return this.Insert (index
, new ListViewItem (text
, imageIndex
));
4644 public ListViewItem
Insert (int index
, string key
, string text
, int imageIndex
)
4646 ListViewItem lvi
= new ListViewItem (text
, imageIndex
);
4648 return Insert (index
, lvi
);
4652 public virtual void Remove (ListViewItem item
)
4655 if (owner
!= null && owner
.VirtualMode
)
4656 throw new InvalidOperationException ();
4658 if (!list
.Contains (item
))
4661 bool selection_changed
= false;
4662 if (is_main_collection
&& owner
!= null) {
4663 selection_changed
= owner
.SelectedItems
.Contains (item
);
4664 owner
.item_control
.CancelEdit (item
);
4669 if (is_main_collection
)
4673 item
.SetGroup (null);
4676 CollectionChanged (false);
4677 if (selection_changed
&& owner
!= null)
4678 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
4681 public virtual void RemoveAt (int index
)
4683 if (index
< 0 || index
>= Count
)
4684 throw new ArgumentOutOfRangeException ("index");
4687 if (owner
!= null && owner
.VirtualMode
)
4688 throw new InvalidOperationException ();
4691 ListViewItem item
= (ListViewItem
) list
[index
];
4696 public virtual void RemoveByKey (string key
)
4698 int idx
= IndexOfKey (key
);
4704 #endregion // Public Methods
4706 internal ListView Owner
{
4716 internal ListViewGroup Group
{
4726 void AddItem (ListViewItem
value)
4728 if (list
.Contains (value))
4729 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4731 if (value.ListView
!= null && value.ListView
!= owner
)
4732 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");
4733 if (is_main_collection
)
4734 value.Owner
= owner
;
4737 if (value.Group
!= null)
4738 value.Group
.Items
.Remove (value);
4740 value.SetGroup (group);
4747 void CollectionChanged (bool sort
)
4749 if (owner
!= null) {
4754 owner
.Redraw (true);
4759 ListViewItem
RetrieveVirtualItemFromOwner (int displayIndex
)
4761 RetrieveVirtualItemEventArgs args
= new RetrieveVirtualItemEventArgs (displayIndex
);
4763 owner
.OnRetrieveVirtualItem (args
);
4764 ListViewItem retval
= args
.Item
;
4765 retval
.Owner
= owner
;
4766 retval
.SetIndex (displayIndex
);
4772 internal event CollectionChangedHandler Changed
;
4774 internal void Sort (IComparer comparer
)
4776 list
.Sort (comparer
);
4780 internal void OnChange ()
4782 if (Changed
!= null)
4785 } // ListViewItemCollection
4788 // In normal mode, the selection information resides in the Items,
4789 // making SelectedIndexCollection.List read-only
4791 // In virtual mode, SelectedIndexCollection directly saves the selection
4792 // information, instead of getting it from Items, making List read-and-write
4793 public class SelectedIndexCollection
: IList
, ICollection
, IEnumerable
4795 private readonly ListView owner
;
4796 private ArrayList list
;
4798 #region Public Constructor
4799 public SelectedIndexCollection (ListView owner
)
4802 owner
.Items
.Changed
+= new CollectionChangedHandler (ItemsCollection_Changed
);
4804 #endregion // Public Constructor
4806 #region Public Properties
4810 if (!owner
.IsHandleCreated
)
4817 public bool IsReadOnly
{
4827 public int this [int index
] {
4829 if (!owner
.IsHandleCreated
|| index
< 0 || index
>= List
.Count
)
4830 throw new ArgumentOutOfRangeException ("index");
4832 return (int) List
[index
];
4836 bool ICollection
.IsSynchronized
{
4837 get { return false; }
4840 object ICollection
.SyncRoot
{
4841 get { return this; }
4844 bool IList
.IsFixedSize
{
4854 object IList
.this [int index
] {
4855 get { return this [index]; }
4856 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4858 #endregion // Public Properties
4860 #region Public Methods
4862 public int Add (int itemIndex
)
4864 if (itemIndex
< 0 || itemIndex
>= owner
.Items
.Count
)
4865 throw new ArgumentOutOfRangeException ("index");
4867 if (owner
.virtual_mode
&& !owner
.IsHandleCreated
)
4870 owner
.Items
[itemIndex
].Selected
= true;
4872 if (!owner
.IsHandleCreated
)
4886 if (!owner
.IsHandleCreated
)
4889 int [] indexes
= (int []) List
.ToArray (typeof (int));
4890 foreach (int index
in indexes
)
4891 owner
.Items
[index
].Selected
= false;
4894 public bool Contains (int selectedIndex
)
4896 return IndexOf (selectedIndex
) != -1;
4899 public void CopyTo (Array dest
, int index
)
4901 List
.CopyTo (dest
, index
);
4904 public IEnumerator
GetEnumerator ()
4906 return List
.GetEnumerator ();
4909 int IList
.Add (object value)
4911 throw new NotSupportedException ("Add operation is not supported.");
4919 bool IList
.Contains (object selectedIndex
)
4921 if (!(selectedIndex
is int))
4923 return Contains ((int) selectedIndex
);
4926 int IList
.IndexOf (object selectedIndex
)
4928 if (!(selectedIndex
is int))
4930 return IndexOf ((int) selectedIndex
);
4933 void IList
.Insert (int index
, object value)
4935 throw new NotSupportedException ("Insert operation is not supported.");
4938 void IList
.Remove (object value)
4940 throw new NotSupportedException ("Remove operation is not supported.");
4943 void IList
.RemoveAt (int index
)
4945 throw new NotSupportedException ("RemoveAt operation is not supported.");
4948 public int IndexOf (int selectedIndex
)
4950 if (!owner
.IsHandleCreated
)
4953 return List
.IndexOf (selectedIndex
);
4957 public void Remove (int itemIndex
)
4959 if (itemIndex
< 0 || itemIndex
>= owner
.Items
.Count
)
4960 throw new ArgumentOutOfRangeException ("itemIndex");
4962 owner
.Items
[itemIndex
].Selected
= false;
4965 #endregion // Public Methods
4967 internal ArrayList List
{
4970 list
= new ArrayList ();
4972 if (!owner
.VirtualMode
)
4974 for (int i
= 0; i
< owner
.Items
.Count
; i
++) {
4975 if (owner
.Items
[i
].Selected
)
4983 internal void Reset ()
4985 // force re-population of list
4987 if (!owner
.VirtualMode
)
4992 private void ItemsCollection_Changed ()
4998 internal void RemoveIndex (int index
)
5000 int idx
= List
.BinarySearch (index
);
5002 List
.RemoveAt (idx
);
5005 // actually store index in the collection
5006 // also, keep the collection sorted, as .Net does
5007 internal void InsertIndex (int index
)
5010 int iMax
= List
.Count
- 1;
5011 while (iMin
<= iMax
) {
5012 int iMid
= (iMin
+ iMax
) / 2;
5013 int current_index
= (int) List
[iMid
];
5015 if (current_index
== index
)
5016 return; // Already added
5017 if (current_index
> index
)
5023 List
.Insert (iMin
, index
);
5027 } // SelectedIndexCollection
5029 public class SelectedListViewItemCollection
: IList
, ICollection
, IEnumerable
5031 private readonly ListView owner
;
5033 #region Public Constructor
5034 public SelectedListViewItemCollection (ListView owner
)
5038 #endregion // Public Constructor
5040 #region Public Properties
5044 return owner
.SelectedIndices
.Count
;
5048 public bool IsReadOnly
{
5049 get { return true; }
5052 public ListViewItem
this [int index
] {
5054 if (!owner
.IsHandleCreated
|| index
< 0 || index
>= Count
)
5055 throw new ArgumentOutOfRangeException ("index");
5057 int item_index
= owner
.SelectedIndices
[index
];
5058 return owner
.Items
[item_index
];
5063 public virtual ListViewItem
this [string key
] {
5065 int idx
= IndexOfKey (key
);
5074 bool ICollection
.IsSynchronized
{
5075 get { return false; }
5078 object ICollection
.SyncRoot
{
5079 get { return this; }
5082 bool IList
.IsFixedSize
{
5083 get { return true; }
5086 object IList
.this [int index
] {
5087 get { return this [index]; }
5088 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5090 #endregion // Public Properties
5092 #region Public Methods
5093 public void Clear ()
5095 owner
.SelectedIndices
.Clear ();
5098 public bool Contains (ListViewItem item
)
5100 return IndexOf (item
) != -1;
5104 public virtual bool ContainsKey (string key
)
5106 return IndexOfKey (key
) != -1;
5110 public void CopyTo (Array dest
, int index
)
5112 if (!owner
.IsHandleCreated
)
5114 if (index
> Count
) // Throws ArgumentException instead of IOOR exception
5115 throw new ArgumentException ("index");
5117 for (int i
= 0; i
< Count
; i
++)
5118 dest
.SetValue (this [i
], index
++);
5121 public IEnumerator
GetEnumerator ()
5123 if (!owner
.IsHandleCreated
)
5124 return (new ListViewItem
[0]).GetEnumerator ();
5126 ListViewItem
[] items
= new ListViewItem
[Count
];
5127 for (int i
= 0; i
< Count
; i
++)
5128 items
[i
] = this [i
];
5130 return items
.GetEnumerator ();
5133 int IList
.Add (object value)
5135 throw new NotSupportedException ("Add operation is not supported.");
5138 bool IList
.Contains (object item
)
5140 if (!(item
is ListViewItem
))
5142 return Contains ((ListViewItem
) item
);
5145 int IList
.IndexOf (object item
)
5147 if (!(item
is ListViewItem
))
5149 return IndexOf ((ListViewItem
) item
);
5152 void IList
.Insert (int index
, object value)
5154 throw new NotSupportedException ("Insert operation is not supported.");
5157 void IList
.Remove (object value)
5159 throw new NotSupportedException ("Remove operation is not supported.");
5162 void IList
.RemoveAt (int index
)
5164 throw new NotSupportedException ("RemoveAt operation is not supported.");
5167 public int IndexOf (ListViewItem item
)
5169 if (!owner
.IsHandleCreated
)
5172 for (int i
= 0; i
< Count
; i
++)
5173 if (this [i
] == item
)
5180 public virtual int IndexOfKey (string key
)
5182 if (!owner
.IsHandleCreated
|| key
== null || key
.Length
== 0)
5185 for (int i
= 0; i
< Count
; i
++) {
5186 ListViewItem item
= this [i
];
5187 if (String
.Compare (item
.Name
, key
, true) == 0)
5194 #endregion // Public Methods
5196 } // SelectedListViewItemCollection
5198 internal delegate void CollectionChangedHandler ();
5200 struct ItemMatrixLocation
5205 public ItemMatrixLocation (int row
, int col
)
5232 #endregion // Subclasses
5234 protected override void OnResize (EventArgs e
)
5239 protected override void OnMouseLeave (EventArgs e
)
5241 base.OnMouseLeave (e
);
5245 // ColumnReorder event
5247 static object ColumnReorderedEvent
= new object ();
5248 public event ColumnReorderedEventHandler ColumnReordered
{
5249 add { Events.AddHandler (ColumnReorderedEvent, value); }
5250 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
5253 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e
)
5255 ColumnReorderedEventHandler creh
= (ColumnReorderedEventHandler
) (Events
[ColumnReorderedEvent
]);
5262 // ColumnWidthChanged
5264 static object ColumnWidthChangedEvent
= new object ();
5265 public event ColumnWidthChangedEventHandler ColumnWidthChanged
{
5266 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
5267 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
5270 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e
)
5272 ColumnWidthChangedEventHandler eh
= (ColumnWidthChangedEventHandler
) (Events
[ColumnWidthChangedEvent
]);
5277 void RaiseColumnWidthChanged (int resize_column
)
5279 ColumnWidthChangedEventArgs n
= new ColumnWidthChangedEventArgs (resize_column
);
5281 OnColumnWidthChanged (n
);
5285 // ColumnWidthChanging
5287 static object ColumnWidthChangingEvent
= new object ();
5288 public event ColumnWidthChangingEventHandler ColumnWidthChanging
{
5289 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
5290 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
5293 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e
)
5295 ColumnWidthChangingEventHandler cwceh
= (ColumnWidthChangingEventHandler
) (Events
[ColumnWidthChangingEvent
]);
5301 // 2.0 profile based implementation
5303 bool CanProceedWithResize (ColumnHeader col
, int width
)
5305 ColumnWidthChangingEventHandler cwceh
= (ColumnWidthChangingEventHandler
) (Events
[ColumnWidthChangingEvent
]);
5309 ColumnWidthChangingEventArgs changing
= new ColumnWidthChangingEventArgs (col
.Index
, width
);
5310 cwceh (this, changing
);
5311 return !changing
.Cancel
;
5315 // 1.0 profile based implementation
5317 bool CanProceedWithResize (ColumnHeader col
, int width
)
5322 void RaiseColumnWidthChanged (int resize_column
)