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 Controls.AddImplicit (header_control);
148 item_control = new ItemControl (this);
149 Controls.AddImplicit (item_control);
151 h_scroll = new HScrollBar ();
152 Controls.AddImplicit (this.h_scroll);
154 v_scroll = new VScrollBar ();
155 Controls.AddImplicit (this.v_scroll);
157 h_marker = v_marker = 0;
158 keysearch_tickcnt = 0;
160 // scroll bars are disabled initially
161 h_scroll.Visible = false;
162 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
163 v_scroll.Visible = false;
164 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
167 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
168 SizeChanged += new EventHandler (ListView_SizeChanged);
170 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
172 #endregion // Public Constructors
174 #region Private Internal Properties
175 internal Size CheckBoxSize {
177 if (this.check_boxes) {
178 if (this.state_image_list != null)
179 return this.state_image_list.ImageSize;
181 return ThemeEngine.Current.ListViewCheckBoxSize;
189 bool CanMultiselect {
193 else if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
200 #endregion // Private Internal Properties
202 #region Protected Properties
203 protected override CreateParams CreateParams {
204 get { return base.CreateParams; }
207 protected override Size DefaultSize {
208 get { return ThemeEngine.Current.ListViewDefaultSize; }
210 #endregion // Protected Properties
212 #region Public Instance Properties
213 [DefaultValue (ItemActivation.Standard)]
214 public ItemActivation Activation {
215 get { return activation; }
217 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
218 value != ItemActivation.TwoClick) {
219 throw new InvalidEnumArgumentException (string.Format
220 ("Enum argument value '{0}' is not valid for Activation", value));
227 [DefaultValue (ListViewAlignment.Top)]
229 public ListViewAlignment Alignment {
230 get { return alignment; }
232 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
233 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
234 throw new InvalidEnumArgumentException (string.Format
235 ("Enum argument value '{0}' is not valid for Alignment", value));
238 if (this.alignment != value) {
240 // alignment does not matter in Details/List views
241 if (this.view == View.LargeIcon ||
242 this.View == View.SmallIcon)
248 [DefaultValue (false)]
249 public bool AllowColumnReorder {
250 get { return allow_column_reorder; }
251 set { allow_column_reorder = value; }
254 [DefaultValue (true)]
255 public bool AutoArrange {
256 get { return auto_arrange; }
258 if (auto_arrange != value) {
259 auto_arrange = value;
260 // autoarrange does not matter in Details/List views
261 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
267 public override Color BackColor {
269 if (background_color.IsEmpty)
270 return ThemeEngine.Current.ColorWindow;
272 return background_color;
274 set { background_color = value; }
278 [EditorBrowsable (EditorBrowsableState.Never)]
279 public override Image BackgroundImage {
280 get { return background_image; }
282 if (value == background_image)
285 background_image = value;
286 OnBackgroundImageChanged (EventArgs.Empty);
290 [DefaultValue (BorderStyle.Fixed3D)]
292 public BorderStyle BorderStyle {
293 get { return InternalBorderStyle; }
294 set { InternalBorderStyle = value; }
297 [DefaultValue (false)]
298 public bool CheckBoxes {
299 get { return check_boxes; }
301 if (check_boxes != value) {
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 public CheckedIndexCollection CheckedIndices {
311 get { return checked_indices; }
315 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
316 public CheckedListViewItemCollection CheckedItems {
317 get { return checked_items; }
320 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
322 [MergableProperty (false)]
323 public ColumnHeaderCollection Columns {
324 get { return columns; }
328 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
329 public ListViewItem FocusedItem {
335 public override Color ForeColor {
337 if (foreground_color.IsEmpty)
338 return ThemeEngine.Current.ColorWindowText;
340 return foreground_color;
342 set { foreground_color = value; }
345 [DefaultValue (false)]
346 public bool FullRowSelect {
347 get { return full_row_select; }
348 set { full_row_select = value; }
351 [DefaultValue (false)]
352 public bool GridLines {
353 get { return grid_lines; }
355 if (grid_lines != value) {
362 [DefaultValue (ColumnHeaderStyle.Clickable)]
363 public ColumnHeaderStyle HeaderStyle {
364 get { return header_style; }
366 if (header_style == value)
370 case ColumnHeaderStyle.Clickable:
371 case ColumnHeaderStyle.Nonclickable:
372 case ColumnHeaderStyle.None:
375 throw new InvalidEnumArgumentException (string.Format
376 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
379 header_style = value;
380 if (view == View.Details)
385 [DefaultValue (true)]
386 public bool HideSelection {
387 get { return hide_selection; }
389 if (hide_selection != value) {
390 hide_selection = value;
396 [DefaultValue (false)]
397 public bool HoverSelection {
398 get { return hover_selection; }
399 set { hover_selection = value; }
402 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
404 [MergableProperty (false)]
405 public ListViewItemCollection Items {
406 get { return items; }
409 [DefaultValue (false)]
410 public bool LabelEdit {
411 get { return label_edit; }
412 set { label_edit = value; }
415 [DefaultValue (true)]
417 public bool LabelWrap {
418 get { return label_wrap; }
420 if (label_wrap != value) {
427 [DefaultValue (null)]
428 public ImageList LargeImageList {
429 get { return large_image_list; }
431 large_image_list = value;
437 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
438 public IComparer ListViewItemSorter {
439 get { return item_sorter; }
440 set { item_sorter = value; }
443 [DefaultValue (true)]
444 public bool MultiSelect {
445 get { return multiselect; }
446 set { multiselect = value; }
449 [DefaultValue (true)]
450 public bool Scrollable {
451 get { return scrollable; }
453 if (scrollable != value) {
461 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
462 public SelectedIndexCollection SelectedIndices {
463 get { return selected_indices; }
467 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
468 public SelectedListViewItemCollection SelectedItems {
469 get { return selected_items; }
473 [MonoTODO("Implement")]
474 public bool ShowGroups {
484 [DefaultValue (null)]
485 public ImageList SmallImageList {
486 get { return small_image_list; }
488 small_image_list = value;
493 [DefaultValue (SortOrder.None)]
494 public SortOrder Sorting {
495 get { return sort_order; }
497 if (value != SortOrder.Ascending && value != SortOrder.Descending &&
498 value != SortOrder.None) {
499 throw new InvalidEnumArgumentException (string.Format
500 ("Enum argument value '{0}' is not valid for Sorting", value));
503 if (sort_order != value) {
510 [DefaultValue (null)]
511 public ImageList StateImageList {
512 get { return state_image_list; }
514 state_image_list = value;
521 [EditorBrowsable (EditorBrowsableState.Never)]
522 public override string Text {
531 OnTextChanged (EventArgs.Empty);
536 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
537 public ListViewItem TopItem {
540 if (this.items.Count == 0)
542 // if contents are not scrolled
543 // it is the first item
544 else if (h_marker == 0 && v_marker == 0)
545 return this.items [0];
546 // do a hit test for the scrolled position
548 foreach (ListViewItem item in this.items) {
549 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
558 [MonoTODO("Implement")]
559 public bool UseCompatibleStateImageBehavior {
569 [DefaultValue (View.LargeIcon)]
573 if (value != View.Details && value != View.LargeIcon &&
574 value != View.List && value != View.SmallIcon ) {
575 throw new InvalidEnumArgumentException (string.Format
576 ("Enum argument value '{0}' is not valid for View", value));
580 h_scroll.Value = v_scroll.Value = 0;
586 #endregion // Public Instance Properties
588 #region Internal Methods Properties
590 internal int FirstVisibleIndex {
593 if (this.items.Count == 0)
596 if (h_marker == 0 && v_marker == 0)
599 foreach (ListViewItem item in this.items) {
600 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
609 internal int LastVisibleIndex {
611 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
612 if (View == View.List || Alignment == ListViewAlignment.Left) {
613 if (Items[i].Bounds.X > ClientRectangle.Right)
616 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
621 return Items.Count - 1;
625 internal int TotalWidth {
626 get { return Math.Max (this.Width, this.layout_wd); }
629 internal int TotalHeight {
630 get { return Math.Max (this.Height, this.layout_ht); }
633 internal void Redraw (bool recalculate)
635 // Avoid calculations when control is being updated
640 CalculateListView (this.alignment);
645 internal Size GetChildColumnSize (int index)
647 Size ret_size = Size.Empty;
648 ColumnHeader col = this.columns [index];
650 if (col.Width == -2) { // autosize = max(items, columnheader)
651 Size size = Size.Ceiling (this.DeviceContext.MeasureString
652 (col.Text, this.Font));
653 ret_size = BiggestItem (index);
654 if (size.Width > ret_size.Width)
657 else { // -1 and all the values < -2 are put under one category
658 ret_size = BiggestItem (index);
659 // fall back to empty columns' width if no subitem is available for a column
660 if (ret_size.IsEmpty) {
661 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
662 if (col.Text.Length > 0)
663 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
664 (col.Text, this.Font)).Height;
666 ret_size.Height = this.Font.Height;
670 // adjust the size for icon and checkbox for 0th column
672 ret_size.Width += (this.CheckBoxSize.Width + 4);
673 if (this.small_image_list != null)
674 ret_size.Width += this.small_image_list.ImageSize.Width;
679 // Returns the size of biggest item text in a column.
680 private Size BiggestItem (int col)
682 Size temp = Size.Empty;
683 Size ret_size = Size.Empty;
685 // 0th column holds the item text, we check the size of
686 // the various subitems falling in that column and get
687 // the biggest one's size.
688 foreach (ListViewItem item in items) {
689 if (col >= item.SubItems.Count)
692 temp = Size.Ceiling (this.DeviceContext.MeasureString
693 (item.SubItems [col].Text, this.Font));
694 if (temp.Width > ret_size.Width)
698 // adjustment for space
699 if (!ret_size.IsEmpty)
705 // Sets the size of the biggest item text as per the view
706 private void CalcTextSize ()
708 // clear the old value
709 text_size = Size.Empty;
711 if (items.Count == 0)
714 text_size = BiggestItem (0);
716 if (view == View.LargeIcon && this.label_wrap) {
717 Size temp = Size.Empty;
718 if (this.check_boxes)
719 temp.Width += 2 * this.CheckBoxSize.Width;
720 if (large_image_list != null)
721 temp.Width += large_image_list.ImageSize.Width;
724 // wrapping is done for two lines only
725 if (text_size.Width > temp.Width) {
726 text_size.Width = temp.Width;
727 text_size.Height *= 2;
730 else if (view == View.List) {
731 // in list view max text shown in determined by the
732 // control width, even if scolling is enabled.
733 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
734 if (this.small_image_list != null)
735 max_wd -= this.small_image_list.ImageSize.Width;
737 if (text_size.Width > max_wd)
738 text_size.Width = max_wd;
741 // we do the default settings, if we have got 0's
742 if (text_size.Height <= 0)
743 text_size.Height = this.Font.Height;
744 if (text_size.Width <= 0)
745 text_size.Width = this.Width;
748 text_size.Width += 4;
749 text_size.Height += 2;
752 private void Scroll (ScrollBar scrollbar, int delta)
754 if (delta == 0 || !scrollbar.Visible)
758 if (scrollbar == h_scroll)
759 max = h_scroll.Maximum - item_control.Width;
761 max = v_scroll.Maximum - item_control.Height;
763 int val = scrollbar.Value + delta;
766 else if (val < scrollbar.Minimum)
767 val = scrollbar.Minimum;
768 scrollbar.Value = val;
771 private void CalculateScrollBars ()
773 Rectangle client_area = ClientRectangle;
775 if (!this.scrollable || this.items.Count <= 0) {
776 h_scroll.Visible = false;
777 v_scroll.Visible = false;
781 // making a scroll bar visible might make
782 // other scroll bar visible
783 if (layout_wd > client_area.Right) {
784 h_scroll.Visible = true;
785 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
786 v_scroll.Visible = true;
788 v_scroll.Visible = false;
789 } else if (layout_ht > client_area.Bottom) {
790 v_scroll.Visible = true;
791 if ((layout_wd + v_scroll.Width) > client_area.Right)
792 h_scroll.Visible = true;
794 h_scroll.Visible = false;
796 h_scroll.Visible = false;
797 v_scroll.Visible = false;
800 item_control.Height = ClientRectangle.Height - header_control.Height;
802 if (h_scroll.Visible) {
803 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
804 h_scroll.Minimum = 0;
806 // if v_scroll is visible, adjust the maximum of the
807 // h_scroll to account for the width of v_scroll
808 if (v_scroll.Visible) {
809 h_scroll.Maximum = layout_wd + v_scroll.Width;
810 h_scroll.Width = client_area.Width - v_scroll.Width;
813 h_scroll.Maximum = layout_wd;
814 h_scroll.Width = client_area.Width;
817 h_scroll.LargeChange = client_area.Width;
818 h_scroll.SmallChange = Font.Height;
819 item_control.Height -= h_scroll.Height;
822 if (header_control.Visible)
823 header_control.Width = ClientRectangle.Width;
824 item_control.Width = ClientRectangle.Width;
826 if (v_scroll.Visible) {
827 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
828 v_scroll.Minimum = 0;
830 // if h_scroll is visible, adjust the maximum of the
831 // v_scroll to account for the height of h_scroll
832 if (h_scroll.Visible) {
833 v_scroll.Maximum = layout_ht + h_scroll.Height;
834 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
836 v_scroll.Maximum = layout_ht;
837 v_scroll.Height = client_area.Height;
840 v_scroll.LargeChange = client_area.Height;
841 v_scroll.SmallChange = Font.Height;
842 if (header_control.Visible)
843 header_control.Width -= v_scroll.Width;
844 item_control.Width -= v_scroll.Width;
848 ColumnHeader GetReorderedColumn (int index)
850 if (reordered_column_indices == null)
851 return Columns [index];
853 return Columns [reordered_column_indices [index]];
856 void ReorderColumn (ColumnHeader col, int index)
858 if (reordered_column_indices == null) {
859 reordered_column_indices = new int [Columns.Count];
860 for (int i = 0; i < Columns.Count; i++)
861 reordered_column_indices [i] = i;
864 if (reordered_column_indices [index] == col.Index)
867 int[] curr = reordered_column_indices;
868 int[] result = new int [Columns.Count];
870 for (int i = 0; i < Columns.Count; i++) {
871 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
875 result [i] = col.Index;
877 result [i] = curr [curr_idx++];
880 reordered_column_indices = result;
882 header_control.Invalidate ();
883 item_control.Invalidate ();
886 Size LargeIconItemSize {
888 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
889 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
890 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
891 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
892 return new Size (w, h);
896 Size SmallIconItemSize {
898 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
899 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
900 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
901 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
902 return new Size (w, h);
908 ListViewItem[,] item_matrix;
910 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
912 header_control.Visible = false;
913 header_control.Size = Size.Empty;
914 item_control.Visible = true;
915 item_control.Location = Point.Empty;
917 if (items.Count == 0)
920 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
922 Rectangle area = ClientRectangle;
925 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
928 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
930 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
933 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
936 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
937 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
938 item_matrix = new ListViewItem [rows, cols];
941 foreach (ListViewItem item in items) {
942 int x = col * (sz.Width + x_spacing);
943 int y = row * (sz.Height + y_spacing);
944 item.Location = new Point (x, y);
948 item_matrix [row, col] = item;
962 item_control.Size = new Size (layout_wd, layout_ht);
967 if (header_style == ColumnHeaderStyle.None) {
968 header_control.Visible = false;
969 header_control.Size = Size.Empty;
974 for (int i = 0; i < Columns.Count; i++) {
975 ColumnHeader col = GetReorderedColumn (i);
978 col.CalcColumnHeader ();
982 if (x < ClientRectangle.Width)
983 x = ClientRectangle.Width;
985 header_control.Width = x;
986 header_control.Height = columns [0].Ht;
987 header_control.Visible = true;
990 void LayoutDetails ()
992 if (columns.Count == 0) {
993 header_control.Visible = false;
994 item_control.Visible = false;
1000 item_control.Visible = true;
1001 item_control.Location = new Point (0, header_control.Height);
1004 if (items.Count > 0) {
1005 foreach (ListViewItem item in items) {
1007 item.Location = new Point (0, y);
1008 y += item.Bounds.Height + 2;
1011 // some space for bottom gridline
1016 layout_wd = Math.Max (header_control.Width, item_control.Width);
1017 layout_ht = y + header_control.Height;
1020 private void CalculateListView (ListViewAlignment align)
1029 case View.SmallIcon:
1030 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1033 case View.LargeIcon:
1034 LayoutIcons (true, alignment == ListViewAlignment.Left,
1035 ThemeEngine.Current.ListViewHorizontalSpacing,
1036 ThemeEngine.Current.ListViewVerticalSpacing);
1040 LayoutIcons (false, true, 4, 2);
1044 CalculateScrollBars ();
1047 internal void UpdateSelection (ListViewItem item)
1049 if (item.Selected) {
1051 if (!CanMultiselect && SelectedItems.Count > 0) {
1052 SelectedItems.Clear ();
1053 SelectedIndices.list.Clear ();
1056 if (!SelectedItems.Contains (item)) {
1057 SelectedItems.list.Add (item);
1058 SelectedIndices.list.Add (item.Index);
1061 SelectedItems.list.Remove (item);
1062 SelectedIndices.list.Remove (item.Index);
1066 private bool KeySearchString (KeyEventArgs ke)
1068 int current_tickcnt = Environment.TickCount;
1069 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1070 keysearch_text = string.Empty;
1073 keysearch_text += (char) ke.KeyData;
1074 keysearch_tickcnt = current_tickcnt;
1076 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1079 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1080 CompareOptions.IgnoreCase)) {
1081 SetFocusedItem (Items [i]);
1082 items [i].Selected = true;
1086 i = (i + 1 < Items.Count) ? i+1 : 0;
1094 int GetAdjustedIndex (Keys key)
1098 if (View == View.Details) {
1100 result = FocusedItem.Index - 1;
1101 else if (key == Keys.Down) {
1102 result = FocusedItem.Index + 1;
1103 if (result == items.Count)
1109 int row = FocusedItem.row;
1110 int col = FocusedItem.col;
1116 return item_matrix [row, col - 1].Index;
1119 if (col == (cols - 1))
1121 while (item_matrix [row, col + 1] == null)
1123 return item_matrix [row, col + 1].Index;
1128 return item_matrix [row - 1, col].Index;
1131 if (row == (rows - 1))
1133 while (item_matrix [row + 1, col] == null)
1135 return item_matrix [row + 1, col].Index;
1142 ListViewItem selection_start;
1144 private void SelectItems (ArrayList sel_items)
1146 multiselecting = true;
1147 ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
1148 foreach (ListViewItem item in curr_items)
1149 if (!sel_items.Contains (item))
1150 item.Selected = false;
1151 foreach (ListViewItem item in sel_items)
1152 item.Selected = true;
1153 multiselecting = false;
1156 private void UpdateMultiSelection (int index)
1158 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1159 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1160 ListViewItem item = items [index];
1162 if (shift_pressed && selection_start != null) {
1163 ArrayList list = new ArrayList ();
1164 int start = Math.Min (selection_start.Index, index);
1165 int end = Math.Max (selection_start.Index, index);
1166 if (View == View.Details) {
1167 for (int i = start; i <= end; i++)
1168 list.Add (items [i]);
1170 int left = Math.Min (items [start].col, items [end].col);
1171 int right = Math.Max (items [start].col, items [end].col);
1172 int top = Math.Min (items [start].row, items [end].row);
1173 int bottom = Math.Max (items [start].row, items [end].row);
1174 foreach (ListViewItem curr in items)
1175 if (curr.row >= top && curr.row <= bottom &&
1176 curr.col >= left && curr.col <= right)
1180 } else if (!ctrl_pressed) {
1181 SelectedItems.Clear ();
1182 SelectedIndices.list.Clear ();
1183 item.Selected = true;
1184 selection_start = item;
1188 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1190 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1196 switch (ke.KeyCode) {
1199 index = Items.Count - 1;
1210 index = GetAdjustedIndex (ke.KeyCode);
1214 ke.Handled = KeySearchString (ke);
1222 UpdateMultiSelection (index);
1224 items [index].Selected = true;
1226 SetFocusedItem (items [index]);
1227 EnsureVisible (index);
1231 internal class ItemControl : Control {
1234 ListViewItem clicked_item;
1235 ListViewItem last_clicked_item;
1236 bool hover_processed = false;
1238 public ItemControl (ListView owner)
1241 DoubleClick += new EventHandler(ItemsDoubleClick);
1242 KeyDown += new KeyEventHandler (ItemsKeyDown);
1243 KeyUp += new KeyEventHandler (ItemsKeyUp);
1244 MouseDown += new MouseEventHandler(ItemsMouseDown);
1245 MouseMove += new MouseEventHandler(ItemsMouseMove);
1246 MouseHover += new EventHandler(ItemsMouseHover);
1247 MouseUp += new MouseEventHandler(ItemsMouseUp);
1248 MouseWheel += new MouseEventHandler(ItemsMouseWheel);
1249 GotFocus += new EventHandler (FocusChanged);
1250 LostFocus += new EventHandler (FocusChanged);
1253 void ItemsDoubleClick (object sender, EventArgs e)
1255 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1256 owner.ItemActivate (this, e);
1259 void ItemsKeyDown (object sender, KeyEventArgs args)
1261 owner.OnKeyDown (args);
1264 void ItemsKeyUp (object sender, KeyEventArgs args)
1266 owner.OnKeyUp (args);
1276 BoxSelect box_select_mode = BoxSelect.None;
1277 ArrayList prev_selection;
1278 Point box_select_start;
1280 Rectangle box_select_rect;
1281 internal Rectangle BoxSelectRectangle {
1282 get { return box_select_rect; }
1284 if (box_select_rect == value)
1287 InvalidateBoxSelectRect ();
1288 box_select_rect = value;
1289 InvalidateBoxSelectRect ();
1293 void InvalidateBoxSelectRect ()
1295 if (BoxSelectRectangle.Size.IsEmpty)
1298 Rectangle edge = BoxSelectRectangle;
1304 edge.Y = BoxSelectRectangle.Bottom - 1;
1306 edge.Y = BoxSelectRectangle.Y - 1;
1308 edge.Height = BoxSelectRectangle.Height + 2;
1310 edge.X = BoxSelectRectangle.Right - 1;
1314 private Rectangle CalculateBoxSelectRectangle (Point pt)
1316 int left = Math.Min (box_select_start.X, pt.X);
1317 int right = Math.Max (box_select_start.X, pt.X);
1318 int top = Math.Min (box_select_start.Y, pt.Y);
1319 int bottom = Math.Max (box_select_start.Y, pt.Y);
1320 return Rectangle.FromLTRB (left, top, right, bottom);
1323 ArrayList BoxSelectedItems {
1325 ArrayList result = new ArrayList ();
1326 foreach (ListViewItem item in owner.Items) {
1327 Rectangle r = item.Bounds;
1329 r.Y += r.Height / 4;
1332 if (BoxSelectRectangle.IntersectsWith (r))
1339 private bool PerformBoxSelection (Point pt)
1341 if (box_select_mode == BoxSelect.None)
1344 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1346 ArrayList box_items = BoxSelectedItems;
1350 switch (box_select_mode) {
1352 case BoxSelect.Normal:
1356 case BoxSelect.Control:
1357 items = new ArrayList ();
1358 foreach (ListViewItem item in prev_selection)
1359 if (!box_items.Contains (item))
1361 foreach (ListViewItem item in box_items)
1362 if (!prev_selection.Contains (item))
1366 case BoxSelect.Shift:
1368 foreach (ListViewItem item in box_items)
1369 prev_selection.Remove (item);
1370 foreach (ListViewItem item in prev_selection)
1375 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1379 owner.SelectItems (items);
1385 private void ItemsMouseDown (object sender, MouseEventArgs me)
1387 if (owner.items.Count == 0)
1390 Point pt = new Point (me.X, me.Y);
1391 foreach (ListViewItem item in owner.items) {
1392 if (item.CheckRectReal.Contains (pt)) {
1393 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1394 item.Checked = !item.Checked;
1396 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1398 // Raise the ItemCheck event
1399 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1400 owner.OnItemCheck (ice);
1404 if (owner.View == View.Details && !owner.FullRowSelect) {
1405 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1406 clicked_item = item;
1410 if (item.Bounds.Contains (pt)) {
1411 clicked_item = item;
1418 if (clicked_item != null) {
1419 owner.SetFocusedItem (clicked_item);
1420 bool changed = !clicked_item.Selected;
1421 if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
1422 owner.UpdateMultiSelection (clicked_item.Index);
1424 clicked_item.Selected = true;
1427 owner.OnSelectedIndexChanged (EventArgs.Empty);
1429 // Raise double click if the item was clicked. On MS the
1430 // double click is only raised if you double click an item
1431 if (me.Clicks > 1 && clicked_item != null)
1432 owner.OnDoubleClick (EventArgs.Empty);
1433 else if (me.Clicks == 1 && clicked_item != null)
1434 owner.OnClick (EventArgs.Empty);
1436 if (owner.MultiSelect) {
1437 Keys mods = XplatUI.State.ModifierKeys;
1438 if ((mods & Keys.Shift) != 0)
1439 box_select_mode = BoxSelect.Shift;
1440 else if ((mods & Keys.Control) != 0)
1441 box_select_mode = BoxSelect.Control;
1443 box_select_mode = BoxSelect.Normal;
1444 box_select_start = pt;
1445 prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
1446 } else if (owner.selected_indices.Count > 0) {
1447 owner.SelectedItems.Clear ();
1448 owner.SelectedIndices.list.Clear ();
1449 owner.OnSelectedIndexChanged (EventArgs.Empty);
1454 private void ItemsMouseMove (object sender, MouseEventArgs me)
1456 if (PerformBoxSelection (new Point (me.X, me.Y)))
1459 if (owner.HoverSelection && hover_processed) {
1461 Point pt = PointToClient (Control.MousePosition);
1462 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1463 if (item == null || item.Selected)
1466 hover_processed = false;
1467 XplatUI.ResetMouseHover (Handle);
1472 private void ItemsMouseHover (object sender, EventArgs e)
1474 if (Capture || !owner.HoverSelection)
1477 hover_processed = true;
1478 Point pt = PointToClient (Control.MousePosition);
1479 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1484 item.Selected = true;
1485 owner.OnSelectedIndexChanged (new EventArgs ());
1488 private void ItemsMouseUp (object sender, MouseEventArgs me)
1491 if (owner.Items.Count == 0)
1494 Point pt = new Point (me.X, me.Y);
1496 Rectangle rect = Rectangle.Empty;
1497 if (clicked_item != null) {
1498 if (owner.view == View.Details && !owner.full_row_select)
1499 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1501 rect = clicked_item.Bounds;
1503 if (rect.Contains (pt)) {
1504 switch (owner.activation) {
1505 case ItemActivation.OneClick:
1506 owner.OnItemActivate (EventArgs.Empty);
1509 case ItemActivation.TwoClick:
1510 if (last_clicked_item == clicked_item) {
1511 owner.OnItemActivate (EventArgs.Empty);
1512 last_clicked_item = null;
1514 last_clicked_item = clicked_item;
1517 // DoubleClick activation is handled in another handler
1521 } else if (owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1522 // Need this to clean up background clicks
1523 owner.SelectedItems.Clear ();
1524 owner.SelectedIndices.list.Clear ();
1525 owner.OnSelectedIndexChanged (EventArgs.Empty);
1528 clicked_item = null;
1529 box_select_start = Point.Empty;
1530 BoxSelectRectangle = Rectangle.Empty;
1531 prev_selection = null;
1532 box_select_mode = BoxSelect.None;
1535 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1537 if (owner.Items.Count == 0)
1540 int lines = me.Delta / 120;
1545 switch (owner.View) {
1547 case View.SmallIcon:
1548 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1550 case View.LargeIcon:
1551 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1554 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1559 void FocusChanged (object o, EventArgs args)
1561 if (owner.Items.Count == 0)
1564 if (owner.FocusedItem == null)
1565 owner.SetFocusedItem (owner.Items [0]);
1567 Invalidate (owner.FocusedItem.Bounds);
1570 internal override void OnPaintInternal (PaintEventArgs pe)
1572 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1576 internal override void OnPaintInternal (PaintEventArgs pe)
1581 CalculateScrollBars ();
1584 private void ListView_SizeChanged (object sender, EventArgs e)
1586 CalculateListView (alignment);
1589 private void SetFocusedItem (ListViewItem item)
1591 if (focused_item != null)
1592 focused_item.Focused = false;
1595 item.Focused = true;
1597 focused_item = item;
1600 private void HorizontalScroller (object sender, EventArgs e)
1602 // Avoid unnecessary flickering, when button is
1603 // kept pressed at the end
1604 if (h_marker != h_scroll.Value) {
1606 int pixels = h_marker - h_scroll.Value;
1608 h_marker = h_scroll.Value;
1609 if (header_control.Visible)
1610 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1612 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1616 private void VerticalScroller (object sender, EventArgs e)
1618 // Avoid unnecessary flickering, when button is
1619 // kept pressed at the end
1620 if (v_marker != v_scroll.Value) {
1621 int pixels = v_marker - v_scroll.Value;
1622 Rectangle area = item_control.ClientRectangle;
1623 v_marker = v_scroll.Value;
1624 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1627 #endregion // Internal Methods Properties
1629 #region Protected Methods
1630 protected override void CreateHandle ()
1632 base.CreateHandle ();
1635 protected override void Dispose (bool disposing)
1638 h_scroll.Dispose ();
1639 v_scroll.Dispose ();
1641 large_image_list = null;
1642 small_image_list = null;
1643 state_image_list = null;
1646 base.Dispose (disposing);
1649 protected override bool IsInputKey (Keys keyData)
1666 return base.IsInputKey (keyData);
1669 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1671 if (AfterLabelEdit != null)
1672 AfterLabelEdit (this, e);
1675 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1677 if (BeforeLabelEdit != null)
1678 BeforeLabelEdit (this, e);
1681 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1683 if (ColumnClick != null)
1684 ColumnClick (this, e);
1687 protected override void OnEnabledChanged (EventArgs e)
1689 base.OnEnabledChanged (e);
1692 protected override void OnFontChanged (EventArgs e)
1694 base.OnFontChanged (e);
1698 protected override void OnHandleCreated (EventArgs e)
1700 base.OnHandleCreated (e);
1703 protected override void OnHandleDestroyed (EventArgs e)
1705 base.OnHandleDestroyed (e);
1708 protected virtual void OnItemActivate (EventArgs e)
1710 if (ItemActivate != null)
1711 ItemActivate (this, e);
1714 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1716 if (ItemCheck != null)
1717 ItemCheck (this, ice);
1720 protected virtual void OnItemDrag (ItemDragEventArgs e)
1722 if (ItemDrag != null)
1726 protected virtual void OnSelectedIndexChanged (EventArgs e)
1728 if (SelectedIndexChanged != null)
1729 SelectedIndexChanged (this, e);
1732 protected override void OnSystemColorsChanged (EventArgs e)
1734 base.OnSystemColorsChanged (e);
1737 protected void RealizeProperties ()
1742 protected void UpdateExtendedStyles ()
1747 protected override void WndProc (ref Message m)
1749 base.WndProc (ref m);
1751 #endregion // Protected Methods
1753 #region Public Instance Methods
1754 public void ArrangeIcons ()
1756 ArrangeIcons (this.alignment);
1759 public void ArrangeIcons (ListViewAlignment alignment)
1761 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1762 if (view == View.LargeIcon || view == View.SmallIcon) {
1763 this.CalculateListView (alignment);
1764 // we have done the calculations already
1765 this.Redraw (false);
1769 public void BeginUpdate ()
1771 // flag to avoid painting
1775 public void Clear ()
1778 items.Clear (); // Redraw (true) called here
1781 public void EndUpdate ()
1783 // flag to avoid painting
1786 // probably, now we need a redraw with recalculations
1790 public void EnsureVisible (int index)
1792 if (index < 0 || index >= items.Count || scrollable == false)
1795 Rectangle view_rect = item_control.ClientRectangle;
1796 Rectangle bounds = items [index].Bounds;
1798 if (view_rect.Contains (bounds))
1801 if (bounds.Left < 0)
1802 h_scroll.Value += bounds.Left;
1803 else if (bounds.Right > view_rect.Right)
1804 h_scroll.Value += (bounds.Right - view_rect.Right);
1807 v_scroll.Value += bounds.Top;
1808 else if (bounds.Bottom > view_rect.Bottom)
1809 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1812 public ListViewItem GetItemAt (int x, int y)
1814 foreach (ListViewItem item in items) {
1815 if (item.Bounds.Contains (x, y))
1821 public Rectangle GetItemRect (int index)
1823 return GetItemRect (index, ItemBoundsPortion.Entire);
1826 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1828 if (index < 0 || index >= items.Count)
1829 throw new IndexOutOfRangeException ("index");
1831 return items [index].GetBounds (portion);
1836 if (sort_order != SortOrder.None)
1837 items.list.Sort (item_sorter);
1839 if (sort_order == SortOrder.Descending)
1840 items.list.Reverse ();
1845 public override string ToString ()
1847 int count = this.Items.Count;
1850 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1852 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1854 #endregion // Public Instance Methods
1859 class HeaderControl : Control {
1862 bool column_resize_active = false;
1863 ColumnHeader resize_column;
1864 ColumnHeader clicked_column;
1865 ColumnHeader drag_column;
1867 int drag_to_index = -1;
1869 public HeaderControl (ListView owner)
1872 MouseDown += new MouseEventHandler (HeaderMouseDown);
1873 MouseMove += new MouseEventHandler (HeaderMouseMove);
1874 MouseUp += new MouseEventHandler (HeaderMouseUp);
1877 private ColumnHeader ColumnAtX (int x)
1879 Point pt = new Point (x, 0);
1880 ColumnHeader result = null;
1881 foreach (ColumnHeader col in owner.Columns) {
1882 if (col.Rect.Contains (pt)) {
1890 private int GetReorderedIndex (ColumnHeader col)
1892 if (owner.reordered_column_indices == null)
1895 for (int i = 0; i < owner.Columns.Count; i++)
1896 if (owner.reordered_column_indices [i] == col.Index)
1898 throw new Exception ("Column index missing from reordered array");
1901 private void HeaderMouseDown (object sender, MouseEventArgs me)
1903 if (resize_column != null) {
1904 column_resize_active = true;
1909 clicked_column = ColumnAtX (me.X + owner.h_marker);
1911 if (clicked_column != null) {
1913 if (owner.AllowColumnReorder) {
1915 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1916 drag_column.column_rect = clicked_column.Rect;
1917 drag_to_index = GetReorderedIndex (clicked_column);
1919 clicked_column.pressed = true;
1920 Rectangle bounds = clicked_column.Rect;
1921 bounds.X -= owner.h_marker;
1922 Invalidate (bounds);
1927 private void HeaderMouseMove (object sender, MouseEventArgs me)
1929 Point pt = new Point (me.X + owner.h_marker, me.Y);
1931 if (column_resize_active) {
1932 resize_column.Width = pt.X - resize_column.X;
1933 if (resize_column.Width < 0)
1934 resize_column.Width = 0;
1938 resize_column = null;
1940 if (clicked_column != null) {
1941 if (owner.AllowColumnReorder) {
1944 r = drag_column.column_rect;
1945 r.X = clicked_column.Rect.X + me.X - drag_x;
1946 drag_column.column_rect = r;
1948 int x = me.X + owner.h_marker;
1949 ColumnHeader over = ColumnAtX (x);
1951 drag_to_index = owner.Columns.Count;
1952 else if (x < over.X + over.Width / 2)
1953 drag_to_index = GetReorderedIndex (over);
1955 drag_to_index = GetReorderedIndex (over) + 1;
1958 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1959 bool pressed = clicked_column.pressed;
1960 clicked_column.pressed = over == clicked_column;
1961 if (clicked_column.pressed ^ pressed) {
1962 Rectangle bounds = clicked_column.Rect;
1963 bounds.X -= owner.h_marker;
1964 Invalidate (bounds);
1970 for (int i = 0; i < owner.Columns.Count; i++) {
1971 Rectangle zone = owner.Columns [i].Rect;
1972 zone.X = zone.Right - 5;
1974 if (zone.Contains (pt)) {
1975 resize_column = owner.Columns [i];
1980 if (resize_column == null)
1981 Cursor = Cursors.Default;
1983 Cursor = Cursors.VSplit;
1986 void HeaderMouseUp (object sender, MouseEventArgs me)
1990 if (column_resize_active) {
1991 column_resize_active = false;
1992 resize_column = null;
1993 Cursor = Cursors.Default;
1997 if (clicked_column != null && clicked_column.pressed) {
1998 clicked_column.pressed = false;
1999 Rectangle bounds = clicked_column.Rect;
2000 bounds.X -= owner.h_marker;
2001 Invalidate (bounds);
2002 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2005 if (drag_column != null && owner.AllowColumnReorder) {
2007 if (drag_to_index > GetReorderedIndex (clicked_column))
2009 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2010 owner.ReorderColumn (clicked_column, drag_to_index);
2015 clicked_column = null;
2018 internal override void OnPaintInternal (PaintEventArgs pe)
2023 Theme theme = ThemeEngine.Current;
2024 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2026 if (drag_column == null)
2030 if (drag_to_index == owner.Columns.Count)
2031 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2033 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2034 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2038 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2040 internal ArrayList list;
2041 private ListView owner;
2043 #region Public Constructor
2044 public CheckedIndexCollection (ListView owner)
2046 list = new ArrayList ();
2049 #endregion // Public Constructor
2051 #region Public Properties
2054 get { return list.Count; }
2057 public bool IsReadOnly {
2058 get { return true; }
2061 public int this [int index] {
2063 if (index < 0 || index >= list.Count)
2064 throw new ArgumentOutOfRangeException ("index");
2065 return (int) list [index];
2069 bool ICollection.IsSynchronized {
2070 get { return false; }
2073 object ICollection.SyncRoot {
2074 get { return this; }
2077 bool IList.IsFixedSize {
2078 get { return true; }
2081 object IList.this [int index] {
2082 get { return this [index]; }
2083 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2085 #endregion // Public Properties
2087 #region Public Methods
2088 public bool Contains (int checkedIndex)
2090 return list.Contains (checkedIndex);
2093 public IEnumerator GetEnumerator ()
2095 return list.GetEnumerator ();
2098 void ICollection.CopyTo (Array dest, int index)
2100 list.CopyTo (dest, index);
2103 int IList.Add (object value)
2105 throw new NotSupportedException ("Add operation is not supported.");
2110 throw new NotSupportedException ("Clear operation is not supported.");
2113 bool IList.Contains (object checkedIndex)
2115 return list.Contains (checkedIndex);
2118 int IList.IndexOf (object checkedIndex)
2120 return list.IndexOf (checkedIndex);
2123 void IList.Insert (int index, object value)
2125 throw new NotSupportedException ("Insert operation is not supported.");
2128 void IList.Remove (object value)
2130 throw new NotSupportedException ("Remove operation is not supported.");
2133 void IList.RemoveAt (int index)
2135 throw new NotSupportedException ("RemoveAt operation is not supported.");
2138 public int IndexOf (int checkedIndex)
2140 return list.IndexOf (checkedIndex);
2142 #endregion // Public Methods
2144 } // CheckedIndexCollection
2146 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2148 internal ArrayList list;
2149 private ListView owner;
2151 #region Public Constructor
2152 public CheckedListViewItemCollection (ListView owner)
2154 list = new ArrayList ();
2157 #endregion // Public Constructor
2159 #region Public Properties
2162 get { return list.Count; }
2165 public bool IsReadOnly {
2166 get { return true; }
2169 public ListViewItem this [int index] {
2171 if (index < 0 || index >= list.Count)
2172 throw new ArgumentOutOfRangeException ("index");
2173 return (ListViewItem) list [index];
2177 bool ICollection.IsSynchronized {
2178 get { return list.IsSynchronized; }
2181 object ICollection.SyncRoot {
2182 get { return this; }
2185 bool IList.IsFixedSize {
2186 get { return true; }
2189 object IList.this [int index] {
2190 get { return this [index]; }
2191 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2193 #endregion // Public Properties
2195 #region Public Methods
2196 public bool Contains (ListViewItem item)
2198 return list.Contains (item);
2201 public void CopyTo (Array dest, int index)
2203 list.CopyTo (dest, index);
2206 public IEnumerator GetEnumerator ()
2208 return list.GetEnumerator ();
2211 int IList.Add (object value)
2213 throw new NotSupportedException ("Add operation is not supported.");
2218 throw new NotSupportedException ("Clear operation is not supported.");
2221 bool IList.Contains (object item)
2223 return list.Contains (item);
2226 int IList.IndexOf (object item)
2228 return list.IndexOf (item);
2231 void IList.Insert (int index, object value)
2233 throw new NotSupportedException ("Insert operation is not supported.");
2236 void IList.Remove (object value)
2238 throw new NotSupportedException ("Remove operation is not supported.");
2241 void IList.RemoveAt (int index)
2243 throw new NotSupportedException ("RemoveAt operation is not supported.");
2246 public int IndexOf (ListViewItem item)
2248 return list.IndexOf (item);
2250 #endregion // Public Methods
2252 } // CheckedListViewItemCollection
2254 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2256 internal ArrayList list;
2257 private ListView owner;
2259 #region Public Constructor
2260 public ColumnHeaderCollection (ListView owner)
2262 list = new ArrayList ();
2265 #endregion // Public Constructor
2267 #region Public Properties
2270 get { return list.Count; }
2273 public bool IsReadOnly {
2274 get { return false; }
2277 public virtual ColumnHeader this [int index] {
2279 if (index < 0 || index >= list.Count)
2280 throw new ArgumentOutOfRangeException ("index");
2281 return (ColumnHeader) list [index];
2285 bool ICollection.IsSynchronized {
2286 get { return true; }
2289 object ICollection.SyncRoot {
2290 get { return this; }
2293 bool IList.IsFixedSize {
2294 get { return list.IsFixedSize; }
2297 object IList.this [int index] {
2298 get { return this [index]; }
2299 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2301 #endregion // Public Properties
2303 #region Public Methods
2304 public virtual int Add (ColumnHeader value)
2307 value.owner = this.owner;
2308 idx = list.Add (value);
2309 if (owner.IsHandleCreated) {
2310 owner.Redraw (true);
2315 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2317 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2318 this.Add (colHeader);
2322 public virtual void AddRange (ColumnHeader [] values)
2324 foreach (ColumnHeader colHeader in values) {
2325 colHeader.owner = this.owner;
2329 owner.Redraw (true);
2332 public virtual void Clear ()
2335 owner.Redraw (true);
2338 public bool Contains (ColumnHeader value)
2340 return list.Contains (value);
2343 public IEnumerator GetEnumerator ()
2345 return list.GetEnumerator ();
2348 void ICollection.CopyTo (Array dest, int index)
2350 list.CopyTo (dest, index);
2353 int IList.Add (object value)
2355 if (! (value is ColumnHeader)) {
2356 throw new ArgumentException ("Not of type ColumnHeader", "value");
2359 return this.Add ((ColumnHeader) value);
2362 bool IList.Contains (object value)
2364 if (! (value is ColumnHeader)) {
2365 throw new ArgumentException ("Not of type ColumnHeader", "value");
2368 return this.Contains ((ColumnHeader) value);
2371 int IList.IndexOf (object value)
2373 if (! (value is ColumnHeader)) {
2374 throw new ArgumentException ("Not of type ColumnHeader", "value");
2377 return this.IndexOf ((ColumnHeader) value);
2380 void IList.Insert (int index, object value)
2382 if (! (value is ColumnHeader)) {
2383 throw new ArgumentException ("Not of type ColumnHeader", "value");
2386 this.Insert (index, (ColumnHeader) value);
2389 void IList.Remove (object value)
2391 if (! (value is ColumnHeader)) {
2392 throw new ArgumentException ("Not of type ColumnHeader", "value");
2395 this.Remove ((ColumnHeader) value);
2398 public int IndexOf (ColumnHeader value)
2400 return list.IndexOf (value);
2403 public void Insert (int index, ColumnHeader value)
2405 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2406 // but it's really only greater.
2407 if (index < 0 || index > list.Count)
2408 throw new ArgumentOutOfRangeException ("index");
2410 value.owner = this.owner;
2411 list.Insert (index, value);
2412 owner.Redraw (true);
2415 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2417 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2418 this.Insert (index, colHeader);
2421 public virtual void Remove (ColumnHeader column)
2423 // TODO: Update Column internal index ?
2424 list.Remove (column);
2425 owner.Redraw (true);
2428 public virtual void RemoveAt (int index)
2430 if (index < 0 || index >= list.Count)
2431 throw new ArgumentOutOfRangeException ("index");
2433 // TODO: Update Column internal index ?
2434 list.RemoveAt (index);
2435 owner.Redraw (true);
2437 #endregion // Public Methods
2440 } // ColumnHeaderCollection
2442 public class ListViewItemCollection : IList, ICollection, IEnumerable
2444 internal ArrayList list;
2445 private ListView owner;
2447 #region Public Constructor
2448 public ListViewItemCollection (ListView owner)
2450 list = new ArrayList ();
2453 #endregion // Public Constructor
2455 #region Public Properties
2458 get { return list.Count; }
2461 public bool IsReadOnly {
2462 get { return false; }
2465 public virtual ListViewItem this [int displayIndex] {
2467 if (displayIndex < 0 || displayIndex >= list.Count)
2468 throw new ArgumentOutOfRangeException ("displayIndex");
2469 return (ListViewItem) list [displayIndex];
2473 if (displayIndex < 0 || displayIndex >= list.Count)
2474 throw new ArgumentOutOfRangeException ("displayIndex");
2476 if (list.Contains (value))
2477 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2479 value.Owner = owner;
2480 list [displayIndex] = value;
2482 owner.Redraw (true);
2486 bool ICollection.IsSynchronized {
2487 get { return true; }
2490 object ICollection.SyncRoot {
2491 get { return this; }
2494 bool IList.IsFixedSize {
2495 get { return list.IsFixedSize; }
2498 object IList.this [int index] {
2499 get { return this [index]; }
2501 if (value is ListViewItem)
2502 this [index] = (ListViewItem) value;
2504 this [index] = new ListViewItem (value.ToString ());
2507 #endregion // Public Properties
2509 #region Public Methods
2510 public virtual ListViewItem Add (ListViewItem value)
2512 if (list.Contains (value))
2513 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2515 value.Owner = owner;
2518 if (owner.Sorting != SortOrder.None)
2521 owner.Redraw (true);
2526 public virtual ListViewItem Add (string text)
2528 ListViewItem item = new ListViewItem (text);
2529 return this.Add (item);
2532 public virtual ListViewItem Add (string text, int imageIndex)
2534 ListViewItem item = new ListViewItem (text, imageIndex);
2535 return this.Add (item);
2538 public void AddRange (ListViewItem [] values)
2541 owner.SelectedItems.list.Clear ();
2542 owner.SelectedIndices.list.Clear ();
2543 owner.CheckedItems.list.Clear ();
2544 owner.CheckedIndices.list.Clear ();
2546 foreach (ListViewItem item in values) {
2551 if (owner.Sorting != SortOrder.None)
2554 owner.Redraw (true);
2557 public virtual void Clear ()
2559 owner.SetFocusedItem (null);
2560 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2562 owner.SelectedItems.list.Clear ();
2563 owner.SelectedIndices.list.Clear ();
2564 owner.CheckedItems.list.Clear ();
2565 owner.CheckedIndices.list.Clear ();
2566 owner.Redraw (true);
2569 public bool Contains (ListViewItem item)
2571 return list.Contains (item);
2574 public void CopyTo (Array dest, int index)
2576 list.CopyTo (dest, index);
2579 public IEnumerator GetEnumerator ()
2581 return list.GetEnumerator ();
2584 int IList.Add (object item)
2589 if (item is ListViewItem) {
2590 li = (ListViewItem) item;
2591 if (list.Contains (li))
2592 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2595 li = new ListViewItem (item.ToString ());
2598 result = list.Add (li);
2599 owner.Redraw (true);
2604 bool IList.Contains (object item)
2606 return list.Contains (item);
2609 int IList.IndexOf (object item)
2611 return list.IndexOf (item);
2614 void IList.Insert (int index, object item)
2616 if (item is ListViewItem)
2617 this.Insert (index, (ListViewItem) item);
2619 this.Insert (index, item.ToString ());
2622 void IList.Remove (object item)
2624 Remove ((ListViewItem) item);
2627 public int IndexOf (ListViewItem item)
2629 return list.IndexOf (item);
2632 public ListViewItem Insert (int index, ListViewItem item)
2634 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2635 // but it's really only greater.
2636 if (index < 0 || index > list.Count)
2637 throw new ArgumentOutOfRangeException ("index");
2639 if (list.Contains (item))
2640 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2643 list.Insert (index, item);
2644 owner.Redraw (true);
2648 public ListViewItem Insert (int index, string text)
2650 return this.Insert (index, new ListViewItem (text));
2653 public ListViewItem Insert (int index, string text, int imageIndex)
2655 return this.Insert (index, new ListViewItem (text, imageIndex));
2658 public virtual void Remove (ListViewItem item)
2660 if (!list.Contains (item))
2663 owner.SelectedItems.list.Remove (item);
2664 owner.SelectedIndices.list.Remove (item.Index);
2665 owner.CheckedItems.list.Remove (item);
2666 owner.CheckedIndices.list.Remove (item.Index);
2668 owner.Redraw (true);
2671 public virtual void RemoveAt (int index)
2673 if (index < 0 || index >= list.Count)
2674 throw new ArgumentOutOfRangeException ("index");
2676 list.RemoveAt (index);
2677 owner.SelectedItems.list.RemoveAt (index);
2678 owner.SelectedIndices.list.RemoveAt (index);
2679 owner.CheckedItems.list.RemoveAt (index);
2680 owner.CheckedIndices.list.RemoveAt (index);
2681 owner.Redraw (false);
2683 #endregion // Public Methods
2685 } // ListViewItemCollection
2687 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2689 internal ArrayList list;
2690 private ListView owner;
2692 #region Public Constructor
2693 public SelectedIndexCollection (ListView owner)
2695 list = new ArrayList ();
2698 #endregion // Public Constructor
2700 #region Public Properties
2703 get { return list.Count; }
2706 public bool IsReadOnly {
2707 get { return true; }
2710 public int this [int index] {
2712 if (index < 0 || index >= list.Count)
2713 throw new ArgumentOutOfRangeException ("index");
2714 return (int) list [index];
2718 bool ICollection.IsSynchronized {
2719 get { return list.IsSynchronized; }
2722 object ICollection.SyncRoot {
2723 get { return this; }
2726 bool IList.IsFixedSize {
2727 get { return true; }
2730 object IList.this [int index] {
2731 get { return this [index]; }
2732 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2734 #endregion // Public Properties
2736 #region Public Methods
2737 public bool Contains (int selectedIndex)
2739 return list.Contains (selectedIndex);
2742 public void CopyTo (Array dest, int index)
2744 list.CopyTo (dest, index);
2747 public IEnumerator GetEnumerator ()
2749 return list.GetEnumerator ();
2752 int IList.Add (object value)
2754 throw new NotSupportedException ("Add operation is not supported.");
2759 throw new NotSupportedException ("Clear operation is not supported.");
2762 bool IList.Contains (object selectedIndex)
2764 return list.Contains (selectedIndex);
2767 int IList.IndexOf (object selectedIndex)
2769 return list.IndexOf (selectedIndex);
2772 void IList.Insert (int index, object value)
2774 throw new NotSupportedException ("Insert operation is not supported.");
2777 void IList.Remove (object value)
2779 throw new NotSupportedException ("Remove operation is not supported.");
2782 void IList.RemoveAt (int index)
2784 throw new NotSupportedException ("RemoveAt operation is not supported.");
2787 public int IndexOf (int selectedIndex)
2789 return list.IndexOf (selectedIndex);
2791 #endregion // Public Methods
2793 } // SelectedIndexCollection
2795 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2797 internal ArrayList list;
2798 private ListView owner;
2800 #region Public Constructor
2801 public SelectedListViewItemCollection (ListView owner)
2803 list = new ArrayList ();
2806 #endregion // Public Constructor
2808 #region Public Properties
2811 get { return list.Count; }
2814 public bool IsReadOnly {
2815 get { return true; }
2818 public ListViewItem this [int index] {
2820 if (index < 0 || index >= list.Count)
2821 throw new ArgumentOutOfRangeException ("index");
2822 return (ListViewItem) list [index];
2826 bool ICollection.IsSynchronized {
2827 get { return list.IsSynchronized; }
2830 object ICollection.SyncRoot {
2831 get { return this; }
2834 bool IList.IsFixedSize {
2835 get { return true; }
2838 object IList.this [int index] {
2839 get { return this [index]; }
2840 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2842 #endregion // Public Properties
2844 #region Public Methods
2845 public void Clear ()
2847 ArrayList copy = (ArrayList) list.Clone ();
2848 for (int i = 0; i < copy.Count; i++)
2849 ((ListViewItem) copy [i]).Selected = false;
2854 public bool Contains (ListViewItem item)
2856 return list.Contains (item);
2859 public void CopyTo (Array dest, int index)
2861 list.CopyTo (dest, index);
2864 public IEnumerator GetEnumerator ()
2866 return list.GetEnumerator ();
2869 int IList.Add (object value)
2871 throw new NotSupportedException ("Add operation is not supported.");
2874 bool IList.Contains (object item)
2876 return list.Contains (item);
2879 int IList.IndexOf (object item)
2881 return list.IndexOf (item);
2884 void IList.Insert (int index, object value)
2886 throw new NotSupportedException ("Insert operation is not supported.");
2889 void IList.Remove (object value)
2891 throw new NotSupportedException ("Remove operation is not supported.");
2894 void IList.RemoveAt (int index)
2896 throw new NotSupportedException ("RemoveAt operation is not supported.");
2899 public int IndexOf (ListViewItem item)
2901 return list.IndexOf (item);
2903 #endregion // Public Methods
2905 } // SelectedListViewItemCollection
2907 #endregion // Subclasses