1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
23 // Ravindra Kumar (rkumar@novell.com)
24 // Jordi Mas i Hernandez, jordi@ximian.com
25 // Mike Kestner (mkestner@novell.com)
26 // Daniel Nauck (dna(at)mono-project(dot)de)
29 // - Feedback for item activation, change in cursor types as mouse moves.
36 using System.Collections;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
40 using System.Runtime.InteropServices;
41 using System.Globalization;
43 using System.Collections.Generic;
46 namespace System.Windows.Forms
48 [DefaultEvent ("SelectedIndexChanged")]
49 [DefaultProperty ("Items")]
50 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
52 [ClassInterface (ClassInterfaceType.AutoDispatch)]
54 [Docking (DockingBehavior.Ask)]
56 public class ListView : Control
58 private ItemActivation activation = ItemActivation.Standard;
59 private ListViewAlignment alignment = ListViewAlignment.Top;
60 private bool allow_column_reorder;
61 private bool auto_arrange = true;
62 private bool check_boxes;
63 private readonly CheckedIndexCollection checked_indices;
64 private readonly CheckedListViewItemCollection checked_items;
65 private readonly ColumnHeaderCollection columns;
66 internal ListViewItem focused_item;
67 private bool full_row_select;
68 private bool grid_lines;
69 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
70 private bool hide_selection = true;
71 private bool hover_selection;
72 private IComparer item_sorter;
73 private readonly ListViewItemCollection items;
75 private readonly ListViewGroupCollection groups;
76 private bool show_groups = true;
78 private bool label_edit;
79 private bool label_wrap = true;
80 private bool multiselect = true;
81 private bool scrollable = true;
82 private readonly SelectedIndexCollection selected_indices;
83 private readonly SelectedListViewItemCollection selected_items;
84 private SortOrder sort_order = SortOrder.None;
85 private ImageList state_image_list;
86 private bool updating;
87 private View view = View.LargeIcon;
88 private int layout_wd; // We might draw more than our client area
89 private int layout_ht; // therefore we need to have these two.
90 HeaderControl header_control;
91 internal ItemControl item_control;
92 internal ScrollBar h_scroll; // used for scrolling horizontally
93 internal ScrollBar v_scroll; // used for scrolling vertically
94 internal int h_marker; // Position markers for scrolling
95 internal int v_marker;
96 private int keysearch_tickcnt;
97 private string keysearch_text;
98 static private readonly int keysearch_keydelay = 1000;
99 private int[] reordered_column_indices;
100 private Point [] items_location;
101 private ItemMatrixLocation [] items_matrix_location;
102 private Size item_size; // used for caching item size
104 private Size tile_size;
105 private bool virtual_mode;
106 private int virtual_list_size;
109 // internal variables
110 internal ImageList large_image_list;
111 internal ImageList small_image_list;
112 internal Size text_size = Size.Empty;
115 static object AfterLabelEditEvent = new object ();
116 static object BeforeLabelEditEvent = new object ();
117 static object ColumnClickEvent = new object ();
118 static object ItemActivateEvent = new object ();
119 static object ItemCheckEvent = new object ();
120 static object ItemDragEvent = new object ();
121 static object SelectedIndexChangedEvent = new object ();
123 static object ItemCheckedEvent = new object ();
124 static object CacheVirtualItemsEvent = new object ();
125 static object RetrieveVirtualItemEvent = new object ();
128 public event LabelEditEventHandler AfterLabelEdit {
129 add { Events.AddHandler (AfterLabelEditEvent, value); }
130 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
134 [EditorBrowsable (EditorBrowsableState.Never)]
135 public new event EventHandler BackgroundImageChanged {
136 add { base.BackgroundImageChanged += value; }
137 remove { base.BackgroundImageChanged -= value; }
140 public event LabelEditEventHandler BeforeLabelEdit {
141 add { Events.AddHandler (BeforeLabelEditEvent, value); }
142 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
145 public event ColumnClickEventHandler ColumnClick {
146 add { Events.AddHandler (ColumnClickEvent, value); }
147 remove { Events.RemoveHandler (ColumnClickEvent, value); }
150 public event EventHandler ItemActivate {
151 add { Events.AddHandler (ItemActivateEvent, value); }
152 remove { Events.RemoveHandler (ItemActivateEvent, value); }
155 public event ItemCheckEventHandler ItemCheck {
156 add { Events.AddHandler (ItemCheckEvent, value); }
157 remove { Events.RemoveHandler (ItemCheckEvent, value); }
161 public event ItemCheckedEventHandler ItemChecked {
162 add { Events.AddHandler (ItemCheckedEvent, value); }
163 remove { Events.RemoveHandler (ItemCheckedEvent, value); }
167 public event ItemDragEventHandler ItemDrag {
168 add { Events.AddHandler (ItemDragEvent, value); }
169 remove { Events.RemoveHandler (ItemDragEvent, value); }
173 [EditorBrowsable (EditorBrowsableState.Never)]
174 public new event PaintEventHandler Paint {
175 add { base.Paint += value; }
176 remove { base.Paint -= value; }
179 public event EventHandler SelectedIndexChanged {
180 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
181 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
185 [EditorBrowsable (EditorBrowsableState.Never)]
186 public new event EventHandler TextChanged {
187 add { base.TextChanged += value; }
188 remove { base.TextChanged -= value; }
192 public event CacheVirtualItemsEventHandler CacheVirtualItems {
193 add { Events.AddHandler (CacheVirtualItemsEvent, value); }
194 remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); }
197 public event RetrieveVirtualItemEventHandler RetrieveVirtualItem {
198 add { Events.AddHandler (RetrieveVirtualItemEvent, value); }
199 remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); }
205 #region Public Constructors
208 background_color = ThemeEngine.Current.ColorWindow;
209 items = new ListViewItemCollection (this);
211 groups = new ListViewGroupCollection (this);
213 checked_indices = new CheckedIndexCollection (this);
214 checked_items = new CheckedListViewItemCollection (this);
215 columns = new ColumnHeaderCollection (this);
216 foreground_color = SystemColors.WindowText;
217 selected_indices = new SelectedIndexCollection (this);
218 selected_items = new SelectedListViewItemCollection (this);
219 items_location = new Point [16];
220 items_matrix_location = new ItemMatrixLocation [16];
222 border_style = BorderStyle.Fixed3D;
224 header_control = new HeaderControl (this);
225 header_control.Visible = false;
226 Controls.AddImplicit (header_control);
228 item_control = new ItemControl (this);
229 Controls.AddImplicit (item_control);
231 h_scroll = new ImplicitHScrollBar ();
232 Controls.AddImplicit (this.h_scroll);
234 v_scroll = new ImplicitVScrollBar ();
235 Controls.AddImplicit (this.v_scroll);
237 h_marker = v_marker = 0;
238 keysearch_tickcnt = 0;
240 // scroll bars are disabled initially
241 h_scroll.Visible = false;
242 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
243 v_scroll.Visible = false;
244 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
247 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
248 SizeChanged += new EventHandler (ListView_SizeChanged);
249 GotFocus += new EventHandler (FocusChanged);
250 LostFocus += new EventHandler (FocusChanged);
251 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
253 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
255 | ControlStyles.UseTextForAccessibility
259 #endregion // Public Constructors
261 #region Private Internal Properties
262 internal Size CheckBoxSize {
264 if (this.check_boxes) {
265 if (this.state_image_list != null)
266 return this.state_image_list.ImageSize;
268 return ThemeEngine.Current.ListViewCheckBoxSize;
274 internal Size ItemSize {
276 if (view != View.Details)
279 Size size = new Size ();
280 size.Height = item_size.Height;
281 for (int i = 0; i < columns.Count; i++)
282 size.Width += columns [i].Wd;
291 #endregion // Private Internal Properties
293 #region Protected Properties
294 protected override CreateParams CreateParams {
295 get { return base.CreateParams; }
298 protected override Size DefaultSize {
299 get { return ThemeEngine.Current.ListViewDefaultSize; }
301 #endregion // Protected Properties
303 #region Public Instance Properties
304 [DefaultValue (ItemActivation.Standard)]
305 public ItemActivation Activation {
306 get { return activation; }
308 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
309 value != ItemActivation.TwoClick) {
310 throw new InvalidEnumArgumentException (string.Format
311 ("Enum argument value '{0}' is not valid for Activation", value));
318 [DefaultValue (ListViewAlignment.Top)]
320 public ListViewAlignment Alignment {
321 get { return alignment; }
323 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
324 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
325 throw new InvalidEnumArgumentException (string.Format
326 ("Enum argument value '{0}' is not valid for Alignment", value));
329 if (this.alignment != value) {
331 // alignment does not matter in Details/List views
332 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
338 [DefaultValue (false)]
339 public bool AllowColumnReorder {
340 get { return allow_column_reorder; }
341 set { allow_column_reorder = value; }
344 [DefaultValue (true)]
345 public bool AutoArrange {
346 get { return auto_arrange; }
348 if (auto_arrange != value) {
349 auto_arrange = value;
350 // autoarrange does not matter in Details/List views
351 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
357 public override Color BackColor {
359 if (background_color.IsEmpty)
360 return ThemeEngine.Current.ColorWindow;
362 return background_color;
364 set { background_color = value; }
368 [EditorBrowsable (EditorBrowsableState.Never)]
369 public override Image BackgroundImage {
370 get { return base.BackgroundImage; }
371 set { base.BackgroundImage = value; }
374 [DefaultValue (BorderStyle.Fixed3D)]
376 public BorderStyle BorderStyle {
377 get { return InternalBorderStyle; }
378 set { InternalBorderStyle = value; }
381 [DefaultValue (false)]
382 public bool CheckBoxes {
383 get { return check_boxes; }
385 if (check_boxes != value) {
387 if (value && View == View.Tile)
388 throw new NotSupportedException ("CheckBoxes are not"
389 + " supported in Tile view. Choose a different"
390 + " view or set CheckBoxes to false.");
400 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 public CheckedIndexCollection CheckedIndices {
402 get { return checked_indices; }
406 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
407 public CheckedListViewItemCollection CheckedItems {
408 get { return checked_items; }
411 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
413 [MergableProperty (false)]
414 public ColumnHeaderCollection Columns {
415 get { return columns; }
419 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
420 public ListViewItem FocusedItem {
426 throw new NotImplementedException ();
431 public override Color ForeColor {
433 if (foreground_color.IsEmpty)
434 return ThemeEngine.Current.ColorWindowText;
436 return foreground_color;
438 set { foreground_color = value; }
441 [DefaultValue (false)]
442 public bool FullRowSelect {
443 get { return full_row_select; }
444 set { full_row_select = value; }
447 [DefaultValue (false)]
448 public bool GridLines {
449 get { return grid_lines; }
451 if (grid_lines != value) {
458 [DefaultValue (ColumnHeaderStyle.Clickable)]
459 public ColumnHeaderStyle HeaderStyle {
460 get { return header_style; }
462 if (header_style == value)
466 case ColumnHeaderStyle.Clickable:
467 case ColumnHeaderStyle.Nonclickable:
468 case ColumnHeaderStyle.None:
471 throw new InvalidEnumArgumentException (string.Format
472 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
475 header_style = value;
476 if (view == View.Details)
481 [DefaultValue (true)]
482 public bool HideSelection {
483 get { return hide_selection; }
485 if (hide_selection != value) {
486 hide_selection = value;
492 [DefaultValue (false)]
493 public bool HoverSelection {
494 get { return hover_selection; }
495 set { hover_selection = value; }
498 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
500 [MergableProperty (false)]
501 public ListViewItemCollection Items {
502 get { return items; }
505 [DefaultValue (false)]
506 public bool LabelEdit {
507 get { return label_edit; }
508 set { label_edit = value; }
511 [DefaultValue (true)]
513 public bool LabelWrap {
514 get { return label_wrap; }
516 if (label_wrap != value) {
523 [DefaultValue (null)]
524 public ImageList LargeImageList {
525 get { return large_image_list; }
527 large_image_list = value;
533 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
534 public IComparer ListViewItemSorter {
536 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
541 if (item_sorter != value) {
548 [DefaultValue (true)]
549 public bool MultiSelect {
550 get { return multiselect; }
551 set { multiselect = value; }
554 [DefaultValue (true)]
555 public bool Scrollable {
556 get { return scrollable; }
558 if (scrollable != value) {
566 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
567 public SelectedIndexCollection SelectedIndices {
568 get { return selected_indices; }
572 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
573 public SelectedListViewItemCollection SelectedItems {
574 get { return selected_items; }
579 public bool ShowGroups {
580 get { return show_groups; }
582 if (show_groups != value) {
589 [LocalizableAttribute (true)]
590 [MergableProperty (false)]
591 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
592 public ListViewGroupCollection Groups {
593 get { return groups; }
597 [DefaultValue (null)]
598 public ImageList SmallImageList {
599 get { return small_image_list; }
601 small_image_list = value;
606 [DefaultValue (SortOrder.None)]
607 public SortOrder Sorting {
608 get { return sort_order; }
610 if (!Enum.IsDefined (typeof (SortOrder), value)) {
611 throw new InvalidEnumArgumentException ("value", (int) value,
615 if (sort_order == value)
621 if (virtual_mode) // Sorting is not allowed in virtual mode
625 if (value == SortOrder.None) {
626 if (item_sorter != null) {
627 // ListViewItemSorter should never be reset for SmallIcon
628 // and LargeIcon view
629 if (View != View.SmallIcon && View != View.LargeIcon)
633 // in .NET 1.1, only internal IComparer would be
635 if (item_sorter is ItemComparer)
641 if (item_sorter == null)
642 item_sorter = new ItemComparer (value);
643 if (item_sorter is ItemComparer) {
645 item_sorter = new ItemComparer (value);
647 // in .NET 1.1, the sort order is not updated for
648 // SmallIcon and LargeIcon views if no custom IComparer
650 if (View != View.SmallIcon && View != View.LargeIcon)
651 item_sorter = new ItemComparer (value);
659 [DefaultValue (null)]
660 public ImageList StateImageList {
661 get { return state_image_list; }
663 state_image_list = value;
670 [EditorBrowsable (EditorBrowsableState.Never)]
671 public override string Text {
672 get { return base.Text; }
674 if (value == base.Text)
684 public Size TileSize {
689 if (value.Width <= 0 || value.Height <= 0)
690 throw new ArgumentOutOfRangeException ("value");
699 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
700 public ListViewItem TopItem {
703 if (this.items.Count == 0)
705 // if contents are not scrolled
706 // it is the first item
707 else if (h_marker == 0 && v_marker == 0)
708 return this.items [0];
709 // do a hit test for the scrolled position
711 for (int i = 0; i < items.Count; i++) {
712 Point item_loc = GetItemLocation (i);
713 if (item_loc.X >= 0 && item_loc.Y >= 0)
721 throw new NotImplementedException ();
727 [EditorBrowsable (EditorBrowsableState.Advanced)]
728 [DefaultValue (true)]
730 [MonoInternalNote ("Stub, not implemented")]
731 public bool UseCompatibleStateImageBehavior {
740 [DefaultValue (View.LargeIcon)]
744 if (!Enum.IsDefined (typeof (View), value))
745 throw new InvalidEnumArgumentException ("value", (int) value,
750 if (CheckBoxes && value == View.Tile)
751 throw new NotSupportedException ("CheckBoxes are not"
752 + " supported in Tile view. Choose a different"
753 + " view or set CheckBoxes to false.");
756 h_scroll.Value = v_scroll.Value = 0;
764 public bool VirtualMode {
769 if (virtual_mode == value)
772 if (!virtual_mode && items.Count > 0)
773 throw new InvalidOperationException ();
775 virtual_mode = value;
780 public int VirtualListSize {
782 return virtual_list_size;
786 throw new ArgumentException ("value");
788 if (virtual_list_size == value)
791 virtual_list_size = value;
797 #endregion // Public Instance Properties
799 #region Internal Methods Properties
801 internal int FirstVisibleIndex {
804 if (this.items.Count == 0)
807 if (h_marker == 0 && v_marker == 0)
810 Size item_size = ItemSize;
811 for (int i = 0; i < items.Count; i++) {
812 Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size);
813 if (item_rect.Right >= 0 && item_rect.Bottom >= 0)
822 internal int LastVisibleIndex {
824 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
825 if (View == View.List || Alignment == ListViewAlignment.Left) {
826 if (GetItemLocation (i).X > item_control.ClientRectangle.Right)
829 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
834 return Items.Count - 1;
838 internal void OnSelectedIndexChanged ()
841 OnSelectedIndexChanged (EventArgs.Empty);
844 internal int TotalWidth {
845 get { return Math.Max (this.Width, this.layout_wd); }
848 internal int TotalHeight {
849 get { return Math.Max (this.Height, this.layout_ht); }
852 internal void Redraw (bool recalculate)
854 // Avoid calculations when control is being updated
858 // VirtualMode doesn't do any calculations until handle is created
859 if (virtual_mode && !IsHandleCreated)
865 CalculateListView (this.alignment);
870 const int text_padding = 15;
872 internal Size GetChildColumnSize (int index)
874 Size ret_size = Size.Empty;
875 ColumnHeader col = this.columns [index];
877 if (col.Width == -2) { // autosize = max(items, columnheader)
878 Size size = Size.Ceiling (this.DeviceContext.MeasureString
879 (col.Text, this.Font));
880 size.Width += text_padding;
881 ret_size = BiggestItem (index);
882 if (size.Width > ret_size.Width)
885 else { // -1 and all the values < -2 are put under one category
886 ret_size = BiggestItem (index);
887 // fall back to empty columns' width if no subitem is available for a column
888 if (ret_size.IsEmpty) {
889 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
890 if (col.Text.Length > 0)
891 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
892 (col.Text, this.Font)).Height;
894 ret_size.Height = this.Font.Height;
898 ret_size.Height += text_padding;
900 // adjust the size for icon and checkbox for 0th column
902 ret_size.Width += (this.CheckBoxSize.Width + 4);
903 if (this.small_image_list != null)
904 ret_size.Width += this.small_image_list.ImageSize.Width;
909 // Returns the size of biggest item text in a column.
910 private Size BiggestItem (int col)
912 Size temp = Size.Empty;
913 Size ret_size = Size.Empty;
916 // VirtualMode uses the first item text size
917 if (virtual_mode && items.Count > 0) {
918 ListViewItem item = items [0];
919 ret_size = Size.Ceiling (DeviceContext.MeasureString (item.SubItems [col].Text,
923 // 0th column holds the item text, we check the size of
924 // the various subitems falling in that column and get
925 // the biggest one's size.
926 foreach (ListViewItem item in items) {
927 if (col >= item.SubItems.Count)
930 temp = Size.Ceiling (DeviceContext.MeasureString
931 (item.SubItems [col].Text, Font));
932 if (temp.Width > ret_size.Width)
939 // adjustment for space
940 if (!ret_size.IsEmpty)
946 const int max_wrap_padding = 38;
948 // Sets the size of the biggest item text as per the view
949 private void CalcTextSize ()
951 // clear the old value
952 text_size = Size.Empty;
954 if (items.Count == 0)
957 text_size = BiggestItem (0);
959 if (view == View.LargeIcon && this.label_wrap) {
960 Size temp = Size.Empty;
961 if (this.check_boxes)
962 temp.Width += 2 * this.CheckBoxSize.Width;
963 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
964 temp.Width += icon_w + max_wrap_padding;
965 // wrapping is done for two lines only
966 if (text_size.Width > temp.Width) {
967 text_size.Width = temp.Width;
968 text_size.Height *= 2;
971 else if (view == View.List) {
972 // in list view max text shown in determined by the
973 // control width, even if scolling is enabled.
974 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
975 if (this.small_image_list != null)
976 max_wd -= this.small_image_list.ImageSize.Width;
978 if (text_size.Width > max_wd)
979 text_size.Width = max_wd;
982 // we do the default settings, if we have got 0's
983 if (text_size.Height <= 0)
984 text_size.Height = this.Font.Height;
985 if (text_size.Width <= 0)
986 text_size.Width = this.Width;
989 text_size.Width += 4;
990 text_size.Height += 2;
993 private void Scroll (ScrollBar scrollbar, int delta)
995 if (delta == 0 || !scrollbar.Visible)
999 if (scrollbar == h_scroll)
1000 max = h_scroll.Maximum - item_control.Width;
1002 max = v_scroll.Maximum - item_control.Height;
1004 int val = scrollbar.Value + delta;
1007 else if (val < scrollbar.Minimum)
1008 val = scrollbar.Minimum;
1009 scrollbar.Value = val;
1012 private void CalculateScrollBars ()
1014 Rectangle client_area = ClientRectangle;
1016 if (!this.scrollable || this.items.Count <= 0) {
1017 h_scroll.Visible = false;
1018 v_scroll.Visible = false;
1019 item_control.Location = new Point (0, header_control.Height);
1020 item_control.Height = ClientRectangle.Width - header_control.Height;
1021 item_control.Width = ClientRectangle.Width;
1022 header_control.Width = ClientRectangle.Width;
1026 // Don't calculate if the view is not displayable
1027 if (client_area.Height < 0 || client_area.Width < 0)
1030 // making a scroll bar visible might make
1031 // other scroll bar visible
1032 if (layout_wd > client_area.Right) {
1033 h_scroll.Visible = true;
1034 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1035 v_scroll.Visible = true;
1037 v_scroll.Visible = false;
1038 } else if (layout_ht > client_area.Bottom) {
1039 v_scroll.Visible = true;
1040 if ((layout_wd + v_scroll.Width) > client_area.Right)
1041 h_scroll.Visible = true;
1043 h_scroll.Visible = false;
1045 h_scroll.Visible = false;
1046 v_scroll.Visible = false;
1049 item_control.Height = ClientRectangle.Height - header_control.Height;
1051 if (h_scroll.is_visible) {
1052 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1053 h_scroll.Minimum = 0;
1055 // if v_scroll is visible, adjust the maximum of the
1056 // h_scroll to account for the width of v_scroll
1057 if (v_scroll.Visible) {
1058 h_scroll.Maximum = layout_wd + v_scroll.Width;
1059 h_scroll.Width = client_area.Width - v_scroll.Width;
1062 h_scroll.Maximum = layout_wd;
1063 h_scroll.Width = client_area.Width;
1066 h_scroll.LargeChange = client_area.Width;
1067 h_scroll.SmallChange = Font.Height;
1068 item_control.Height -= h_scroll.Height;
1071 if (header_control.is_visible)
1072 header_control.Width = ClientRectangle.Width;
1073 item_control.Width = ClientRectangle.Width;
1075 if (v_scroll.is_visible) {
1076 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1077 v_scroll.Minimum = 0;
1079 // if h_scroll is visible, adjust the maximum of the
1080 // v_scroll to account for the height of h_scroll
1081 if (h_scroll.Visible) {
1082 v_scroll.Maximum = layout_ht + h_scroll.Height;
1083 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
1085 v_scroll.Maximum = layout_ht;
1086 v_scroll.Height = client_area.Height;
1089 v_scroll.LargeChange = client_area.Height;
1090 v_scroll.SmallChange = Font.Height;
1091 if (header_control.Visible)
1092 header_control.Width -= v_scroll.Width;
1093 item_control.Width -= v_scroll.Width;
1098 internal int GetReorderedColumnIndex (ColumnHeader column)
1100 if (reordered_column_indices == null)
1101 return column.Index;
1103 for (int i = 0; i < Columns.Count; i++)
1104 if (reordered_column_indices [i] == column.Index)
1111 internal ColumnHeader GetReorderedColumn (int index)
1113 if (reordered_column_indices == null)
1114 return Columns [index];
1116 return Columns [reordered_column_indices [index]];
1119 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1123 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1125 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1129 header_control.Invalidate ();
1130 item_control.Invalidate ();
1136 int column_count = Columns.Count;
1138 if (reordered_column_indices == null) {
1139 reordered_column_indices = new int [column_count];
1140 for (int i = 0; i < column_count; i++)
1141 reordered_column_indices [i] = i;
1144 if (reordered_column_indices [index] == col.Index)
1147 int[] curr = reordered_column_indices;
1148 int [] result = new int [column_count];
1150 for (int i = 0; i < column_count; i++) {
1151 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1155 result [i] = col.Index;
1157 result [i] = curr [curr_idx++];
1160 ReorderColumns (result, true);
1163 internal void ReorderColumns (int [] display_indices, bool redraw)
1165 reordered_column_indices = display_indices;
1166 for (int i = 0; i < Columns.Count; i++) {
1167 ColumnHeader col = Columns [i];
1168 col.InternalDisplayIndex = reordered_column_indices [i];
1170 if (redraw && view == View.Details && IsHandleCreated) {
1172 header_control.Invalidate ();
1173 item_control.Invalidate ();
1177 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1179 int column_count = Columns.Count;
1180 newCol.SetListView (this);
1182 int [] display_indices = new int [column_count];
1183 for (int i = 0; i < column_count; i++) {
1184 ColumnHeader col = Columns [i];
1186 display_indices [i] = index;
1188 int display_index = col.InternalDisplayIndex;
1189 if (display_index < index) {
1190 display_indices [i] = display_index;
1192 display_indices [i] = (display_index + 1);
1197 ReorderColumns (display_indices, redraw);
1201 Size LargeIconItemSize
1204 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1205 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1206 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
1207 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1208 return new Size (w, h);
1212 Size SmallIconItemSize {
1214 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1215 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1216 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
1217 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1218 return new Size (w, h);
1225 // Calculate tile size if needed
1226 // It appears that using Font.Size instead of a SizeF value can give us
1227 // a slightly better approach to the proportions defined in .Net
1228 if (tile_size == Size.Empty) {
1229 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1230 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1231 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1232 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1234 tile_size = new Size (w, h);
1242 int GetDetailsItemHeight ()
1245 int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1246 int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1247 item_height = Math.Max (checkbox_height, text_size.Height);
1248 item_height = Math.Max (item_height, small_image_height);
1253 void SetItemLocation (int index, int x, int y, int row, int col)
1255 Point old_location = items_location [index];
1256 if (old_location.X == x && old_location.Y == y)
1259 Size item_size = ItemSize;
1260 Rectangle old_rect = new Rectangle (GetItemLocation (index), item_size);
1262 items_location [index] = new Point (x, y);
1263 items_matrix_location [index] = new ItemMatrixLocation (row, col);
1265 // Invalidate both previous and new bounds
1266 item_control.Invalidate (old_rect);
1267 item_control.Invalidate (new Rectangle (GetItemLocation (index), item_size));
1272 int[,] item_index_matrix;
1274 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1276 header_control.Visible = false;
1277 header_control.Size = Size.Empty;
1278 item_control.Visible = true;
1279 item_control.Location = Point.Empty;
1280 ItemSize = item_size; // Cache item size
1282 if (items.Count == 0)
1285 Size sz = item_size;
1286 Rectangle area = ClientRectangle;
1289 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
1292 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1294 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
1297 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1300 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1301 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
1302 item_index_matrix = new int [rows, cols];
1305 for (int i = 0; i < items.Count; i++) {
1306 int x = col * (sz.Width + x_spacing);
1307 int y = row * (sz.Height + y_spacing);
1308 SetItemLocation (i, x, y, row, col);
1309 item_index_matrix [row, col] = i;
1311 if (!virtual_mode) // Virtual mode sets Layout until draw time
1313 items [i].Layout ();
1316 if (++row == rows) {
1321 if (++col == cols) {
1328 item_control.Size = new Size (layout_wd, layout_ht);
1331 void LayoutHeader ()
1334 for (int i = 0; i < Columns.Count; i++) {
1335 ColumnHeader col = GetReorderedColumn (i);
1338 col.CalcColumnHeader ();
1342 if (x < ClientRectangle.Width)
1343 x = ClientRectangle.Width;
1345 if (header_style == ColumnHeaderStyle.None) {
1346 header_control.Visible = false;
1347 header_control.Size = Size.Empty;
1349 header_control.Width = x;
1350 header_control.Height = columns [0].Ht;
1351 header_control.Visible = true;
1355 void LayoutDetails ()
1357 if (columns.Count == 0) {
1358 header_control.Visible = false;
1359 item_control.Visible = false;
1365 item_control.Visible = true;
1366 item_control.Location = new Point (0, header_control.Height);
1368 int item_height = GetDetailsItemHeight ();
1369 ItemSize = new Size (0, item_height); // We only cache Height for details view
1372 if (items.Count > 0) {
1373 for (int i = 0; i < items.Count; i++) {
1374 SetItemLocation (i, 0, y, 0, 0);
1376 if (!virtual_mode) // Virtual mode sets Layout until draw time
1378 items [i].Layout ();
1380 y += item_height + 2;
1383 // some space for bottom gridline
1388 layout_wd = Math.Max (header_control.Width, item_control.Width);
1389 layout_ht = y + header_control.Height;
1392 private void AdjustItemsPositionArray (int count)
1394 if (items_location.Length >= count)
1397 // items_location and items_matrix_location must keep the same length
1398 count = Math.Max (count, items_location.Length * 2);
1399 items_location = new Point [count];
1400 items_matrix_location = new ItemMatrixLocation [count];
1403 private void CalculateListView (ListViewAlignment align)
1407 AdjustItemsPositionArray (items.Count);
1414 case View.SmallIcon:
1415 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left, 4, 2);
1418 case View.LargeIcon:
1419 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
1420 ThemeEngine.Current.ListViewHorizontalSpacing,
1421 ThemeEngine.Current.ListViewVerticalSpacing);
1425 LayoutIcons (SmallIconItemSize, true, 4, 2);
1429 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
1430 ThemeEngine.Current.ListViewHorizontalSpacing,
1431 ThemeEngine.Current.ListViewVerticalSpacing);
1436 CalculateScrollBars ();
1439 internal Point GetItemLocation (int index)
1441 Point loc = items_location [index];
1442 loc.X -= h_marker; // Adjust to scroll
1448 private bool KeySearchString (KeyEventArgs ke)
1450 int current_tickcnt = Environment.TickCount;
1451 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1452 keysearch_text = string.Empty;
1455 keysearch_text += (char) ke.KeyData;
1456 keysearch_tickcnt = current_tickcnt;
1458 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1461 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1462 CompareOptions.IgnoreCase)) {
1463 SetFocusedItem (Items [i]);
1464 items [i].Selected = true;
1468 i = (i + 1 < Items.Count) ? i+1 : 0;
1476 int GetAdjustedIndex (Keys key)
1480 if (View == View.Details) {
1483 result = FocusedItem.Index - 1;
1486 result = FocusedItem.Index + 1;
1487 if (result == items.Count)
1491 int last_index = LastVisibleIndex;
1492 Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
1493 if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
1495 if (FocusedItem.Index == last_index) {
1496 if (FocusedItem.Index < Items.Count - 1) {
1497 int page_size = item_control.Height / ItemSize.Height - 1;
1498 result = FocusedItem.Index + page_size - 1;
1499 if (result >= Items.Count)
1500 result = Items.Count - 1;
1503 result = last_index;
1506 int first_index = FirstVisibleIndex;
1507 if (GetItemLocation (first_index).Y < 0)
1509 if (FocusedItem.Index == first_index) {
1510 if (first_index > 0) {
1511 int page_size = item_control.Height / ItemSize.Height - 1;
1512 result = first_index - page_size + 1;
1517 result = first_index;
1523 ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.Index];
1524 int row = item_matrix_location.Row;
1525 int col = item_matrix_location.Col;
1531 return item_index_matrix [row, col - 1];
1534 if (col == (cols - 1))
1536 while (item_index_matrix [row, col + 1] == 0) {
1541 return item_index_matrix [row, col + 1];
1546 return item_index_matrix [row - 1, col];
1549 if (row == (rows - 1) || row == Items.Count - 1)
1551 while (item_index_matrix [row + 1, col] == 0) {
1556 return item_index_matrix [row + 1, col];
1563 ListViewItem selection_start;
1565 private bool SelectItems (ArrayList sel_items)
1567 bool changed = false;
1568 ArrayList curr_items = SelectedItems.List;
1569 foreach (ListViewItem item in curr_items)
1570 if (!sel_items.Contains (item)) {
1571 item.Selected = false;
1574 foreach (ListViewItem item in sel_items)
1575 if (!item.Selected) {
1576 item.Selected = true;
1582 private void UpdateMultiSelection (int index, bool reselect)
1584 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1585 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1586 ListViewItem item = items [index];
1588 if (shift_pressed && selection_start != null) {
1589 ArrayList list = new ArrayList ();
1590 int start_index = selection_start.Index;
1591 int start = Math.Min (start_index, index);
1592 int end = Math.Max (start_index, index);
1593 if (View == View.Details) {
1594 for (int i = start; i <= end; i++)
1595 list.Add (items [i]);
1597 ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
1598 ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
1599 int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
1600 int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
1601 int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
1602 int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
1604 for (int i = 0; i < items.Count; i++) {
1605 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
1607 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
1608 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
1609 list.Add (items [i]);
1613 } else if (ctrl_pressed) {
1614 item.Selected = !item.Selected;
1615 selection_start = item;
1618 // do not unselect, and reselect the item
1619 foreach (int itemIndex in SelectedIndices) {
1620 if (index == itemIndex)
1622 items [itemIndex].Selected = false;
1625 SelectedItems.Clear ();
1626 item.Selected = true;
1628 selection_start = item;
1632 internal override bool InternalPreProcessMessage (ref Message msg)
1634 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
1635 Keys key_data = (Keys)msg.WParam.ToInt32();
1636 if (HandleNavKeys (key_data))
1639 return base.InternalPreProcessMessage (ref msg);
1642 bool HandleNavKeys (Keys key_data)
1644 if (Items.Count == 0 || !item_control.Visible)
1647 if (FocusedItem == null)
1648 SetFocusedItem (Items [0]);
1652 SelectIndex (Items.Count - 1);
1665 SelectIndex (GetAdjustedIndex (key_data));
1675 void SelectIndex (int index)
1681 UpdateMultiSelection (index, true);
1682 else if (!items [index].Selected)
1683 items [index].Selected = true;
1685 SetFocusedItem (items [index]);
1686 EnsureVisible (index);
1689 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1691 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1694 ke.Handled = KeySearchString (ke);
1697 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
1699 Point loc = PointToClient (Control.MousePosition);
1700 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
1703 internal class ItemControl : Control {
1706 ListViewItem clicked_item;
1707 ListViewItem last_clicked_item;
1708 bool hover_processed = false;
1709 bool checking = false;
1711 ListViewLabelEditTextBox edit_text_box;
1712 internal ListViewItem edit_item;
1713 LabelEditEventArgs edit_args;
1715 public ItemControl (ListView owner)
1718 DoubleClick += new EventHandler(ItemsDoubleClick);
1719 MouseDown += new MouseEventHandler(ItemsMouseDown);
1720 MouseMove += new MouseEventHandler(ItemsMouseMove);
1721 MouseHover += new EventHandler(ItemsMouseHover);
1722 MouseUp += new MouseEventHandler(ItemsMouseUp);
1725 void ItemsDoubleClick (object sender, EventArgs e)
1727 if (owner.activation == ItemActivation.Standard)
1728 owner.OnItemActivate (EventArgs.Empty);
1738 BoxSelect box_select_mode = BoxSelect.None;
1739 ArrayList prev_selection;
1740 Point box_select_start;
1742 Rectangle box_select_rect;
1743 internal Rectangle BoxSelectRectangle {
1744 get { return box_select_rect; }
1746 if (box_select_rect == value)
1749 InvalidateBoxSelectRect ();
1750 box_select_rect = value;
1751 InvalidateBoxSelectRect ();
1755 void InvalidateBoxSelectRect ()
1757 if (BoxSelectRectangle.Size.IsEmpty)
1760 Rectangle edge = BoxSelectRectangle;
1766 edge.Y = BoxSelectRectangle.Bottom - 1;
1768 edge.Y = BoxSelectRectangle.Y - 1;
1770 edge.Height = BoxSelectRectangle.Height + 2;
1772 edge.X = BoxSelectRectangle.Right - 1;
1776 private Rectangle CalculateBoxSelectRectangle (Point pt)
1778 int left = Math.Min (box_select_start.X, pt.X);
1779 int right = Math.Max (box_select_start.X, pt.X);
1780 int top = Math.Min (box_select_start.Y, pt.Y);
1781 int bottom = Math.Max (box_select_start.Y, pt.Y);
1782 return Rectangle.FromLTRB (left, top, right, bottom);
1785 ArrayList BoxSelectedItems {
1787 ArrayList result = new ArrayList ();
1788 Size item_size = owner.ItemSize;
1789 for (int i = 0; i < owner.Items.Count; i++) {
1790 Rectangle r = new Rectangle (owner.GetItemLocation (i), item_size);
1792 r.Y += r.Height / 4;
1795 if (BoxSelectRectangle.IntersectsWith (r))
1796 result.Add (owner.Items [i]);
1802 private bool PerformBoxSelection (Point pt)
1804 if (box_select_mode == BoxSelect.None)
1807 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1809 ArrayList box_items = BoxSelectedItems;
1813 switch (box_select_mode) {
1815 case BoxSelect.Normal:
1819 case BoxSelect.Control:
1820 items = new ArrayList ();
1821 foreach (ListViewItem item in prev_selection)
1822 if (!box_items.Contains (item))
1824 foreach (ListViewItem item in box_items)
1825 if (!prev_selection.Contains (item))
1829 case BoxSelect.Shift:
1831 foreach (ListViewItem item in box_items)
1832 prev_selection.Remove (item);
1833 foreach (ListViewItem item in prev_selection)
1838 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1842 owner.SelectItems (items);
1848 private void ToggleCheckState (ListViewItem item)
1850 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1851 item.Checked = !item.Checked;
1852 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1854 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1855 owner.OnItemCheck (ice);
1858 // ItemCheckedEvent goes after the checked state has changed
1859 ItemCheckedEventArgs icea = new ItemCheckedEventArgs (item);
1860 owner.OnItemChecked (icea);
1864 private void ItemsMouseDown (object sender, MouseEventArgs me)
1866 if (owner.items.Count == 0) {
1867 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
1871 Size item_size = owner.ItemSize;
1872 Point pt = new Point (me.X, me.Y);
1873 for (int i = 0; i < owner.items.Count; i++) {
1874 Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
1875 if (!item_rect.Contains (pt))
1878 if (me.Clicks == 1 && owner.items [i].CheckRectReal.Contains (pt)) {
1880 ToggleCheckState (owner.items [i]);
1881 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
1885 if (owner.View == View.Details && !owner.FullRowSelect) {
1886 if (owner.items [i].GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1887 clicked_item = owner.items [i];
1891 clicked_item = owner.items [i];
1895 if (clicked_item != null) {
1896 owner.SetFocusedItem (clicked_item);
1897 bool changed = !clicked_item.Selected;
1899 if (owner.MultiSelect) {
1900 bool reselect = (!owner.LabelEdit || changed);
1901 owner.UpdateMultiSelection (clicked_item.Index, reselect);
1903 clicked_item.Selected = true;
1906 // Raise double click if the item was clicked. On MS the
1907 // double click is only raised if you double click an item
1908 if (me.Clicks > 1) {
1909 owner.OnDoubleClick (EventArgs.Empty);
1910 if (owner.CheckBoxes)
1911 ToggleCheckState (clicked_item);
1912 } else if (me.Clicks == 1) {
1913 owner.OnClick (EventArgs.Empty);
1914 if (owner.LabelEdit && !changed)
1915 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
1918 if (owner.MultiSelect) {
1919 Keys mods = XplatUI.State.ModifierKeys;
1920 if ((mods & Keys.Shift) != 0)
1921 box_select_mode = BoxSelect.Shift;
1922 else if ((mods & Keys.Control) != 0)
1923 box_select_mode = BoxSelect.Control;
1925 box_select_mode = BoxSelect.Normal;
1926 box_select_start = pt;
1927 prev_selection = owner.SelectedItems.List;
1928 } else if (owner.SelectedItems.Count > 0) {
1929 owner.SelectedItems.Clear ();
1933 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
1936 private void ItemsMouseMove (object sender, MouseEventArgs me)
1938 bool done = PerformBoxSelection (new Point (me.X, me.Y));
1940 if (!done && owner.HoverSelection && hover_processed) {
1942 Point pt = PointToClient (Control.MousePosition);
1943 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1944 if (item != null && !item.Selected) {
1945 hover_processed = false;
1946 XplatUI.ResetMouseHover (Handle);
1950 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
1954 private void ItemsMouseHover (object sender, EventArgs e)
1956 owner.OnMouseHover(e);
1958 if (Capture || !owner.HoverSelection)
1961 hover_processed = true;
1962 Point pt = PointToClient (Control.MousePosition);
1963 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1968 item.Selected = true;
1971 private void ItemsMouseUp (object sender, MouseEventArgs me)
1974 if (owner.Items.Count == 0) {
1975 owner.OnMouseUp (owner.TranslateMouseEventArgs (me));
1979 Point pt = new Point (me.X, me.Y);
1981 Rectangle rect = Rectangle.Empty;
1982 if (clicked_item != null) {
1983 if (owner.view == View.Details && !owner.full_row_select)
1984 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1986 rect = clicked_item.Bounds;
1988 if (rect.Contains (pt)) {
1989 switch (owner.activation) {
1990 case ItemActivation.OneClick:
1991 owner.OnItemActivate (EventArgs.Empty);
1994 case ItemActivation.TwoClick:
1995 if (last_clicked_item == clicked_item) {
1996 owner.OnItemActivate (EventArgs.Empty);
1997 last_clicked_item = null;
1999 last_clicked_item = clicked_item;
2002 // DoubleClick activation is handled in another handler
2006 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
2007 // Need this to clean up background clicks
2008 owner.SelectedItems.Clear ();
2011 clicked_item = null;
2012 box_select_start = Point.Empty;
2013 BoxSelectRectangle = Rectangle.Empty;
2014 prev_selection = null;
2015 box_select_mode = BoxSelect.None;
2017 owner.OnMouseUp (owner.TranslateMouseEventArgs (me));
2020 private void LabelEditFinished (object sender, EventArgs e)
2022 EndEdit (edit_item);
2025 private void LabelEditCancelled (object sender, EventArgs e)
2027 edit_args.SetLabel (null);
2028 EndEdit (edit_item);
2031 private void LabelTextChanged (object sender, EventArgs e)
2033 if (edit_args != null)
2034 edit_args.SetLabel (edit_text_box.Text);
2037 internal void BeginEdit (ListViewItem item)
2039 if (edit_item != null)
2040 EndEdit (edit_item);
2042 if (edit_text_box == null) {
2043 edit_text_box = new ListViewLabelEditTextBox ();
2044 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
2045 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
2046 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
2047 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
2048 edit_text_box.Visible = false;
2049 Controls.Add (edit_text_box);
2052 item.EnsureVisible();
2054 edit_text_box.Reset ();
2056 switch (owner.view) {
2058 case View.SmallIcon:
2060 edit_text_box.TextAlign = HorizontalAlignment.Left;
2061 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2062 SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
2063 edit_text_box.Width = (int)sizef.Width + 4;
2064 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
2065 edit_text_box.WordWrap = false;
2066 edit_text_box.Multiline = false;
2068 case View.LargeIcon:
2069 edit_text_box.TextAlign = HorizontalAlignment.Center;
2070 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2071 sizef = DeviceContext.MeasureString (item.Text, item.Font);
2072 edit_text_box.Width = (int)sizef.Width + 4;
2073 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
2074 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
2075 edit_text_box.WordWrap = true;
2076 edit_text_box.Multiline = true;
2082 edit_text_box.Text = item.Text;
2083 edit_text_box.Font = item.Font;
2084 edit_text_box.Visible = true;
2085 edit_text_box.Focus ();
2086 edit_text_box.SelectAll ();
2088 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
2089 owner.OnBeforeLabelEdit (edit_args);
2091 if (edit_args.CancelEdit)
2095 internal void CancelEdit (ListViewItem item)
2097 // do nothing if there's no item being edited, or if the
2098 // item being edited is not the one passed in
2099 if (edit_item == null || edit_item != item)
2102 edit_args.SetLabel (null);
2106 internal void EndEdit (ListViewItem item)
2108 // do nothing if there's no item being edited, or if the
2109 // item being edited is not the one passed in
2110 if (edit_item == null || edit_item != item)
2113 owner.OnAfterLabelEdit (edit_args);
2114 if (!edit_args.CancelEdit && edit_args.Label != null)
2115 edit_item.Text = edit_text_box.Text;
2117 if (edit_text_box != null) {
2118 if (edit_text_box.Visible)
2119 edit_text_box.Visible = false;
2120 // ensure listview gets focus
2127 internal override void OnPaintInternal (PaintEventArgs pe)
2129 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
2132 protected override void WndProc (ref Message m)
2134 switch ((Msg)m.Msg) {
2135 case Msg.WM_KILLFOCUS:
2136 owner.Select (false, true);
2138 case Msg.WM_SETFOCUS:
2139 owner.Select (false, true);
2141 case Msg.WM_RBUTTONDOWN:
2142 owner.Select (false, true);
2147 base.WndProc (ref m);
2151 internal class ListViewLabelEditTextBox : TextBox
2156 int max_height = -1;
2157 int min_height = -1;
2159 int old_number_lines = 1;
2161 SizeF text_size_one_char;
2163 public ListViewLabelEditTextBox ()
2165 min_height = DefaultSize.Height;
2166 text_size_one_char = DeviceContext.MeasureString ("B", Font);
2169 public int MaxWidth {
2171 if (value < min_width)
2172 max_width = min_width;
2178 public int MaxHeight {
2180 if (value < min_height)
2181 max_height = min_height;
2187 public new int Width {
2197 public override Font Font {
2203 text_size_one_char = DeviceContext.MeasureString ("B", Font);
2207 protected override void OnTextChanged (EventArgs e)
2209 SizeF text_size = DeviceContext.MeasureString (Text, Font);
2211 int new_width = (int)text_size.Width + 8;
2214 ResizeTextBoxWidth (new_width);
2216 if (Width != max_width)
2217 ResizeTextBoxWidth (new_width);
2219 int number_lines = Lines.Length;
2221 if (number_lines != old_number_lines) {
2222 int new_height = number_lines * (int)text_size_one_char.Height + 4;
2223 old_number_lines = number_lines;
2225 ResizeTextBoxHeight (new_height);
2229 base.OnTextChanged (e);
2232 protected override bool IsInputKey (Keys key_data)
2234 if ((key_data & Keys.Alt) == 0) {
2235 switch (key_data & Keys.KeyCode) {
2242 return base.IsInputKey (key_data);
2245 protected override void OnKeyDown (KeyEventArgs e)
2250 switch (e.KeyCode) {
2254 OnEditingFinished (e);
2259 OnEditingCancelled (e);
2264 protected override void OnLostFocus (EventArgs e)
2267 OnEditingFinished (e);
2271 protected void OnEditingCancelled (EventArgs e)
2273 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
2278 protected void OnEditingFinished (EventArgs e)
2280 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
2285 private void ResizeTextBoxWidth (int new_width)
2287 if (new_width > max_width)
2288 base.Width = max_width;
2290 if (new_width >= min_width)
2291 base.Width = new_width;
2293 base.Width = min_width;
2296 private void ResizeTextBoxHeight (int new_height)
2298 if (new_height > max_height)
2299 base.Height = max_height;
2301 if (new_height >= min_height)
2302 base.Height = new_height;
2304 base.Height = min_height;
2307 public void Reset ()
2314 old_number_lines = 1;
2316 Text = String.Empty;
2321 static object EditingCancelledEvent = new object ();
2322 public event EventHandler EditingCancelled {
2323 add { Events.AddHandler (EditingCancelledEvent, value); }
2324 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
2327 static object EditingFinishedEvent = new object ();
2328 public event EventHandler EditingFinished {
2329 add { Events.AddHandler (EditingFinishedEvent, value); }
2330 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
2334 internal override void OnPaintInternal (PaintEventArgs pe)
2339 CalculateScrollBars ();
2342 void FocusChanged (object o, EventArgs args)
2344 if (Items.Count == 0)
2347 if (FocusedItem == null)
2348 SetFocusedItem (Items [0]);
2350 item_control.Invalidate (FocusedItem.Bounds);
2353 private void ListView_MouseWheel (object sender, MouseEventArgs me)
2355 if (Items.Count == 0)
2358 int lines = me.Delta / 120;
2365 case View.SmallIcon:
2366 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
2368 case View.LargeIcon:
2369 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
2372 Scroll (h_scroll, -ItemSize.Width * lines);
2377 private void ListView_SizeChanged (object sender, EventArgs e)
2379 CalculateListView (alignment);
2382 private void SetFocusedItem (ListViewItem item)
2384 if (focused_item != null)
2385 focused_item.Focused = false;
2388 item.Focused = true;
2390 focused_item = item;
2393 private void HorizontalScroller (object sender, EventArgs e)
2395 item_control.EndEdit (item_control.edit_item);
2397 // Avoid unnecessary flickering, when button is
2398 // kept pressed at the end
2399 if (h_marker != h_scroll.Value) {
2401 int pixels = h_marker - h_scroll.Value;
2403 h_marker = h_scroll.Value;
2404 if (header_control.Visible)
2405 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
2407 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
2411 private void VerticalScroller (object sender, EventArgs e)
2413 item_control.EndEdit (item_control.edit_item);
2415 // Avoid unnecessary flickering, when button is
2416 // kept pressed at the end
2417 if (v_marker != v_scroll.Value) {
2418 int pixels = v_marker - v_scroll.Value;
2419 Rectangle area = item_control.ClientRectangle;
2420 v_marker = v_scroll.Value;
2421 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
2424 #endregion // Internal Methods Properties
2426 #region Protected Methods
2427 protected override void CreateHandle ()
2429 base.CreateHandle ();
2430 for (int i = 0; i < SelectedItems.Count; i++)
2431 OnSelectedIndexChanged (EventArgs.Empty);
2434 protected override void Dispose (bool disposing)
2437 h_scroll.Dispose ();
2438 v_scroll.Dispose ();
2440 large_image_list = null;
2441 small_image_list = null;
2442 state_image_list = null;
2444 foreach (ColumnHeader col in columns)
2445 col.SetListView (null);
2448 if (!virtual_mode) // In virtual mode we don't save the items
2450 foreach (ListViewItem item in items)
2454 base.Dispose (disposing);
2457 protected override bool IsInputKey (Keys keyData)
2474 return base.IsInputKey (keyData);
2477 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
2479 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
2484 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
2486 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
2491 protected virtual void OnColumnClick (ColumnClickEventArgs e)
2493 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
2498 protected override void OnEnabledChanged (EventArgs e)
2500 base.OnEnabledChanged (e);
2503 protected override void OnFontChanged (EventArgs e)
2505 base.OnFontChanged (e);
2509 protected override void OnHandleCreated (EventArgs e)
2511 base.OnHandleCreated (e);
2512 CalculateListView (alignment);
2514 if (!virtual_mode) // Sorting is not allowed in virtual mode
2519 protected override void OnHandleDestroyed (EventArgs e)
2521 base.OnHandleDestroyed (e);
2524 protected virtual void OnItemActivate (EventArgs e)
2526 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
2531 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
2533 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
2539 protected virtual void OnItemChecked (ItemCheckedEventArgs icea)
2541 ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
2547 protected virtual void OnItemDrag (ItemDragEventArgs e)
2549 EventHandler eh = (EventHandler)(Events [ItemDragEvent]);
2554 protected virtual void OnSelectedIndexChanged (EventArgs e)
2556 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
2561 protected override void OnSystemColorsChanged (EventArgs e)
2563 base.OnSystemColorsChanged (e);
2567 protected virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs args)
2569 EventHandler eh = (EventHandler)Events [CacheVirtualItemsEvent];
2574 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs args)
2576 RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
2582 protected void RealizeProperties ()
2587 protected void UpdateExtendedStyles ()
2592 bool refocusing = false;
2594 protected override void WndProc (ref Message m)
2596 switch ((Msg)m.Msg) {
2597 case Msg.WM_KILLFOCUS:
2598 Control receiver = Control.FromHandle (m.WParam);
2599 if (receiver == item_control) {
2605 case Msg.WM_SETFOCUS:
2615 base.WndProc (ref m);
2617 #endregion // Protected Methods
2619 #region Public Instance Methods
2620 public void ArrangeIcons ()
2622 ArrangeIcons (this.alignment);
2625 public void ArrangeIcons (ListViewAlignment alignment)
2627 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2628 if (view == View.LargeIcon || view == View.SmallIcon) {
2629 this.CalculateListView (alignment);
2630 // we have done the calculations already
2631 this.Redraw (false);
2636 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
2638 if (columnIndex < 0 || columnIndex >= columns.Count)
2639 throw new ArgumentOutOfRangeException ("columnIndex");
2641 columns [columnIndex].AutoResize (headerAutoResize);
2644 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
2647 foreach (ColumnHeader col in columns)
2648 col.AutoResize (headerAutoResize);
2653 public void BeginUpdate ()
2655 // flag to avoid painting
2659 public void Clear ()
2662 items.Clear (); // Redraw (true) called here
2665 public void EndUpdate ()
2667 // flag to avoid painting
2670 // probably, now we need a redraw with recalculations
2674 public void EnsureVisible (int index)
2676 if (index < 0 || index >= items.Count || scrollable == false)
2679 Rectangle view_rect = item_control.ClientRectangle;
2680 Rectangle bounds = new Rectangle (GetItemLocation (index), ItemSize);
2682 if (view_rect.Contains (bounds))
2685 if (View != View.Details) {
2686 if (bounds.Left < 0)
2687 h_scroll.Value += bounds.Left;
2688 else if (bounds.Right > view_rect.Right)
2689 h_scroll.Value += (bounds.Right - view_rect.Right);
2693 v_scroll.Value += bounds.Top;
2694 else if (bounds.Bottom > view_rect.Bottom)
2695 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
2699 public ListViewItem FindItemWithText (string text)
2701 if (items.Count == 0)
2704 return FindItemWithText (text, true, 0, true);
2707 public ListViewItem FindItemWithText (string text, bool includeSubItems, int startIndex)
2709 return FindItemWithText (text, includeSubItems, startIndex, true);
2712 public ListViewItem FindItemWithText (string text, bool includeSubItems, int startIndex, bool prefixSearch)
2714 if (startIndex < 0 || startIndex >= items.Count)
2715 throw new ArgumentOutOfRangeException ("startIndex");
2718 throw new ArgumentNullException ("text");
2720 for (int i = startIndex; i < items.Count; i++) {
2721 ListViewItem lvi = items [i];
2723 if ((prefixSearch && lvi.Text.StartsWith (text, true, CultureInfo.CurrentCulture)) // prefix search
2724 || String.Compare (lvi.Text, text, true) == 0) // match
2728 if (includeSubItems) {
2729 for (int i = startIndex; i < items.Count; i++) {
2730 ListViewItem lvi = items [i];
2731 foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
2732 if ((prefixSearch && sub_item.Text.StartsWith (text, true, CultureInfo.CurrentCulture))
2733 || String.Compare (sub_item.Text, text, true) == 0)
2742 public ListViewItem GetItemAt (int x, int y)
2744 Size item_size = ItemSize;
2745 for (int i = 0; i < items.Count; i++) {
2746 Point item_location = GetItemLocation (i);
2747 Rectangle item_rect = new Rectangle (item_location, item_size);
2748 if (item_rect.Contains (x, y))
2755 public Rectangle GetItemRect (int index)
2757 return GetItemRect (index, ItemBoundsPortion.Entire);
2760 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
2762 if (index < 0 || index >= items.Count)
2763 throw new IndexOutOfRangeException ("index");
2765 return items [index].GetBounds (portion);
2772 throw new InvalidOperationException ();
2778 // we need this overload to reuse the logic for sorting, while allowing
2779 // redrawing to be done by caller or have it done by this method when
2780 // sorting is really performed
2782 // ListViewItemCollection's Add and AddRange methods call this overload
2783 // with redraw set to false, as they take care of redrawing themselves
2784 // (they even want to redraw the listview if no sort is performed, as
2785 // an item was added), while ListView.Sort () only wants to redraw if
2786 // sorting was actually performed
2787 private void Sort (bool redraw)
2789 if (!IsHandleCreated || item_sorter == null) {
2793 items.Sort (item_sorter);
2798 public override string ToString ()
2800 int count = this.Items.Count;
2803 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2805 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
2807 #endregion // Public Instance Methods
2812 class HeaderControl : Control {
2815 bool column_resize_active = false;
2816 ColumnHeader resize_column;
2817 ColumnHeader clicked_column;
2818 ColumnHeader drag_column;
2820 int drag_to_index = -1;
2822 public HeaderControl (ListView owner)
2825 MouseDown += new MouseEventHandler (HeaderMouseDown);
2826 MouseMove += new MouseEventHandler (HeaderMouseMove);
2827 MouseUp += new MouseEventHandler (HeaderMouseUp);
2830 private ColumnHeader ColumnAtX (int x)
2832 Point pt = new Point (x, 0);
2833 ColumnHeader result = null;
2834 foreach (ColumnHeader col in owner.Columns) {
2835 if (col.Rect.Contains (pt)) {
2843 private int GetReorderedIndex (ColumnHeader col)
2845 if (owner.reordered_column_indices == null)
2848 for (int i = 0; i < owner.Columns.Count; i++)
2849 if (owner.reordered_column_indices [i] == col.Index)
2851 throw new Exception ("Column index missing from reordered array");
2854 private void HeaderMouseDown (object sender, MouseEventArgs me)
2856 if (resize_column != null) {
2857 column_resize_active = true;
2862 clicked_column = ColumnAtX (me.X + owner.h_marker);
2864 if (clicked_column != null) {
2866 if (owner.AllowColumnReorder) {
2868 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
2869 drag_column.Rect = clicked_column.Rect;
2870 drag_to_index = GetReorderedIndex (clicked_column);
2872 clicked_column.Pressed = true;
2873 Rectangle bounds = clicked_column.Rect;
2874 bounds.X -= owner.h_marker;
2875 Invalidate (bounds);
2882 column_resize_active = false;
2883 resize_column = null;
2885 Cursor = Cursors.Default;
2888 private void HeaderMouseMove (object sender, MouseEventArgs me)
2890 Point pt = new Point (me.X + owner.h_marker, me.Y);
2892 if (column_resize_active) {
2893 int width = pt.X - resize_column.X;
2897 if (!owner.CanProceedWithResize (resize_column, width)){
2901 resize_column.Width = width;
2905 resize_column = null;
2907 if (clicked_column != null) {
2908 if (owner.AllowColumnReorder) {
2911 r = drag_column.Rect;
2912 r.X = clicked_column.Rect.X + me.X - drag_x;
2913 drag_column.Rect = r;
2915 int x = me.X + owner.h_marker;
2916 ColumnHeader over = ColumnAtX (x);
2918 drag_to_index = owner.Columns.Count;
2919 else if (x < over.X + over.Width / 2)
2920 drag_to_index = GetReorderedIndex (over);
2922 drag_to_index = GetReorderedIndex (over) + 1;
2925 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
2926 bool pressed = clicked_column.Pressed;
2927 clicked_column.Pressed = over == clicked_column;
2928 if (clicked_column.Pressed ^ pressed) {
2929 Rectangle bounds = clicked_column.Rect;
2930 bounds.X -= owner.h_marker;
2931 Invalidate (bounds);
2937 for (int i = 0; i < owner.Columns.Count; i++) {
2938 Rectangle zone = owner.Columns [i].Rect;
2939 zone.X = zone.Right - 5;
2941 if (zone.Contains (pt)) {
2942 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
2944 resize_column = owner.Columns [i];
2949 if (resize_column == null)
2950 Cursor = Cursors.Default;
2952 Cursor = Cursors.VSplit;
2955 void HeaderMouseUp (object sender, MouseEventArgs me)
2959 if (column_resize_active) {
2960 int column_idx = resize_column.Index;
2962 owner.RaiseColumnWidthChanged (column_idx);
2966 if (clicked_column != null && clicked_column.Pressed) {
2967 clicked_column.Pressed = false;
2968 Rectangle bounds = clicked_column.Rect;
2969 bounds.X -= owner.h_marker;
2970 Invalidate (bounds);
2971 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2974 if (drag_column != null && owner.AllowColumnReorder) {
2976 if (drag_to_index > GetReorderedIndex (clicked_column))
2978 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2979 owner.ReorderColumn (clicked_column, drag_to_index, true);
2984 clicked_column = null;
2987 internal override void OnPaintInternal (PaintEventArgs pe)
2992 Theme theme = ThemeEngine.Current;
2993 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2995 if (drag_column == null)
2999 if (drag_to_index == owner.Columns.Count)
3000 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
3002 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
3003 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
3006 protected override void WndProc (ref Message m)
3008 switch ((Msg)m.Msg) {
3009 case Msg.WM_SETFOCUS:
3013 base.WndProc (ref m);
3019 private class ItemComparer : IComparer {
3020 readonly SortOrder sort_order;
3022 public ItemComparer (SortOrder sortOrder)
3024 sort_order = sortOrder;
3027 public int Compare (object x, object y)
3029 ListViewItem item_x = x as ListViewItem;
3030 ListViewItem item_y = y as ListViewItem;
3031 if (sort_order == SortOrder.Ascending)
3032 return String.Compare (item_x.Text, item_y.Text);
3034 return String.Compare (item_y.Text, item_x.Text);
3038 public class CheckedIndexCollection : IList, ICollection, IEnumerable
3040 private readonly ListView owner;
3042 #region Public Constructor
3043 public CheckedIndexCollection (ListView owner)
3047 #endregion // Public Constructor
3049 #region Public Properties
3052 get { return owner.CheckedItems.Count; }
3055 public bool IsReadOnly {
3056 get { return true; }
3059 public int this [int index] {
3061 int [] indices = GetIndices ();
3062 if (index < 0 || index >= indices.Length)
3063 throw new ArgumentOutOfRangeException ("index");
3064 return indices [index];
3068 bool ICollection.IsSynchronized {
3069 get { return false; }
3072 object ICollection.SyncRoot {
3073 get { return this; }
3076 bool IList.IsFixedSize {
3077 get { return true; }
3080 object IList.this [int index] {
3081 get { return this [index]; }
3082 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3084 #endregion // Public Properties
3086 #region Public Methods
3087 public bool Contains (int checkedIndex)
3089 int [] indices = GetIndices ();
3090 for (int i = 0; i < indices.Length; i++) {
3091 if (indices [i] == checkedIndex)
3097 public IEnumerator GetEnumerator ()
3099 int [] indices = GetIndices ();
3100 return indices.GetEnumerator ();
3103 void ICollection.CopyTo (Array dest, int index)
3105 int [] indices = GetIndices ();
3106 Array.Copy (indices, 0, dest, index, indices.Length);
3109 int IList.Add (object value)
3111 throw new NotSupportedException ("Add operation is not supported.");
3116 throw new NotSupportedException ("Clear operation is not supported.");
3119 bool IList.Contains (object checkedIndex)
3121 if (!(checkedIndex is int))
3123 return Contains ((int) checkedIndex);
3126 int IList.IndexOf (object checkedIndex)
3128 if (!(checkedIndex is int))
3130 return IndexOf ((int) checkedIndex);
3133 void IList.Insert (int index, object value)
3135 throw new NotSupportedException ("Insert operation is not supported.");
3138 void IList.Remove (object value)
3140 throw new NotSupportedException ("Remove operation is not supported.");
3143 void IList.RemoveAt (int index)
3145 throw new NotSupportedException ("RemoveAt operation is not supported.");
3148 public int IndexOf (int checkedIndex)
3150 int [] indices = GetIndices ();
3151 for (int i = 0; i < indices.Length; i++) {
3152 if (indices [i] == checkedIndex)
3157 #endregion // Public Methods
3159 private int [] GetIndices ()
3161 ArrayList checked_items = owner.CheckedItems.List;
3162 int [] indices = new int [checked_items.Count];
3163 for (int i = 0; i < checked_items.Count; i++) {
3164 ListViewItem item = (ListViewItem) checked_items [i];
3165 indices [i] = item.Index;
3169 } // CheckedIndexCollection
3171 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
3173 private readonly ListView owner;
3174 private ArrayList list;
3176 #region Public Constructor
3177 public CheckedListViewItemCollection (ListView owner)
3180 this.owner.Items.Changed += new CollectionChangedHandler (
3181 ItemsCollection_Changed);
3183 #endregion // Public Constructor
3185 #region Public Properties
3189 if (!owner.CheckBoxes)
3195 public bool IsReadOnly {
3196 get { return true; }
3199 public ListViewItem this [int index] {
3201 ArrayList checked_items = List;
3202 if (index < 0 || index >= checked_items.Count)
3203 throw new ArgumentOutOfRangeException ("index");
3204 return (ListViewItem) checked_items [index];
3209 public virtual ListViewItem this [string key] {
3211 int idx = IndexOfKey (key);
3212 return idx == -1 ? null : (ListViewItem) List [idx];
3217 bool ICollection.IsSynchronized {
3218 get { return false; }
3221 object ICollection.SyncRoot {
3222 get { return this; }
3225 bool IList.IsFixedSize {
3226 get { return true; }
3229 object IList.this [int index] {
3230 get { return this [index]; }
3231 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3233 #endregion // Public Properties
3235 #region Public Methods
3236 public bool Contains (ListViewItem item)
3238 if (!owner.CheckBoxes)
3240 return List.Contains (item);
3244 public virtual bool ContainsKey (string key)
3246 return IndexOfKey (key) != -1;
3250 public void CopyTo (Array dest, int index)
3252 if (!owner.CheckBoxes)
3254 List.CopyTo (dest, index);
3257 public IEnumerator GetEnumerator ()
3259 if (!owner.CheckBoxes)
3260 return (new ListViewItem [0]).GetEnumerator ();
3261 return List.GetEnumerator ();
3264 int IList.Add (object value)
3266 throw new NotSupportedException ("Add operation is not supported.");
3271 throw new NotSupportedException ("Clear operation is not supported.");
3274 bool IList.Contains (object item)
3276 if (!(item is ListViewItem))
3278 return Contains ((ListViewItem) item);
3281 int IList.IndexOf (object item)
3283 if (!(item is ListViewItem))
3285 return IndexOf ((ListViewItem) item);
3288 void IList.Insert (int index, object value)
3290 throw new NotSupportedException ("Insert operation is not supported.");
3293 void IList.Remove (object value)
3295 throw new NotSupportedException ("Remove operation is not supported.");
3298 void IList.RemoveAt (int index)
3300 throw new NotSupportedException ("RemoveAt operation is not supported.");
3303 public int IndexOf (ListViewItem item)
3305 if (!owner.CheckBoxes)
3307 return List.IndexOf (item);
3311 public virtual int IndexOfKey (string key)
3313 if (key == null || key.Length == 0)
3316 ArrayList checked_items = List;
3317 for (int i = 0; i < checked_items.Count; i++) {
3318 ListViewItem item = (ListViewItem) checked_items [i];
3319 if (String.Compare (key, item.Name, true) == 0)
3326 #endregion // Public Methods
3328 internal ArrayList List {
3331 list = new ArrayList ();
3332 foreach (ListViewItem item in owner.Items) {
3341 internal void Reset ()
3343 // force re-population of list
3347 private void ItemsCollection_Changed ()
3351 } // CheckedListViewItemCollection
3353 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
3355 internal ArrayList list;
3356 private ListView owner;
3358 #region Public Constructor
3359 public ColumnHeaderCollection (ListView owner)
3361 list = new ArrayList ();
3364 #endregion // Public Constructor
3366 #region Public Properties
3369 get { return list.Count; }
3372 public bool IsReadOnly {
3373 get { return false; }
3376 public virtual ColumnHeader this [int index] {
3378 if (index < 0 || index >= list.Count)
3379 throw new ArgumentOutOfRangeException ("index");
3380 return (ColumnHeader) list [index];
3385 public virtual ColumnHeader this [string key] {
3387 int idx = IndexOfKey (key);
3391 return (ColumnHeader) list [idx];
3396 bool ICollection.IsSynchronized {
3397 get { return true; }
3400 object ICollection.SyncRoot {
3401 get { return this; }
3404 bool IList.IsFixedSize {
3405 get { return list.IsFixedSize; }
3408 object IList.this [int index] {
3409 get { return this [index]; }
3410 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3412 #endregion // Public Properties
3414 #region Public Methods
3415 public virtual int Add (ColumnHeader value)
3417 int idx = list.Add (value);
3418 owner.AddColumn (value, idx, true);
3422 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
3424 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
3425 this.Add (colHeader);
3430 public virtual ColumnHeader Add (string text)
3432 return Add (String.Empty, text);
3435 public virtual ColumnHeader Add (string text, int iwidth)
3437 return Add (String.Empty, text, iwidth);
3440 public virtual ColumnHeader Add (string key, string text)
3442 ColumnHeader colHeader = new ColumnHeader ();
3443 colHeader.Name = key;
3444 colHeader.Text = text;
3449 public virtual ColumnHeader Add (string key, string text, int iwidth)
3451 return Add (key, text, iwidth, HorizontalAlignment.Left, -1);
3454 public virtual ColumnHeader Add (string key, string text, int iwidth, HorizontalAlignment textAlign, int imageIndex)
3456 ColumnHeader colHeader = new ColumnHeader (key, text, iwidth, textAlign);
3457 colHeader.ImageIndex = imageIndex;
3462 public virtual ColumnHeader Add (string key, string text, int iwidth, HorizontalAlignment textAlign, string imageKey)
3464 ColumnHeader colHeader = new ColumnHeader (key, text, iwidth, textAlign);
3465 colHeader.ImageKey = imageKey;
3471 public virtual void AddRange (ColumnHeader [] values)
3473 foreach (ColumnHeader colHeader in values) {
3474 int idx = list.Add (colHeader);
3475 owner.AddColumn (colHeader, idx, false);
3478 owner.Redraw (true);
3481 public virtual void Clear ()
3483 foreach (ColumnHeader col in list)
3484 col.SetListView (null);
3486 owner.ReorderColumns (new int [0], true);
3489 public bool Contains (ColumnHeader value)
3491 return list.Contains (value);
3495 public virtual bool ContainsKey (string key)
3497 return IndexOfKey (key) != -1;
3501 public IEnumerator GetEnumerator ()
3503 return list.GetEnumerator ();
3506 void ICollection.CopyTo (Array dest, int index)
3508 list.CopyTo (dest, index);
3511 int IList.Add (object value)
3513 if (! (value is ColumnHeader)) {
3514 throw new ArgumentException ("Not of type ColumnHeader", "value");
3517 return this.Add ((ColumnHeader) value);
3520 bool IList.Contains (object value)
3522 if (! (value is ColumnHeader)) {
3523 throw new ArgumentException ("Not of type ColumnHeader", "value");
3526 return this.Contains ((ColumnHeader) value);
3529 int IList.IndexOf (object value)
3531 if (! (value is ColumnHeader)) {
3532 throw new ArgumentException ("Not of type ColumnHeader", "value");
3535 return this.IndexOf ((ColumnHeader) value);
3538 void IList.Insert (int index, object value)
3540 if (! (value is ColumnHeader)) {
3541 throw new ArgumentException ("Not of type ColumnHeader", "value");
3544 this.Insert (index, (ColumnHeader) value);
3547 void IList.Remove (object value)
3549 if (! (value is ColumnHeader)) {
3550 throw new ArgumentException ("Not of type ColumnHeader", "value");
3553 this.Remove ((ColumnHeader) value);
3556 public int IndexOf (ColumnHeader value)
3558 return list.IndexOf (value);
3562 public virtual int IndexOfKey (string key)
3564 if (key == null || key.Length == 0)
3567 for (int i = 0; i < list.Count; i++) {
3568 ColumnHeader col = (ColumnHeader) list [i];
3569 if (String.Compare (key, col.Name, true) == 0)
3577 public void Insert (int index, ColumnHeader value)
3579 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
3580 // but it's really only greater.
3581 if (index < 0 || index > list.Count)
3582 throw new ArgumentOutOfRangeException ("index");
3584 list.Insert (index, value);
3585 owner.AddColumn (value, index, true);
3589 public void Insert (int index, string text)
3591 Insert (index, String.Empty, text);
3594 public void Insert (int index, string text, int width)
3596 Insert (index, String.Empty, text, width);
3599 public void Insert (int index, string key, string text)
3601 ColumnHeader colHeader = new ColumnHeader ();
3602 colHeader.Name = key;
3603 colHeader.Text = text;
3604 Insert (index, colHeader);
3607 public void Insert (int index, string key, string text, int width)
3609 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
3610 Insert (index, colHeader);
3613 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
3615 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
3616 colHeader.ImageIndex = imageIndex;
3617 Insert (index, colHeader);
3620 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
3622 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
3623 colHeader.ImageKey = imageKey;
3624 Insert (index, colHeader);
3628 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
3630 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
3631 this.Insert (index, colHeader);
3634 public virtual void Remove (ColumnHeader column)
3636 if (!Contains (column))
3639 list.Remove (column);
3640 column.SetListView (null);
3642 int rem_display_index = column.InternalDisplayIndex;
3643 int [] display_indices = new int [list.Count];
3644 for (int i = 0; i < display_indices.Length; i++) {
3645 ColumnHeader col = (ColumnHeader) list [i];
3646 int display_index = col.InternalDisplayIndex;
3647 if (display_index < rem_display_index) {
3648 display_indices [i] = display_index;
3650 display_indices [i] = (display_index - 1);
3654 column.InternalDisplayIndex = -1;
3655 owner.ReorderColumns (display_indices, true);
3659 public virtual void RemoveByKey (string key)
3661 int idx = IndexOfKey (key);
3667 public virtual void RemoveAt (int index)
3669 if (index < 0 || index >= list.Count)
3670 throw new ArgumentOutOfRangeException ("index");
3672 ColumnHeader col = (ColumnHeader) list [index];
3675 #endregion // Public Methods
3678 } // ColumnHeaderCollection
3680 public class ListViewItemCollection : IList, ICollection, IEnumerable
3682 private readonly ArrayList list;
3683 private readonly ListView owner;
3685 #region Public Constructor
3686 public ListViewItemCollection (ListView owner)
3688 list = new ArrayList (0);
3691 #endregion // Public Constructor
3693 #region Public Properties
3698 if (owner != null && owner.VirtualMode)
3699 return owner.VirtualListSize;
3706 public bool IsReadOnly {
3707 get { return false; }
3710 public virtual ListViewItem this [int displayIndex] {
3712 if (displayIndex < 0 || displayIndex >= Count)
3713 throw new ArgumentOutOfRangeException ("displayIndex");
3716 if (owner != null && owner.VirtualMode)
3717 return RetrieveVirtualItemFromOwner (displayIndex);
3719 return (ListViewItem) list [displayIndex];
3723 if (displayIndex < 0 || displayIndex >= Count)
3724 throw new ArgumentOutOfRangeException ("displayIndex");
3727 if (owner != null && owner.VirtualMode)
3728 throw new InvalidOperationException ();
3731 if (list.Contains (value))
3732 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
3734 if (value.ListView != null && value.ListView != owner)
3735 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");
3737 value.Owner = owner;
3738 list [displayIndex] = value;
3741 owner.Redraw (true);
3746 public virtual ListViewItem this [string key] {
3748 int idx = IndexOfKey (key);
3757 bool ICollection.IsSynchronized {
3758 get { return true; }
3761 object ICollection.SyncRoot {
3762 get { return this; }
3765 bool IList.IsFixedSize {
3766 get { return list.IsFixedSize; }
3769 object IList.this [int index] {
3770 get { return this [index]; }
3772 if (value is ListViewItem)
3773 this [index] = (ListViewItem) value;
3775 this [index] = new ListViewItem (value.ToString ());
3779 #endregion // Public Properties
3781 #region Public Methods
3782 public virtual ListViewItem Add (ListViewItem value)
3785 if (owner != null && owner.VirtualMode)
3786 throw new InvalidOperationException ();
3790 CollectionChanged (true);
3795 public virtual ListViewItem Add (string text)
3797 ListViewItem item = new ListViewItem (text);
3798 return this.Add (item);
3801 public virtual ListViewItem Add (string text, int imageIndex)
3803 ListViewItem item = new ListViewItem (text, imageIndex);
3804 return this.Add (item);
3808 public virtual ListViewItem Add (string text, string imageKey)
3810 ListViewItem item = new ListViewItem (text, imageKey);
3811 return this.Add (item);
3814 public virtual ListViewItem Add (string key, string text, int imageIndex)
3816 ListViewItem item = new ListViewItem (text, imageIndex);
3818 return this.Add (item);
3821 public virtual ListViewItem Add (string key, string text, string imageKey)
3823 ListViewItem item = new ListViewItem (text, imageKey);
3825 return this.Add (item);
3829 public void AddRange (ListViewItem [] values)
3832 throw new ArgumentNullException ("Argument cannot be null!", "values");
3834 if (owner != null && owner.VirtualMode)
3835 throw new InvalidOperationException ();
3838 foreach (ListViewItem item in values)
3841 CollectionChanged (true);
3845 public void AddRange (ListViewItemCollection items)
3848 throw new ArgumentNullException ("Argument cannot be null!", "items");
3850 ListViewItem[] itemArray = new ListViewItem[items.Count];
3851 items.CopyTo (itemArray,0);
3852 this.AddRange (itemArray);
3856 public virtual void Clear ()
3859 if (owner != null && owner.VirtualMode)
3860 throw new InvalidOperationException ();
3862 owner.SetFocusedItem (null);
3863 owner.h_scroll.Value = owner.v_scroll.Value = 0;
3864 foreach (ListViewItem item in list) {
3865 owner.item_control.CancelEdit (item);
3869 CollectionChanged (false);
3872 public bool Contains (ListViewItem item)
3874 return IndexOf (item) != -1;
3878 public virtual bool ContainsKey (string key)
3880 return IndexOfKey (key) != -1;
3884 public void CopyTo (Array dest, int index)
3886 list.CopyTo (dest, index);
3890 public ListViewItem [] Find (string key, bool searchAllSubitems)
3893 return new ListViewItem [0];
3895 List<ListViewItem> temp_list = new List<ListViewItem> ();
3897 for (int i = 0; i < list.Count; i++) {
3898 ListViewItem lvi = (ListViewItem) list [i];
3899 if (String.Compare (key, lvi.Name, true) == 0)
3900 temp_list.Add (lvi);
3903 ListViewItem [] retval = new ListViewItem [temp_list.Count];
3904 temp_list.CopyTo (retval);
3910 public IEnumerator GetEnumerator ()
3913 if (owner != null && owner.VirtualMode)
3914 throw new InvalidOperationException ();
3917 return list.GetEnumerator ();
3920 int IList.Add (object item)
3926 if (owner != null && owner.VirtualMode)
3927 throw new InvalidOperationException ();
3930 if (item is ListViewItem) {
3931 li = (ListViewItem) item;
3932 if (list.Contains (li))
3933 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3935 if (li.ListView != null && li.ListView != owner)
3936 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");
3939 li = new ListViewItem (item.ToString ());
3942 result = list.Add (li);
3943 CollectionChanged (true);
3948 bool IList.Contains (object item)
3950 return Contains ((ListViewItem) item);
3953 int IList.IndexOf (object item)
3955 return IndexOf ((ListViewItem) item);
3958 void IList.Insert (int index, object item)
3960 if (item is ListViewItem)
3961 this.Insert (index, (ListViewItem) item);
3963 this.Insert (index, item.ToString ());
3966 void IList.Remove (object item)
3968 Remove ((ListViewItem) item);
3971 public int IndexOf (ListViewItem item)
3974 if (owner != null && owner.VirtualMode) {
3975 for (int i = 0; i < Count; i++)
3976 if (RetrieveVirtualItemFromOwner (i) == item)
3983 return list.IndexOf (item);
3987 public virtual int IndexOfKey (string key)
3989 if (key == null || key.Length == 0)
3992 for (int i = 0; i < Count; i++) {
3993 ListViewItem lvi = this [i];
3994 if (String.Compare (key, lvi.Name, true) == 0)
4002 public ListViewItem Insert (int index, ListViewItem item)
4004 if (index < 0 || index > list.Count)
4005 throw new ArgumentOutOfRangeException ("index");
4008 if (owner != null && owner.VirtualMode)
4009 throw new InvalidOperationException ();
4012 if (list.Contains (item))
4013 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
4015 if (item.ListView != null && item.ListView != owner)
4016 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");
4019 list.Insert (index, item);
4020 CollectionChanged (true);
4024 public ListViewItem Insert (int index, string text)
4026 return this.Insert (index, new ListViewItem (text));
4029 public ListViewItem Insert (int index, string text, int imageIndex)
4031 return this.Insert (index, new ListViewItem (text, imageIndex));
4035 public ListViewItem Insert (int index, string key, string text, int imageIndex)
4037 ListViewItem lvi = new ListViewItem (text, imageIndex);
4039 return Insert (index, lvi);
4043 public virtual void Remove (ListViewItem item)
4046 if (owner != null && owner.VirtualMode)
4047 throw new InvalidOperationException ();
4049 if (!list.Contains (item))
4052 bool selection_changed = owner.SelectedItems.Contains (item);
4053 owner.item_control.CancelEdit (item);
4056 CollectionChanged (false);
4057 if (selection_changed)
4058 owner.OnSelectedIndexChanged (EventArgs.Empty);
4061 public virtual void RemoveAt (int index)
4063 if (index < 0 || index >= Count)
4064 throw new ArgumentOutOfRangeException ("index");
4067 if (owner != null && owner.VirtualMode)
4068 throw new InvalidOperationException ();
4071 ListViewItem item = (ListViewItem) list [index];
4076 public virtual void RemoveByKey (string key)
4078 int idx = IndexOfKey (key);
4084 #endregion // Public Methods
4086 void AddItem (ListViewItem value)
4088 if (list.Contains (value))
4089 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4091 if (value.ListView != null && value.ListView != owner)
4092 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");
4093 value.Owner = owner;
4097 void CollectionChanged (bool sort)
4099 if (owner != null) {
4104 owner.Redraw (true);
4109 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
4111 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
4113 owner.OnRetrieveVirtualItem (args);
4114 ListViewItem retval = args.Item;
4115 retval.Owner = owner;
4116 retval.SetIndex (displayIndex);
4122 internal event CollectionChangedHandler Changed;
4124 internal void Sort (IComparer comparer)
4126 list.Sort (comparer);
4130 internal void OnChange ()
4132 if (Changed != null)
4135 } // ListViewItemCollection
4137 public class SelectedIndexCollection : IList, ICollection, IEnumerable
4139 private readonly ListView owner;
4141 #region Public Constructor
4142 public SelectedIndexCollection (ListView owner)
4146 #endregion // Public Constructor
4148 #region Public Properties
4152 return owner.SelectedItems.Count;
4156 public bool IsReadOnly {
4166 public int this [int index] {
4168 int [] indices = GetIndices ();
4169 if (index < 0 || index >= indices.Length)
4170 throw new ArgumentOutOfRangeException ("index");
4171 return indices [index];
4175 bool ICollection.IsSynchronized {
4176 get { return false; }
4179 object ICollection.SyncRoot {
4180 get { return this; }
4183 bool IList.IsFixedSize {
4193 object IList.this [int index] {
4194 get { return this [index]; }
4195 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4197 #endregion // Public Properties
4199 #region Public Methods
4201 public int Add (int itemIndex)
4203 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
4204 throw new ArgumentOutOfRangeException ("index");
4206 owner.Items [itemIndex].Selected = true;
4207 if (!owner.IsHandleCreated)
4210 return owner.SelectedItems.Count;
4213 public void Clear ()
4215 owner.SelectedItems.Clear ();
4218 public bool Contains (int selectedIndex)
4220 int [] indices = GetIndices ();
4221 for (int i = 0; i < indices.Length; i++) {
4222 if (indices [i] == selectedIndex)
4228 public void CopyTo (Array dest, int index)
4230 int [] indices = GetIndices ();
4231 Array.Copy (indices, 0, dest, index, indices.Length);
4234 public IEnumerator GetEnumerator ()
4236 int [] indices = GetIndices ();
4237 return indices.GetEnumerator ();
4240 int IList.Add (object value)
4242 throw new NotSupportedException ("Add operation is not supported.");
4247 throw new NotSupportedException ("Clear operation is not supported.");
4250 bool IList.Contains (object selectedIndex)
4252 if (!(selectedIndex is int))
4254 return Contains ((int) selectedIndex);
4257 int IList.IndexOf (object selectedIndex)
4259 if (!(selectedIndex is int))
4261 return IndexOf ((int) selectedIndex);
4264 void IList.Insert (int index, object value)
4266 throw new NotSupportedException ("Insert operation is not supported.");
4269 void IList.Remove (object value)
4271 throw new NotSupportedException ("Remove operation is not supported.");
4274 void IList.RemoveAt (int index)
4276 throw new NotSupportedException ("RemoveAt operation is not supported.");
4279 public int IndexOf (int selectedIndex)
4281 int [] indices = GetIndices ();
4282 for (int i = 0; i < indices.Length; i++) {
4283 if (indices [i] == selectedIndex)
4290 public void Remove (int itemIndex)
4292 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
4293 throw new ArgumentOutOfRangeException ("itemIndex");
4295 owner.Items [itemIndex].Selected = false;
4298 #endregion // Public Methods
4300 private int [] GetIndices ()
4302 ArrayList selected_items = owner.SelectedItems.List;
4303 int [] indices = new int [selected_items.Count];
4304 for (int i = 0; i < selected_items.Count; i++) {
4305 ListViewItem item = (ListViewItem) selected_items [i];
4306 indices [i] = item.Index;
4310 } // SelectedIndexCollection
4312 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
4314 private readonly ListView owner;
4315 private ArrayList list;
4317 #region Public Constructor
4318 public SelectedListViewItemCollection (ListView owner)
4321 this.owner.Items.Changed += new CollectionChangedHandler (
4322 ItemsCollection_Changed);
4324 #endregion // Public Constructor
4326 #region Public Properties
4330 if (!owner.IsHandleCreated)
4336 public bool IsReadOnly {
4337 get { return true; }
4340 public ListViewItem this [int index] {
4342 ArrayList selected_items = List;
4343 if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
4344 throw new ArgumentOutOfRangeException ("index");
4345 return (ListViewItem) selected_items [index];
4350 public virtual ListViewItem this [string key] {
4352 int idx = IndexOfKey (key);
4356 return (ListViewItem) List [idx];
4361 bool ICollection.IsSynchronized {
4362 get { return false; }
4365 object ICollection.SyncRoot {
4366 get { return this; }
4369 bool IList.IsFixedSize {
4370 get { return true; }
4373 object IList.this [int index] {
4374 get { return this [index]; }
4375 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4377 #endregion // Public Properties
4379 #region Public Methods
4380 public void Clear ()
4382 if (!owner.IsHandleCreated)
4385 foreach (ListViewItem item in List)
4386 item.Selected = false;
4389 public bool Contains (ListViewItem item)
4391 if (!owner.IsHandleCreated)
4393 return List.Contains (item);
4397 public virtual bool ContainsKey (string key)
4399 return IndexOfKey (key) != -1;
4403 public void CopyTo (Array dest, int index)
4405 if (!owner.IsHandleCreated)
4407 List.CopyTo (dest, index);
4410 public IEnumerator GetEnumerator ()
4412 if (!owner.IsHandleCreated)
4413 return (new ListViewItem [0]).GetEnumerator ();
4414 return List.GetEnumerator ();
4417 int IList.Add (object value)
4419 throw new NotSupportedException ("Add operation is not supported.");
4422 bool IList.Contains (object item)
4424 if (!(item is ListViewItem))
4426 return Contains ((ListViewItem) item);
4429 int IList.IndexOf (object item)
4431 if (!(item is ListViewItem))
4433 return IndexOf ((ListViewItem) item);
4436 void IList.Insert (int index, object value)
4438 throw new NotSupportedException ("Insert operation is not supported.");
4441 void IList.Remove (object value)
4443 throw new NotSupportedException ("Remove operation is not supported.");
4446 void IList.RemoveAt (int index)
4448 throw new NotSupportedException ("RemoveAt operation is not supported.");
4451 public int IndexOf (ListViewItem item)
4453 if (!owner.IsHandleCreated)
4455 return List.IndexOf (item);
4459 public virtual int IndexOfKey (string key)
4461 if (!owner.IsHandleCreated || key == null || key.Length == 0)
4464 ArrayList selected_items = List;
4465 for (int i = 0; i < selected_items.Count; i++) {
4466 ListViewItem item = (ListViewItem) selected_items [i];
4467 if (String.Compare (item.Name, key, true) == 0)
4474 #endregion // Public Methods
4476 internal ArrayList List {
4479 list = new ArrayList ();
4480 for (int i = 0; i < owner.Items.Count; i++) {
4481 ListViewItem item = owner.Items [i];
4490 internal void Reset ()
4492 // force re-population of list
4496 private void ItemsCollection_Changed ()
4500 } // SelectedListViewItemCollection
4502 internal delegate void CollectionChangedHandler ();
4504 struct ItemMatrixLocation
4509 public ItemMatrixLocation (int row, int col)
4536 #endregion // Subclasses
4538 protected override void OnResize (EventArgs e)
4543 protected override void OnMouseLeave (EventArgs e)
4545 base.OnMouseLeave (e);
4549 // ColumnReorder event
4551 static object ColumnReorderedEvent = new object ();
4552 public event ColumnReorderedEventHandler ColumnReordered {
4553 add { Events.AddHandler (ColumnReorderedEvent, value); }
4554 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
4557 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
4559 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
4566 // ColumnWidthChanged
4568 static object ColumnWidthChangedEvent = new object ();
4569 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
4570 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
4571 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
4574 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
4576 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
4581 void RaiseColumnWidthChanged (int resize_column)
4583 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
4585 OnColumnWidthChanged (n);
4589 // ColumnWidthChanging
4591 static object ColumnWidthChangingEvent = new object ();
4592 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
4593 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
4594 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
4597 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
4599 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
4605 // 2.0 profile based implementation
4607 bool CanProceedWithResize (ColumnHeader col, int width)
4609 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
4613 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
4614 cwceh (this, changing);
4615 return !changing.Cancel;
4619 // 1.0 profile based implementation
4621 bool CanProceedWithResize (ColumnHeader col, int width)
4626 void RaiseColumnWidthChanged (int resize_column)