2007-08-14 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mcs.git] / class / Managed.Windows.Forms / System.Windows.Forms / ListView.cs
blob7a47605903a679247674138580c7766361699f21
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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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)
22 // Authors:
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)
28 // TODO:
29 // - Drag and drop
32 // NOT COMPLETE
35 using System.Collections;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
38 using System.Drawing;
39 using System.Runtime.InteropServices;
40 using System.Globalization;
41 #if NET_2_0
42 using System.Collections.Generic;
43 #endif
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")]
50 #if NET_2_0
51 [ClassInterface (ClassInterfaceType.AutoDispatch)]
52 [ComVisible (true)]
53 [Docking (DockingBehavior.Ask)]
54 #endif
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;
73 #if NET_2_0
74 private readonly ListViewGroupCollection groups;
75 private bool owner_draw;
76 private bool show_groups = true;
77 #endif
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;
105 #if NET_2_0
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;
112 #endif
114 // internal variables
115 internal ImageList large_image_list;
116 internal ImageList small_image_list;
117 internal Size text_size = Size.Empty;
119 #region Events
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 ();
127 #if NET_2_0
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 ();
137 #endif
139 public event LabelEditEventHandler AfterLabelEdit {
140 add { Events.AddHandler (AfterLabelEditEvent, value); }
141 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
144 [Browsable (false)]
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); }
161 #if NET_2_0
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); }
176 #endif
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); }
188 #if NET_2_0
189 public event ItemCheckedEventHandler ItemChecked {
190 add { Events.AddHandler (ItemCheckedEvent, value); }
191 remove { Events.RemoveHandler (ItemCheckedEvent, value); }
193 #endif
195 public event ItemDragEventHandler ItemDrag {
196 add { Events.AddHandler (ItemDragEvent, value); }
197 remove { Events.RemoveHandler (ItemDragEvent, value); }
200 #if NET_2_0
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); }
210 #endif
212 [Browsable (false)]
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); }
224 [Browsable (false)]
225 [EditorBrowsable (EditorBrowsableState.Never)]
226 public new event EventHandler TextChanged {
227 add { base.TextChanged += value; }
228 remove { base.TextChanged -= value; }
231 #if NET_2_0
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); }
246 #endif
248 #endregion // Events
250 #region Public Constructors
251 public ListView ()
253 background_color = ThemeEngine.Current.ColorWindow;
254 items = new ListViewItemCollection (this);
255 #if NET_2_0
256 groups = new ListViewGroupCollection (this);
257 #endif
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];
266 #if NET_2_0
267 item_tooltip = new ToolTip ();
268 item_tooltip.Active = false;
269 #endif
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);
295 // event handlers
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
304 #if NET_2_0
305 | ControlStyles.UseTextForAccessibility
306 #endif
307 , false);
309 #endregion // Public Constructors
311 #region Private Internal Properties
312 internal Size CheckBoxSize {
313 get {
314 if (this.check_boxes) {
315 if (this.state_image_list != null)
316 return this.state_image_list.ImageSize;
317 else
318 return ThemeEngine.Current.ListViewCheckBoxSize;
320 return Size.Empty;
324 internal Size ItemSize {
325 get {
326 if (view != View.Details)
327 return item_size;
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;
334 return size;
336 set {
337 item_size = value;
341 internal int HotItemIndex {
342 get {
343 return hot_item_index;
345 set {
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; }
366 set {
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));
372 #if NET_2_0
373 if (hot_tracking && value != ItemActivation.OneClick)
374 throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick");
375 #endif
377 activation = value;
381 [DefaultValue (ListViewAlignment.Top)]
382 [Localizable (true)]
383 public ListViewAlignment Alignment {
384 get { return alignment; }
385 set {
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) {
393 alignment = value;
394 // alignment does not matter in Details/List views
395 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
396 this.Redraw (true);
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; }
410 set {
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)
415 this.Redraw (true);
420 public override Color BackColor {
421 get {
422 if (background_color.IsEmpty)
423 return ThemeEngine.Current.ColorWindow;
424 else
425 return background_color;
427 set { background_color = value; }
430 [Browsable (false)]
431 [EditorBrowsable (EditorBrowsableState.Never)]
432 public override Image BackgroundImage {
433 get { return base.BackgroundImage; }
434 set { base.BackgroundImage = value; }
437 [DefaultValue (BorderStyle.Fixed3D)]
438 [DispId (-504)]
439 public BorderStyle BorderStyle {
440 get { return InternalBorderStyle; }
441 set { InternalBorderStyle = value; }
444 [DefaultValue (false)]
445 public bool CheckBoxes {
446 get { return check_boxes; }
447 set {
448 if (check_boxes != value) {
449 #if NET_2_0
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.");
454 #endif
456 check_boxes = value;
457 this.Redraw (true);
462 [Browsable (false)]
463 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
464 public CheckedIndexCollection CheckedIndices {
465 get { return checked_indices; }
468 [Browsable (false)]
469 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
470 public CheckedListViewItemCollection CheckedItems {
471 get { return checked_items; }
474 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
475 [Localizable (true)]
476 [MergableProperty (false)]
477 public ColumnHeaderCollection Columns {
478 get { return columns; }
481 [Browsable (false)]
482 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
483 public ListViewItem FocusedItem {
484 get {
485 if (focused_item_index == -1)
486 return null;
488 return items [focused_item_index];
490 #if NET_2_0
491 set {
492 if (value == null || value.ListView != this ||
493 !IsHandleCreated)
494 return;
496 SetFocusedItem (value.Index);
498 #endif
501 public override Color ForeColor {
502 get {
503 if (foreground_color.IsEmpty)
504 return ThemeEngine.Current.ColorWindowText;
505 else
506 return foreground_color;
508 set { foreground_color = value; }
511 [DefaultValue (false)]
512 public bool FullRowSelect {
513 get { return full_row_select; }
514 set {
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; }
525 set {
526 if (grid_lines != value) {
527 grid_lines = value;
528 this.Redraw (false);
533 [DefaultValue (ColumnHeaderStyle.Clickable)]
534 public ColumnHeaderStyle HeaderStyle {
535 get { return header_style; }
536 set {
537 if (header_style == value)
538 return;
540 switch (value) {
541 case ColumnHeaderStyle.Clickable:
542 case ColumnHeaderStyle.Nonclickable:
543 case ColumnHeaderStyle.None:
544 break;
545 default:
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)
552 Redraw (true);
556 [DefaultValue (true)]
557 public bool HideSelection {
558 get { return hide_selection; }
559 set {
560 if (hide_selection != value) {
561 hide_selection = value;
562 InvalidateSelection ();
567 #if NET_2_0
568 [DefaultValue (false)]
569 public bool HotTracking {
570 get {
571 return hot_tracking;
573 set {
574 if (hot_tracking == value)
575 return;
577 hot_tracking = value;
578 if (hot_tracking) {
579 hover_selection = true;
580 activation = ItemActivation.OneClick;
584 #endif
586 [DefaultValue (false)]
587 public bool HoverSelection {
588 get { return hover_selection; }
589 set {
590 #if NET_2_0
591 if (hot_tracking && value == false)
592 throw new ArgumentException ("When HotTracking is on, hover selection must be true");
593 #endif
594 hover_selection = value;
598 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
599 [Localizable (true)]
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)]
612 [Localizable (true)]
613 public bool LabelWrap {
614 get { return label_wrap; }
615 set {
616 if (label_wrap != value) {
617 label_wrap = value;
618 this.Redraw (true);
623 [DefaultValue (null)]
624 public ImageList LargeImageList {
625 get { return large_image_list; }
626 set {
627 large_image_list = value;
628 this.Redraw (true);
632 [Browsable (false)]
633 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
634 public IComparer ListViewItemSorter {
635 get {
636 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
637 return null;
638 return item_sorter;
640 set {
641 if (item_sorter != value) {
642 item_sorter = value;
643 Sort ();
648 [DefaultValue (true)]
649 public bool MultiSelect {
650 get { return multiselect; }
651 set { multiselect = value; }
655 #if NET_2_0
656 [DefaultValue(false)]
657 public bool OwnerDraw {
658 get { return owner_draw; }
659 set {
660 owner_draw = value;
661 Redraw (true);
664 #endif
666 [DefaultValue (true)]
667 public bool Scrollable {
668 get { return scrollable; }
669 set {
670 if (scrollable != value) {
671 scrollable = value;
672 this.Redraw (true);
677 [Browsable (false)]
678 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
679 public SelectedIndexCollection SelectedIndices {
680 get { return selected_indices; }
683 [Browsable (false)]
684 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
685 public SelectedListViewItemCollection SelectedItems {
686 get { return selected_items; }
689 #if NET_2_0
690 [DefaultValue(true)]
691 public bool ShowGroups {
692 get { return show_groups; }
693 set {
694 if (show_groups != value) {
695 show_groups = value;
696 Redraw(true);
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 {
710 get {
711 return show_item_tooltips;
713 set {
714 show_item_tooltips = value;
715 item_tooltip.Active = false;
718 #endif
720 [DefaultValue (null)]
721 public ImageList SmallImageList {
722 get { return small_image_list; }
723 set {
724 small_image_list = value;
725 this.Redraw (true);
729 [DefaultValue (SortOrder.None)]
730 public SortOrder Sorting {
731 get { return sort_order; }
732 set {
733 if (!Enum.IsDefined (typeof (SortOrder), value)) {
734 throw new InvalidEnumArgumentException ("value", (int) value,
735 typeof (SortOrder));
738 if (sort_order == value)
739 return;
741 sort_order = value;
743 #if NET_2_0
744 if (virtual_mode) // Sorting is not allowed in virtual mode
745 return;
746 #endif
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)
753 #if NET_2_0
754 item_sorter = null;
755 #else
756 // in .NET 1.1, only internal IComparer would be
757 // set to null
758 if (item_sorter is ItemComparer)
759 item_sorter = null;
760 #endif
762 this.Redraw (false);
763 } else {
764 if (item_sorter == null)
765 item_sorter = new ItemComparer (value);
766 if (item_sorter is ItemComparer) {
767 #if NET_2_0
768 item_sorter = new ItemComparer (value);
769 #else
770 // in .NET 1.1, the sort order is not updated for
771 // SmallIcon and LargeIcon views if no custom IComparer
772 // is set
773 if (View != View.SmallIcon && View != View.LargeIcon)
774 item_sorter = new ItemComparer (value);
775 #endif
777 Sort ();
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; }
790 set {
791 if (state_image_list == value)
792 return;
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);
802 this.Redraw (true);
806 [Bindable (false)]
807 [Browsable (false)]
808 [EditorBrowsable (EditorBrowsableState.Never)]
809 public override string Text {
810 get { return base.Text; }
811 set {
812 if (value == base.Text)
813 return;
815 base.Text = value;
816 this.Redraw (true);
820 #if NET_2_0
821 [Browsable (true)]
822 public Size TileSize {
823 get {
824 return tile_size;
826 set {
827 if (value.Width <= 0 || value.Height <= 0)
828 throw new ArgumentOutOfRangeException ("value");
830 tile_size = value;
831 Redraw (true);
834 #endif
836 [Browsable (false)]
837 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
838 public ListViewItem TopItem {
839 get {
840 #if NET_2_0
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.");
843 #endif
844 // there is no item
845 if (this.items.Count == 0)
846 return null;
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
852 else {
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)
856 return items [i];
858 return null;
861 #if NET_2_0
862 set {
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)
868 return;
870 EnsureVisible (value.Index);
872 #endif
875 #if NET_2_0
876 [EditorBrowsable (EditorBrowsableState.Advanced)]
877 [DefaultValue (true)]
878 [Browsable (false)]
879 [MonoInternalNote ("Stub, not implemented")]
880 public bool UseCompatibleStateImageBehavior {
881 get {
882 return false;
884 set {
887 #endif
889 [DefaultValue (View.LargeIcon)]
890 public View View {
891 get { return view; }
892 set {
893 if (!Enum.IsDefined (typeof (View), value))
894 throw new InvalidEnumArgumentException ("value", (int) value,
895 typeof (View));
897 if (view != value) {
898 #if NET_2_0
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.");
903 #endif
905 h_scroll.Value = v_scroll.Value = 0;
906 view = value;
907 Redraw (true);
912 #if NET_2_0
913 [DefaultValue (false)]
914 [RefreshProperties (RefreshProperties.Repaint)]
915 public bool VirtualMode {
916 get {
917 return virtual_mode;
919 set {
920 if (virtual_mode == value)
921 return;
923 if (!virtual_mode && items.Count > 0)
924 throw new InvalidOperationException ();
926 virtual_mode = value;
927 Redraw (true);
931 [DefaultValue (0)]
932 [RefreshProperties (RefreshProperties.Repaint)]
933 public int VirtualListSize {
934 get {
935 return virtual_list_size;
937 set {
938 if (value < 0)
939 throw new ArgumentException ("value");
941 if (virtual_list_size == value)
942 return;
944 virtual_list_size = value;
945 if (virtual_mode)
946 Redraw (true);
949 #endif
950 #endregion // Public Instance Properties
952 #region Internal Methods Properties
954 internal int FirstVisibleIndex {
955 get {
956 // there is no item
957 if (this.items.Count == 0)
958 return 0;
960 if (h_marker == 0 && v_marker == 0)
961 return 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)
967 return i;
970 return 0;
975 internal int LastVisibleIndex {
976 get {
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)
980 return i - 1;
981 } else {
982 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
983 return i - 1;
987 return Items.Count - 1;
991 internal void OnSelectedIndexChanged ()
993 if (IsHandleCreated)
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
1008 if (updating)
1009 return;
1010 #if NET_2_0
1011 // VirtualMode doesn't do any calculations until handle is created
1012 if (virtual_mode && !IsHandleCreated)
1013 return;
1014 #endif
1017 if (recalculate)
1018 CalculateListView (this.alignment);
1020 Refresh ();
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)
1042 ret_size = size;
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;
1052 else
1053 ret_size.Height = this.Font.Height;
1057 ret_size.Height += text_padding;
1059 // adjust the size for icon and checkbox for 0th column
1060 if (index == 0) {
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;
1065 return ret_size;
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;
1074 #if NET_2_0
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,
1079 Font));
1080 } else {
1081 #endif
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)
1087 continue;
1089 temp = Size.Ceiling (TextRenderer.MeasureString
1090 (item.SubItems [col].Text, Font));
1091 if (temp.Width > ret_size.Width)
1092 ret_size = temp;
1094 #if NET_2_0
1096 #endif
1098 // adjustment for space
1099 if (!ret_size.IsEmpty)
1100 ret_size.Width += 4;
1102 return ret_size;
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)
1114 return;
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)
1155 return;
1157 int max;
1158 if (scrollbar == h_scroll)
1159 max = h_scroll.Maximum - item_control.Width;
1160 else
1161 max = v_scroll.Maximum - item_control.Height;
1163 int val = scrollbar.Value + delta;
1164 if (val > max)
1165 val = max;
1166 else if (val < scrollbar.Minimum)
1167 val = scrollbar.Minimum;
1168 scrollbar.Value = val;
1171 private void CalculateScrollBars ()
1173 if (!IsHandleCreated)
1174 return;
1176 Rectangle client_area = ClientRectangle;
1178 if (!scrollable) {
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;
1184 return;
1187 // Don't calculate if the view is not displayable
1188 if (client_area.Height < 0 || client_area.Width < 0)
1189 return;
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;
1197 else
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;
1203 else
1204 h_scroll.Visible = false;
1205 } else {
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;
1222 else {
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
1245 } else {
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;
1258 #if NET_2_0
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)
1266 return i;
1268 return -1;
1270 #endif
1272 internal ColumnHeader GetReorderedColumn (int index)
1274 if (reordered_column_indices == null)
1275 return Columns [index];
1276 else
1277 return Columns [reordered_column_indices [index]];
1280 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1282 #if NET_2_0
1283 if (fireEvent) {
1284 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1285 if (eh != null){
1286 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1288 eh (this, args);
1289 if (args.Cancel) {
1290 header_control.Invalidate ();
1291 item_control.Invalidate ();
1292 return;
1296 #endif
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)
1306 return;
1308 int[] curr = reordered_column_indices;
1309 int [] result = new int [column_count];
1310 int curr_idx = 0;
1311 for (int i = 0; i < column_count; i++) {
1312 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1313 curr_idx++;
1315 if (i == index)
1316 result [i] = col.Index;
1317 else
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) {
1332 LayoutDetails ();
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];
1346 if (i == index) {
1347 display_indices [i] = index;
1348 } else {
1349 int display_index = col.InternalDisplayIndex;
1350 if (display_index < index) {
1351 display_indices [i] = display_index;
1352 } else {
1353 display_indices [i] = (display_index + 1);
1358 ReorderColumns (display_indices, redraw);
1359 Invalidate ();
1362 Size LargeIconItemSize
1364 get {
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 {
1374 get {
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);
1383 #if NET_2_0
1384 Size TileItemSize {
1385 get {
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);
1398 return tile_size;
1401 #endif
1403 int GetDetailsItemHeight ()
1405 int item_height;
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);
1410 return item_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)
1418 return;
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));
1431 int rows;
1432 int cols;
1433 int[,] item_index_matrix;
1435 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1437 Rectangle area = ClientRectangle;
1438 #if NET_2_0
1439 if (show_groups && groups.Count > 0 && view != View.List) {
1440 // When groups are used the alignment is always top-aligned
1441 rows = 0;
1442 cols = 0;
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)
1450 group_cols = 1;
1451 int group_rows = (int) Math.Ceiling ((double)group.Items.Count / (double)group_cols);
1453 cols = Math.Max (group_cols, cols);
1454 rows += group_rows;
1457 else {
1458 #endif
1459 // Simple matrix if no groups are used
1460 if (left_aligned) {
1461 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1462 if (rows <= 0)
1463 rows = 1;
1464 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1465 } else {
1466 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1467 if (cols <= 0)
1468 cols = 1;
1469 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1471 #if NET_2_0
1473 #endif
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)
1487 return;
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;
1497 int current_y = 0;
1498 #if NET_2_0
1499 if (show_groups && groups.Count > 0 && view != View.List)
1500 LayoutIconsGroups (left_aligned, x_spacing, y_spacing);
1501 else
1502 #endif
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);
1509 #if NET_2_0
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;
1517 int current_y = 0;
1519 for (int i = 0; i < groups.Count; i++) {
1520 ListViewGroup group = groups [i];
1521 if (group.Items.Count == 0)
1522 continue;
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),
1528 ref current_item);
1530 current_y += header_spacing;
1533 layout_ht = current_y; // Adjust with the header heights
1535 #endif
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
1542 int x, y = 0;
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;
1555 current_item++;
1556 #if NET_2_0
1557 if (!virtual_mode)
1558 #endif
1559 item.Layout ();
1561 if (left_aligned) {
1562 current_global_row++;
1563 row++;
1564 if (row == rows) {
1565 current_global_row = row = 0;
1566 col++;
1568 } else {
1569 if (++col == cols) {
1570 col = 0;
1571 row++;
1572 current_global_row++;
1577 // Return the lower bounds of the icons section
1578 y_origin = y + item_size.Height;
1581 void LayoutHeader ()
1583 int x = 0;
1584 for (int i = 0; i < Columns.Count; i++) {
1585 ColumnHeader col = GetReorderedColumn (i);
1586 col.X = x;
1587 col.Y = 0;
1588 col.CalcColumnHeader ();
1589 x += col.Wd;
1592 layout_wd = x;
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;
1601 } else {
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 ()
1610 LayoutHeader ();
1612 if (columns.Count == 0) {
1613 item_control.Visible = false;
1614 layout_wd = ClientRectangle.Width;
1615 layout_ht = ClientRectangle.Height;
1616 return;
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);
1630 #if NET_2_0
1631 if (!virtual_mode) // Virtual mode sets Layout until draw time
1632 #endif
1633 items [i].Layout ();
1635 y += item_height + 2;
1638 // some space for bottom gridline
1639 if (grid_lines)
1640 y += 2;
1643 layout_ht = y;
1646 private void AdjustItemsPositionArray (int count)
1648 if (items_location.Length >= count)
1649 return;
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)
1659 CalcTextSize ();
1661 AdjustItemsPositionArray (items.Count);
1663 switch (view) {
1664 case View.Details:
1665 LayoutDetails ();
1666 break;
1668 case View.SmallIcon:
1669 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left,
1670 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
1671 break;
1673 case View.LargeIcon:
1674 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
1675 ThemeEngine.Current.ListViewHorizontalSpacing,
1676 ThemeEngine.Current.ListViewVerticalSpacing);
1677 break;
1679 case View.List:
1680 LayoutIcons (SmallIconItemSize, true,
1681 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
1682 break;
1683 #if NET_2_0
1684 case View.Tile:
1685 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
1686 ThemeEngine.Current.ListViewHorizontalSpacing,
1687 ThemeEngine.Current.ListViewVerticalSpacing);
1688 break;
1689 #endif
1692 CalculateScrollBars ();
1695 internal Point GetItemLocation (int index)
1697 Point loc = items_location [index];
1698 loc.X -= h_marker; // Adjust to scroll
1699 loc.Y -= v_marker;
1701 return loc;
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))
1712 return false;
1714 keysearch_text += (char)ke.KeyCode;
1715 keysearch_tickcnt = current_tickcnt;
1717 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1718 int i = start;
1719 while (true) {
1720 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1721 CompareOptions.IgnoreCase)) {
1722 SetFocusedItem (i);
1723 items [i].Selected = true;
1724 EnsureVisible (i);
1725 break;
1727 i = (i + 1 < Items.Count) ? i+1 : 0;
1729 if (i == start)
1730 break;
1732 return true;
1735 int GetAdjustedIndex (Keys key)
1737 int result = -1;
1739 if (View == View.Details) {
1740 switch (key) {
1741 case Keys.Up:
1742 result = FocusedItem.Index - 1;
1743 break;
1744 case Keys.Down:
1745 result = FocusedItem.Index + 1;
1746 if (result == items.Count)
1747 result = -1;
1748 break;
1749 case Keys.PageDown:
1750 int last_index = LastVisibleIndex;
1751 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
1752 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
1753 last_index--;
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;
1761 } else
1762 result = last_index;
1763 break;
1764 case Keys.PageUp:
1765 int first_index = FirstVisibleIndex;
1766 if (GetItemLocation (first_index).Y < 0)
1767 first_index++;
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;
1772 if (result < 0)
1773 result = 0;
1775 } else
1776 result = first_index;
1777 break;
1779 return result;
1782 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.Index];
1783 int row = item_matrix_location.Row;
1784 int col = item_matrix_location.Col;
1786 switch (key) {
1787 case Keys.Left:
1788 if (col == 0)
1789 return -1;
1790 return item_index_matrix [row, col - 1];
1792 case Keys.Right:
1793 if (col == (cols - 1))
1794 return -1;
1795 while (item_index_matrix [row, col + 1] == 0) {
1796 row--;
1797 if (row < 0)
1798 return -1;
1800 return item_index_matrix [row, col + 1];
1802 case Keys.Up:
1803 if (row == 0)
1804 return -1;
1805 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
1806 col--;
1807 if (col < 0)
1808 return -1;
1810 return item_index_matrix [row - 1, col];
1812 case Keys.Down:
1813 if (row == (rows - 1) || row == Items.Count - 1)
1814 return -1;
1815 while (item_index_matrix [row + 1, col] == 0) {
1816 col--;
1817 if (col < 0)
1818 return -1;
1820 return item_index_matrix [row + 1, col];
1822 default:
1823 return -1;
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;
1835 changed = true;
1837 foreach (ListViewItem item in sel_items)
1838 if (!item.Selected) {
1839 item.Selected = true;
1840 changed = true;
1842 return changed;
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]);
1859 } else {
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]);
1875 SelectItems (list);
1876 } else if (ctrl_pressed) {
1877 item.Selected = !item.Selected;
1878 selection_start = item;
1879 } else {
1880 if (!reselect) {
1881 // do not unselect, and reselect the item
1882 foreach (int itemIndex in SelectedIndices) {
1883 if (index == itemIndex)
1884 continue;
1885 items [itemIndex].Selected = false;
1887 } else {
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)
1909 return false;
1911 if (FocusedItem == null)
1912 SetFocusedItem (0);
1914 switch (key_data) {
1915 case Keys.End:
1916 SelectIndex (Items.Count - 1);
1917 break;
1919 case Keys.Home:
1920 SelectIndex (0);
1921 break;
1923 case Keys.Left:
1924 case Keys.Right:
1925 case Keys.Up:
1926 case Keys.Down:
1927 case Keys.PageUp:
1928 case Keys.PageDown:
1929 SelectIndex (GetAdjustedIndex (key_data));
1930 break;
1932 case Keys.Space:
1933 ToggleItemsCheckState ();
1934 break;
1935 case Keys.Enter:
1936 if (selected_indices.Count > 0)
1937 OnItemActivate (EventArgs.Empty);
1938 break;
1940 default:
1941 return false;
1944 return true;
1947 void ToggleItemsCheckState ()
1949 if (!CheckBoxes)
1950 return;
1952 // Don't modify check state if StateImageList has less than 2 elements
1953 if (StateImageList != null && StateImageList.Images.Count < 2)
1954 return;
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;
1961 return;
1964 if (FocusedItem != null) {
1965 FocusedItem.Checked = !FocusedItem.Checked;
1966 SelectIndex (FocusedItem.Index);
1970 void SelectIndex (int index)
1972 if (index == -1)
1973 return;
1975 if (MultiSelect)
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)
1987 return;
1989 if (ke.Alt || ke.Control)
1990 return;
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 {
2003 ListView owner;
2004 ListViewItem clicked_item;
2005 ListViewItem last_clicked_item;
2006 bool hover_processed = false;
2007 bool checking = false;
2008 ListViewItem prev_hovered_item;
2009 #if NET_2_0
2010 ListViewItem prev_tooltip_item;
2011 #endif
2012 int clicks;
2014 ListViewLabelEditTextBox edit_text_box;
2015 internal ListViewItem edit_item;
2016 LabelEditEventArgs edit_args;
2018 public ItemControl (ListView owner)
2020 this.owner = 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);
2034 enum BoxSelect {
2035 None,
2036 Normal,
2037 Shift,
2038 Control
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; }
2048 set {
2049 if (box_select_rect == value)
2050 return;
2052 InvalidateBoxSelectRect ();
2053 box_select_rect = value;
2054 InvalidateBoxSelectRect ();
2058 void InvalidateBoxSelectRect ()
2060 if (BoxSelectRectangle.Size.IsEmpty)
2061 return;
2063 Rectangle edge = BoxSelectRectangle;
2064 edge.X -= 1;
2065 edge.Y -= 1;
2066 edge.Width += 2;
2067 edge.Height = 2;
2068 Invalidate (edge);
2069 edge.Y = BoxSelectRectangle.Bottom - 1;
2070 Invalidate (edge);
2071 edge.Y = BoxSelectRectangle.Y - 1;
2072 edge.Width = 2;
2073 edge.Height = BoxSelectRectangle.Height + 2;
2074 Invalidate (edge);
2075 edge.X = BoxSelectRectangle.Right - 1;
2076 Invalidate (edge);
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) {
2092 r.X += r.Width / 4;
2093 r.Y += r.Height / 4;
2094 r.Width /= 2;
2095 r.Height /= 2;
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 {
2107 get {
2108 ArrayList result = new ArrayList ();
2109 for (int i = 0; i < owner.Items.Count; i++) {
2110 bool intersects;
2111 if (owner.View == View.Details && !owner.FullRowSelect)
2112 intersects = BoxIntersectsText (i);
2113 else
2114 intersects = BoxIntersectsItem (i);
2116 if (intersects)
2117 result.Add (owner.Items [i]);
2119 return result;
2123 private bool PerformBoxSelection (Point pt)
2125 if (box_select_mode == BoxSelect.None)
2126 return false;
2128 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2130 ArrayList box_items = BoxSelectedItems;
2132 ArrayList items;
2134 switch (box_select_mode) {
2136 case BoxSelect.Normal:
2137 items = box_items;
2138 break;
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))
2147 items.Add (item);
2148 break;
2150 case BoxSelect.Shift:
2151 items = box_items;
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]);
2156 break;
2158 default:
2159 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2162 SuspendLayout ();
2163 owner.SelectItems (items);
2164 ResumeLayout ();
2166 return true;
2169 private void ItemsMouseDown (object sender, MouseEventArgs me)
2171 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2172 if (owner.items.Count == 0)
2173 return;
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))
2181 continue;
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
2188 // double clicks
2189 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2
2190 #if !NET_2_0
2191 && me.Clicks == 1
2192 #endif
2194 return;
2196 // Generate an extra ItemCheck event when we got two clicks
2197 // (Match weird .Net behaviour)
2198 if (me.Clicks == 2)
2199 item.Checked = !item.Checked;
2201 item.Checked = !item.Checked;
2202 checking = true;
2203 return;
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];
2215 else
2216 owner.SetFocusedItem (i);
2217 } else
2218 clicked_item = owner.items [i];
2220 break;
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);
2233 } else {
2234 clicked_item.Selected = true;
2237 #if NET_2_0
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);
2245 #endif
2246 // Report clicks only if the item was clicked. On MS the
2247 // clicks are only raised if you click an item
2248 clicks = me.Clicks;
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
2256 } else {
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;
2269 else
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));
2282 if (done)
2283 return;
2284 if (!hover_processed && owner.Activation != ItemActivation.OneClick
2285 #if NET_2_0
2286 && !owner.ShowItemToolTips
2287 #endif
2289 return;
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) {
2302 #if NET_2_0
2303 if (owner.HotTracking)
2304 Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2305 #endif
2307 Cursor = Cursors.Default;
2308 owner.HotItemIndex = -1;
2309 } else if (item != null && owner.HotItemIndex == -1) {
2310 #if NET_2_0
2311 if (owner.HotTracking)
2312 Invalidate (item.Bounds);
2313 #endif
2315 Cursor = Cursors.Hand;
2316 owner.HotItemIndex = item.Index;
2320 #if NET_2_0
2321 if (owner.ShowItemToolTips) {
2322 if (item == null) {
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;
2331 #endif
2336 private void ItemsMouseHover (object sender, EventArgs e)
2338 if (owner.hover_pending) {
2339 owner.OnMouseHover (e);
2340 owner.hover_pending = false;
2343 if (Capture)
2344 return;
2346 hover_processed = true;
2347 Point pt = PointToClient (Control.MousePosition);
2348 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2349 if (item == null)
2350 return;
2352 prev_hovered_item = item;
2354 if (owner.HoverSelection) {
2355 if (owner.MultiSelect)
2356 owner.UpdateMultiSelection (item.Index, true);
2357 else
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
2364 #if NET_2_0
2365 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2366 #endif
2369 void HandleClicks (MouseEventArgs me)
2371 // if the click is not on an item,
2372 // clicks remains as 0
2373 if (clicks > 1) {
2374 #if !NET_2_0
2375 owner.OnDoubleClick (EventArgs.Empty);
2376 } else if (clicks == 1) {
2377 owner.OnClick (EventArgs.Empty);
2378 #else
2379 owner.OnDoubleClick (EventArgs.Empty);
2380 owner.OnMouseDoubleClick (me);
2381 } else if (clicks == 1) {
2382 owner.OnClick (EventArgs.Empty);
2383 owner.OnMouseClick (me);
2384 #endif
2387 clicks = 0;
2390 private void ItemsMouseUp (object sender, MouseEventArgs me)
2392 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
2393 HandleClicks (owner_me);
2395 Capture = false;
2396 if (owner.Items.Count == 0) {
2397 owner.OnMouseUp (owner_me);
2398 return;
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);
2407 else
2408 rect = clicked_item.Bounds;
2410 if (rect.Contains (pt)) {
2411 switch (owner.activation) {
2412 case ItemActivation.OneClick:
2413 owner.OnItemActivate (EventArgs.Empty);
2414 break;
2416 case ItemActivation.TwoClick:
2417 if (last_clicked_item == clicked_item) {
2418 owner.OnItemActivate (EventArgs.Empty);
2419 last_clicked_item = null;
2420 } else
2421 last_clicked_item = clicked_item;
2422 break;
2423 default:
2424 // DoubleClick activation is handled in another handler
2425 break;
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;
2438 checking = false;
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) {
2479 case View.List:
2480 case View.SmallIcon:
2481 case View.Details:
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;
2489 break;
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;
2499 break;
2502 edit_item = item;
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)
2514 EndEdit (item);
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)
2522 return;
2524 edit_args.SetLabel (null);
2525 EndEdit (item);
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)
2533 return;
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
2543 owner.Focus ();
2546 edit_item = null;
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);
2559 break;
2560 case Msg.WM_SETFOCUS:
2561 owner.Select (false, true);
2562 break;
2563 case Msg.WM_RBUTTONDOWN:
2564 owner.Select (false, true);
2565 break;
2566 default:
2567 break;
2569 base.WndProc (ref m);
2573 internal class ListViewLabelEditTextBox : TextBox
2575 int max_width = -1;
2576 int min_width = -1;
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 {
2592 set {
2593 if (value < min_width)
2594 max_width = min_width;
2595 else
2596 max_width = value;
2600 public int MaxHeight {
2601 set {
2602 if (value < min_height)
2603 max_height = min_height;
2604 else
2605 max_height = value;
2609 public new int Width {
2610 get {
2611 return base.Width;
2613 set {
2614 min_width = value;
2615 base.Width = value;
2619 public override Font Font {
2620 get {
2621 return base.Font;
2623 set {
2624 base.Font = value;
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;
2635 if (!Multiline)
2636 ResizeTextBoxWidth (new_width);
2637 else {
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) {
2658 case Keys.Enter:
2659 return true;
2660 case Keys.Escape:
2661 return true;
2664 return base.IsInputKey (key_data);
2667 protected override void OnKeyDown (KeyEventArgs e)
2669 if (!Visible)
2670 return;
2672 switch (e.KeyCode) {
2673 case Keys.Return:
2674 Visible = false;
2675 e.Handled = true;
2676 OnEditingFinished (e);
2677 break;
2678 case Keys.Escape:
2679 Visible = false;
2680 e.Handled = true;
2681 OnEditingCancelled (e);
2682 break;
2686 protected override void OnLostFocus (EventArgs e)
2688 if (Visible) {
2689 OnEditingFinished (e);
2693 protected void OnEditingCancelled (EventArgs e)
2695 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
2696 if (eh != null)
2697 eh (this, e);
2700 protected void OnEditingFinished (EventArgs e)
2702 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
2703 if (eh != null)
2704 eh (this, e);
2707 private void ResizeTextBoxWidth (int new_width)
2709 if (new_width > max_width)
2710 base.Width = max_width;
2711 else
2712 if (new_width >= min_width)
2713 base.Width = new_width;
2714 else
2715 base.Width = min_width;
2718 private void ResizeTextBoxHeight (int new_height)
2720 if (new_height > max_height)
2721 base.Height = max_height;
2722 else
2723 if (new_height >= min_height)
2724 base.Height = new_height;
2725 else
2726 base.Height = min_height;
2729 public void Reset ()
2731 max_width = -1;
2732 min_width = -1;
2734 max_height = -1;
2736 old_number_lines = 1;
2738 Text = String.Empty;
2740 Size = DefaultSize;
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)
2758 if (updating)
2759 return;
2761 CalculateScrollBars ();
2764 void FocusChanged (object o, EventArgs args)
2766 if (Items.Count == 0)
2767 return;
2769 if (FocusedItem == null)
2770 SetFocusedItem (0);
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)
2789 return;
2791 int lines = me.Delta / 120;
2793 if (lines == 0)
2794 return;
2796 switch (View) {
2797 case View.Details:
2798 case View.SmallIcon:
2799 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
2800 break;
2801 case View.LargeIcon:
2802 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
2803 break;
2804 case View.List:
2805 Scroll (h_scroll, -ItemSize.Width * lines);
2806 break;
2807 #if NET_2_0
2808 case View.Tile:
2809 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
2810 break;
2811 #endif
2815 private void ListView_SizeChanged (object sender, EventArgs e)
2817 CalculateListView (alignment);
2820 private void SetFocusedItem (int index)
2822 if (index != -1)
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)
2878 if (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);
2889 #if NET_2_0
2890 if (!virtual_mode) // In virtual mode we don't save the items
2891 #endif
2892 foreach (ListViewItem item in items)
2893 item.Owner = null;
2896 base.Dispose (disposing);
2899 protected override bool IsInputKey (Keys keyData)
2901 switch (keyData) {
2902 case Keys.Up:
2903 case Keys.Down:
2904 case Keys.PageUp:
2905 case Keys.PageDown:
2906 case Keys.Right:
2907 case Keys.Left:
2908 case Keys.End:
2909 case Keys.Home:
2910 return true;
2912 default:
2913 break;
2916 return base.IsInputKey (keyData);
2919 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
2921 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
2922 if (eh != null)
2923 eh (this, e);
2926 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
2928 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
2929 if (eh != null)
2930 eh (this, e);
2933 protected virtual void OnColumnClick (ColumnClickEventArgs e)
2935 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
2936 if (eh != null)
2937 eh (this, e);
2940 #if NET_2_0
2941 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
2943 DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
2944 if (eh != null)
2945 eh(this, e);
2948 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
2950 DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
2951 if (eh != null)
2952 eh(this, e);
2955 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
2957 DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
2958 if (eh != null)
2959 eh(this, e);
2961 #endif
2963 protected override void OnEnabledChanged (EventArgs e)
2965 base.OnEnabledChanged (e);
2968 protected override void OnFontChanged (EventArgs e)
2970 base.OnFontChanged (e);
2971 Redraw (true);
2974 protected override void OnHandleCreated (EventArgs e)
2976 base.OnHandleCreated (e);
2977 CalculateListView (alignment);
2978 #if NET_2_0
2979 if (!virtual_mode) // Sorting is not allowed in virtual mode
2980 #endif
2981 Sort ();
2984 protected override void OnHandleDestroyed (EventArgs e)
2986 base.OnHandleDestroyed (e);
2989 protected virtual void OnItemActivate (EventArgs e)
2991 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
2992 if (eh != null)
2993 eh (this, e);
2996 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
2998 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
2999 if (eh != null)
3000 eh (this, ice);
3003 #if NET_2_0
3004 protected internal virtual void OnItemChecked (ItemCheckedEventArgs icea)
3006 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3007 if (eh != null)
3008 eh (this, icea);
3010 #endif
3012 protected virtual void OnItemDrag (ItemDragEventArgs e)
3014 EventHandler eh = (EventHandler)(Events [ItemDragEvent]);
3015 if (eh != null)
3016 eh (this, e);
3019 #if NET_2_0
3020 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs args)
3022 ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3023 if (eh != null)
3024 eh (this, args);
3027 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs args)
3029 ListViewItemSelectionChangedEventHandler eh =
3030 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3031 if (eh != null)
3032 eh (this, args);
3034 #endif
3036 protected virtual void OnSelectedIndexChanged (EventArgs e)
3038 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3039 if (eh != null)
3040 eh (this, e);
3043 protected override void OnSystemColorsChanged (EventArgs e)
3045 base.OnSystemColorsChanged (e);
3048 #if NET_2_0
3049 protected virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs args)
3051 EventHandler eh = (EventHandler)Events [CacheVirtualItemsEvent];
3052 if (eh != null)
3053 eh (this, args);
3056 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs args)
3058 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3059 if (eh != null)
3060 eh (this, args);
3063 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs args)
3065 ListViewVirtualItemsSelectionRangeChangedEventHandler eh =
3066 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3067 if (eh != null)
3068 eh (this, args);
3070 #endif
3072 protected void RealizeProperties ()
3074 // FIXME: TODO
3077 protected void UpdateExtendedStyles ()
3079 // FIXME: TODO
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) {
3090 has_focus = false;
3091 refocusing = true;
3092 return;
3094 break;
3095 case Msg.WM_SETFOCUS:
3096 if (refocusing) {
3097 has_focus = true;
3098 refocusing = false;
3099 return;
3101 break;
3102 default:
3103 break;
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);
3125 #if NET_2_0
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)
3136 BeginUpdate ();
3137 foreach (ColumnHeader col in columns)
3138 col.AutoResize (headerAutoResize);
3139 EndUpdate ();
3141 #endif
3143 public void BeginUpdate ()
3145 // flag to avoid painting
3146 updating = true;
3149 public void Clear ()
3151 columns.Clear ();
3152 items.Clear (); // Redraw (true) called here
3155 public void EndUpdate ()
3157 // flag to avoid painting
3158 updating = false;
3160 // probably, now we need a redraw with recalculations
3161 this.Redraw (true);
3164 public void EnsureVisible (int index)
3166 if (index < 0 || index >= items.Count || scrollable == false)
3167 return;
3169 Rectangle view_rect = item_control.ClientRectangle;
3170 Rectangle bounds = new Rectangle (GetItemLocation (index), ItemSize);
3172 if (view_rect.Contains (bounds))
3173 return;
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);
3182 if (bounds.Top < 0)
3183 v_scroll.Value += bounds.Top;
3184 else if (bounds.Bottom > view_rect.Bottom)
3185 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3188 #if NET_2_0
3189 public ListViewItem FindItemWithText (string text)
3191 if (items.Count == 0)
3192 return null;
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");
3207 if (text == null)
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
3215 return lvi;
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)
3224 return lvi;
3228 return null;
3230 #endif
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))
3239 return items [i];
3242 return null;
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);
3258 #if NET_2_0
3259 public ListViewHitTestInfo HitTest (Point pt)
3261 return HitTest (pt.X, pt.Y);
3264 public ListViewHitTestInfo HitTest (int x, int y)
3266 if (x < 0)
3267 throw new ArgumentOutOfRangeException ("x");
3268 if (y < 0)
3269 throw new ArgumentOutOfRangeException ("y");
3271 ListViewItem item = GetItemAt (x, y);
3272 if (item == null)
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)) {
3287 subitem = si;
3288 break;
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");
3303 if (updating)
3304 return;
3306 for (int i = startIndex; i <= endIndex; i++)
3307 item_control.Invalidate (items [i].Bounds);
3309 if (!invalidateOnly)
3310 Update ();
3312 #endif
3314 public void Sort ()
3316 #if NET_2_0
3317 if (virtual_mode)
3318 throw new InvalidOperationException ();
3319 #endif
3321 Sort (true);
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) {
3336 return;
3339 items.Sort (item_sorter);
3340 if (redraw)
3341 this.Redraw (true);
3344 public override string ToString ()
3346 int count = this.Items.Count;
3348 if (count == 0)
3349 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
3350 else
3351 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
3353 #endregion // Public Instance Methods
3356 #region Subclasses
3358 class HeaderControl : Control {
3360 ListView owner;
3361 bool column_resize_active = false;
3362 ColumnHeader resize_column;
3363 ColumnHeader clicked_column;
3364 ColumnHeader drag_column;
3365 int drag_x;
3366 int drag_to_index = -1;
3368 public HeaderControl (ListView owner)
3370 this.owner = 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)) {
3382 result = col;
3383 break;
3386 return result;
3389 private int GetReorderedIndex (ColumnHeader col)
3391 if (owner.reordered_column_indices == null)
3392 return col.Index;
3393 else
3394 for (int i = 0; i < owner.Columns.Count; i++)
3395 if (owner.reordered_column_indices [i] == col.Index)
3396 return i;
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;
3404 Capture = true;
3405 return;
3408 clicked_column = ColumnAtX (me.X + owner.h_marker);
3410 if (clicked_column != null) {
3411 Capture = true;
3412 if (owner.AllowColumnReorder) {
3413 drag_x = me.X;
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);
3422 return;
3426 void StopResize ()
3428 column_resize_active = false;
3429 resize_column = null;
3430 Capture = false;
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;
3440 if (width < 0)
3441 width = 0;
3443 if (!owner.CanProceedWithResize (resize_column, width)){
3444 StopResize ();
3445 return;
3447 resize_column.Width = width;
3448 return;
3451 resize_column = null;
3453 if (clicked_column != null) {
3454 if (owner.AllowColumnReorder) {
3455 Rectangle r;
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);
3463 if (over == null)
3464 drag_to_index = owner.Columns.Count;
3465 else if (x < over.X + over.Width / 2)
3466 drag_to_index = GetReorderedIndex (over);
3467 else
3468 drag_to_index = GetReorderedIndex (over) + 1;
3469 Invalidate ();
3470 } else {
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);
3480 return;
3483 for (int i = 0; i < owner.Columns.Count; i++) {
3484 Rectangle zone = owner.Columns [i].Rect;
3485 zone.X = zone.Right - 5;
3486 zone.Width = 10;
3487 if (zone.Contains (pt)) {
3488 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
3489 i++;
3490 resize_column = owner.Columns [i];
3491 break;
3495 if (resize_column == null)
3496 Cursor = Cursors.Default;
3497 else
3498 Cursor = Cursors.VSplit;
3501 void HeaderMouseUp (object sender, MouseEventArgs me)
3503 Capture = false;
3505 if (column_resize_active) {
3506 int column_idx = resize_column.Index;
3507 StopResize ();
3508 owner.RaiseColumnWidthChanged (column_idx);
3509 return;
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) {
3521 drag_column = null;
3522 if (drag_to_index > GetReorderedIndex (clicked_column))
3523 drag_to_index--;
3524 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
3525 owner.ReorderColumn (clicked_column, drag_to_index, true);
3526 drag_to_index = -1;
3527 Invalidate ();
3530 clicked_column = null;
3533 internal override void OnPaintInternal (PaintEventArgs pe)
3535 if (owner.updating)
3536 return;
3538 Theme theme = ThemeEngine.Current;
3539 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
3541 if (drag_column == null)
3542 return;
3544 int target_x;
3545 if (drag_to_index == owner.Columns.Count)
3546 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
3547 else
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:
3556 owner.Focus ();
3557 break;
3558 default:
3559 base.WndProc (ref m);
3560 break;
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);
3579 else
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)
3591 this.owner = owner;
3593 #endregion // Public Constructor
3595 #region Public Properties
3596 [Browsable (false)]
3597 public int Count {
3598 get { return owner.CheckedItems.Count; }
3601 public bool IsReadOnly {
3602 get { return true; }
3605 public int this [int index] {
3606 get {
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)
3638 return true;
3640 return false;
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.");
3660 void IList.Clear ()
3662 throw new NotSupportedException ("Clear operation is not supported.");
3665 bool IList.Contains (object checkedIndex)
3667 if (!(checkedIndex is int))
3668 return false;
3669 return Contains ((int) checkedIndex);
3672 int IList.IndexOf (object checkedIndex)
3674 if (!(checkedIndex is int))
3675 return -1;
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)
3699 return i;
3701 return -1;
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;
3713 return indices;
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)
3725 this.owner = owner;
3726 this.owner.Items.Changed += new CollectionChangedHandler (
3727 ItemsCollection_Changed);
3729 #endregion // Public Constructor
3731 #region Public Properties
3732 [Browsable (false)]
3733 public int Count {
3734 get {
3735 if (!owner.CheckBoxes)
3736 return 0;
3737 return List.Count;
3741 public bool IsReadOnly {
3742 get { return true; }
3745 public ListViewItem this [int index] {
3746 get {
3747 #if NET_2_0
3748 if (owner.VirtualMode)
3749 throw new InvalidOperationException ();
3750 #endif
3751 ArrayList checked_items = List;
3752 if (index < 0 || index >= checked_items.Count)
3753 throw new ArgumentOutOfRangeException ("index");
3754 return (ListViewItem) checked_items [index];
3758 #if NET_2_0
3759 public virtual ListViewItem this [string key] {
3760 get {
3761 int idx = IndexOfKey (key);
3762 return idx == -1 ? null : (ListViewItem) List [idx];
3765 #endif
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)
3789 return false;
3790 return List.Contains (item);
3793 #if NET_2_0
3794 public virtual bool ContainsKey (string key)
3796 return IndexOfKey (key) != -1;
3798 #endif
3800 public void CopyTo (Array dest, int index)
3802 #if NET_2_0
3803 if (owner.VirtualMode)
3804 throw new InvalidOperationException ();
3805 #endif
3806 if (!owner.CheckBoxes)
3807 return;
3808 List.CopyTo (dest, index);
3811 public IEnumerator GetEnumerator ()
3813 #if NET_2_0
3814 if (owner.VirtualMode)
3815 throw new InvalidOperationException ();
3816 #endif
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.");
3827 void IList.Clear ()
3829 throw new NotSupportedException ("Clear operation is not supported.");
3832 bool IList.Contains (object item)
3834 if (!(item is ListViewItem))
3835 return false;
3836 return Contains ((ListViewItem) item);
3839 int IList.IndexOf (object item)
3841 if (!(item is ListViewItem))
3842 return -1;
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)
3863 #if NET_2_0
3864 if (owner.VirtualMode)
3865 throw new InvalidOperationException ();
3866 #endif
3867 if (!owner.CheckBoxes)
3868 return -1;
3869 return List.IndexOf (item);
3872 #if NET_2_0
3873 public virtual int IndexOfKey (string key)
3875 #if NET_2_0
3876 if (owner.VirtualMode)
3877 throw new InvalidOperationException ();
3878 #endif
3879 if (key == null || key.Length == 0)
3880 return -1;
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)
3886 return i;
3889 return -1;
3891 #endif
3892 #endregion // Public Methods
3894 internal ArrayList List {
3895 get {
3896 if (list == null) {
3897 list = new ArrayList ();
3898 foreach (ListViewItem item in owner.Items) {
3899 if (item.Checked)
3900 list.Add (item);
3903 return list;
3907 internal void Reset ()
3909 // force re-population of list
3910 list = null;
3913 private void ItemsCollection_Changed ()
3915 Reset ();
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 ();
3928 this.owner = owner;
3930 #endregion // Public Constructor
3932 #region Public Properties
3933 [Browsable (false)]
3934 public int Count {
3935 get { return list.Count; }
3938 public bool IsReadOnly {
3939 get { return false; }
3942 public virtual ColumnHeader this [int index] {
3943 get {
3944 if (index < 0 || index >= list.Count)
3945 throw new ArgumentOutOfRangeException ("index");
3946 return (ColumnHeader) list [index];
3950 #if NET_2_0
3951 public virtual ColumnHeader this [string key] {
3952 get {
3953 int idx = IndexOfKey (key);
3954 if (idx == -1)
3955 return null;
3957 return (ColumnHeader) list [idx];
3960 #endif
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);
3985 return idx;
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);
3992 return colHeader;
3995 #if NET_2_0
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;
4011 Add (colHeader);
4012 return colHeader;
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;
4024 Add (colHeader);
4025 return colHeader;
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;
4032 Add (colHeader);
4033 return colHeader;
4035 #endif
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);
4051 list.Clear ();
4052 owner.ReorderColumns (new int [0], true);
4055 public bool Contains (ColumnHeader value)
4057 return list.Contains (value);
4060 #if NET_2_0
4061 public virtual bool ContainsKey (string key)
4063 return IndexOfKey (key) != -1;
4065 #endif
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);
4127 #if NET_2_0
4128 public virtual int IndexOfKey (string key)
4130 if (key == null || key.Length == 0)
4131 return -1;
4133 for (int i = 0; i < list.Count; i++) {
4134 ColumnHeader col = (ColumnHeader) list [i];
4135 if (String.Compare (key, col.Name, true) == 0)
4136 return i;
4139 return -1;
4141 #endif
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);
4154 #if NET_2_0
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);
4192 #endif
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))
4203 return;
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;
4215 } else {
4216 display_indices [i] = (display_index - 1);
4220 column.InternalDisplayIndex = -1;
4221 owner.ReorderColumns (display_indices, true);
4224 #if NET_2_0
4225 public virtual void RemoveByKey (string key)
4227 int idx = IndexOfKey (key);
4228 if (idx != -1)
4229 RemoveAt (idx);
4231 #endif
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];
4239 Remove (col);
4241 #endregion // Public Methods
4244 } // ColumnHeaderCollection
4246 public class ListViewItemCollection : IList, ICollection, IEnumerable
4248 private readonly ArrayList list;
4249 private ListView owner;
4250 #if NET_2_0
4251 private ListViewGroup group;
4252 #endif
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);
4262 this.owner = owner;
4264 #endregion // Public Constructor
4266 #if NET_2_0
4267 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
4269 this.group = group;
4270 is_main_collection = false;
4272 #endif
4274 #region Public Properties
4275 [Browsable (false)]
4276 public int Count {
4277 get {
4278 #if NET_2_0
4279 if (owner != null && owner.VirtualMode)
4280 return owner.VirtualListSize;
4281 #endif
4283 return list.Count;
4287 public bool IsReadOnly {
4288 get { return false; }
4291 public virtual ListViewItem this [int displayIndex] {
4292 get {
4293 if (displayIndex < 0 || displayIndex >= Count)
4294 throw new ArgumentOutOfRangeException ("displayIndex");
4296 #if NET_2_0
4297 if (owner != null && owner.VirtualMode)
4298 return RetrieveVirtualItemFromOwner (displayIndex);
4299 #endif
4300 return (ListViewItem) list [displayIndex];
4303 set {
4304 if (displayIndex < 0 || displayIndex >= Count)
4305 throw new ArgumentOutOfRangeException ("displayIndex");
4307 #if NET_2_0
4308 if (owner != null && owner.VirtualMode)
4309 throw new InvalidOperationException ();
4310 #endif
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;
4320 #if NET_2_0
4321 else {
4322 if (value.Group != null)
4323 value.Group.Items.Remove (value);
4325 value.SetGroup (group);
4327 #endif
4329 list [displayIndex] = value;
4330 CollectionChanged (true);
4334 #if NET_2_0
4335 public virtual ListViewItem this [string key] {
4336 get {
4337 int idx = IndexOfKey (key);
4338 if (idx == -1)
4339 return null;
4341 return this [idx];
4344 #endif
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]; }
4360 set {
4361 if (value is ListViewItem)
4362 this [index] = (ListViewItem) value;
4363 else
4364 this [index] = new ListViewItem (value.ToString ());
4365 OnChange ();
4368 #endregion // Public Properties
4370 #region Public Methods
4371 public virtual ListViewItem Add (ListViewItem value)
4373 #if NET_2_0
4374 if (owner != null && owner.VirtualMode)
4375 throw new InvalidOperationException ();
4376 #endif
4378 AddItem (value);
4379 CollectionChanged (true);
4381 return value;
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);
4396 #if NET_2_0
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);
4406 item.Name = key;
4407 return this.Add (item);
4410 public virtual ListViewItem Add (string key, string text, string imageKey)
4412 ListViewItem item = new ListViewItem (text, imageKey);
4413 item.Name = key;
4414 return this.Add (item);
4416 #endif
4418 public void AddRange (ListViewItem [] values)
4420 if (values == null)
4421 throw new ArgumentNullException ("Argument cannot be null!", "values");
4422 #if NET_2_0
4423 if (owner != null && owner.VirtualMode)
4424 throw new InvalidOperationException ();
4425 #endif
4427 foreach (ListViewItem item in values)
4428 AddItem (item);
4430 CollectionChanged (true);
4433 #if NET_2_0
4434 public void AddRange (ListViewItemCollection items)
4436 if (items == null)
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);
4443 #endif
4445 public virtual void Clear ()
4447 #if NET_2_0
4448 if (owner != null && owner.VirtualMode)
4449 throw new InvalidOperationException ();
4450 #endif
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);
4457 item.Owner = null;
4461 #if NET_2_0
4462 else
4463 foreach (ListViewItem item in list)
4464 item.SetGroup (null);
4465 #endif
4467 list.Clear ();
4468 CollectionChanged (false);
4471 public bool Contains (ListViewItem item)
4473 return IndexOf (item) != -1;
4476 #if NET_2_0
4477 public virtual bool ContainsKey (string key)
4479 return IndexOfKey (key) != -1;
4481 #endif
4483 public void CopyTo (Array dest, int index)
4485 list.CopyTo (dest, index);
4488 #if NET_2_0
4489 public ListViewItem [] Find (string key, bool searchAllSubitems)
4491 if (key == null)
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);
4505 return retval;
4507 #endif
4509 public IEnumerator GetEnumerator ()
4511 #if NET_2_0
4512 if (owner != null && owner.VirtualMode)
4513 throw new InvalidOperationException ();
4514 #endif
4516 return list.GetEnumerator ();
4519 int IList.Add (object item)
4521 int result;
4522 ListViewItem li;
4524 #if NET_2_0
4525 if (owner != null && owner.VirtualMode)
4526 throw new InvalidOperationException ();
4527 #endif
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");
4537 else
4538 li = new ListViewItem (item.ToString ());
4540 li.Owner = owner;
4541 result = list.Add (li);
4542 CollectionChanged (true);
4544 return result;
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);
4561 else
4562 this.Insert (index, item.ToString ());
4565 void IList.Remove (object item)
4567 Remove ((ListViewItem) item);
4570 public int IndexOf (ListViewItem item)
4572 #if NET_2_0
4573 if (owner != null && owner.VirtualMode) {
4574 for (int i = 0; i < Count; i++)
4575 if (RetrieveVirtualItemFromOwner (i) == item)
4576 return i;
4578 return -1;
4580 #endif
4582 return list.IndexOf (item);
4585 #if NET_2_0
4586 public virtual int IndexOfKey (string key)
4588 if (key == null || key.Length == 0)
4589 return -1;
4591 for (int i = 0; i < Count; i++) {
4592 ListViewItem lvi = this [i];
4593 if (String.Compare (key, lvi.Name, true) == 0)
4594 return i;
4597 return -1;
4599 #endif
4601 public ListViewItem Insert (int index, ListViewItem item)
4603 if (index < 0 || index > list.Count)
4604 throw new ArgumentOutOfRangeException ("index");
4606 #if NET_2_0
4607 if (owner != null && owner.VirtualMode)
4608 throw new InvalidOperationException ();
4609 #endif
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)
4618 item.Owner = owner;
4619 #if NET_2_0
4620 else {
4621 if (item.Group != null)
4622 item.Group.Items.Remove (item);
4624 item.SetGroup (group);
4626 #endif
4628 list.Insert (index, item);
4629 CollectionChanged (true);
4630 return item;
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));
4643 #if NET_2_0
4644 public ListViewItem Insert (int index, string key, string text, int imageIndex)
4646 ListViewItem lvi = new ListViewItem (text, imageIndex);
4647 lvi.Name = key;
4648 return Insert (index, lvi);
4650 #endif
4652 public virtual void Remove (ListViewItem item)
4654 #if NET_2_0
4655 if (owner != null && owner.VirtualMode)
4656 throw new InvalidOperationException ();
4657 #endif
4658 if (!list.Contains (item))
4659 return;
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);
4667 list.Remove (item);
4669 if (is_main_collection)
4670 item.Owner = null;
4671 #if NET_2_0
4672 else
4673 item.SetGroup (null);
4674 #endif
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");
4686 #if NET_2_0
4687 if (owner != null && owner.VirtualMode)
4688 throw new InvalidOperationException ();
4689 #endif
4691 ListViewItem item = (ListViewItem) list [index];
4692 Remove (item);
4695 #if NET_2_0
4696 public virtual void RemoveByKey (string key)
4698 int idx = IndexOfKey (key);
4699 if (idx != -1)
4700 RemoveAt (idx);
4702 #endif
4704 #endregion // Public Methods
4706 internal ListView Owner {
4707 get {
4708 return owner;
4710 set {
4711 owner = value;
4715 #if NET_2_0
4716 internal ListViewGroup Group {
4717 get {
4718 return group;
4720 set {
4721 group = value;
4724 #endif
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;
4735 #if NET_2_0
4736 else {
4737 if (value.Group != null)
4738 value.Group.Items.Remove (value);
4740 value.SetGroup (group);
4742 #endif
4744 list.Add (value);
4747 void CollectionChanged (bool sort)
4749 if (owner != null) {
4750 if (sort)
4751 owner.Sort (false);
4753 OnChange ();
4754 owner.Redraw (true);
4758 #if NET_2_0
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);
4768 return retval;
4770 #endif
4772 internal event CollectionChangedHandler Changed;
4774 internal void Sort (IComparer comparer)
4776 list.Sort (comparer);
4777 OnChange ();
4780 internal void OnChange ()
4782 if (Changed != null)
4783 Changed ();
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)
4801 this.owner = owner;
4802 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
4804 #endregion // Public Constructor
4806 #region Public Properties
4807 [Browsable (false)]
4808 public int Count {
4809 get {
4810 if (!owner.IsHandleCreated)
4811 return 0;
4813 return List.Count;
4817 public bool IsReadOnly {
4818 get {
4819 #if NET_2_0
4820 return false;
4821 #else
4822 return true;
4823 #endif
4827 public int this [int index] {
4828 get {
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 {
4845 get {
4846 #if NET_2_0
4847 return false;
4848 #else
4849 return true;
4850 #endif
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
4861 #if NET_2_0
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)
4868 return -1;
4870 owner.Items [itemIndex].Selected = true;
4872 if (!owner.IsHandleCreated)
4873 return 0;
4875 return List.Count;
4877 #endif
4879 #if NET_2_0
4880 public
4881 #else
4882 internal
4883 #endif
4884 void Clear ()
4886 if (!owner.IsHandleCreated)
4887 return;
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.");
4914 void IList.Clear ()
4916 Clear ();
4919 bool IList.Contains (object selectedIndex)
4921 if (!(selectedIndex is int))
4922 return false;
4923 return Contains ((int) selectedIndex);
4926 int IList.IndexOf (object selectedIndex)
4928 if (!(selectedIndex is int))
4929 return -1;
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)
4951 return -1;
4953 return List.IndexOf (selectedIndex);
4956 #if NET_2_0
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;
4964 #endif
4965 #endregion // Public Methods
4967 internal ArrayList List {
4968 get {
4969 if (list == null) {
4970 list = new ArrayList ();
4971 #if NET_2_0
4972 if (!owner.VirtualMode)
4973 #endif
4974 for (int i = 0; i < owner.Items.Count; i++) {
4975 if (owner.Items [i].Selected)
4976 list.Add (i);
4979 return list;
4983 internal void Reset ()
4985 // force re-population of list
4986 #if NET_2_0
4987 if (!owner.VirtualMode)
4988 #endif
4989 list = null;
4992 private void ItemsCollection_Changed ()
4994 Reset ();
4997 #if NET_2_0
4998 internal void RemoveIndex (int index)
5000 int idx = List.BinarySearch (index);
5001 if (idx != -1)
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)
5009 int iMin = 0;
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)
5018 iMax = iMid - 1;
5019 else
5020 iMin = iMid + 1;
5023 List.Insert (iMin, index);
5025 #endif
5027 } // SelectedIndexCollection
5029 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
5031 private readonly ListView owner;
5033 #region Public Constructor
5034 public SelectedListViewItemCollection (ListView owner)
5036 this.owner = owner;
5038 #endregion // Public Constructor
5040 #region Public Properties
5041 [Browsable (false)]
5042 public int Count {
5043 get {
5044 return owner.SelectedIndices.Count;
5048 public bool IsReadOnly {
5049 get { return true; }
5052 public ListViewItem this [int index] {
5053 get {
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];
5062 #if NET_2_0
5063 public virtual ListViewItem this [string key] {
5064 get {
5065 int idx = IndexOfKey (key);
5066 if (idx == -1)
5067 return null;
5069 return this [idx];
5072 #endif
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;
5103 #if NET_2_0
5104 public virtual bool ContainsKey (string key)
5106 return IndexOfKey (key) != -1;
5108 #endif
5110 public void CopyTo (Array dest, int index)
5112 if (!owner.IsHandleCreated)
5113 return;
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))
5141 return false;
5142 return Contains ((ListViewItem) item);
5145 int IList.IndexOf (object item)
5147 if (!(item is ListViewItem))
5148 return -1;
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)
5170 return -1;
5172 for (int i = 0; i < Count; i++)
5173 if (this [i] == item)
5174 return i;
5176 return -1;
5179 #if NET_2_0
5180 public virtual int IndexOfKey (string key)
5182 if (!owner.IsHandleCreated || key == null || key.Length == 0)
5183 return -1;
5185 for (int i = 0; i < Count; i++) {
5186 ListViewItem item = this [i];
5187 if (String.Compare (item.Name, key, true) == 0)
5188 return i;
5191 return -1;
5193 #endif
5194 #endregion // Public Methods
5196 } // SelectedListViewItemCollection
5198 internal delegate void CollectionChangedHandler ();
5200 struct ItemMatrixLocation
5202 int row;
5203 int col;
5205 public ItemMatrixLocation (int row, int col)
5207 this.row = row;
5208 this.col = col;
5212 public int Col {
5213 get {
5214 return col;
5216 set {
5217 col = value;
5221 public int Row {
5222 get {
5223 return row;
5225 set {
5226 row = value;
5232 #endregion // Subclasses
5233 #if NET_2_0
5234 protected override void OnResize (EventArgs e)
5236 base.OnResize (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]);
5257 if (creh != null)
5258 creh (this, e);
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]);
5273 if (eh != null)
5274 eh (this, e);
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]);
5296 if (cwceh != null)
5297 cwceh (this, e);
5301 // 2.0 profile based implementation
5303 bool CanProceedWithResize (ColumnHeader col, int width)
5305 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
5306 if (cwceh == null)
5307 return true;
5309 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
5310 cwceh (this, changing);
5311 return !changing.Cancel;
5313 #else
5315 // 1.0 profile based implementation
5317 bool CanProceedWithResize (ColumnHeader col, int width)
5319 return true;
5322 void RaiseColumnWidthChanged (int resize_column)
5325 #endif