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);
970 for (int i = 0; i < Columns.Count; i++) {
971 ColumnHeader col = GetReorderedColumn (i);
974 col.CalcColumnHeader ();
978 if (x < ClientRectangle.Width)
979 x = ClientRectangle.Width;
981 if (header_style == ColumnHeaderStyle.None) {
982 header_control.Visible = false;
983 header_control.Size = Size.Empty;
985 header_control.Width = x;
986 header_control.Height = columns [0].Ht;
987 header_control.Visible = true;
991 void LayoutDetails ()
993 if (columns.Count == 0) {
994 header_control.Visible = false;
995 item_control.Visible = false;
1001 item_control.Visible = true;
1002 item_control.Location = new Point (0, header_control.Height);
1005 if (items.Count > 0) {
1006 foreach (ListViewItem item in items) {
1008 item.Location = new Point (0, y);
1009 y += item.Bounds.Height + 2;
1012 // some space for bottom gridline
1017 layout_wd = Math.Max (header_control.Width, item_control.Width);
1018 layout_ht = y + header_control.Height;
1021 private void CalculateListView (ListViewAlignment align)
1030 case View.SmallIcon:
1031 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1034 case View.LargeIcon:
1035 LayoutIcons (true, alignment == ListViewAlignment.Left,
1036 ThemeEngine.Current.ListViewHorizontalSpacing,
1037 ThemeEngine.Current.ListViewVerticalSpacing);
1041 LayoutIcons (false, true, 4, 2);
1045 CalculateScrollBars ();
1048 internal void UpdateSelection (ListViewItem item)
1050 if (item.Selected) {
1052 if (!CanMultiselect && SelectedItems.Count > 0) {
1053 SelectedItems.Clear ();
1054 SelectedIndices.list.Clear ();
1057 if (!SelectedItems.Contains (item)) {
1058 SelectedItems.list.Add (item);
1059 SelectedIndices.list.Add (item.Index);
1062 SelectedItems.list.Remove (item);
1063 SelectedIndices.list.Remove (item.Index);
1067 private bool KeySearchString (KeyEventArgs ke)
1069 int current_tickcnt = Environment.TickCount;
1070 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1071 keysearch_text = string.Empty;
1074 keysearch_text += (char) ke.KeyData;
1075 keysearch_tickcnt = current_tickcnt;
1077 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1080 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1081 CompareOptions.IgnoreCase)) {
1082 SetFocusedItem (Items [i]);
1083 items [i].Selected = true;
1087 i = (i + 1 < Items.Count) ? i+1 : 0;
1095 int GetAdjustedIndex (Keys key)
1099 if (View == View.Details) {
1101 result = FocusedItem.Index - 1;
1102 else if (key == Keys.Down) {
1103 result = FocusedItem.Index + 1;
1104 if (result == items.Count)
1110 int row = FocusedItem.row;
1111 int col = FocusedItem.col;
1117 return item_matrix [row, col - 1].Index;
1120 if (col == (cols - 1))
1122 while (item_matrix [row, col + 1] == null)
1124 return item_matrix [row, col + 1].Index;
1129 return item_matrix [row - 1, col].Index;
1132 if (row == (rows - 1) || row == Items.Count - 1)
1134 while (item_matrix [row + 1, col] == null)
1136 return item_matrix [row + 1, col].Index;
1143 ListViewItem selection_start;
1145 private bool SelectItems (ArrayList sel_items)
1147 bool changed = false;
1148 multiselecting = true;
1149 ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
1150 foreach (ListViewItem item in curr_items)
1151 if (!sel_items.Contains (item)) {
1152 item.Selected = false;
1155 foreach (ListViewItem item in sel_items)
1156 if (!item.Selected) {
1157 item.Selected = true;
1160 multiselecting = false;
1164 private void UpdateMultiSelection (int index)
1166 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1167 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1168 ListViewItem item = items [index];
1170 if (shift_pressed && selection_start != null) {
1171 ArrayList list = new ArrayList ();
1172 int start = Math.Min (selection_start.Index, index);
1173 int end = Math.Max (selection_start.Index, index);
1174 if (View == View.Details) {
1175 for (int i = start; i <= end; i++)
1176 list.Add (items [i]);
1178 int left = Math.Min (items [start].col, items [end].col);
1179 int right = Math.Max (items [start].col, items [end].col);
1180 int top = Math.Min (items [start].row, items [end].row);
1181 int bottom = Math.Max (items [start].row, items [end].row);
1182 foreach (ListViewItem curr in items)
1183 if (curr.row >= top && curr.row <= bottom &&
1184 curr.col >= left && curr.col <= right)
1187 if (SelectItems (list))
1188 OnSelectedIndexChanged (EventArgs.Empty);
1189 } else if (!ctrl_pressed) {
1190 SelectedItems.Clear ();
1191 SelectedIndices.list.Clear ();
1192 item.Selected = true;
1193 selection_start = item;
1194 OnSelectedIndexChanged (EventArgs.Empty);
1198 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1200 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1206 if (FocusedItem == null)
1207 SetFocusedItem (Items [0]);
1209 switch (ke.KeyCode) {
1212 index = Items.Count - 1;
1223 index = GetAdjustedIndex (ke.KeyCode);
1227 ke.Handled = KeySearchString (ke);
1235 UpdateMultiSelection (index);
1236 else if (!items [index].Selected) {
1237 items [index].Selected = true;
1238 OnSelectedIndexChanged (EventArgs.Empty);
1241 SetFocusedItem (items [index]);
1242 EnsureVisible (index);
1246 internal class ItemControl : Control {
1249 ListViewItem clicked_item;
1250 ListViewItem last_clicked_item;
1251 bool hover_processed = false;
1252 bool checking = 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 ToggleCheckState (ListViewItem item)
1389 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1390 item.Checked = !item.Checked;
1391 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1393 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1394 owner.OnItemCheck (ice);
1397 private void ItemsMouseDown (object sender, MouseEventArgs me)
1399 if (owner.items.Count == 0)
1402 Point pt = new Point (me.X, me.Y);
1403 foreach (ListViewItem item in owner.items) {
1404 if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
1408 ToggleCheckState (item);
1412 if (owner.View == View.Details && !owner.FullRowSelect) {
1413 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1414 clicked_item = item;
1418 if (item.Bounds.Contains (pt)) {
1419 clicked_item = item;
1426 if (clicked_item != null) {
1427 owner.SetFocusedItem (clicked_item);
1428 bool changed = !clicked_item.Selected;
1429 if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
1430 owner.UpdateMultiSelection (clicked_item.Index);
1432 clicked_item.Selected = true;
1435 owner.OnSelectedIndexChanged (EventArgs.Empty);
1437 // Raise double click if the item was clicked. On MS the
1438 // double click is only raised if you double click an item
1439 if (me.Clicks > 1) {
1440 owner.OnDoubleClick (EventArgs.Empty);
1441 if (owner.CheckBoxes)
1442 ToggleCheckState (clicked_item);
1443 } else if (me.Clicks == 1)
1444 owner.OnClick (EventArgs.Empty);
1446 if (owner.MultiSelect) {
1447 Keys mods = XplatUI.State.ModifierKeys;
1448 if ((mods & Keys.Shift) != 0)
1449 box_select_mode = BoxSelect.Shift;
1450 else if ((mods & Keys.Control) != 0)
1451 box_select_mode = BoxSelect.Control;
1453 box_select_mode = BoxSelect.Normal;
1454 box_select_start = pt;
1455 prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
1456 } else if (owner.selected_indices.Count > 0) {
1457 owner.SelectedItems.Clear ();
1458 owner.SelectedIndices.list.Clear ();
1459 owner.OnSelectedIndexChanged (EventArgs.Empty);
1464 private void ItemsMouseMove (object sender, MouseEventArgs me)
1466 if (PerformBoxSelection (new Point (me.X, me.Y)))
1469 if (owner.HoverSelection && hover_processed) {
1471 Point pt = PointToClient (Control.MousePosition);
1472 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1473 if (item == null || item.Selected)
1476 hover_processed = false;
1477 XplatUI.ResetMouseHover (Handle);
1482 private void ItemsMouseHover (object sender, EventArgs e)
1484 if (Capture || !owner.HoverSelection)
1487 hover_processed = true;
1488 Point pt = PointToClient (Control.MousePosition);
1489 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1494 item.Selected = true;
1495 owner.OnSelectedIndexChanged (new EventArgs ());
1498 private void ItemsMouseUp (object sender, MouseEventArgs me)
1501 if (owner.Items.Count == 0)
1504 Point pt = new Point (me.X, me.Y);
1506 Rectangle rect = Rectangle.Empty;
1507 if (clicked_item != null) {
1508 if (owner.view == View.Details && !owner.full_row_select)
1509 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1511 rect = clicked_item.Bounds;
1513 if (rect.Contains (pt)) {
1514 switch (owner.activation) {
1515 case ItemActivation.OneClick:
1516 owner.OnItemActivate (EventArgs.Empty);
1519 case ItemActivation.TwoClick:
1520 if (last_clicked_item == clicked_item) {
1521 owner.OnItemActivate (EventArgs.Empty);
1522 last_clicked_item = null;
1524 last_clicked_item = clicked_item;
1527 // DoubleClick activation is handled in another handler
1531 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1532 // Need this to clean up background clicks
1533 owner.SelectedItems.Clear ();
1534 owner.SelectedIndices.list.Clear ();
1535 owner.OnSelectedIndexChanged (EventArgs.Empty);
1538 clicked_item = null;
1539 box_select_start = Point.Empty;
1540 BoxSelectRectangle = Rectangle.Empty;
1541 prev_selection = null;
1542 box_select_mode = BoxSelect.None;
1546 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1548 if (owner.Items.Count == 0)
1551 int lines = me.Delta / 120;
1556 switch (owner.View) {
1558 case View.SmallIcon:
1559 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1561 case View.LargeIcon:
1562 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1565 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1570 internal override void OnPaintInternal (PaintEventArgs pe)
1572 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1575 internal override void OnGotFocusInternal (EventArgs e)
1581 internal override void OnPaintInternal (PaintEventArgs pe)
1586 CalculateScrollBars ();
1589 void FocusChanged (object o, EventArgs args)
1591 if (Items.Count == 0)
1594 if (FocusedItem == null)
1595 SetFocusedItem (Items [0]);
1597 item_control.Invalidate (FocusedItem.Bounds);
1600 private void ListView_SizeChanged (object sender, EventArgs e)
1602 CalculateListView (alignment);
1605 private void SetFocusedItem (ListViewItem item)
1607 if (focused_item != null)
1608 focused_item.Focused = false;
1611 item.Focused = true;
1613 focused_item = item;
1616 private void HorizontalScroller (object sender, EventArgs e)
1618 // Avoid unnecessary flickering, when button is
1619 // kept pressed at the end
1620 if (h_marker != h_scroll.Value) {
1622 int pixels = h_marker - h_scroll.Value;
1624 h_marker = h_scroll.Value;
1625 if (header_control.Visible)
1626 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1628 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1632 private void VerticalScroller (object sender, EventArgs e)
1634 // Avoid unnecessary flickering, when button is
1635 // kept pressed at the end
1636 if (v_marker != v_scroll.Value) {
1637 int pixels = v_marker - v_scroll.Value;
1638 Rectangle area = item_control.ClientRectangle;
1639 v_marker = v_scroll.Value;
1640 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1643 #endregion // Internal Methods Properties
1645 #region Protected Methods
1646 protected override void CreateHandle ()
1648 base.CreateHandle ();
1651 protected override void Dispose (bool disposing)
1654 h_scroll.Dispose ();
1655 v_scroll.Dispose ();
1657 large_image_list = null;
1658 small_image_list = null;
1659 state_image_list = null;
1662 base.Dispose (disposing);
1665 protected override bool IsInputKey (Keys keyData)
1682 return base.IsInputKey (keyData);
1685 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1687 if (AfterLabelEdit != null)
1688 AfterLabelEdit (this, e);
1691 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1693 if (BeforeLabelEdit != null)
1694 BeforeLabelEdit (this, e);
1697 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1699 if (ColumnClick != null)
1700 ColumnClick (this, e);
1703 protected override void OnEnabledChanged (EventArgs e)
1705 base.OnEnabledChanged (e);
1708 protected override void OnFontChanged (EventArgs e)
1710 base.OnFontChanged (e);
1714 protected override void OnHandleCreated (EventArgs e)
1716 base.OnHandleCreated (e);
1719 protected override void OnHandleDestroyed (EventArgs e)
1721 base.OnHandleDestroyed (e);
1724 protected virtual void OnItemActivate (EventArgs e)
1726 if (ItemActivate != null)
1727 ItemActivate (this, e);
1730 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1732 if (ItemCheck != null)
1733 ItemCheck (this, ice);
1736 protected virtual void OnItemDrag (ItemDragEventArgs e)
1738 if (ItemDrag != null)
1742 protected virtual void OnSelectedIndexChanged (EventArgs e)
1744 if (SelectedIndexChanged != null)
1745 SelectedIndexChanged (this, e);
1748 protected override void OnSystemColorsChanged (EventArgs e)
1750 base.OnSystemColorsChanged (e);
1753 protected void RealizeProperties ()
1758 protected void UpdateExtendedStyles ()
1763 protected override void WndProc (ref Message m)
1765 base.WndProc (ref m);
1767 #endregion // Protected Methods
1769 #region Public Instance Methods
1770 public void ArrangeIcons ()
1772 ArrangeIcons (this.alignment);
1775 public void ArrangeIcons (ListViewAlignment alignment)
1777 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1778 if (view == View.LargeIcon || view == View.SmallIcon) {
1779 this.CalculateListView (alignment);
1780 // we have done the calculations already
1781 this.Redraw (false);
1785 public void BeginUpdate ()
1787 // flag to avoid painting
1791 public void Clear ()
1794 items.Clear (); // Redraw (true) called here
1797 public void EndUpdate ()
1799 // flag to avoid painting
1802 // probably, now we need a redraw with recalculations
1806 public void EnsureVisible (int index)
1808 if (index < 0 || index >= items.Count || scrollable == false)
1811 Rectangle view_rect = item_control.ClientRectangle;
1812 Rectangle bounds = items [index].Bounds;
1814 if (view_rect.Contains (bounds))
1817 if (bounds.Left < 0)
1818 h_scroll.Value += bounds.Left;
1819 else if (bounds.Right > view_rect.Right)
1820 h_scroll.Value += (bounds.Right - view_rect.Right);
1823 v_scroll.Value += bounds.Top;
1824 else if (bounds.Bottom > view_rect.Bottom)
1825 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1828 public ListViewItem GetItemAt (int x, int y)
1830 foreach (ListViewItem item in items) {
1831 if (item.Bounds.Contains (x, y))
1837 public Rectangle GetItemRect (int index)
1839 return GetItemRect (index, ItemBoundsPortion.Entire);
1842 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1844 if (index < 0 || index >= items.Count)
1845 throw new IndexOutOfRangeException ("index");
1847 return items [index].GetBounds (portion);
1852 if (sort_order != SortOrder.None)
1853 items.list.Sort (item_sorter);
1855 if (sort_order == SortOrder.Descending)
1856 items.list.Reverse ();
1861 public override string ToString ()
1863 int count = this.Items.Count;
1866 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1868 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1870 #endregion // Public Instance Methods
1875 class HeaderControl : Control {
1878 bool column_resize_active = false;
1879 ColumnHeader resize_column;
1880 ColumnHeader clicked_column;
1881 ColumnHeader drag_column;
1883 int drag_to_index = -1;
1885 public HeaderControl (ListView owner)
1888 MouseDown += new MouseEventHandler (HeaderMouseDown);
1889 MouseMove += new MouseEventHandler (HeaderMouseMove);
1890 MouseUp += new MouseEventHandler (HeaderMouseUp);
1893 private ColumnHeader ColumnAtX (int x)
1895 Point pt = new Point (x, 0);
1896 ColumnHeader result = null;
1897 foreach (ColumnHeader col in owner.Columns) {
1898 if (col.Rect.Contains (pt)) {
1906 private int GetReorderedIndex (ColumnHeader col)
1908 if (owner.reordered_column_indices == null)
1911 for (int i = 0; i < owner.Columns.Count; i++)
1912 if (owner.reordered_column_indices [i] == col.Index)
1914 throw new Exception ("Column index missing from reordered array");
1917 private void HeaderMouseDown (object sender, MouseEventArgs me)
1919 if (resize_column != null) {
1920 column_resize_active = true;
1925 clicked_column = ColumnAtX (me.X + owner.h_marker);
1927 if (clicked_column != null) {
1929 if (owner.AllowColumnReorder) {
1931 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1932 drag_column.column_rect = clicked_column.Rect;
1933 drag_to_index = GetReorderedIndex (clicked_column);
1935 clicked_column.pressed = true;
1936 Rectangle bounds = clicked_column.Rect;
1937 bounds.X -= owner.h_marker;
1938 Invalidate (bounds);
1943 private void HeaderMouseMove (object sender, MouseEventArgs me)
1945 Point pt = new Point (me.X + owner.h_marker, me.Y);
1947 if (column_resize_active) {
1948 resize_column.Width = pt.X - resize_column.X;
1949 if (resize_column.Width < 0)
1950 resize_column.Width = 0;
1954 resize_column = null;
1956 if (clicked_column != null) {
1957 if (owner.AllowColumnReorder) {
1960 r = drag_column.column_rect;
1961 r.X = clicked_column.Rect.X + me.X - drag_x;
1962 drag_column.column_rect = r;
1964 int x = me.X + owner.h_marker;
1965 ColumnHeader over = ColumnAtX (x);
1967 drag_to_index = owner.Columns.Count;
1968 else if (x < over.X + over.Width / 2)
1969 drag_to_index = GetReorderedIndex (over);
1971 drag_to_index = GetReorderedIndex (over) + 1;
1974 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1975 bool pressed = clicked_column.pressed;
1976 clicked_column.pressed = over == clicked_column;
1977 if (clicked_column.pressed ^ pressed) {
1978 Rectangle bounds = clicked_column.Rect;
1979 bounds.X -= owner.h_marker;
1980 Invalidate (bounds);
1986 for (int i = 0; i < owner.Columns.Count; i++) {
1987 Rectangle zone = owner.Columns [i].Rect;
1988 zone.X = zone.Right - 5;
1990 if (zone.Contains (pt)) {
1991 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
1993 resize_column = owner.Columns [i];
1998 if (resize_column == null)
1999 Cursor = Cursors.Default;
2001 Cursor = Cursors.VSplit;
2004 void HeaderMouseUp (object sender, MouseEventArgs me)
2008 if (column_resize_active) {
2009 column_resize_active = false;
2010 resize_column = null;
2011 Cursor = Cursors.Default;
2015 if (clicked_column != null && clicked_column.pressed) {
2016 clicked_column.pressed = false;
2017 Rectangle bounds = clicked_column.Rect;
2018 bounds.X -= owner.h_marker;
2019 Invalidate (bounds);
2020 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2023 if (drag_column != null && owner.AllowColumnReorder) {
2025 if (drag_to_index > GetReorderedIndex (clicked_column))
2027 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2028 owner.ReorderColumn (clicked_column, drag_to_index);
2033 clicked_column = null;
2036 internal override void OnPaintInternal (PaintEventArgs pe)
2041 Theme theme = ThemeEngine.Current;
2042 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2044 if (drag_column == null)
2048 if (drag_to_index == owner.Columns.Count)
2049 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2051 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2052 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2055 protected override void WndProc (ref Message m)
2057 switch ((Msg)m.Msg) {
2058 case Msg.WM_SETFOCUS:
2062 base.WndProc (ref m);
2068 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2070 internal ArrayList list;
2071 private ListView owner;
2073 #region Public Constructor
2074 public CheckedIndexCollection (ListView owner)
2076 list = new ArrayList ();
2079 #endregion // Public Constructor
2081 #region Public Properties
2084 get { return list.Count; }
2087 public bool IsReadOnly {
2088 get { return true; }
2091 public int this [int index] {
2093 if (index < 0 || index >= list.Count)
2094 throw new ArgumentOutOfRangeException ("index");
2095 return (int) list [index];
2099 bool ICollection.IsSynchronized {
2100 get { return false; }
2103 object ICollection.SyncRoot {
2104 get { return this; }
2107 bool IList.IsFixedSize {
2108 get { return true; }
2111 object IList.this [int index] {
2112 get { return this [index]; }
2113 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2115 #endregion // Public Properties
2117 #region Public Methods
2118 public bool Contains (int checkedIndex)
2120 return list.Contains (checkedIndex);
2123 public IEnumerator GetEnumerator ()
2125 return list.GetEnumerator ();
2128 void ICollection.CopyTo (Array dest, int index)
2130 list.CopyTo (dest, index);
2133 int IList.Add (object value)
2135 throw new NotSupportedException ("Add operation is not supported.");
2140 throw new NotSupportedException ("Clear operation is not supported.");
2143 bool IList.Contains (object checkedIndex)
2145 return list.Contains (checkedIndex);
2148 int IList.IndexOf (object checkedIndex)
2150 return list.IndexOf (checkedIndex);
2153 void IList.Insert (int index, object value)
2155 throw new NotSupportedException ("Insert operation is not supported.");
2158 void IList.Remove (object value)
2160 throw new NotSupportedException ("Remove operation is not supported.");
2163 void IList.RemoveAt (int index)
2165 throw new NotSupportedException ("RemoveAt operation is not supported.");
2168 public int IndexOf (int checkedIndex)
2170 return list.IndexOf (checkedIndex);
2172 #endregion // Public Methods
2174 } // CheckedIndexCollection
2176 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2178 internal ArrayList list;
2179 private ListView owner;
2181 #region Public Constructor
2182 public CheckedListViewItemCollection (ListView owner)
2184 list = new ArrayList ();
2187 #endregion // Public Constructor
2189 #region Public Properties
2192 get { return list.Count; }
2195 public bool IsReadOnly {
2196 get { return true; }
2199 public ListViewItem this [int index] {
2201 if (index < 0 || index >= list.Count)
2202 throw new ArgumentOutOfRangeException ("index");
2203 return (ListViewItem) list [index];
2207 bool ICollection.IsSynchronized {
2208 get { return list.IsSynchronized; }
2211 object ICollection.SyncRoot {
2212 get { return this; }
2215 bool IList.IsFixedSize {
2216 get { return true; }
2219 object IList.this [int index] {
2220 get { return this [index]; }
2221 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2223 #endregion // Public Properties
2225 #region Public Methods
2226 public bool Contains (ListViewItem item)
2228 return list.Contains (item);
2231 public void CopyTo (Array dest, int index)
2233 list.CopyTo (dest, index);
2236 public IEnumerator GetEnumerator ()
2238 return list.GetEnumerator ();
2241 int IList.Add (object value)
2243 throw new NotSupportedException ("Add operation is not supported.");
2248 throw new NotSupportedException ("Clear operation is not supported.");
2251 bool IList.Contains (object item)
2253 return list.Contains (item);
2256 int IList.IndexOf (object item)
2258 return list.IndexOf (item);
2261 void IList.Insert (int index, object value)
2263 throw new NotSupportedException ("Insert operation is not supported.");
2266 void IList.Remove (object value)
2268 throw new NotSupportedException ("Remove operation is not supported.");
2271 void IList.RemoveAt (int index)
2273 throw new NotSupportedException ("RemoveAt operation is not supported.");
2276 public int IndexOf (ListViewItem item)
2278 return list.IndexOf (item);
2280 #endregion // Public Methods
2282 } // CheckedListViewItemCollection
2284 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2286 internal ArrayList list;
2287 private ListView owner;
2289 #region Public Constructor
2290 public ColumnHeaderCollection (ListView owner)
2292 list = new ArrayList ();
2295 #endregion // Public Constructor
2297 #region Public Properties
2300 get { return list.Count; }
2303 public bool IsReadOnly {
2304 get { return false; }
2307 public virtual ColumnHeader this [int index] {
2309 if (index < 0 || index >= list.Count)
2310 throw new ArgumentOutOfRangeException ("index");
2311 return (ColumnHeader) list [index];
2315 bool ICollection.IsSynchronized {
2316 get { return true; }
2319 object ICollection.SyncRoot {
2320 get { return this; }
2323 bool IList.IsFixedSize {
2324 get { return list.IsFixedSize; }
2327 object IList.this [int index] {
2328 get { return this [index]; }
2329 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2331 #endregion // Public Properties
2333 #region Public Methods
2334 public virtual int Add (ColumnHeader value)
2337 value.owner = this.owner;
2338 idx = list.Add (value);
2339 if (owner.IsHandleCreated) {
2340 owner.Redraw (true);
2345 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2347 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2348 this.Add (colHeader);
2352 public virtual void AddRange (ColumnHeader [] values)
2354 foreach (ColumnHeader colHeader in values) {
2355 colHeader.owner = this.owner;
2359 owner.Redraw (true);
2362 public virtual void Clear ()
2365 owner.Redraw (true);
2368 public bool Contains (ColumnHeader value)
2370 return list.Contains (value);
2373 public IEnumerator GetEnumerator ()
2375 return list.GetEnumerator ();
2378 void ICollection.CopyTo (Array dest, int index)
2380 list.CopyTo (dest, index);
2383 int IList.Add (object value)
2385 if (! (value is ColumnHeader)) {
2386 throw new ArgumentException ("Not of type ColumnHeader", "value");
2389 return this.Add ((ColumnHeader) value);
2392 bool IList.Contains (object value)
2394 if (! (value is ColumnHeader)) {
2395 throw new ArgumentException ("Not of type ColumnHeader", "value");
2398 return this.Contains ((ColumnHeader) value);
2401 int IList.IndexOf (object value)
2403 if (! (value is ColumnHeader)) {
2404 throw new ArgumentException ("Not of type ColumnHeader", "value");
2407 return this.IndexOf ((ColumnHeader) value);
2410 void IList.Insert (int index, object value)
2412 if (! (value is ColumnHeader)) {
2413 throw new ArgumentException ("Not of type ColumnHeader", "value");
2416 this.Insert (index, (ColumnHeader) value);
2419 void IList.Remove (object value)
2421 if (! (value is ColumnHeader)) {
2422 throw new ArgumentException ("Not of type ColumnHeader", "value");
2425 this.Remove ((ColumnHeader) value);
2428 public int IndexOf (ColumnHeader value)
2430 return list.IndexOf (value);
2433 public void Insert (int index, ColumnHeader value)
2435 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2436 // but it's really only greater.
2437 if (index < 0 || index > list.Count)
2438 throw new ArgumentOutOfRangeException ("index");
2440 value.owner = this.owner;
2441 list.Insert (index, value);
2442 owner.Redraw (true);
2445 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2447 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2448 this.Insert (index, colHeader);
2451 public virtual void Remove (ColumnHeader column)
2453 // TODO: Update Column internal index ?
2454 list.Remove (column);
2455 owner.Redraw (true);
2458 public virtual void RemoveAt (int index)
2460 if (index < 0 || index >= list.Count)
2461 throw new ArgumentOutOfRangeException ("index");
2463 // TODO: Update Column internal index ?
2464 list.RemoveAt (index);
2465 owner.Redraw (true);
2467 #endregion // Public Methods
2470 } // ColumnHeaderCollection
2472 public class ListViewItemCollection : IList, ICollection, IEnumerable
2474 internal ArrayList list;
2475 private ListView owner;
2477 #region Public Constructor
2478 public ListViewItemCollection (ListView owner)
2480 list = new ArrayList ();
2483 #endregion // Public Constructor
2485 #region Public Properties
2488 get { return list.Count; }
2491 public bool IsReadOnly {
2492 get { return false; }
2495 public virtual ListViewItem this [int displayIndex] {
2497 if (displayIndex < 0 || displayIndex >= list.Count)
2498 throw new ArgumentOutOfRangeException ("displayIndex");
2499 return (ListViewItem) list [displayIndex];
2503 if (displayIndex < 0 || displayIndex >= list.Count)
2504 throw new ArgumentOutOfRangeException ("displayIndex");
2506 if (list.Contains (value))
2507 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2509 value.Owner = owner;
2510 list [displayIndex] = value;
2512 owner.Redraw (true);
2516 bool ICollection.IsSynchronized {
2517 get { return true; }
2520 object ICollection.SyncRoot {
2521 get { return this; }
2524 bool IList.IsFixedSize {
2525 get { return list.IsFixedSize; }
2528 object IList.this [int index] {
2529 get { return this [index]; }
2531 if (value is ListViewItem)
2532 this [index] = (ListViewItem) value;
2534 this [index] = new ListViewItem (value.ToString ());
2537 #endregion // Public Properties
2539 #region Public Methods
2540 public virtual ListViewItem Add (ListViewItem value)
2542 if (list.Contains (value))
2543 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2545 value.Owner = owner;
2548 if (owner.Sorting != SortOrder.None)
2551 owner.Redraw (true);
2556 public virtual ListViewItem Add (string text)
2558 ListViewItem item = new ListViewItem (text);
2559 return this.Add (item);
2562 public virtual ListViewItem Add (string text, int imageIndex)
2564 ListViewItem item = new ListViewItem (text, imageIndex);
2565 return this.Add (item);
2568 public void AddRange (ListViewItem [] values)
2571 owner.SelectedItems.list.Clear ();
2572 owner.SelectedIndices.list.Clear ();
2573 owner.CheckedItems.list.Clear ();
2574 owner.CheckedIndices.list.Clear ();
2576 foreach (ListViewItem item in values) {
2581 if (owner.Sorting != SortOrder.None)
2584 owner.Redraw (true);
2587 public virtual void Clear ()
2589 owner.SetFocusedItem (null);
2590 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2592 owner.SelectedItems.list.Clear ();
2593 owner.SelectedIndices.list.Clear ();
2594 owner.CheckedItems.list.Clear ();
2595 owner.CheckedIndices.list.Clear ();
2596 owner.Redraw (true);
2599 public bool Contains (ListViewItem item)
2601 return list.Contains (item);
2604 public void CopyTo (Array dest, int index)
2606 list.CopyTo (dest, index);
2609 public IEnumerator GetEnumerator ()
2611 return list.GetEnumerator ();
2614 int IList.Add (object item)
2619 if (item is ListViewItem) {
2620 li = (ListViewItem) item;
2621 if (list.Contains (li))
2622 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2625 li = new ListViewItem (item.ToString ());
2628 result = list.Add (li);
2629 owner.Redraw (true);
2634 bool IList.Contains (object item)
2636 return list.Contains (item);
2639 int IList.IndexOf (object item)
2641 return list.IndexOf (item);
2644 void IList.Insert (int index, object item)
2646 if (item is ListViewItem)
2647 this.Insert (index, (ListViewItem) item);
2649 this.Insert (index, item.ToString ());
2652 void IList.Remove (object item)
2654 Remove ((ListViewItem) item);
2657 public int IndexOf (ListViewItem item)
2659 return list.IndexOf (item);
2662 public ListViewItem Insert (int index, ListViewItem item)
2664 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2665 // but it's really only greater.
2666 if (index < 0 || index > list.Count)
2667 throw new ArgumentOutOfRangeException ("index");
2669 if (list.Contains (item))
2670 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2673 list.Insert (index, item);
2674 owner.Redraw (true);
2678 public ListViewItem Insert (int index, string text)
2680 return this.Insert (index, new ListViewItem (text));
2683 public ListViewItem Insert (int index, string text, int imageIndex)
2685 return this.Insert (index, new ListViewItem (text, imageIndex));
2688 public virtual void Remove (ListViewItem item)
2690 if (!list.Contains (item))
2693 owner.SelectedItems.list.Remove (item);
2694 owner.SelectedIndices.list.Remove (item.Index);
2695 owner.CheckedItems.list.Remove (item);
2696 owner.CheckedIndices.list.Remove (item.Index);
2698 owner.Redraw (true);
2701 public virtual void RemoveAt (int index)
2703 if (index < 0 || index >= list.Count)
2704 throw new ArgumentOutOfRangeException ("index");
2706 list.RemoveAt (index);
2707 owner.SelectedItems.list.RemoveAt (index);
2708 owner.SelectedIndices.list.RemoveAt (index);
2709 owner.CheckedItems.list.RemoveAt (index);
2710 owner.CheckedIndices.list.RemoveAt (index);
2711 owner.Redraw (false);
2713 #endregion // Public Methods
2715 } // ListViewItemCollection
2717 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2719 internal ArrayList list;
2720 private ListView owner;
2722 #region Public Constructor
2723 public SelectedIndexCollection (ListView owner)
2725 list = new ArrayList ();
2728 #endregion // Public Constructor
2730 #region Public Properties
2733 get { return list.Count; }
2736 public bool IsReadOnly {
2737 get { return true; }
2740 public int this [int index] {
2742 if (index < 0 || index >= list.Count)
2743 throw new ArgumentOutOfRangeException ("index");
2744 return (int) list [index];
2748 bool ICollection.IsSynchronized {
2749 get { return list.IsSynchronized; }
2752 object ICollection.SyncRoot {
2753 get { return this; }
2756 bool IList.IsFixedSize {
2757 get { return true; }
2760 object IList.this [int index] {
2761 get { return this [index]; }
2762 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2764 #endregion // Public Properties
2766 #region Public Methods
2767 public bool Contains (int selectedIndex)
2769 return list.Contains (selectedIndex);
2772 public void CopyTo (Array dest, int index)
2774 list.CopyTo (dest, index);
2777 public IEnumerator GetEnumerator ()
2779 return list.GetEnumerator ();
2782 int IList.Add (object value)
2784 throw new NotSupportedException ("Add operation is not supported.");
2789 throw new NotSupportedException ("Clear operation is not supported.");
2792 bool IList.Contains (object selectedIndex)
2794 return list.Contains (selectedIndex);
2797 int IList.IndexOf (object selectedIndex)
2799 return list.IndexOf (selectedIndex);
2802 void IList.Insert (int index, object value)
2804 throw new NotSupportedException ("Insert operation is not supported.");
2807 void IList.Remove (object value)
2809 throw new NotSupportedException ("Remove operation is not supported.");
2812 void IList.RemoveAt (int index)
2814 throw new NotSupportedException ("RemoveAt operation is not supported.");
2817 public int IndexOf (int selectedIndex)
2819 return list.IndexOf (selectedIndex);
2821 #endregion // Public Methods
2823 } // SelectedIndexCollection
2825 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2827 internal ArrayList list;
2828 private ListView owner;
2830 #region Public Constructor
2831 public SelectedListViewItemCollection (ListView owner)
2833 list = new ArrayList ();
2836 #endregion // Public Constructor
2838 #region Public Properties
2841 get { return list.Count; }
2844 public bool IsReadOnly {
2845 get { return true; }
2848 public ListViewItem this [int index] {
2850 if (index < 0 || index >= list.Count)
2851 throw new ArgumentOutOfRangeException ("index");
2852 return (ListViewItem) list [index];
2856 bool ICollection.IsSynchronized {
2857 get { return list.IsSynchronized; }
2860 object ICollection.SyncRoot {
2861 get { return this; }
2864 bool IList.IsFixedSize {
2865 get { return true; }
2868 object IList.this [int index] {
2869 get { return this [index]; }
2870 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2872 #endregion // Public Properties
2874 #region Public Methods
2875 public void Clear ()
2877 ArrayList copy = (ArrayList) list.Clone ();
2878 for (int i = 0; i < copy.Count; i++)
2879 ((ListViewItem) copy [i]).Selected = false;
2884 public bool Contains (ListViewItem item)
2886 return list.Contains (item);
2889 public void CopyTo (Array dest, int index)
2891 list.CopyTo (dest, index);
2894 public IEnumerator GetEnumerator ()
2896 return list.GetEnumerator ();
2899 int IList.Add (object value)
2901 throw new NotSupportedException ("Add operation is not supported.");
2904 bool IList.Contains (object item)
2906 return list.Contains (item);
2909 int IList.IndexOf (object item)
2911 return list.IndexOf (item);
2914 void IList.Insert (int index, object value)
2916 throw new NotSupportedException ("Insert operation is not supported.");
2919 void IList.Remove (object value)
2921 throw new NotSupportedException ("Remove operation is not supported.");
2924 void IList.RemoveAt (int index)
2926 throw new NotSupportedException ("RemoveAt operation is not supported.");
2929 public int IndexOf (ListViewItem item)
2931 return list.IndexOf (item);
2933 #endregion // Public Methods
2935 } // SelectedListViewItemCollection
2937 #endregion // Subclasses