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)
28 // - Feedback for item activation, change in cursor types as mouse moves.
37 using System.Collections;
38 using System.ComponentModel;
39 using System.ComponentModel.Design;
41 using System.Runtime.InteropServices;
42 using System.Globalization;
44 namespace System.Windows.Forms
46 [DefaultEvent ("SelectedIndexChanged")]
47 [DefaultProperty ("Items")]
48 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
49 public class ListView : Control
51 private ItemActivation activation = ItemActivation.Standard;
52 private ListViewAlignment alignment = ListViewAlignment.Top;
53 private bool allow_column_reorder = false;
54 private bool auto_arrange = true;
55 private bool check_boxes = false;
56 private CheckedIndexCollection checked_indices;
57 private CheckedListViewItemCollection checked_items;
58 private ColumnHeaderCollection columns;
59 internal ListViewItem focused_item;
60 private bool full_row_select = false;
61 private bool grid_lines = false;
62 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
63 private bool hide_selection = true;
64 private bool hover_selection = false;
65 private IComparer item_sorter;
66 private ListViewItemCollection items;
67 private bool label_edit = false;
68 private bool label_wrap = true;
69 private bool multiselect = true;
70 private bool scrollable = true;
71 private SelectedIndexCollection selected_indices;
72 private SelectedListViewItemCollection selected_items;
73 private SortOrder sort_order = SortOrder.None;
74 private ImageList state_image_list;
75 private bool updating = false;
76 private View view = View.LargeIcon;
77 private int layout_wd; // We might draw more than our client area
78 private int layout_ht; // therefore we need to have these two.
79 //private TextBox editor; // Used for editing an item text
80 HeaderControl header_control;
81 internal ItemControl item_control;
82 internal ScrollBar h_scroll; // used for scrolling horizontally
83 internal ScrollBar v_scroll; // used for scrolling vertically
84 internal int h_marker; // Position markers for scrolling
85 internal int v_marker;
86 private int keysearch_tickcnt;
87 private string keysearch_text;
88 static private readonly int keysearch_keydelay = 1000;
89 private int[] reordered_column_indices;
92 internal ImageList large_image_list;
93 internal ImageList small_image_list;
94 internal Size text_size = Size.Empty;
97 public event LabelEditEventHandler AfterLabelEdit;
100 [EditorBrowsable (EditorBrowsableState.Never)]
101 public new event EventHandler BackgroundImageChanged {
102 add { base.BackgroundImageChanged += value; }
103 remove { base.BackgroundImageChanged -= value; }
106 public event LabelEditEventHandler BeforeLabelEdit;
107 public event ColumnClickEventHandler ColumnClick;
108 public event EventHandler ItemActivate;
109 public event ItemCheckEventHandler ItemCheck;
110 public event ItemDragEventHandler ItemDrag;
113 [EditorBrowsable (EditorBrowsableState.Never)]
114 public new event PaintEventHandler Paint {
115 add { base.Paint += value; }
116 remove { base.Paint -= value; }
119 public event EventHandler SelectedIndexChanged;
122 [EditorBrowsable (EditorBrowsableState.Never)]
123 public new event EventHandler TextChanged {
124 add { base.TextChanged += value; }
125 remove { base.TextChanged -= value; }
130 #region Public Constructors
133 background_color = ThemeEngine.Current.ColorWindow;
134 checked_indices = new CheckedIndexCollection (this);
135 checked_items = new CheckedListViewItemCollection (this);
136 columns = new ColumnHeaderCollection (this);
137 foreground_color = SystemColors.WindowText;
138 items = new ListViewItemCollection (this);
139 selected_indices = new SelectedIndexCollection (this);
140 selected_items = new SelectedListViewItemCollection (this);
142 border_style = BorderStyle.Fixed3D;
144 header_control = new HeaderControl (this);
145 header_control.Visible = false;
146 item_control = new ItemControl (this);
147 item_control.Visible = true;
149 h_scroll = new HScrollBar ();
150 v_scroll = new VScrollBar ();
151 h_marker = v_marker = 0;
152 keysearch_tickcnt = 0;
154 // scroll bars are disabled initially
155 h_scroll.Visible = false;
156 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
157 v_scroll.Visible = false;
158 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
161 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
162 SizeChanged += new EventHandler (ListView_SizeChanged);
164 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
166 #endregion // Public Constructors
168 #region Private Internal Properties
169 internal Size CheckBoxSize {
171 if (this.check_boxes) {
172 if (this.state_image_list != null)
173 return this.state_image_list.ImageSize;
175 return ThemeEngine.Current.ListViewCheckBoxSize;
183 bool CanMultiselect {
187 else if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
194 #endregion // Private Internal Properties
196 #region Protected Properties
197 protected override CreateParams CreateParams {
198 get { return base.CreateParams; }
201 protected override Size DefaultSize {
202 get { return ThemeEngine.Current.ListViewDefaultSize; }
204 #endregion // Protected Properties
206 #region Public Instance Properties
207 [DefaultValue (ItemActivation.Standard)]
208 public ItemActivation Activation {
209 get { return activation; }
211 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
212 value != ItemActivation.TwoClick) {
213 throw new InvalidEnumArgumentException (string.Format
214 ("Enum argument value '{0}' is not valid for Activation", value));
221 [DefaultValue (ListViewAlignment.Top)]
223 public ListViewAlignment Alignment {
224 get { return alignment; }
226 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
227 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
228 throw new InvalidEnumArgumentException (string.Format
229 ("Enum argument value '{0}' is not valid for Alignment", value));
232 if (this.alignment != value) {
234 // alignment does not matter in Details/List views
235 if (this.view == View.LargeIcon ||
236 this.View == View.SmallIcon)
242 [DefaultValue (false)]
243 public bool AllowColumnReorder {
244 get { return allow_column_reorder; }
245 set { allow_column_reorder = value; }
248 [DefaultValue (true)]
249 public bool AutoArrange {
250 get { return auto_arrange; }
252 if (auto_arrange != value) {
253 auto_arrange = value;
254 // autoarrange does not matter in Details/List views
255 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
261 public override Color BackColor {
263 if (background_color.IsEmpty)
264 return ThemeEngine.Current.ColorWindow;
266 return background_color;
268 set { background_color = value; }
272 [EditorBrowsable (EditorBrowsableState.Never)]
273 public override Image BackgroundImage {
274 get { return background_image; }
276 if (value == background_image)
279 background_image = value;
280 OnBackgroundImageChanged (EventArgs.Empty);
284 [DefaultValue (BorderStyle.Fixed3D)]
286 public BorderStyle BorderStyle {
287 get { return InternalBorderStyle; }
288 set { InternalBorderStyle = value; }
291 [DefaultValue (false)]
292 public bool CheckBoxes {
293 get { return check_boxes; }
295 if (check_boxes != value) {
303 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
304 public CheckedIndexCollection CheckedIndices {
305 get { return checked_indices; }
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 public CheckedListViewItemCollection CheckedItems {
311 get { return checked_items; }
314 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
316 [MergableProperty (false)]
317 public ColumnHeaderCollection Columns {
318 get { return columns; }
322 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
323 public ListViewItem FocusedItem {
325 if (focused_item == null && Focused && items.Count > 0)
326 focused_item = items [0];
331 public override Color ForeColor {
333 if (foreground_color.IsEmpty)
334 return ThemeEngine.Current.ColorWindowText;
336 return foreground_color;
338 set { foreground_color = value; }
341 [DefaultValue (false)]
342 public bool FullRowSelect {
343 get { return full_row_select; }
344 set { full_row_select = value; }
347 [DefaultValue (false)]
348 public bool GridLines {
349 get { return grid_lines; }
351 if (grid_lines != value) {
358 [DefaultValue (ColumnHeaderStyle.Clickable)]
359 public ColumnHeaderStyle HeaderStyle {
360 get { return header_style; }
362 if (header_style == value)
366 case ColumnHeaderStyle.Clickable:
367 case ColumnHeaderStyle.Nonclickable:
368 case ColumnHeaderStyle.None:
371 throw new InvalidEnumArgumentException (string.Format
372 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
375 header_style = value;
376 if (view == View.Details)
381 [DefaultValue (true)]
382 public bool HideSelection {
383 get { return hide_selection; }
385 if (hide_selection != value) {
386 hide_selection = value;
392 [DefaultValue (false)]
393 public bool HoverSelection {
394 get { return hover_selection; }
395 set { hover_selection = value; }
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
400 [MergableProperty (false)]
401 public ListViewItemCollection Items {
402 get { return items; }
405 [DefaultValue (false)]
406 public bool LabelEdit {
407 get { return label_edit; }
408 set { label_edit = value; }
411 [DefaultValue (true)]
413 public bool LabelWrap {
414 get { return label_wrap; }
416 if (label_wrap != value) {
423 [DefaultValue (null)]
424 public ImageList LargeImageList {
425 get { return large_image_list; }
427 large_image_list = value;
433 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
434 public IComparer ListViewItemSorter {
435 get { return item_sorter; }
436 set { item_sorter = value; }
439 [DefaultValue (true)]
440 public bool MultiSelect {
441 get { return multiselect; }
442 set { multiselect = value; }
445 [DefaultValue (true)]
446 public bool Scrollable {
447 get { return scrollable; }
449 if (scrollable != value) {
457 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
458 public SelectedIndexCollection SelectedIndices {
459 get { return selected_indices; }
463 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
464 public SelectedListViewItemCollection SelectedItems {
465 get { return selected_items; }
468 [DefaultValue (null)]
469 public ImageList SmallImageList {
470 get { return small_image_list; }
472 small_image_list = value;
477 [DefaultValue (SortOrder.None)]
478 public SortOrder Sorting {
479 get { return sort_order; }
481 if (value != SortOrder.Ascending && value != SortOrder.Descending &&
482 value != SortOrder.None) {
483 throw new InvalidEnumArgumentException (string.Format
484 ("Enum argument value '{0}' is not valid for Sorting", value));
487 if (sort_order != value) {
494 [DefaultValue (null)]
495 public ImageList StateImageList {
496 get { return state_image_list; }
498 state_image_list = value;
505 [EditorBrowsable (EditorBrowsableState.Never)]
506 public override string Text {
515 OnTextChanged (EventArgs.Empty);
520 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
521 public ListViewItem TopItem {
524 if (this.items.Count == 0)
526 // if contents are not scrolled
527 // it is the first item
528 else if (h_marker == 0 && v_marker == 0)
529 return this.items [0];
530 // do a hit test for the scrolled position
532 foreach (ListViewItem item in this.items) {
533 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
541 [DefaultValue (View.LargeIcon)]
545 if (value != View.Details && value != View.LargeIcon &&
546 value != View.List && value != View.SmallIcon ) {
547 throw new InvalidEnumArgumentException (string.Format
548 ("Enum argument value '{0}' is not valid for View", value));
552 h_scroll.Value = v_scroll.Value = 0;
558 #endregion // Public Instance Properties
560 #region Internal Methods Properties
562 internal int FirstVisibleIndex {
565 if (this.items.Count == 0)
568 if (h_marker == 0 && v_marker == 0)
571 foreach (ListViewItem item in this.items) {
572 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
581 internal int LastVisibleIndex {
583 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
584 if (View == View.List || Alignment == ListViewAlignment.Left) {
585 if (Items[i].Bounds.X > ClientRectangle.Right)
588 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
593 return Items.Count - 1;
597 internal int TotalWidth {
598 get { return Math.Max (this.Width, this.layout_wd); }
601 internal int TotalHeight {
602 get { return Math.Max (this.Height, this.layout_ht); }
605 internal void Redraw (bool recalculate)
607 // Avoid calculations when control is being updated
612 CalculateListView (this.alignment);
617 internal Size GetChildColumnSize (int index)
619 Size ret_size = Size.Empty;
620 ColumnHeader col = this.columns [index];
622 if (col.Width == -2) { // autosize = max(items, columnheader)
623 Size size = Size.Ceiling (this.DeviceContext.MeasureString
624 (col.Text, this.Font));
625 ret_size = BiggestItem (index);
626 if (size.Width > ret_size.Width)
629 else { // -1 and all the values < -2 are put under one category
630 ret_size = BiggestItem (index);
631 // fall back to empty columns' width if no subitem is available for a column
632 if (ret_size.IsEmpty) {
633 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
634 if (col.Text.Length > 0)
635 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
636 (col.Text, this.Font)).Height;
638 ret_size.Height = this.Font.Height;
642 // adjust the size for icon and checkbox for 0th column
644 ret_size.Width += (this.CheckBoxSize.Width + 4);
645 if (this.small_image_list != null)
646 ret_size.Width += this.small_image_list.ImageSize.Width;
651 // Returns the size of biggest item text in a column.
652 private Size BiggestItem (int col)
654 Size temp = Size.Empty;
655 Size ret_size = Size.Empty;
657 // 0th column holds the item text, we check the size of
658 // the various subitems falling in that column and get
659 // the biggest one's size.
660 foreach (ListViewItem item in items) {
661 if (col >= item.SubItems.Count)
664 temp = Size.Ceiling (this.DeviceContext.MeasureString
665 (item.SubItems [col].Text, this.Font));
666 if (temp.Width > ret_size.Width)
670 // adjustment for space
671 if (!ret_size.IsEmpty)
677 // Sets the size of the biggest item text as per the view
678 private void CalcTextSize ()
680 // clear the old value
681 text_size = Size.Empty;
683 if (items.Count == 0)
686 text_size = BiggestItem (0);
688 if (view == View.LargeIcon && this.label_wrap) {
689 Size temp = Size.Empty;
690 if (this.check_boxes)
691 temp.Width += 2 * this.CheckBoxSize.Width;
692 if (large_image_list != null)
693 temp.Width += large_image_list.ImageSize.Width;
696 // wrapping is done for two lines only
697 if (text_size.Width > temp.Width) {
698 text_size.Width = temp.Width;
699 text_size.Height *= 2;
702 else if (view == View.List) {
703 // in list view max text shown in determined by the
704 // control width, even if scolling is enabled.
705 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
706 if (this.small_image_list != null)
707 max_wd -= this.small_image_list.ImageSize.Width;
709 if (text_size.Width > max_wd)
710 text_size.Width = max_wd;
713 // we do the default settings, if we have got 0's
714 if (text_size.Height <= 0)
715 text_size.Height = this.Font.Height;
716 if (text_size.Width <= 0)
717 text_size.Width = this.Width;
720 text_size.Width += 4;
721 text_size.Height += 2;
724 private void Scroll (ScrollBar scrollbar, int delta)
726 if (delta == 0 || !scrollbar.Visible)
730 if (scrollbar == h_scroll)
731 max = h_scroll.Maximum - item_control.Width;
733 max = v_scroll.Maximum - item_control.Height;
735 int val = scrollbar.Value + delta;
738 else if (val < scrollbar.Minimum)
739 val = scrollbar.Minimum;
740 scrollbar.Value = val;
743 private void CalculateScrollBars ()
745 Rectangle client_area = ClientRectangle;
747 if (!this.scrollable || this.items.Count <= 0) {
748 h_scroll.Visible = false;
749 v_scroll.Visible = false;
753 // making a scroll bar visible might make
754 // other scroll bar visible
755 if (layout_wd > client_area.Right) {
756 h_scroll.Visible = true;
757 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
758 v_scroll.Visible = true;
760 v_scroll.Visible = false;
761 } else if (layout_ht > client_area.Bottom) {
762 v_scroll.Visible = true;
763 if ((layout_wd + v_scroll.Width) > client_area.Right)
764 h_scroll.Visible = true;
766 h_scroll.Visible = false;
768 h_scroll.Visible = false;
769 v_scroll.Visible = false;
772 item_control.Height = ClientRectangle.Height - header_control.Height;
774 if (h_scroll.Visible) {
775 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
776 h_scroll.Minimum = 0;
778 // if v_scroll is visible, adjust the maximum of the
779 // h_scroll to account for the width of v_scroll
780 if (v_scroll.Visible) {
781 h_scroll.Maximum = layout_wd + v_scroll.Width;
782 h_scroll.Width = client_area.Width - v_scroll.Width;
785 h_scroll.Maximum = layout_wd;
786 h_scroll.Width = client_area.Width;
789 h_scroll.LargeChange = client_area.Width;
790 h_scroll.SmallChange = Font.Height;
791 item_control.Height -= h_scroll.Height;
794 if (header_control.Visible)
795 header_control.Width = ClientRectangle.Width;
796 item_control.Width = ClientRectangle.Width;
798 if (v_scroll.Visible) {
799 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
800 v_scroll.Minimum = 0;
802 // if h_scroll is visible, adjust the maximum of the
803 // v_scroll to account for the height of h_scroll
804 if (h_scroll.Visible) {
805 v_scroll.Maximum = layout_ht + h_scroll.Height;
806 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
808 v_scroll.Maximum = layout_ht;
809 v_scroll.Height = client_area.Height;
812 v_scroll.LargeChange = client_area.Height;
813 v_scroll.SmallChange = Font.Height;
814 if (header_control.Visible)
815 header_control.Width -= v_scroll.Width;
816 item_control.Width -= v_scroll.Width;
820 ColumnHeader GetReorderedColumn (int index)
822 if (reordered_column_indices == null)
823 return Columns [index];
825 return Columns [reordered_column_indices [index]];
828 void ReorderColumn (ColumnHeader col, int index)
830 if (reordered_column_indices == null) {
831 reordered_column_indices = new int [Columns.Count];
832 for (int i = 0; i < Columns.Count; i++)
833 reordered_column_indices [i] = i;
836 if (reordered_column_indices [index] == col.Index)
839 int[] curr = reordered_column_indices;
840 int[] result = new int [Columns.Count];
842 for (int i = 0; i < Columns.Count; i++) {
843 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
847 result [i] = col.Index;
849 result [i] = curr [curr_idx++];
852 reordered_column_indices = result;
854 header_control.Invalidate ();
855 item_control.Invalidate ();
858 Size LargeIconItemSize {
860 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
861 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
862 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
863 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
864 return new Size (w, h);
868 Size SmallIconItemSize {
870 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
871 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
872 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
873 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
874 return new Size (w, h);
880 ListViewItem[,] item_matrix;
882 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
884 header_control.Visible = false;
885 header_control.Size = Size.Empty;
886 item_control.Location = Point.Empty;
888 if (items.Count == 0)
891 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
893 Rectangle area = ClientRectangle;
896 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
899 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
901 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
904 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
907 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
908 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
909 item_matrix = new ListViewItem [rows, cols];
912 foreach (ListViewItem item in items) {
913 int x = col * (sz.Width + x_spacing);
914 int y = row * (sz.Height + y_spacing);
915 item.Location = new Point (x, y);
919 item_matrix [row, col] = item;
933 item_control.Size = new Size (layout_wd, layout_ht);
938 if (columns.Count == 0 || header_style == ColumnHeaderStyle.None) {
939 header_control.Visible = false;
940 header_control.Size = Size.Empty;
945 for (int i = 0; i < Columns.Count; i++) {
946 ColumnHeader col = GetReorderedColumn (i);
949 col.CalcColumnHeader ();
953 if (x < ClientRectangle.Width)
954 x = ClientRectangle.Width;
956 header_control.Width = x;
957 header_control.Height = columns [0].Ht;
958 header_control.Visible = true;
961 void LayoutDetails ()
965 item_control.Location = new Point (0, header_control.Height);
968 if (items.Count > 0) {
969 foreach (ListViewItem item in items) {
971 item.Location = new Point (0, y);
972 y += item.Bounds.Height + 2;
975 // some space for bottom gridline
980 layout_wd = Math.Max (header_control.Width, item_control.Width);
981 layout_ht = y + header_control.Height;
984 private void CalculateListView (ListViewAlignment align)
994 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
998 LayoutIcons (true, alignment == ListViewAlignment.Left,
999 ThemeEngine.Current.ListViewHorizontalSpacing,
1000 ThemeEngine.Current.ListViewVerticalSpacing);
1004 LayoutIcons (false, true, 4, 2);
1008 CalculateScrollBars ();
1011 internal void UpdateSelection (ListViewItem item)
1013 if (item.Selected) {
1015 if (!CanMultiselect && SelectedItems.Count > 0) {
1016 SelectedItems.Clear ();
1017 SelectedIndices.list.Clear ();
1020 if (!SelectedItems.Contains (item)) {
1021 SelectedItems.list.Add (item);
1022 SelectedIndices.list.Add (item.Index);
1025 SelectedItems.list.Remove (item);
1026 SelectedIndices.list.Remove (item.Index);
1030 private bool KeySearchString (KeyEventArgs ke)
1032 int current_tickcnt = Environment.TickCount;
1033 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1034 keysearch_text = string.Empty;
1037 keysearch_text += (char) ke.KeyData;
1038 keysearch_tickcnt = current_tickcnt;
1040 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1043 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1044 CompareOptions.IgnoreCase)) {
1045 SetFocusedItem (Items [i]);
1046 items [i].Selected = true;
1050 i = (i + 1 < Items.Count) ? i+1 : 0;
1058 int GetAdjustedIndex (Keys key)
1062 if (View == View.Details) {
1064 result = FocusedItem.Index - 1;
1065 else if (key == Keys.Down) {
1066 result = FocusedItem.Index + 1;
1067 if (result == items.Count)
1073 int row = FocusedItem.row;
1074 int col = FocusedItem.col;
1080 return item_matrix [row, col - 1].Index;
1083 if (col == (cols - 1))
1085 while (item_matrix [row, col + 1] == null)
1087 return item_matrix [row, col + 1].Index;
1092 return item_matrix [row - 1, col].Index;
1095 if (row == (rows - 1))
1097 while (item_matrix [row + 1, col] == null)
1099 return item_matrix [row + 1, col].Index;
1106 ListViewItem selection_start;
1108 private void SelectItems (ArrayList sel_items)
1110 multiselecting = true;
1111 ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
1112 foreach (ListViewItem item in curr_items)
1113 if (!sel_items.Contains (item))
1114 item.Selected = false;
1115 foreach (ListViewItem item in sel_items)
1116 item.Selected = true;
1117 multiselecting = false;
1120 private void UpdateMultiSelection (int index)
1122 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1123 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1124 ListViewItem item = items [index];
1126 if (shift_pressed && selection_start != null) {
1127 ArrayList list = new ArrayList ();
1128 int start = Math.Min (selection_start.Index, index);
1129 int end = Math.Max (selection_start.Index, index);
1130 if (View == View.Details) {
1131 for (int i = start; i <= end; i++)
1132 list.Add (items [i]);
1134 int left = Math.Min (items [start].col, items [end].col);
1135 int right = Math.Max (items [start].col, items [end].col);
1136 int top = Math.Min (items [start].row, items [end].row);
1137 int bottom = Math.Max (items [start].row, items [end].row);
1138 foreach (ListViewItem curr in items)
1139 if (curr.row >= top && curr.row <= bottom &&
1140 curr.col >= left && curr.col <= right)
1144 } else if (!ctrl_pressed) {
1145 SelectedItems.Clear ();
1146 SelectedIndices.list.Clear ();
1147 item.Selected = true;
1148 selection_start = item;
1152 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1154 if (ke.Handled || Items.Count == 0)
1160 switch (ke.KeyCode) {
1163 index = Items.Count - 1;
1174 index = GetAdjustedIndex (ke.KeyCode);
1178 ke.Handled = KeySearchString (ke);
1186 UpdateMultiSelection (index);
1188 items [index].Selected = true;
1190 SetFocusedItem (items [index]);
1191 EnsureVisible (index);
1195 internal class ItemControl : Control {
1198 ListViewItem clicked_item;
1199 ListViewItem last_clicked_item;
1200 bool hover_processed = false;
1202 public ItemControl (ListView owner)
1205 DoubleClick += new EventHandler(ItemsDoubleClick);
1206 KeyDown += new KeyEventHandler (ItemsKeyDown);
1207 KeyUp += new KeyEventHandler (ItemsKeyUp);
1208 MouseDown += new MouseEventHandler(ItemsMouseDown);
1209 MouseMove += new MouseEventHandler(ItemsMouseMove);
1210 MouseHover += new EventHandler(ItemsMouseHover);
1211 MouseUp += new MouseEventHandler(ItemsMouseUp);
1212 MouseWheel += new MouseEventHandler(ItemsMouseWheel);
1215 void ItemsDoubleClick (object sender, EventArgs e)
1217 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1218 owner.ItemActivate (this, e);
1221 void ItemsKeyDown (object sender, KeyEventArgs args)
1223 owner.OnKeyDown (args);
1226 void ItemsKeyUp (object sender, KeyEventArgs args)
1228 owner.OnKeyUp (args);
1238 BoxSelect box_select_mode = BoxSelect.None;
1239 ArrayList prev_selection;
1240 Point box_select_start;
1242 Rectangle box_select_rect;
1243 internal Rectangle BoxSelectRectangle {
1244 get { return box_select_rect; }
1246 if (box_select_rect == value)
1249 InvalidateBoxSelectRect ();
1250 box_select_rect = value;
1251 InvalidateBoxSelectRect ();
1255 void InvalidateBoxSelectRect ()
1257 if (BoxSelectRectangle.Size.IsEmpty)
1260 Rectangle edge = BoxSelectRectangle;
1266 edge.Y = BoxSelectRectangle.Bottom - 1;
1268 edge.Y = BoxSelectRectangle.Y - 1;
1270 edge.Height = BoxSelectRectangle.Height + 2;
1272 edge.X = BoxSelectRectangle.Right - 1;
1276 private Rectangle CalculateBoxSelectRectangle (Point pt)
1278 int left = Math.Min (box_select_start.X, pt.X);
1279 int right = Math.Max (box_select_start.X, pt.X);
1280 int top = Math.Min (box_select_start.Y, pt.Y);
1281 int bottom = Math.Max (box_select_start.Y, pt.Y);
1282 return Rectangle.FromLTRB (left, top, right, bottom);
1285 ArrayList BoxSelectedItems {
1287 ArrayList result = new ArrayList ();
1288 foreach (ListViewItem item in owner.Items) {
1289 Rectangle r = item.Bounds;
1291 r.Y += r.Height / 4;
1294 if (BoxSelectRectangle.IntersectsWith (r))
1301 private bool PerformBoxSelection (Point pt)
1303 if (box_select_mode == BoxSelect.None)
1306 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1308 ArrayList box_items = BoxSelectedItems;
1312 switch (box_select_mode) {
1314 case BoxSelect.Normal:
1318 case BoxSelect.Control:
1319 items = new ArrayList ();
1320 foreach (ListViewItem item in prev_selection)
1321 if (!box_items.Contains (item))
1323 foreach (ListViewItem item in box_items)
1324 if (!prev_selection.Contains (item))
1328 case BoxSelect.Shift:
1330 foreach (ListViewItem item in box_items)
1331 prev_selection.Remove (item);
1332 foreach (ListViewItem item in prev_selection)
1337 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1341 owner.SelectItems (items);
1347 private void ItemsMouseDown (object sender, MouseEventArgs me)
1349 if (owner.items.Count == 0)
1352 Point pt = new Point (me.X, me.Y);
1353 foreach (ListViewItem item in owner.items) {
1354 if (item.CheckRectReal.Contains (pt)) {
1355 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1356 item.Checked = !item.Checked;
1358 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1360 // Raise the ItemCheck event
1361 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1362 owner.OnItemCheck (ice);
1366 if (owner.View == View.Details && !owner.FullRowSelect) {
1367 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1368 clicked_item = item;
1372 if (item.Bounds.Contains (pt)) {
1373 clicked_item = item;
1379 owner.SetFocusedItem (clicked_item);
1381 if (clicked_item != null) {
1382 bool changed = !clicked_item.Selected;
1383 if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
1384 owner.UpdateMultiSelection (clicked_item.Index);
1386 clicked_item.Selected = true;
1389 owner.OnSelectedIndexChanged (EventArgs.Empty);
1391 // Raise double click if the item was clicked. On MS the
1392 // double click is only raised if you double click an item
1393 if (me.Clicks > 1 && clicked_item != null)
1394 owner.OnDoubleClick (EventArgs.Empty);
1395 else if (me.Clicks == 1 && clicked_item != null)
1396 owner.OnClick (EventArgs.Empty);
1398 if (owner.MultiSelect) {
1399 Keys mods = XplatUI.State.ModifierKeys;
1400 if ((mods & Keys.Shift) != 0)
1401 box_select_mode = BoxSelect.Shift;
1402 else if ((mods & Keys.Control) != 0)
1403 box_select_mode = BoxSelect.Control;
1405 box_select_mode = BoxSelect.Normal;
1406 box_select_start = pt;
1407 prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
1408 } else if (owner.selected_indices.Count > 0) {
1409 owner.SelectedItems.Clear ();
1410 owner.SelectedIndices.list.Clear ();
1411 owner.OnSelectedIndexChanged (EventArgs.Empty);
1416 private void ItemsMouseMove (object sender, MouseEventArgs me)
1418 if (PerformBoxSelection (new Point (me.X, me.Y)))
1421 if (owner.HoverSelection && hover_processed) {
1423 Point pt = PointToClient (Control.MousePosition);
1424 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1425 if (item == null || item.Selected)
1428 hover_processed = false;
1429 XplatUI.ResetMouseHover (Handle);
1434 private void ItemsMouseHover (object sender, EventArgs e)
1436 if (Capture || !owner.HoverSelection)
1439 hover_processed = true;
1440 Point pt = PointToClient (Control.MousePosition);
1441 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1446 item.Selected = true;
1447 owner.OnSelectedIndexChanged (new EventArgs ());
1450 private void ItemsMouseUp (object sender, MouseEventArgs me)
1453 if (owner.Items.Count == 0)
1456 Point pt = new Point (me.X, me.Y);
1458 Rectangle rect = Rectangle.Empty;
1459 if (clicked_item != null) {
1460 if (owner.view == View.Details && !owner.full_row_select)
1461 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1463 rect = clicked_item.Bounds;
1465 if (rect.Contains (pt)) {
1466 switch (owner.activation) {
1467 case ItemActivation.OneClick:
1468 owner.OnItemActivate (EventArgs.Empty);
1471 case ItemActivation.TwoClick:
1472 if (last_clicked_item == clicked_item) {
1473 owner.OnItemActivate (EventArgs.Empty);
1474 last_clicked_item = null;
1476 last_clicked_item = clicked_item;
1479 // DoubleClick activation is handled in another handler
1483 } else if (owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1484 // Need this to clean up background clicks
1485 owner.SelectedItems.Clear ();
1486 owner.SelectedIndices.list.Clear ();
1487 owner.OnSelectedIndexChanged (EventArgs.Empty);
1490 clicked_item = null;
1491 box_select_start = Point.Empty;
1492 BoxSelectRectangle = Rectangle.Empty;
1493 prev_selection = null;
1494 box_select_mode = BoxSelect.None;
1497 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1499 if (owner.Items.Count == 0)
1502 int lines = me.Delta / 120;
1507 switch (owner.View) {
1509 case View.SmallIcon:
1510 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1512 case View.LargeIcon:
1513 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1516 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1521 internal override void OnPaintInternal (PaintEventArgs pe)
1523 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1527 internal override void OnPaintInternal (PaintEventArgs pe)
1532 CalculateScrollBars ();
1535 private void ListView_SizeChanged (object sender, EventArgs e)
1537 CalculateListView (alignment);
1540 private void SetFocusedItem (ListViewItem item)
1542 if (focused_item != null)
1543 focused_item.Focused = false;
1546 item.Focused = true;
1548 focused_item = item;
1551 private void HorizontalScroller (object sender, EventArgs e)
1553 // Avoid unnecessary flickering, when button is
1554 // kept pressed at the end
1555 if (h_marker != h_scroll.Value) {
1557 int pixels = h_marker - h_scroll.Value;
1559 h_marker = h_scroll.Value;
1560 if (header_control.Visible)
1561 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1563 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1567 private void VerticalScroller (object sender, EventArgs e)
1569 // Avoid unnecessary flickering, when button is
1570 // kept pressed at the end
1571 if (v_marker != v_scroll.Value) {
1572 int pixels = v_marker - v_scroll.Value;
1573 Rectangle area = item_control.ClientRectangle;
1574 v_marker = v_scroll.Value;
1575 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1578 #endregion // Internal Methods Properties
1580 #region Protected Methods
1581 protected override void CreateHandle ()
1583 base.CreateHandle ();
1586 protected override void Dispose (bool disposing)
1589 h_scroll.Dispose ();
1590 v_scroll.Dispose ();
1592 large_image_list = null;
1593 small_image_list = null;
1594 state_image_list = null;
1597 base.Dispose (disposing);
1600 protected override bool IsInputKey (Keys keyData)
1617 return base.IsInputKey (keyData);
1620 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1622 if (AfterLabelEdit != null)
1623 AfterLabelEdit (this, e);
1626 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1628 if (BeforeLabelEdit != null)
1629 BeforeLabelEdit (this, e);
1632 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1634 if (ColumnClick != null)
1635 ColumnClick (this, e);
1638 protected override void OnEnabledChanged (EventArgs e)
1640 base.OnEnabledChanged (e);
1643 protected override void OnFontChanged (EventArgs e)
1645 base.OnFontChanged (e);
1649 protected override void OnHandleCreated (EventArgs e)
1651 base.OnHandleCreated (e);
1653 Controls.AddImplicit (header_control);
1654 Controls.AddImplicit (item_control);
1655 Controls.AddImplicit (this.v_scroll);
1656 Controls.AddImplicit (this.h_scroll);
1660 protected override void OnHandleDestroyed (EventArgs e)
1662 base.OnHandleDestroyed (e);
1665 protected virtual void OnItemActivate (EventArgs e)
1667 if (ItemActivate != null)
1668 ItemActivate (this, e);
1671 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1673 if (ItemCheck != null)
1674 ItemCheck (this, ice);
1677 protected virtual void OnItemDrag (ItemDragEventArgs e)
1679 if (ItemDrag != null)
1683 protected virtual void OnSelectedIndexChanged (EventArgs e)
1685 if (SelectedIndexChanged != null)
1686 SelectedIndexChanged (this, e);
1689 protected override void OnSystemColorsChanged (EventArgs e)
1691 base.OnSystemColorsChanged (e);
1694 protected void RealizeProperties ()
1699 protected void UpdateExtendedStyles ()
1704 protected override void WndProc (ref Message m)
1706 base.WndProc (ref m);
1708 #endregion // Protected Methods
1710 #region Public Instance Methods
1711 public void ArrangeIcons ()
1713 ArrangeIcons (this.alignment);
1716 public void ArrangeIcons (ListViewAlignment alignment)
1718 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1719 if (view == View.LargeIcon || view == View.SmallIcon) {
1720 this.CalculateListView (alignment);
1721 // we have done the calculations already
1722 this.Redraw (false);
1726 public void BeginUpdate ()
1728 // flag to avoid painting
1732 public void Clear ()
1735 items.Clear (); // Redraw (true) called here
1738 public void EndUpdate ()
1740 // flag to avoid painting
1743 // probably, now we need a redraw with recalculations
1747 public void EnsureVisible (int index)
1749 if (index < 0 || index >= items.Count || scrollable == false)
1752 Rectangle view_rect = item_control.ClientRectangle;
1753 Rectangle bounds = items [index].Bounds;
1755 if (view_rect.Contains (bounds))
1758 if (bounds.Left < 0)
1759 h_scroll.Value += bounds.Left;
1760 else if (bounds.Right > view_rect.Right)
1761 h_scroll.Value += (bounds.Right - view_rect.Right);
1764 v_scroll.Value += bounds.Top;
1765 else if (bounds.Bottom > view_rect.Bottom)
1766 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1769 public ListViewItem GetItemAt (int x, int y)
1771 foreach (ListViewItem item in items) {
1772 if (item.Bounds.Contains (x, y))
1778 public Rectangle GetItemRect (int index)
1780 return GetItemRect (index, ItemBoundsPortion.Entire);
1783 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1785 if (index < 0 || index >= items.Count)
1786 throw new IndexOutOfRangeException ("Invalid Index");
1788 return items [index].GetBounds (portion);
1793 if (sort_order != SortOrder.None)
1794 items.list.Sort (item_sorter);
1796 if (sort_order == SortOrder.Descending)
1797 items.list.Reverse ();
1802 public override string ToString ()
1804 int count = this.Items.Count;
1807 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1809 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1811 #endregion // Public Instance Methods
1816 class HeaderControl : Control {
1819 bool column_resize_active = false;
1820 ColumnHeader resize_column;
1821 ColumnHeader clicked_column;
1822 ColumnHeader drag_column;
1824 int drag_to_index = -1;
1826 public HeaderControl (ListView owner)
1829 MouseDown += new MouseEventHandler (HeaderMouseDown);
1830 MouseMove += new MouseEventHandler (HeaderMouseMove);
1831 MouseUp += new MouseEventHandler (HeaderMouseUp);
1834 private ColumnHeader ColumnAtX (int x)
1836 Point pt = new Point (x, 0);
1837 ColumnHeader result = null;
1838 foreach (ColumnHeader col in owner.Columns) {
1839 if (col.Rect.Contains (pt)) {
1847 private int GetReorderedIndex (ColumnHeader col)
1849 if (owner.reordered_column_indices == null)
1852 for (int i = 0; i < owner.Columns.Count; i++)
1853 if (owner.reordered_column_indices [i] == col.Index)
1855 throw new Exception ("Column index missing from reordered array");
1858 private void HeaderMouseDown (object sender, MouseEventArgs me)
1860 if (resize_column != null) {
1861 column_resize_active = true;
1866 clicked_column = ColumnAtX (me.X + owner.h_marker);
1868 if (clicked_column != null) {
1870 if (owner.AllowColumnReorder) {
1872 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1873 drag_column.column_rect = clicked_column.Rect;
1874 drag_to_index = GetReorderedIndex (clicked_column);
1876 clicked_column.pressed = true;
1877 Rectangle bounds = clicked_column.Rect;
1878 bounds.X -= owner.h_marker;
1879 Invalidate (bounds);
1884 private void HeaderMouseMove (object sender, MouseEventArgs me)
1886 Point pt = new Point (me.X + owner.h_marker, me.Y);
1888 if (column_resize_active) {
1889 resize_column.Width = pt.X - resize_column.X;
1890 if (resize_column.Width < 0)
1891 resize_column.Width = 0;
1895 resize_column = null;
1897 if (clicked_column != null) {
1898 if (owner.AllowColumnReorder) {
1901 r = drag_column.column_rect;
1902 r.X = clicked_column.Rect.X + me.X - drag_x;
1903 drag_column.column_rect = r;
1905 int x = me.X + owner.h_marker;
1906 ColumnHeader over = ColumnAtX (x);
1908 drag_to_index = owner.Columns.Count;
1909 else if (x < over.X + over.Width / 2)
1910 drag_to_index = GetReorderedIndex (over);
1912 drag_to_index = GetReorderedIndex (over) + 1;
1915 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1916 bool pressed = clicked_column.pressed;
1917 clicked_column.pressed = over == clicked_column;
1918 if (clicked_column.pressed ^ pressed) {
1919 Rectangle bounds = clicked_column.Rect;
1920 bounds.X -= owner.h_marker;
1921 Invalidate (bounds);
1927 for (int i = 0; i < owner.Columns.Count; i++) {
1928 Rectangle zone = owner.Columns [i].Rect;
1929 zone.X = zone.Right - 5;
1931 if (zone.Contains (pt)) {
1932 resize_column = owner.Columns [i];
1937 if (resize_column == null)
1938 Cursor = Cursors.Default;
1940 Cursor = Cursors.VSplit;
1943 void HeaderMouseUp (object sender, MouseEventArgs me)
1947 if (column_resize_active) {
1948 column_resize_active = false;
1949 resize_column = null;
1950 Cursor = Cursors.Default;
1954 if (clicked_column != null && clicked_column.pressed) {
1955 clicked_column.pressed = false;
1956 Rectangle bounds = clicked_column.Rect;
1957 bounds.X -= owner.h_marker;
1958 Invalidate (bounds);
1959 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
1962 if (drag_column != null && owner.AllowColumnReorder) {
1964 if (drag_to_index > GetReorderedIndex (clicked_column))
1966 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
1967 owner.ReorderColumn (clicked_column, drag_to_index);
1972 clicked_column = null;
1975 internal override void OnPaintInternal (PaintEventArgs pe)
1980 Theme theme = ThemeEngine.Current;
1981 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
1983 if (drag_column == null)
1987 if (drag_to_index == owner.Columns.Count)
1988 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
1990 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
1991 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
1996 public class CheckedIndexCollection : IList, ICollection, IEnumerable
1998 internal ArrayList list;
1999 private ListView owner;
2001 #region Public Constructor
2002 public CheckedIndexCollection (ListView owner)
2004 list = new ArrayList ();
2007 #endregion // Public Constructor
2009 #region Public Properties
2012 get { return list.Count; }
2015 public bool IsReadOnly {
2016 get { return true; }
2019 public int this [int index] {
2021 if (index < 0 || index >= list.Count)
2022 throw new ArgumentOutOfRangeException ("Index out of range.");
2023 return (int) list [index];
2027 bool ICollection.IsSynchronized {
2028 get { return false; }
2031 object ICollection.SyncRoot {
2032 get { return this; }
2035 bool IList.IsFixedSize {
2036 get { return true; }
2039 object IList.this [int index] {
2040 get { return this [index]; }
2041 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2043 #endregion // Public Properties
2045 #region Public Methods
2046 public bool Contains (int checkedIndex)
2048 return list.Contains (checkedIndex);
2051 public IEnumerator GetEnumerator ()
2053 return list.GetEnumerator ();
2056 void ICollection.CopyTo (Array dest, int index)
2058 list.CopyTo (dest, index);
2061 int IList.Add (object value)
2063 throw new NotSupportedException ("Add operation is not supported.");
2068 throw new NotSupportedException ("Clear operation is not supported.");
2071 bool IList.Contains (object checkedIndex)
2073 return list.Contains (checkedIndex);
2076 int IList.IndexOf (object checkedIndex)
2078 return list.IndexOf (checkedIndex);
2081 void IList.Insert (int index, object value)
2083 throw new NotSupportedException ("Insert operation is not supported.");
2086 void IList.Remove (object value)
2088 throw new NotSupportedException ("Remove operation is not supported.");
2091 void IList.RemoveAt (int index)
2093 throw new NotSupportedException ("RemoveAt operation is not supported.");
2096 public int IndexOf (int checkedIndex)
2098 return list.IndexOf (checkedIndex);
2100 #endregion // Public Methods
2102 } // CheckedIndexCollection
2104 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2106 internal ArrayList list;
2107 private ListView owner;
2109 #region Public Constructor
2110 public CheckedListViewItemCollection (ListView owner)
2112 list = new ArrayList ();
2115 #endregion // Public Constructor
2117 #region Public Properties
2120 get { return list.Count; }
2123 public bool IsReadOnly {
2124 get { return true; }
2127 public ListViewItem this [int index] {
2129 if (index < 0 || index >= list.Count)
2130 throw new ArgumentOutOfRangeException ("Index out of range.");
2131 return (ListViewItem) list [index];
2135 bool ICollection.IsSynchronized {
2136 get { return list.IsSynchronized; }
2139 object ICollection.SyncRoot {
2140 get { return this; }
2143 bool IList.IsFixedSize {
2144 get { return true; }
2147 object IList.this [int index] {
2148 get { return this [index]; }
2149 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2151 #endregion // Public Properties
2153 #region Public Methods
2154 public bool Contains (ListViewItem item)
2156 return list.Contains (item);
2159 public void CopyTo (Array dest, int index)
2161 list.CopyTo (dest, index);
2164 public IEnumerator GetEnumerator ()
2166 return list.GetEnumerator ();
2169 int IList.Add (object value)
2171 throw new NotSupportedException ("Add operation is not supported.");
2176 throw new NotSupportedException ("Clear operation is not supported.");
2179 bool IList.Contains (object item)
2181 return list.Contains (item);
2184 int IList.IndexOf (object item)
2186 return list.IndexOf (item);
2189 void IList.Insert (int index, object value)
2191 throw new NotSupportedException ("Insert operation is not supported.");
2194 void IList.Remove (object value)
2196 throw new NotSupportedException ("Remove operation is not supported.");
2199 void IList.RemoveAt (int index)
2201 throw new NotSupportedException ("RemoveAt operation is not supported.");
2204 public int IndexOf (ListViewItem item)
2206 return list.IndexOf (item);
2208 #endregion // Public Methods
2210 } // CheckedListViewItemCollection
2212 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2214 internal ArrayList list;
2215 private ListView owner;
2217 #region Public Constructor
2218 public ColumnHeaderCollection (ListView owner)
2220 list = new ArrayList ();
2223 #endregion // Public Constructor
2225 #region Public Properties
2228 get { return list.Count; }
2231 public bool IsReadOnly {
2232 get { return false; }
2235 public virtual ColumnHeader this [int index] {
2237 if (index < 0 || index >= list.Count)
2238 throw new ArgumentOutOfRangeException ("Index out of range.");
2239 return (ColumnHeader) list [index];
2243 bool ICollection.IsSynchronized {
2244 get { return true; }
2247 object ICollection.SyncRoot {
2248 get { return this; }
2251 bool IList.IsFixedSize {
2252 get { return list.IsFixedSize; }
2255 object IList.this [int index] {
2256 get { return this [index]; }
2257 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2259 #endregion // Public Properties
2261 #region Public Methods
2262 public virtual int Add (ColumnHeader value)
2265 value.owner = this.owner;
2266 idx = list.Add (value);
2267 owner.Redraw (true);
2271 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2273 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2274 this.Add (colHeader);
2278 public virtual void AddRange (ColumnHeader [] values)
2280 foreach (ColumnHeader colHeader in values) {
2281 colHeader.owner = this.owner;
2285 owner.Redraw (true);
2288 public virtual void Clear ()
2291 owner.Redraw (true);
2294 public bool Contains (ColumnHeader value)
2296 return list.Contains (value);
2299 public IEnumerator GetEnumerator ()
2301 return list.GetEnumerator ();
2304 void ICollection.CopyTo (Array dest, int index)
2306 list.CopyTo (dest, index);
2309 int IList.Add (object value)
2311 if (! (value is ColumnHeader)) {
2312 throw new ArgumentException ("Not of type ColumnHeader", "value");
2315 return this.Add ((ColumnHeader) value);
2318 bool IList.Contains (object value)
2320 if (! (value is ColumnHeader)) {
2321 throw new ArgumentException ("Not of type ColumnHeader", "value");
2324 return this.Contains ((ColumnHeader) value);
2327 int IList.IndexOf (object value)
2329 if (! (value is ColumnHeader)) {
2330 throw new ArgumentException ("Not of type ColumnHeader", "value");
2333 return this.IndexOf ((ColumnHeader) value);
2336 void IList.Insert (int index, object value)
2338 if (! (value is ColumnHeader)) {
2339 throw new ArgumentException ("Not of type ColumnHeader", "value");
2342 this.Insert (index, (ColumnHeader) value);
2345 void IList.Remove (object value)
2347 if (! (value is ColumnHeader)) {
2348 throw new ArgumentException ("Not of type ColumnHeader", "value");
2351 this.Remove ((ColumnHeader) value);
2354 public int IndexOf (ColumnHeader value)
2356 return list.IndexOf (value);
2359 public void Insert (int index, ColumnHeader value)
2361 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2362 // but it's really only greater.
2363 if (index < 0 || index > list.Count)
2364 throw new ArgumentOutOfRangeException ("Index out of range.");
2366 value.owner = this.owner;
2367 list.Insert (index, value);
2368 owner.Redraw (true);
2371 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2373 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2374 this.Insert (index, colHeader);
2377 public virtual void Remove (ColumnHeader column)
2379 // TODO: Update Column internal index ?
2380 list.Remove (column);
2381 owner.Redraw (true);
2384 public virtual void RemoveAt (int index)
2386 if (index < 0 || index >= list.Count)
2387 throw new ArgumentOutOfRangeException ("Index out of range.");
2389 // TODO: Update Column internal index ?
2390 list.RemoveAt (index);
2391 owner.Redraw (true);
2393 #endregion // Public Methods
2396 } // ColumnHeaderCollection
2398 public class ListViewItemCollection : IList, ICollection, IEnumerable
2400 internal ArrayList list;
2401 private ListView owner;
2403 #region Public Constructor
2404 public ListViewItemCollection (ListView owner)
2406 list = new ArrayList ();
2409 #endregion // Public Constructor
2411 #region Public Properties
2414 get { return list.Count; }
2417 public bool IsReadOnly {
2418 get { return false; }
2421 public virtual ListViewItem this [int displayIndex] {
2423 if (displayIndex < 0 || displayIndex >= list.Count)
2424 throw new ArgumentOutOfRangeException ("Index out of range.");
2425 return (ListViewItem) list [displayIndex];
2429 if (displayIndex < 0 || displayIndex >= list.Count)
2430 throw new ArgumentOutOfRangeException ("Index out of range.");
2432 if (list.Contains (value))
2433 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2435 value.Owner = owner;
2436 list [displayIndex] = value;
2438 owner.Redraw (true);
2442 bool ICollection.IsSynchronized {
2443 get { return true; }
2446 object ICollection.SyncRoot {
2447 get { return this; }
2450 bool IList.IsFixedSize {
2451 get { return list.IsFixedSize; }
2454 object IList.this [int index] {
2455 get { return this [index]; }
2457 if (value is ListViewItem)
2458 this [index] = (ListViewItem) value;
2460 this [index] = new ListViewItem (value.ToString ());
2463 #endregion // Public Properties
2465 #region Public Methods
2466 public virtual ListViewItem Add (ListViewItem value)
2468 if (list.Contains (value))
2469 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2471 value.Owner = owner;
2474 if (owner.Sorting != SortOrder.None)
2477 owner.Redraw (true);
2482 public virtual ListViewItem Add (string text)
2484 ListViewItem item = new ListViewItem (text);
2485 return this.Add (item);
2488 public virtual ListViewItem Add (string text, int imageIndex)
2490 ListViewItem item = new ListViewItem (text, imageIndex);
2491 return this.Add (item);
2494 public void AddRange (ListViewItem [] values)
2497 owner.SelectedItems.list.Clear ();
2498 owner.SelectedIndices.list.Clear ();
2499 owner.CheckedItems.list.Clear ();
2500 owner.CheckedIndices.list.Clear ();
2502 foreach (ListViewItem item in values) {
2507 if (owner.Sorting != SortOrder.None)
2510 owner.Redraw (true);
2513 public virtual void Clear ()
2515 owner.SetFocusedItem (null);
2516 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2518 owner.SelectedItems.list.Clear ();
2519 owner.SelectedIndices.list.Clear ();
2520 owner.CheckedItems.list.Clear ();
2521 owner.CheckedIndices.list.Clear ();
2522 owner.Redraw (true);
2525 public bool Contains (ListViewItem item)
2527 return list.Contains (item);
2530 public void CopyTo (Array dest, int index)
2532 list.CopyTo (dest, index);
2535 public IEnumerator GetEnumerator ()
2537 return list.GetEnumerator ();
2540 int IList.Add (object item)
2545 if (item is ListViewItem) {
2546 li = (ListViewItem) item;
2547 if (list.Contains (li))
2548 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2551 li = new ListViewItem (item.ToString ());
2554 result = list.Add (li);
2555 owner.Redraw (true);
2560 bool IList.Contains (object item)
2562 return list.Contains (item);
2565 int IList.IndexOf (object item)
2567 return list.IndexOf (item);
2570 void IList.Insert (int index, object item)
2572 if (item is ListViewItem)
2573 this.Insert (index, (ListViewItem) item);
2575 this.Insert (index, item.ToString ());
2578 void IList.Remove (object item)
2580 Remove ((ListViewItem) item);
2583 public int IndexOf (ListViewItem item)
2585 return list.IndexOf (item);
2588 public ListViewItem Insert (int index, ListViewItem item)
2590 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2591 // but it's really only greater.
2592 if (index < 0 || index > list.Count)
2593 throw new ArgumentOutOfRangeException ("Index out of range.");
2595 if (list.Contains (item))
2596 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2599 list.Insert (index, item);
2600 owner.Redraw (true);
2604 public ListViewItem Insert (int index, string text)
2606 return this.Insert (index, new ListViewItem (text));
2609 public ListViewItem Insert (int index, string text, int imageIndex)
2611 return this.Insert (index, new ListViewItem (text, imageIndex));
2614 public virtual void Remove (ListViewItem item)
2616 if (!list.Contains (item))
2619 owner.SelectedItems.list.Remove (item);
2620 owner.SelectedIndices.list.Remove (item.Index);
2621 owner.CheckedItems.list.Remove (item);
2622 owner.CheckedIndices.list.Remove (item.Index);
2624 owner.Redraw (true);
2627 public virtual void RemoveAt (int index)
2629 if (index < 0 || index >= list.Count)
2630 throw new ArgumentOutOfRangeException ("Index out of range.");
2632 list.RemoveAt (index);
2633 owner.SelectedItems.list.RemoveAt (index);
2634 owner.SelectedIndices.list.RemoveAt (index);
2635 owner.CheckedItems.list.RemoveAt (index);
2636 owner.CheckedIndices.list.RemoveAt (index);
2637 owner.Redraw (false);
2639 #endregion // Public Methods
2641 } // ListViewItemCollection
2643 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2645 internal ArrayList list;
2646 private ListView owner;
2648 #region Public Constructor
2649 public SelectedIndexCollection (ListView owner)
2651 list = new ArrayList ();
2654 #endregion // Public Constructor
2656 #region Public Properties
2659 get { return list.Count; }
2662 public bool IsReadOnly {
2663 get { return true; }
2666 public int this [int index] {
2668 if (index < 0 || index >= list.Count)
2669 throw new ArgumentOutOfRangeException ("Index out of range.");
2670 return (int) list [index];
2674 bool ICollection.IsSynchronized {
2675 get { return list.IsSynchronized; }
2678 object ICollection.SyncRoot {
2679 get { return this; }
2682 bool IList.IsFixedSize {
2683 get { return true; }
2686 object IList.this [int index] {
2687 get { return this [index]; }
2688 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2690 #endregion // Public Properties
2692 #region Public Methods
2693 public bool Contains (int selectedIndex)
2695 return list.Contains (selectedIndex);
2698 public void CopyTo (Array dest, int index)
2700 list.CopyTo (dest, index);
2703 public IEnumerator GetEnumerator ()
2705 return list.GetEnumerator ();
2708 int IList.Add (object value)
2710 throw new NotSupportedException ("Add operation is not supported.");
2715 throw new NotSupportedException ("Clear operation is not supported.");
2718 bool IList.Contains (object selectedIndex)
2720 return list.Contains (selectedIndex);
2723 int IList.IndexOf (object selectedIndex)
2725 return list.IndexOf (selectedIndex);
2728 void IList.Insert (int index, object value)
2730 throw new NotSupportedException ("Insert operation is not supported.");
2733 void IList.Remove (object value)
2735 throw new NotSupportedException ("Remove operation is not supported.");
2738 void IList.RemoveAt (int index)
2740 throw new NotSupportedException ("RemoveAt operation is not supported.");
2743 public int IndexOf (int selectedIndex)
2745 return list.IndexOf (selectedIndex);
2747 #endregion // Public Methods
2749 } // SelectedIndexCollection
2751 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2753 internal ArrayList list;
2754 private ListView owner;
2756 #region Public Constructor
2757 public SelectedListViewItemCollection (ListView owner)
2759 list = new ArrayList ();
2762 #endregion // Public Constructor
2764 #region Public Properties
2767 get { return list.Count; }
2770 public bool IsReadOnly {
2771 get { return true; }
2774 public ListViewItem this [int index] {
2776 if (index < 0 || index >= list.Count)
2777 throw new ArgumentOutOfRangeException ("Index out of range.");
2778 return (ListViewItem) list [index];
2782 bool ICollection.IsSynchronized {
2783 get { return list.IsSynchronized; }
2786 object ICollection.SyncRoot {
2787 get { return this; }
2790 bool IList.IsFixedSize {
2791 get { return true; }
2794 object IList.this [int index] {
2795 get { return this [index]; }
2796 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2798 #endregion // Public Properties
2800 #region Public Methods
2801 public void Clear ()
2803 ArrayList copy = (ArrayList) list.Clone ();
2804 for (int i = 0; i < copy.Count; i++)
2805 ((ListViewItem) copy [i]).Selected = false;
2810 public bool Contains (ListViewItem item)
2812 return list.Contains (item);
2815 public void CopyTo (Array dest, int index)
2817 list.CopyTo (dest, index);
2820 public IEnumerator GetEnumerator ()
2822 return list.GetEnumerator ();
2825 int IList.Add (object value)
2827 throw new NotSupportedException ("Add operation is not supported.");
2830 bool IList.Contains (object item)
2832 return list.Contains (item);
2835 int IList.IndexOf (object item)
2837 return list.IndexOf (item);
2840 void IList.Insert (int index, object value)
2842 throw new NotSupportedException ("Insert operation is not supported.");
2845 void IList.Remove (object value)
2847 throw new NotSupportedException ("Remove operation is not supported.");
2850 void IList.RemoveAt (int index)
2852 throw new NotSupportedException ("RemoveAt operation is not supported.");
2855 public int IndexOf (ListViewItem item)
2857 return list.IndexOf (item);
2859 #endregion // Public Methods
2861 } // SelectedListViewItemCollection
2863 #endregion // Subclasses