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);
169 GotFocus += new EventHandler (FocusChanged);
170 LostFocus += new EventHandler (FocusChanged);
172 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
174 #endregion // Public Constructors
176 #region Private Internal Properties
177 internal Size CheckBoxSize {
179 if (this.check_boxes) {
180 if (this.state_image_list != null)
181 return this.state_image_list.ImageSize;
183 return ThemeEngine.Current.ListViewCheckBoxSize;
191 bool CanMultiselect {
195 else if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
202 #endregion // Private Internal Properties
204 #region Protected Properties
205 protected override CreateParams CreateParams {
206 get { return base.CreateParams; }
209 protected override Size DefaultSize {
210 get { return ThemeEngine.Current.ListViewDefaultSize; }
212 #endregion // Protected Properties
214 #region Public Instance Properties
215 [DefaultValue (ItemActivation.Standard)]
216 public ItemActivation Activation {
217 get { return activation; }
219 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
220 value != ItemActivation.TwoClick) {
221 throw new InvalidEnumArgumentException (string.Format
222 ("Enum argument value '{0}' is not valid for Activation", value));
229 [DefaultValue (ListViewAlignment.Top)]
231 public ListViewAlignment Alignment {
232 get { return alignment; }
234 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
235 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
236 throw new InvalidEnumArgumentException (string.Format
237 ("Enum argument value '{0}' is not valid for Alignment", value));
240 if (this.alignment != value) {
242 // alignment does not matter in Details/List views
243 if (this.view == View.LargeIcon ||
244 this.View == View.SmallIcon)
250 [DefaultValue (false)]
251 public bool AllowColumnReorder {
252 get { return allow_column_reorder; }
253 set { allow_column_reorder = value; }
256 [DefaultValue (true)]
257 public bool AutoArrange {
258 get { return auto_arrange; }
260 if (auto_arrange != value) {
261 auto_arrange = value;
262 // autoarrange does not matter in Details/List views
263 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
269 public override Color BackColor {
271 if (background_color.IsEmpty)
272 return ThemeEngine.Current.ColorWindow;
274 return background_color;
276 set { background_color = value; }
280 [EditorBrowsable (EditorBrowsableState.Never)]
281 public override Image BackgroundImage {
282 get { return background_image; }
284 if (value == background_image)
287 background_image = value;
288 OnBackgroundImageChanged (EventArgs.Empty);
292 [DefaultValue (BorderStyle.Fixed3D)]
294 public BorderStyle BorderStyle {
295 get { return InternalBorderStyle; }
296 set { InternalBorderStyle = value; }
299 [DefaultValue (false)]
300 public bool CheckBoxes {
301 get { return check_boxes; }
303 if (check_boxes != value) {
311 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
312 public CheckedIndexCollection CheckedIndices {
313 get { return checked_indices; }
317 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
318 public CheckedListViewItemCollection CheckedItems {
319 get { return checked_items; }
322 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
324 [MergableProperty (false)]
325 public ColumnHeaderCollection Columns {
326 get { return columns; }
330 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
331 public ListViewItem FocusedItem {
337 public override Color ForeColor {
339 if (foreground_color.IsEmpty)
340 return ThemeEngine.Current.ColorWindowText;
342 return foreground_color;
344 set { foreground_color = value; }
347 [DefaultValue (false)]
348 public bool FullRowSelect {
349 get { return full_row_select; }
350 set { full_row_select = value; }
353 [DefaultValue (false)]
354 public bool GridLines {
355 get { return grid_lines; }
357 if (grid_lines != value) {
364 [DefaultValue (ColumnHeaderStyle.Clickable)]
365 public ColumnHeaderStyle HeaderStyle {
366 get { return header_style; }
368 if (header_style == value)
372 case ColumnHeaderStyle.Clickable:
373 case ColumnHeaderStyle.Nonclickable:
374 case ColumnHeaderStyle.None:
377 throw new InvalidEnumArgumentException (string.Format
378 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
381 header_style = value;
382 if (view == View.Details)
387 [DefaultValue (true)]
388 public bool HideSelection {
389 get { return hide_selection; }
391 if (hide_selection != value) {
392 hide_selection = value;
398 [DefaultValue (false)]
399 public bool HoverSelection {
400 get { return hover_selection; }
401 set { hover_selection = value; }
404 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
406 [MergableProperty (false)]
407 public ListViewItemCollection Items {
408 get { return items; }
411 [DefaultValue (false)]
412 public bool LabelEdit {
413 get { return label_edit; }
414 set { label_edit = value; }
417 [DefaultValue (true)]
419 public bool LabelWrap {
420 get { return label_wrap; }
422 if (label_wrap != value) {
429 [DefaultValue (null)]
430 public ImageList LargeImageList {
431 get { return large_image_list; }
433 large_image_list = value;
439 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440 public IComparer ListViewItemSorter {
441 get { return item_sorter; }
442 set { item_sorter = value; }
445 [DefaultValue (true)]
446 public bool MultiSelect {
447 get { return multiselect; }
448 set { multiselect = value; }
451 [DefaultValue (true)]
452 public bool Scrollable {
453 get { return scrollable; }
455 if (scrollable != value) {
463 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
464 public SelectedIndexCollection SelectedIndices {
465 get { return selected_indices; }
469 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
470 public SelectedListViewItemCollection SelectedItems {
471 get { return selected_items; }
475 [MonoTODO("Implement")]
476 public bool ShowGroups {
486 [DefaultValue (null)]
487 public ImageList SmallImageList {
488 get { return small_image_list; }
490 small_image_list = value;
495 [DefaultValue (SortOrder.None)]
496 public SortOrder Sorting {
497 get { return sort_order; }
499 if (value != SortOrder.Ascending && value != SortOrder.Descending &&
500 value != SortOrder.None) {
501 throw new InvalidEnumArgumentException (string.Format
502 ("Enum argument value '{0}' is not valid for Sorting", value));
505 if (sort_order != value) {
512 [DefaultValue (null)]
513 public ImageList StateImageList {
514 get { return state_image_list; }
516 state_image_list = value;
523 [EditorBrowsable (EditorBrowsableState.Never)]
524 public override string Text {
533 OnTextChanged (EventArgs.Empty);
538 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
539 public ListViewItem TopItem {
542 if (this.items.Count == 0)
544 // if contents are not scrolled
545 // it is the first item
546 else if (h_marker == 0 && v_marker == 0)
547 return this.items [0];
548 // do a hit test for the scrolled position
550 foreach (ListViewItem item in this.items) {
551 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
560 [MonoTODO("Implement")]
561 public bool UseCompatibleStateImageBehavior {
571 [DefaultValue (View.LargeIcon)]
575 if (value != View.Details && value != View.LargeIcon &&
576 value != View.List && value != View.SmallIcon ) {
577 throw new InvalidEnumArgumentException (string.Format
578 ("Enum argument value '{0}' is not valid for View", value));
582 h_scroll.Value = v_scroll.Value = 0;
588 #endregion // Public Instance Properties
590 #region Internal Methods Properties
592 internal int FirstVisibleIndex {
595 if (this.items.Count == 0)
598 if (h_marker == 0 && v_marker == 0)
601 foreach (ListViewItem item in this.items) {
602 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
611 internal int LastVisibleIndex {
613 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
614 if (View == View.List || Alignment == ListViewAlignment.Left) {
615 if (Items[i].Bounds.X > ClientRectangle.Right)
618 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
623 return Items.Count - 1;
627 internal int TotalWidth {
628 get { return Math.Max (this.Width, this.layout_wd); }
631 internal int TotalHeight {
632 get { return Math.Max (this.Height, this.layout_ht); }
635 internal void Redraw (bool recalculate)
637 // Avoid calculations when control is being updated
642 CalculateListView (this.alignment);
647 internal Size GetChildColumnSize (int index)
649 Size ret_size = Size.Empty;
650 ColumnHeader col = this.columns [index];
652 if (col.Width == -2) { // autosize = max(items, columnheader)
653 Size size = Size.Ceiling (this.DeviceContext.MeasureString
654 (col.Text, this.Font));
655 ret_size = BiggestItem (index);
656 if (size.Width > ret_size.Width)
659 else { // -1 and all the values < -2 are put under one category
660 ret_size = BiggestItem (index);
661 // fall back to empty columns' width if no subitem is available for a column
662 if (ret_size.IsEmpty) {
663 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
664 if (col.Text.Length > 0)
665 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
666 (col.Text, this.Font)).Height;
668 ret_size.Height = this.Font.Height;
672 // adjust the size for icon and checkbox for 0th column
674 ret_size.Width += (this.CheckBoxSize.Width + 4);
675 if (this.small_image_list != null)
676 ret_size.Width += this.small_image_list.ImageSize.Width;
681 // Returns the size of biggest item text in a column.
682 private Size BiggestItem (int col)
684 Size temp = Size.Empty;
685 Size ret_size = Size.Empty;
687 // 0th column holds the item text, we check the size of
688 // the various subitems falling in that column and get
689 // the biggest one's size.
690 foreach (ListViewItem item in items) {
691 if (col >= item.SubItems.Count)
694 temp = Size.Ceiling (this.DeviceContext.MeasureString
695 (item.SubItems [col].Text, this.Font));
696 if (temp.Width > ret_size.Width)
700 // adjustment for space
701 if (!ret_size.IsEmpty)
707 // Sets the size of the biggest item text as per the view
708 private void CalcTextSize ()
710 // clear the old value
711 text_size = Size.Empty;
713 if (items.Count == 0)
716 text_size = BiggestItem (0);
718 if (view == View.LargeIcon && this.label_wrap) {
719 Size temp = Size.Empty;
720 if (this.check_boxes)
721 temp.Width += 2 * this.CheckBoxSize.Width;
722 if (large_image_list != null)
723 temp.Width += large_image_list.ImageSize.Width;
726 // wrapping is done for two lines only
727 if (text_size.Width > temp.Width) {
728 text_size.Width = temp.Width;
729 text_size.Height *= 2;
732 else if (view == View.List) {
733 // in list view max text shown in determined by the
734 // control width, even if scolling is enabled.
735 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
736 if (this.small_image_list != null)
737 max_wd -= this.small_image_list.ImageSize.Width;
739 if (text_size.Width > max_wd)
740 text_size.Width = max_wd;
743 // we do the default settings, if we have got 0's
744 if (text_size.Height <= 0)
745 text_size.Height = this.Font.Height;
746 if (text_size.Width <= 0)
747 text_size.Width = this.Width;
750 text_size.Width += 4;
751 text_size.Height += 2;
754 private void Scroll (ScrollBar scrollbar, int delta)
756 if (delta == 0 || !scrollbar.Visible)
760 if (scrollbar == h_scroll)
761 max = h_scroll.Maximum - item_control.Width;
763 max = v_scroll.Maximum - item_control.Height;
765 int val = scrollbar.Value + delta;
768 else if (val < scrollbar.Minimum)
769 val = scrollbar.Minimum;
770 scrollbar.Value = val;
773 private void CalculateScrollBars ()
775 Rectangle client_area = ClientRectangle;
777 if (!this.scrollable || this.items.Count <= 0) {
778 h_scroll.Visible = false;
779 v_scroll.Visible = false;
783 // making a scroll bar visible might make
784 // other scroll bar visible
785 if (layout_wd > client_area.Right) {
786 h_scroll.Visible = true;
787 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
788 v_scroll.Visible = true;
790 v_scroll.Visible = false;
791 } else if (layout_ht > client_area.Bottom) {
792 v_scroll.Visible = true;
793 if ((layout_wd + v_scroll.Width) > client_area.Right)
794 h_scroll.Visible = true;
796 h_scroll.Visible = false;
798 h_scroll.Visible = false;
799 v_scroll.Visible = false;
802 item_control.Height = ClientRectangle.Height - header_control.Height;
804 if (h_scroll.Visible) {
805 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
806 h_scroll.Minimum = 0;
808 // if v_scroll is visible, adjust the maximum of the
809 // h_scroll to account for the width of v_scroll
810 if (v_scroll.Visible) {
811 h_scroll.Maximum = layout_wd + v_scroll.Width;
812 h_scroll.Width = client_area.Width - v_scroll.Width;
815 h_scroll.Maximum = layout_wd;
816 h_scroll.Width = client_area.Width;
819 h_scroll.LargeChange = client_area.Width;
820 h_scroll.SmallChange = Font.Height;
821 item_control.Height -= h_scroll.Height;
824 if (header_control.Visible)
825 header_control.Width = ClientRectangle.Width;
826 item_control.Width = ClientRectangle.Width;
828 if (v_scroll.Visible) {
829 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
830 v_scroll.Minimum = 0;
832 // if h_scroll is visible, adjust the maximum of the
833 // v_scroll to account for the height of h_scroll
834 if (h_scroll.Visible) {
835 v_scroll.Maximum = layout_ht + h_scroll.Height;
836 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
838 v_scroll.Maximum = layout_ht;
839 v_scroll.Height = client_area.Height;
842 v_scroll.LargeChange = client_area.Height;
843 v_scroll.SmallChange = Font.Height;
844 if (header_control.Visible)
845 header_control.Width -= v_scroll.Width;
846 item_control.Width -= v_scroll.Width;
850 ColumnHeader GetReorderedColumn (int index)
852 if (reordered_column_indices == null)
853 return Columns [index];
855 return Columns [reordered_column_indices [index]];
858 void ReorderColumn (ColumnHeader col, int index)
860 if (reordered_column_indices == null) {
861 reordered_column_indices = new int [Columns.Count];
862 for (int i = 0; i < Columns.Count; i++)
863 reordered_column_indices [i] = i;
866 if (reordered_column_indices [index] == col.Index)
869 int[] curr = reordered_column_indices;
870 int[] result = new int [Columns.Count];
872 for (int i = 0; i < Columns.Count; i++) {
873 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
877 result [i] = col.Index;
879 result [i] = curr [curr_idx++];
882 reordered_column_indices = result;
884 header_control.Invalidate ();
885 item_control.Invalidate ();
888 Size LargeIconItemSize {
890 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
891 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
892 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
893 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
894 return new Size (w, h);
898 Size SmallIconItemSize {
900 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
901 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
902 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
903 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
904 return new Size (w, h);
910 ListViewItem[,] item_matrix;
912 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
914 header_control.Visible = false;
915 header_control.Size = Size.Empty;
916 item_control.Visible = true;
917 item_control.Location = Point.Empty;
919 if (items.Count == 0)
922 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
924 Rectangle area = ClientRectangle;
927 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
930 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
932 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
935 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
938 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
939 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
940 item_matrix = new ListViewItem [rows, cols];
943 foreach (ListViewItem item in items) {
944 int x = col * (sz.Width + x_spacing);
945 int y = row * (sz.Height + y_spacing);
946 item.Location = new Point (x, y);
950 item_matrix [row, col] = item;
964 item_control.Size = new Size (layout_wd, layout_ht);
969 if (header_style == ColumnHeaderStyle.None) {
970 header_control.Visible = false;
971 header_control.Size = Size.Empty;
976 for (int i = 0; i < Columns.Count; i++) {
977 ColumnHeader col = GetReorderedColumn (i);
980 col.CalcColumnHeader ();
984 if (x < ClientRectangle.Width)
985 x = ClientRectangle.Width;
987 header_control.Width = x;
988 header_control.Height = columns [0].Ht;
989 header_control.Visible = true;
992 void LayoutDetails ()
994 if (columns.Count == 0) {
995 header_control.Visible = false;
996 item_control.Visible = false;
1002 item_control.Visible = true;
1003 item_control.Location = new Point (0, header_control.Height);
1006 if (items.Count > 0) {
1007 foreach (ListViewItem item in items) {
1009 item.Location = new Point (0, y);
1010 y += item.Bounds.Height + 2;
1013 // some space for bottom gridline
1018 layout_wd = Math.Max (header_control.Width, item_control.Width);
1019 layout_ht = y + header_control.Height;
1022 private void CalculateListView (ListViewAlignment align)
1031 case View.SmallIcon:
1032 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1035 case View.LargeIcon:
1036 LayoutIcons (true, alignment == ListViewAlignment.Left,
1037 ThemeEngine.Current.ListViewHorizontalSpacing,
1038 ThemeEngine.Current.ListViewVerticalSpacing);
1042 LayoutIcons (false, true, 4, 2);
1046 CalculateScrollBars ();
1049 internal void UpdateSelection (ListViewItem item)
1051 if (item.Selected) {
1053 if (!CanMultiselect && SelectedItems.Count > 0) {
1054 SelectedItems.Clear ();
1055 SelectedIndices.list.Clear ();
1058 if (!SelectedItems.Contains (item)) {
1059 SelectedItems.list.Add (item);
1060 SelectedIndices.list.Add (item.Index);
1063 SelectedItems.list.Remove (item);
1064 SelectedIndices.list.Remove (item.Index);
1068 private bool KeySearchString (KeyEventArgs ke)
1070 int current_tickcnt = Environment.TickCount;
1071 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1072 keysearch_text = string.Empty;
1075 keysearch_text += (char) ke.KeyData;
1076 keysearch_tickcnt = current_tickcnt;
1078 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1081 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1082 CompareOptions.IgnoreCase)) {
1083 SetFocusedItem (Items [i]);
1084 items [i].Selected = true;
1088 i = (i + 1 < Items.Count) ? i+1 : 0;
1096 int GetAdjustedIndex (Keys key)
1100 if (View == View.Details) {
1102 result = FocusedItem.Index - 1;
1103 else if (key == Keys.Down) {
1104 result = FocusedItem.Index + 1;
1105 if (result == items.Count)
1111 int row = FocusedItem.row;
1112 int col = FocusedItem.col;
1118 return item_matrix [row, col - 1].Index;
1121 if (col == (cols - 1))
1123 while (item_matrix [row, col + 1] == null)
1125 return item_matrix [row, col + 1].Index;
1130 return item_matrix [row - 1, col].Index;
1133 if (row == (rows - 1) || row == Items.Count - 1)
1135 while (item_matrix [row + 1, col] == null)
1137 return item_matrix [row + 1, col].Index;
1144 ListViewItem selection_start;
1146 private bool SelectItems (ArrayList sel_items)
1148 bool changed = false;
1149 multiselecting = true;
1150 ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
1151 foreach (ListViewItem item in curr_items)
1152 if (!sel_items.Contains (item)) {
1153 item.Selected = false;
1156 foreach (ListViewItem item in sel_items)
1157 if (!item.Selected) {
1158 item.Selected = true;
1161 multiselecting = false;
1165 private void UpdateMultiSelection (int index)
1167 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1168 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1169 ListViewItem item = items [index];
1171 if (shift_pressed && selection_start != null) {
1172 ArrayList list = new ArrayList ();
1173 int start = Math.Min (selection_start.Index, index);
1174 int end = Math.Max (selection_start.Index, index);
1175 if (View == View.Details) {
1176 for (int i = start; i <= end; i++)
1177 list.Add (items [i]);
1179 int left = Math.Min (items [start].col, items [end].col);
1180 int right = Math.Max (items [start].col, items [end].col);
1181 int top = Math.Min (items [start].row, items [end].row);
1182 int bottom = Math.Max (items [start].row, items [end].row);
1183 foreach (ListViewItem curr in items)
1184 if (curr.row >= top && curr.row <= bottom &&
1185 curr.col >= left && curr.col <= right)
1188 if (SelectItems (list))
1189 OnSelectedIndexChanged (EventArgs.Empty);
1190 } else if (!ctrl_pressed) {
1191 SelectedItems.Clear ();
1192 SelectedIndices.list.Clear ();
1193 item.Selected = true;
1194 selection_start = item;
1195 OnSelectedIndexChanged (EventArgs.Empty);
1199 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1201 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1207 if (FocusedItem == null)
1208 SetFocusedItem (Items [0]);
1210 switch (ke.KeyCode) {
1213 index = Items.Count - 1;
1224 index = GetAdjustedIndex (ke.KeyCode);
1228 ke.Handled = KeySearchString (ke);
1236 UpdateMultiSelection (index);
1237 else if (!items [index].Selected) {
1238 items [index].Selected = true;
1239 OnSelectedIndexChanged (EventArgs.Empty);
1242 SetFocusedItem (items [index]);
1243 EnsureVisible (index);
1247 internal class ItemControl : Control {
1250 ListViewItem clicked_item;
1251 ListViewItem last_clicked_item;
1252 bool hover_processed = false;
1254 public ItemControl (ListView owner)
1257 DoubleClick += new EventHandler(ItemsDoubleClick);
1258 MouseDown += new MouseEventHandler(ItemsMouseDown);
1259 MouseMove += new MouseEventHandler(ItemsMouseMove);
1260 MouseHover += new EventHandler(ItemsMouseHover);
1261 MouseUp += new MouseEventHandler(ItemsMouseUp);
1262 MouseWheel += new MouseEventHandler(ItemsMouseWheel);
1265 void ItemsDoubleClick (object sender, EventArgs e)
1267 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1268 owner.ItemActivate (this, e);
1278 BoxSelect box_select_mode = BoxSelect.None;
1279 ArrayList prev_selection;
1280 Point box_select_start;
1282 Rectangle box_select_rect;
1283 internal Rectangle BoxSelectRectangle {
1284 get { return box_select_rect; }
1286 if (box_select_rect == value)
1289 InvalidateBoxSelectRect ();
1290 box_select_rect = value;
1291 InvalidateBoxSelectRect ();
1295 void InvalidateBoxSelectRect ()
1297 if (BoxSelectRectangle.Size.IsEmpty)
1300 Rectangle edge = BoxSelectRectangle;
1306 edge.Y = BoxSelectRectangle.Bottom - 1;
1308 edge.Y = BoxSelectRectangle.Y - 1;
1310 edge.Height = BoxSelectRectangle.Height + 2;
1312 edge.X = BoxSelectRectangle.Right - 1;
1316 private Rectangle CalculateBoxSelectRectangle (Point pt)
1318 int left = Math.Min (box_select_start.X, pt.X);
1319 int right = Math.Max (box_select_start.X, pt.X);
1320 int top = Math.Min (box_select_start.Y, pt.Y);
1321 int bottom = Math.Max (box_select_start.Y, pt.Y);
1322 return Rectangle.FromLTRB (left, top, right, bottom);
1325 ArrayList BoxSelectedItems {
1327 ArrayList result = new ArrayList ();
1328 foreach (ListViewItem item in owner.Items) {
1329 Rectangle r = item.Bounds;
1331 r.Y += r.Height / 4;
1334 if (BoxSelectRectangle.IntersectsWith (r))
1341 private bool PerformBoxSelection (Point pt)
1343 if (box_select_mode == BoxSelect.None)
1346 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1348 ArrayList box_items = BoxSelectedItems;
1352 switch (box_select_mode) {
1354 case BoxSelect.Normal:
1358 case BoxSelect.Control:
1359 items = new ArrayList ();
1360 foreach (ListViewItem item in prev_selection)
1361 if (!box_items.Contains (item))
1363 foreach (ListViewItem item in box_items)
1364 if (!prev_selection.Contains (item))
1368 case BoxSelect.Shift:
1370 foreach (ListViewItem item in box_items)
1371 prev_selection.Remove (item);
1372 foreach (ListViewItem item in prev_selection)
1377 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1381 owner.SelectItems (items);
1387 private void ItemsMouseDown (object sender, MouseEventArgs me)
1389 if (owner.items.Count == 0)
1392 Point pt = new Point (me.X, me.Y);
1393 foreach (ListViewItem item in owner.items) {
1394 if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
1395 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1396 item.Checked = !item.Checked;
1398 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1400 // Raise the ItemCheck event
1401 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1402 owner.OnItemCheck (ice);
1406 if (owner.View == View.Details && !owner.FullRowSelect) {
1407 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1408 clicked_item = item;
1412 if (item.Bounds.Contains (pt)) {
1413 clicked_item = item;
1420 if (clicked_item != null) {
1421 owner.SetFocusedItem (clicked_item);
1422 bool changed = !clicked_item.Selected;
1423 if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
1424 owner.UpdateMultiSelection (clicked_item.Index);
1426 clicked_item.Selected = true;
1429 owner.OnSelectedIndexChanged (EventArgs.Empty);
1431 // Raise double click if the item was clicked. On MS the
1432 // double click is only raised if you double click an item
1433 if (me.Clicks > 1 && clicked_item != null)
1434 owner.OnDoubleClick (EventArgs.Empty);
1435 else if (me.Clicks == 1 && clicked_item != null)
1436 owner.OnClick (EventArgs.Empty);
1438 if (owner.MultiSelect) {
1439 Keys mods = XplatUI.State.ModifierKeys;
1440 if ((mods & Keys.Shift) != 0)
1441 box_select_mode = BoxSelect.Shift;
1442 else if ((mods & Keys.Control) != 0)
1443 box_select_mode = BoxSelect.Control;
1445 box_select_mode = BoxSelect.Normal;
1446 box_select_start = pt;
1447 prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
1448 } else if (owner.selected_indices.Count > 0) {
1449 owner.SelectedItems.Clear ();
1450 owner.SelectedIndices.list.Clear ();
1451 owner.OnSelectedIndexChanged (EventArgs.Empty);
1456 private void ItemsMouseMove (object sender, MouseEventArgs me)
1458 if (PerformBoxSelection (new Point (me.X, me.Y)))
1461 if (owner.HoverSelection && hover_processed) {
1463 Point pt = PointToClient (Control.MousePosition);
1464 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1465 if (item == null || item.Selected)
1468 hover_processed = false;
1469 XplatUI.ResetMouseHover (Handle);
1474 private void ItemsMouseHover (object sender, EventArgs e)
1476 if (Capture || !owner.HoverSelection)
1479 hover_processed = true;
1480 Point pt = PointToClient (Control.MousePosition);
1481 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1486 item.Selected = true;
1487 owner.OnSelectedIndexChanged (new EventArgs ());
1490 private void ItemsMouseUp (object sender, MouseEventArgs me)
1493 if (owner.Items.Count == 0)
1496 Point pt = new Point (me.X, me.Y);
1498 Rectangle rect = Rectangle.Empty;
1499 if (clicked_item != null) {
1500 if (owner.view == View.Details && !owner.full_row_select)
1501 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1503 rect = clicked_item.Bounds;
1505 if (rect.Contains (pt)) {
1506 switch (owner.activation) {
1507 case ItemActivation.OneClick:
1508 owner.OnItemActivate (EventArgs.Empty);
1511 case ItemActivation.TwoClick:
1512 if (last_clicked_item == clicked_item) {
1513 owner.OnItemActivate (EventArgs.Empty);
1514 last_clicked_item = null;
1516 last_clicked_item = clicked_item;
1519 // DoubleClick activation is handled in another handler
1523 } else if (owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1524 // Need this to clean up background clicks
1525 owner.SelectedItems.Clear ();
1526 owner.SelectedIndices.list.Clear ();
1527 owner.OnSelectedIndexChanged (EventArgs.Empty);
1530 clicked_item = null;
1531 box_select_start = Point.Empty;
1532 BoxSelectRectangle = Rectangle.Empty;
1533 prev_selection = null;
1534 box_select_mode = BoxSelect.None;
1537 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1539 if (owner.Items.Count == 0)
1542 int lines = me.Delta / 120;
1547 switch (owner.View) {
1549 case View.SmallIcon:
1550 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1552 case View.LargeIcon:
1553 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1556 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1561 internal override void OnPaintInternal (PaintEventArgs pe)
1563 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1566 protected override void WndProc (ref Message m)
1568 switch ((Msg)m.Msg) {
1569 case Msg.WM_SETFOCUS:
1573 base.WndProc (ref m);
1579 internal override void OnPaintInternal (PaintEventArgs pe)
1584 CalculateScrollBars ();
1587 void FocusChanged (object o, EventArgs args)
1589 if (Items.Count == 0)
1592 if (FocusedItem == null)
1593 SetFocusedItem (Items [0]);
1595 item_control.Invalidate (FocusedItem.Bounds);
1598 private void ListView_SizeChanged (object sender, EventArgs e)
1600 CalculateListView (alignment);
1603 private void SetFocusedItem (ListViewItem item)
1605 if (focused_item != null)
1606 focused_item.Focused = false;
1609 item.Focused = true;
1611 focused_item = item;
1614 private void HorizontalScroller (object sender, EventArgs e)
1616 // Avoid unnecessary flickering, when button is
1617 // kept pressed at the end
1618 if (h_marker != h_scroll.Value) {
1620 int pixels = h_marker - h_scroll.Value;
1622 h_marker = h_scroll.Value;
1623 if (header_control.Visible)
1624 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1626 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1630 private void VerticalScroller (object sender, EventArgs e)
1632 // Avoid unnecessary flickering, when button is
1633 // kept pressed at the end
1634 if (v_marker != v_scroll.Value) {
1635 int pixels = v_marker - v_scroll.Value;
1636 Rectangle area = item_control.ClientRectangle;
1637 v_marker = v_scroll.Value;
1638 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1641 #endregion // Internal Methods Properties
1643 #region Protected Methods
1644 protected override void CreateHandle ()
1646 base.CreateHandle ();
1649 protected override void Dispose (bool disposing)
1652 h_scroll.Dispose ();
1653 v_scroll.Dispose ();
1655 large_image_list = null;
1656 small_image_list = null;
1657 state_image_list = null;
1660 base.Dispose (disposing);
1663 protected override bool IsInputKey (Keys keyData)
1680 return base.IsInputKey (keyData);
1683 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1685 if (AfterLabelEdit != null)
1686 AfterLabelEdit (this, e);
1689 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1691 if (BeforeLabelEdit != null)
1692 BeforeLabelEdit (this, e);
1695 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1697 if (ColumnClick != null)
1698 ColumnClick (this, e);
1701 protected override void OnEnabledChanged (EventArgs e)
1703 base.OnEnabledChanged (e);
1706 protected override void OnFontChanged (EventArgs e)
1708 base.OnFontChanged (e);
1712 protected override void OnHandleCreated (EventArgs e)
1714 base.OnHandleCreated (e);
1717 protected override void OnHandleDestroyed (EventArgs e)
1719 base.OnHandleDestroyed (e);
1722 protected virtual void OnItemActivate (EventArgs e)
1724 if (ItemActivate != null)
1725 ItemActivate (this, e);
1728 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1730 if (ItemCheck != null)
1731 ItemCheck (this, ice);
1734 protected virtual void OnItemDrag (ItemDragEventArgs e)
1736 if (ItemDrag != null)
1740 protected virtual void OnSelectedIndexChanged (EventArgs e)
1742 if (SelectedIndexChanged != null)
1743 SelectedIndexChanged (this, e);
1746 protected override void OnSystemColorsChanged (EventArgs e)
1748 base.OnSystemColorsChanged (e);
1751 protected void RealizeProperties ()
1756 protected void UpdateExtendedStyles ()
1761 protected override void WndProc (ref Message m)
1763 base.WndProc (ref m);
1765 #endregion // Protected Methods
1767 #region Public Instance Methods
1768 public void ArrangeIcons ()
1770 ArrangeIcons (this.alignment);
1773 public void ArrangeIcons (ListViewAlignment alignment)
1775 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1776 if (view == View.LargeIcon || view == View.SmallIcon) {
1777 this.CalculateListView (alignment);
1778 // we have done the calculations already
1779 this.Redraw (false);
1783 public void BeginUpdate ()
1785 // flag to avoid painting
1789 public void Clear ()
1792 items.Clear (); // Redraw (true) called here
1795 public void EndUpdate ()
1797 // flag to avoid painting
1800 // probably, now we need a redraw with recalculations
1804 public void EnsureVisible (int index)
1806 if (index < 0 || index >= items.Count || scrollable == false)
1809 Rectangle view_rect = item_control.ClientRectangle;
1810 Rectangle bounds = items [index].Bounds;
1812 if (view_rect.Contains (bounds))
1815 if (bounds.Left < 0)
1816 h_scroll.Value += bounds.Left;
1817 else if (bounds.Right > view_rect.Right)
1818 h_scroll.Value += (bounds.Right - view_rect.Right);
1821 v_scroll.Value += bounds.Top;
1822 else if (bounds.Bottom > view_rect.Bottom)
1823 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1826 public ListViewItem GetItemAt (int x, int y)
1828 foreach (ListViewItem item in items) {
1829 if (item.Bounds.Contains (x, y))
1835 public Rectangle GetItemRect (int index)
1837 return GetItemRect (index, ItemBoundsPortion.Entire);
1840 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1842 if (index < 0 || index >= items.Count)
1843 throw new IndexOutOfRangeException ("index");
1845 return items [index].GetBounds (portion);
1850 if (sort_order != SortOrder.None)
1851 items.list.Sort (item_sorter);
1853 if (sort_order == SortOrder.Descending)
1854 items.list.Reverse ();
1859 public override string ToString ()
1861 int count = this.Items.Count;
1864 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1866 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1868 #endregion // Public Instance Methods
1873 class HeaderControl : Control {
1876 bool column_resize_active = false;
1877 ColumnHeader resize_column;
1878 ColumnHeader clicked_column;
1879 ColumnHeader drag_column;
1881 int drag_to_index = -1;
1883 public HeaderControl (ListView owner)
1886 MouseDown += new MouseEventHandler (HeaderMouseDown);
1887 MouseMove += new MouseEventHandler (HeaderMouseMove);
1888 MouseUp += new MouseEventHandler (HeaderMouseUp);
1891 private ColumnHeader ColumnAtX (int x)
1893 Point pt = new Point (x, 0);
1894 ColumnHeader result = null;
1895 foreach (ColumnHeader col in owner.Columns) {
1896 if (col.Rect.Contains (pt)) {
1904 private int GetReorderedIndex (ColumnHeader col)
1906 if (owner.reordered_column_indices == null)
1909 for (int i = 0; i < owner.Columns.Count; i++)
1910 if (owner.reordered_column_indices [i] == col.Index)
1912 throw new Exception ("Column index missing from reordered array");
1915 private void HeaderMouseDown (object sender, MouseEventArgs me)
1917 if (resize_column != null) {
1918 column_resize_active = true;
1923 clicked_column = ColumnAtX (me.X + owner.h_marker);
1925 if (clicked_column != null) {
1927 if (owner.AllowColumnReorder) {
1929 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1930 drag_column.column_rect = clicked_column.Rect;
1931 drag_to_index = GetReorderedIndex (clicked_column);
1933 clicked_column.pressed = true;
1934 Rectangle bounds = clicked_column.Rect;
1935 bounds.X -= owner.h_marker;
1936 Invalidate (bounds);
1941 private void HeaderMouseMove (object sender, MouseEventArgs me)
1943 Point pt = new Point (me.X + owner.h_marker, me.Y);
1945 if (column_resize_active) {
1946 resize_column.Width = pt.X - resize_column.X;
1947 if (resize_column.Width < 0)
1948 resize_column.Width = 0;
1952 resize_column = null;
1954 if (clicked_column != null) {
1955 if (owner.AllowColumnReorder) {
1958 r = drag_column.column_rect;
1959 r.X = clicked_column.Rect.X + me.X - drag_x;
1960 drag_column.column_rect = r;
1962 int x = me.X + owner.h_marker;
1963 ColumnHeader over = ColumnAtX (x);
1965 drag_to_index = owner.Columns.Count;
1966 else if (x < over.X + over.Width / 2)
1967 drag_to_index = GetReorderedIndex (over);
1969 drag_to_index = GetReorderedIndex (over) + 1;
1972 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1973 bool pressed = clicked_column.pressed;
1974 clicked_column.pressed = over == clicked_column;
1975 if (clicked_column.pressed ^ pressed) {
1976 Rectangle bounds = clicked_column.Rect;
1977 bounds.X -= owner.h_marker;
1978 Invalidate (bounds);
1984 for (int i = 0; i < owner.Columns.Count; i++) {
1985 Rectangle zone = owner.Columns [i].Rect;
1986 zone.X = zone.Right - 5;
1988 if (zone.Contains (pt)) {
1989 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
1991 resize_column = owner.Columns [i];
1996 if (resize_column == null)
1997 Cursor = Cursors.Default;
1999 Cursor = Cursors.VSplit;
2002 void HeaderMouseUp (object sender, MouseEventArgs me)
2006 if (column_resize_active) {
2007 column_resize_active = false;
2008 resize_column = null;
2009 Cursor = Cursors.Default;
2013 if (clicked_column != null && clicked_column.pressed) {
2014 clicked_column.pressed = false;
2015 Rectangle bounds = clicked_column.Rect;
2016 bounds.X -= owner.h_marker;
2017 Invalidate (bounds);
2018 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2021 if (drag_column != null && owner.AllowColumnReorder) {
2023 if (drag_to_index > GetReorderedIndex (clicked_column))
2025 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2026 owner.ReorderColumn (clicked_column, drag_to_index);
2031 clicked_column = null;
2034 internal override void OnPaintInternal (PaintEventArgs pe)
2039 Theme theme = ThemeEngine.Current;
2040 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2042 if (drag_column == null)
2046 if (drag_to_index == owner.Columns.Count)
2047 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2049 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2050 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2053 protected override void WndProc (ref Message m)
2055 switch ((Msg)m.Msg) {
2056 case Msg.WM_SETFOCUS:
2060 base.WndProc (ref m);
2066 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2068 internal ArrayList list;
2069 private ListView owner;
2071 #region Public Constructor
2072 public CheckedIndexCollection (ListView owner)
2074 list = new ArrayList ();
2077 #endregion // Public Constructor
2079 #region Public Properties
2082 get { return list.Count; }
2085 public bool IsReadOnly {
2086 get { return true; }
2089 public int this [int index] {
2091 if (index < 0 || index >= list.Count)
2092 throw new ArgumentOutOfRangeException ("index");
2093 return (int) list [index];
2097 bool ICollection.IsSynchronized {
2098 get { return false; }
2101 object ICollection.SyncRoot {
2102 get { return this; }
2105 bool IList.IsFixedSize {
2106 get { return true; }
2109 object IList.this [int index] {
2110 get { return this [index]; }
2111 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2113 #endregion // Public Properties
2115 #region Public Methods
2116 public bool Contains (int checkedIndex)
2118 return list.Contains (checkedIndex);
2121 public IEnumerator GetEnumerator ()
2123 return list.GetEnumerator ();
2126 void ICollection.CopyTo (Array dest, int index)
2128 list.CopyTo (dest, index);
2131 int IList.Add (object value)
2133 throw new NotSupportedException ("Add operation is not supported.");
2138 throw new NotSupportedException ("Clear operation is not supported.");
2141 bool IList.Contains (object checkedIndex)
2143 return list.Contains (checkedIndex);
2146 int IList.IndexOf (object checkedIndex)
2148 return list.IndexOf (checkedIndex);
2151 void IList.Insert (int index, object value)
2153 throw new NotSupportedException ("Insert operation is not supported.");
2156 void IList.Remove (object value)
2158 throw new NotSupportedException ("Remove operation is not supported.");
2161 void IList.RemoveAt (int index)
2163 throw new NotSupportedException ("RemoveAt operation is not supported.");
2166 public int IndexOf (int checkedIndex)
2168 return list.IndexOf (checkedIndex);
2170 #endregion // Public Methods
2172 } // CheckedIndexCollection
2174 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2176 internal ArrayList list;
2177 private ListView owner;
2179 #region Public Constructor
2180 public CheckedListViewItemCollection (ListView owner)
2182 list = new ArrayList ();
2185 #endregion // Public Constructor
2187 #region Public Properties
2190 get { return list.Count; }
2193 public bool IsReadOnly {
2194 get { return true; }
2197 public ListViewItem this [int index] {
2199 if (index < 0 || index >= list.Count)
2200 throw new ArgumentOutOfRangeException ("index");
2201 return (ListViewItem) list [index];
2205 bool ICollection.IsSynchronized {
2206 get { return list.IsSynchronized; }
2209 object ICollection.SyncRoot {
2210 get { return this; }
2213 bool IList.IsFixedSize {
2214 get { return true; }
2217 object IList.this [int index] {
2218 get { return this [index]; }
2219 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2221 #endregion // Public Properties
2223 #region Public Methods
2224 public bool Contains (ListViewItem item)
2226 return list.Contains (item);
2229 public void CopyTo (Array dest, int index)
2231 list.CopyTo (dest, index);
2234 public IEnumerator GetEnumerator ()
2236 return list.GetEnumerator ();
2239 int IList.Add (object value)
2241 throw new NotSupportedException ("Add operation is not supported.");
2246 throw new NotSupportedException ("Clear operation is not supported.");
2249 bool IList.Contains (object item)
2251 return list.Contains (item);
2254 int IList.IndexOf (object item)
2256 return list.IndexOf (item);
2259 void IList.Insert (int index, object value)
2261 throw new NotSupportedException ("Insert operation is not supported.");
2264 void IList.Remove (object value)
2266 throw new NotSupportedException ("Remove operation is not supported.");
2269 void IList.RemoveAt (int index)
2271 throw new NotSupportedException ("RemoveAt operation is not supported.");
2274 public int IndexOf (ListViewItem item)
2276 return list.IndexOf (item);
2278 #endregion // Public Methods
2280 } // CheckedListViewItemCollection
2282 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2284 internal ArrayList list;
2285 private ListView owner;
2287 #region Public Constructor
2288 public ColumnHeaderCollection (ListView owner)
2290 list = new ArrayList ();
2293 #endregion // Public Constructor
2295 #region Public Properties
2298 get { return list.Count; }
2301 public bool IsReadOnly {
2302 get { return false; }
2305 public virtual ColumnHeader this [int index] {
2307 if (index < 0 || index >= list.Count)
2308 throw new ArgumentOutOfRangeException ("index");
2309 return (ColumnHeader) list [index];
2313 bool ICollection.IsSynchronized {
2314 get { return true; }
2317 object ICollection.SyncRoot {
2318 get { return this; }
2321 bool IList.IsFixedSize {
2322 get { return list.IsFixedSize; }
2325 object IList.this [int index] {
2326 get { return this [index]; }
2327 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2329 #endregion // Public Properties
2331 #region Public Methods
2332 public virtual int Add (ColumnHeader value)
2335 value.owner = this.owner;
2336 idx = list.Add (value);
2337 if (owner.IsHandleCreated) {
2338 owner.Redraw (true);
2343 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2345 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2346 this.Add (colHeader);
2350 public virtual void AddRange (ColumnHeader [] values)
2352 foreach (ColumnHeader colHeader in values) {
2353 colHeader.owner = this.owner;
2357 owner.Redraw (true);
2360 public virtual void Clear ()
2363 owner.Redraw (true);
2366 public bool Contains (ColumnHeader value)
2368 return list.Contains (value);
2371 public IEnumerator GetEnumerator ()
2373 return list.GetEnumerator ();
2376 void ICollection.CopyTo (Array dest, int index)
2378 list.CopyTo (dest, index);
2381 int IList.Add (object value)
2383 if (! (value is ColumnHeader)) {
2384 throw new ArgumentException ("Not of type ColumnHeader", "value");
2387 return this.Add ((ColumnHeader) value);
2390 bool IList.Contains (object value)
2392 if (! (value is ColumnHeader)) {
2393 throw new ArgumentException ("Not of type ColumnHeader", "value");
2396 return this.Contains ((ColumnHeader) value);
2399 int IList.IndexOf (object value)
2401 if (! (value is ColumnHeader)) {
2402 throw new ArgumentException ("Not of type ColumnHeader", "value");
2405 return this.IndexOf ((ColumnHeader) value);
2408 void IList.Insert (int index, object value)
2410 if (! (value is ColumnHeader)) {
2411 throw new ArgumentException ("Not of type ColumnHeader", "value");
2414 this.Insert (index, (ColumnHeader) value);
2417 void IList.Remove (object value)
2419 if (! (value is ColumnHeader)) {
2420 throw new ArgumentException ("Not of type ColumnHeader", "value");
2423 this.Remove ((ColumnHeader) value);
2426 public int IndexOf (ColumnHeader value)
2428 return list.IndexOf (value);
2431 public void Insert (int index, ColumnHeader value)
2433 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2434 // but it's really only greater.
2435 if (index < 0 || index > list.Count)
2436 throw new ArgumentOutOfRangeException ("index");
2438 value.owner = this.owner;
2439 list.Insert (index, value);
2440 owner.Redraw (true);
2443 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2445 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2446 this.Insert (index, colHeader);
2449 public virtual void Remove (ColumnHeader column)
2451 // TODO: Update Column internal index ?
2452 list.Remove (column);
2453 owner.Redraw (true);
2456 public virtual void RemoveAt (int index)
2458 if (index < 0 || index >= list.Count)
2459 throw new ArgumentOutOfRangeException ("index");
2461 // TODO: Update Column internal index ?
2462 list.RemoveAt (index);
2463 owner.Redraw (true);
2465 #endregion // Public Methods
2468 } // ColumnHeaderCollection
2470 public class ListViewItemCollection : IList, ICollection, IEnumerable
2472 internal ArrayList list;
2473 private ListView owner;
2475 #region Public Constructor
2476 public ListViewItemCollection (ListView owner)
2478 list = new ArrayList ();
2481 #endregion // Public Constructor
2483 #region Public Properties
2486 get { return list.Count; }
2489 public bool IsReadOnly {
2490 get { return false; }
2493 public virtual ListViewItem this [int displayIndex] {
2495 if (displayIndex < 0 || displayIndex >= list.Count)
2496 throw new ArgumentOutOfRangeException ("displayIndex");
2497 return (ListViewItem) list [displayIndex];
2501 if (displayIndex < 0 || displayIndex >= list.Count)
2502 throw new ArgumentOutOfRangeException ("displayIndex");
2504 if (list.Contains (value))
2505 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2507 value.Owner = owner;
2508 list [displayIndex] = value;
2510 owner.Redraw (true);
2514 bool ICollection.IsSynchronized {
2515 get { return true; }
2518 object ICollection.SyncRoot {
2519 get { return this; }
2522 bool IList.IsFixedSize {
2523 get { return list.IsFixedSize; }
2526 object IList.this [int index] {
2527 get { return this [index]; }
2529 if (value is ListViewItem)
2530 this [index] = (ListViewItem) value;
2532 this [index] = new ListViewItem (value.ToString ());
2535 #endregion // Public Properties
2537 #region Public Methods
2538 public virtual ListViewItem Add (ListViewItem value)
2540 if (list.Contains (value))
2541 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2543 value.Owner = owner;
2546 if (owner.Sorting != SortOrder.None)
2549 owner.Redraw (true);
2554 public virtual ListViewItem Add (string text)
2556 ListViewItem item = new ListViewItem (text);
2557 return this.Add (item);
2560 public virtual ListViewItem Add (string text, int imageIndex)
2562 ListViewItem item = new ListViewItem (text, imageIndex);
2563 return this.Add (item);
2566 public void AddRange (ListViewItem [] values)
2569 owner.SelectedItems.list.Clear ();
2570 owner.SelectedIndices.list.Clear ();
2571 owner.CheckedItems.list.Clear ();
2572 owner.CheckedIndices.list.Clear ();
2574 foreach (ListViewItem item in values) {
2579 if (owner.Sorting != SortOrder.None)
2582 owner.Redraw (true);
2585 public virtual void Clear ()
2587 owner.SetFocusedItem (null);
2588 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2590 owner.SelectedItems.list.Clear ();
2591 owner.SelectedIndices.list.Clear ();
2592 owner.CheckedItems.list.Clear ();
2593 owner.CheckedIndices.list.Clear ();
2594 owner.Redraw (true);
2597 public bool Contains (ListViewItem item)
2599 return list.Contains (item);
2602 public void CopyTo (Array dest, int index)
2604 list.CopyTo (dest, index);
2607 public IEnumerator GetEnumerator ()
2609 return list.GetEnumerator ();
2612 int IList.Add (object item)
2617 if (item is ListViewItem) {
2618 li = (ListViewItem) item;
2619 if (list.Contains (li))
2620 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2623 li = new ListViewItem (item.ToString ());
2626 result = list.Add (li);
2627 owner.Redraw (true);
2632 bool IList.Contains (object item)
2634 return list.Contains (item);
2637 int IList.IndexOf (object item)
2639 return list.IndexOf (item);
2642 void IList.Insert (int index, object item)
2644 if (item is ListViewItem)
2645 this.Insert (index, (ListViewItem) item);
2647 this.Insert (index, item.ToString ());
2650 void IList.Remove (object item)
2652 Remove ((ListViewItem) item);
2655 public int IndexOf (ListViewItem item)
2657 return list.IndexOf (item);
2660 public ListViewItem Insert (int index, ListViewItem item)
2662 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2663 // but it's really only greater.
2664 if (index < 0 || index > list.Count)
2665 throw new ArgumentOutOfRangeException ("index");
2667 if (list.Contains (item))
2668 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2671 list.Insert (index, item);
2672 owner.Redraw (true);
2676 public ListViewItem Insert (int index, string text)
2678 return this.Insert (index, new ListViewItem (text));
2681 public ListViewItem Insert (int index, string text, int imageIndex)
2683 return this.Insert (index, new ListViewItem (text, imageIndex));
2686 public virtual void Remove (ListViewItem item)
2688 if (!list.Contains (item))
2691 owner.SelectedItems.list.Remove (item);
2692 owner.SelectedIndices.list.Remove (item.Index);
2693 owner.CheckedItems.list.Remove (item);
2694 owner.CheckedIndices.list.Remove (item.Index);
2696 owner.Redraw (true);
2699 public virtual void RemoveAt (int index)
2701 if (index < 0 || index >= list.Count)
2702 throw new ArgumentOutOfRangeException ("index");
2704 list.RemoveAt (index);
2705 owner.SelectedItems.list.RemoveAt (index);
2706 owner.SelectedIndices.list.RemoveAt (index);
2707 owner.CheckedItems.list.RemoveAt (index);
2708 owner.CheckedIndices.list.RemoveAt (index);
2709 owner.Redraw (false);
2711 #endregion // Public Methods
2713 } // ListViewItemCollection
2715 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2717 internal ArrayList list;
2718 private ListView owner;
2720 #region Public Constructor
2721 public SelectedIndexCollection (ListView owner)
2723 list = new ArrayList ();
2726 #endregion // Public Constructor
2728 #region Public Properties
2731 get { return list.Count; }
2734 public bool IsReadOnly {
2735 get { return true; }
2738 public int this [int index] {
2740 if (index < 0 || index >= list.Count)
2741 throw new ArgumentOutOfRangeException ("index");
2742 return (int) list [index];
2746 bool ICollection.IsSynchronized {
2747 get { return list.IsSynchronized; }
2750 object ICollection.SyncRoot {
2751 get { return this; }
2754 bool IList.IsFixedSize {
2755 get { return true; }
2758 object IList.this [int index] {
2759 get { return this [index]; }
2760 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2762 #endregion // Public Properties
2764 #region Public Methods
2765 public bool Contains (int selectedIndex)
2767 return list.Contains (selectedIndex);
2770 public void CopyTo (Array dest, int index)
2772 list.CopyTo (dest, index);
2775 public IEnumerator GetEnumerator ()
2777 return list.GetEnumerator ();
2780 int IList.Add (object value)
2782 throw new NotSupportedException ("Add operation is not supported.");
2787 throw new NotSupportedException ("Clear operation is not supported.");
2790 bool IList.Contains (object selectedIndex)
2792 return list.Contains (selectedIndex);
2795 int IList.IndexOf (object selectedIndex)
2797 return list.IndexOf (selectedIndex);
2800 void IList.Insert (int index, object value)
2802 throw new NotSupportedException ("Insert operation is not supported.");
2805 void IList.Remove (object value)
2807 throw new NotSupportedException ("Remove operation is not supported.");
2810 void IList.RemoveAt (int index)
2812 throw new NotSupportedException ("RemoveAt operation is not supported.");
2815 public int IndexOf (int selectedIndex)
2817 return list.IndexOf (selectedIndex);
2819 #endregion // Public Methods
2821 } // SelectedIndexCollection
2823 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2825 internal ArrayList list;
2826 private ListView owner;
2828 #region Public Constructor
2829 public SelectedListViewItemCollection (ListView owner)
2831 list = new ArrayList ();
2834 #endregion // Public Constructor
2836 #region Public Properties
2839 get { return list.Count; }
2842 public bool IsReadOnly {
2843 get { return true; }
2846 public ListViewItem this [int index] {
2848 if (index < 0 || index >= list.Count)
2849 throw new ArgumentOutOfRangeException ("index");
2850 return (ListViewItem) list [index];
2854 bool ICollection.IsSynchronized {
2855 get { return list.IsSynchronized; }
2858 object ICollection.SyncRoot {
2859 get { return this; }
2862 bool IList.IsFixedSize {
2863 get { return true; }
2866 object IList.this [int index] {
2867 get { return this [index]; }
2868 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2870 #endregion // Public Properties
2872 #region Public Methods
2873 public void Clear ()
2875 ArrayList copy = (ArrayList) list.Clone ();
2876 for (int i = 0; i < copy.Count; i++)
2877 ((ListViewItem) copy [i]).Selected = false;
2882 public bool Contains (ListViewItem item)
2884 return list.Contains (item);
2887 public void CopyTo (Array dest, int index)
2889 list.CopyTo (dest, index);
2892 public IEnumerator GetEnumerator ()
2894 return list.GetEnumerator ();
2897 int IList.Add (object value)
2899 throw new NotSupportedException ("Add operation is not supported.");
2902 bool IList.Contains (object item)
2904 return list.Contains (item);
2907 int IList.IndexOf (object item)
2909 return list.IndexOf (item);
2912 void IList.Insert (int index, object value)
2914 throw new NotSupportedException ("Insert operation is not supported.");
2917 void IList.Remove (object value)
2919 throw new NotSupportedException ("Remove operation is not supported.");
2922 void IList.RemoveAt (int index)
2924 throw new NotSupportedException ("RemoveAt operation is not supported.");
2927 public int IndexOf (ListViewItem item)
2929 return list.IndexOf (item);
2931 #endregion // Public Methods
2933 } // SelectedListViewItemCollection
2935 #endregion // Subclasses