1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
23 // Ravindra Kumar (rkumar@novell.com)
24 // Jordi Mas i Hernandez, jordi@ximian.com
25 // Mike Kestner (mkestner@novell.com)
26 // Daniel Nauck (dna(at)mono-project(dot)de)
29 // - Feedback for item activation, change in cursor types as mouse moves.
37 using System.Collections;
38 using System.ComponentModel;
39 using System.ComponentModel.Design;
41 using System.Runtime.InteropServices;
42 using System.Globalization;
44 using System.Collections.Generic;
47 namespace System.Windows.Forms
49 [DefaultEvent ("SelectedIndexChanged")]
50 [DefaultProperty ("Items")]
51 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
53 [ClassInterface (ClassInterfaceType.AutoDispatch)]
55 [Docking (DockingBehavior.Ask)]
57 public class ListView : Control
59 private ItemActivation activation = ItemActivation.Standard;
60 private ListViewAlignment alignment = ListViewAlignment.Top;
61 private bool allow_column_reorder = false;
62 private bool auto_arrange = true;
63 private bool check_boxes = false;
64 private readonly CheckedIndexCollection checked_indices;
65 private readonly CheckedListViewItemCollection checked_items;
66 private readonly ColumnHeaderCollection columns;
67 internal ListViewItem focused_item;
68 private bool full_row_select = false;
69 private bool grid_lines = false;
70 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
71 private bool hide_selection = true;
72 private bool hover_selection = false;
73 private IComparer item_sorter;
74 private readonly ListViewItemCollection items;
76 private readonly ListViewGroupCollection groups;
77 private bool show_groups = true;
79 private bool label_edit = false;
80 private bool label_wrap = true;
81 private bool multiselect = true;
82 private bool scrollable = true;
83 private readonly SelectedIndexCollection selected_indices;
84 private readonly SelectedListViewItemCollection selected_items;
85 private SortOrder sort_order = SortOrder.None;
86 private ImageList state_image_list;
87 private bool updating = false;
88 private View view = View.LargeIcon;
89 private int layout_wd; // We might draw more than our client area
90 private int layout_ht; // therefore we need to have these two.
91 //private TextBox editor; // Used for editing an item text
92 HeaderControl header_control;
93 internal ItemControl item_control;
94 internal ScrollBar h_scroll; // used for scrolling horizontally
95 internal ScrollBar v_scroll; // used for scrolling vertically
96 internal int h_marker; // Position markers for scrolling
97 internal int v_marker;
98 private int keysearch_tickcnt;
99 private string keysearch_text;
100 static private readonly int keysearch_keydelay = 1000;
101 private int[] reordered_column_indices;
103 private Size tile_size;
106 // internal variables
107 internal ImageList large_image_list;
108 internal ImageList small_image_list;
109 internal Size text_size = Size.Empty;
112 static object AfterLabelEditEvent = new object ();
113 static object BeforeLabelEditEvent = new object ();
114 static object ColumnClickEvent = new object ();
115 static object ItemActivateEvent = new object ();
116 static object ItemCheckEvent = new object ();
117 static object ItemDragEvent = new object ();
118 static object SelectedIndexChangedEvent = new object ();
120 public event LabelEditEventHandler AfterLabelEdit {
121 add { Events.AddHandler (AfterLabelEditEvent, value); }
122 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
126 [EditorBrowsable (EditorBrowsableState.Never)]
127 public new event EventHandler BackgroundImageChanged {
128 add { base.BackgroundImageChanged += value; }
129 remove { base.BackgroundImageChanged -= value; }
132 public event LabelEditEventHandler BeforeLabelEdit {
133 add { Events.AddHandler (BeforeLabelEditEvent, value); }
134 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
137 public event ColumnClickEventHandler ColumnClick {
138 add { Events.AddHandler (ColumnClickEvent, value); }
139 remove { Events.RemoveHandler (ColumnClickEvent, value); }
142 public event EventHandler ItemActivate {
143 add { Events.AddHandler (ItemActivateEvent, value); }
144 remove { Events.RemoveHandler (ItemActivateEvent, value); }
147 public event ItemCheckEventHandler ItemCheck {
148 add { Events.AddHandler (ItemCheckEvent, value); }
149 remove { Events.RemoveHandler (ItemCheckEvent, value); }
152 public event ItemDragEventHandler ItemDrag {
153 add { Events.AddHandler (ItemDragEvent, value); }
154 remove { Events.RemoveHandler (ItemDragEvent, value); }
158 [EditorBrowsable (EditorBrowsableState.Never)]
159 public new event PaintEventHandler Paint {
160 add { base.Paint += value; }
161 remove { base.Paint -= value; }
164 public event EventHandler SelectedIndexChanged {
165 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
166 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
170 [EditorBrowsable (EditorBrowsableState.Never)]
171 public new event EventHandler TextChanged {
172 add { base.TextChanged += value; }
173 remove { base.TextChanged -= value; }
178 #region Public Constructors
181 background_color = ThemeEngine.Current.ColorWindow;
182 items = new ListViewItemCollection (this);
184 groups = new ListViewGroupCollection (this);
186 checked_indices = new CheckedIndexCollection (this);
187 checked_items = new CheckedListViewItemCollection (this);
188 columns = new ColumnHeaderCollection (this);
189 foreground_color = SystemColors.WindowText;
190 selected_indices = new SelectedIndexCollection (this);
191 selected_items = new SelectedListViewItemCollection (this);
193 border_style = BorderStyle.Fixed3D;
195 header_control = new HeaderControl (this);
196 header_control.Visible = false;
197 Controls.AddImplicit (header_control);
199 item_control = new ItemControl (this);
200 Controls.AddImplicit (item_control);
202 h_scroll = new ImplicitHScrollBar ();
203 Controls.AddImplicit (this.h_scroll);
205 v_scroll = new ImplicitVScrollBar ();
206 Controls.AddImplicit (this.v_scroll);
208 h_marker = v_marker = 0;
209 keysearch_tickcnt = 0;
211 // scroll bars are disabled initially
212 h_scroll.Visible = false;
213 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
214 v_scroll.Visible = false;
215 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
218 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
219 SizeChanged += new EventHandler (ListView_SizeChanged);
220 GotFocus += new EventHandler (FocusChanged);
221 LostFocus += new EventHandler (FocusChanged);
222 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
224 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
226 | ControlStyles.UseTextForAccessibility
230 #endregion // Public Constructors
232 #region Private Internal Properties
233 internal Size CheckBoxSize {
235 if (this.check_boxes) {
236 if (this.state_image_list != null)
237 return this.state_image_list.ImageSize;
239 return ThemeEngine.Current.ListViewCheckBoxSize;
245 #endregion // Private Internal Properties
247 #region Protected Properties
248 protected override CreateParams CreateParams {
249 get { return base.CreateParams; }
252 protected override Size DefaultSize {
253 get { return ThemeEngine.Current.ListViewDefaultSize; }
255 #endregion // Protected Properties
257 #region Public Instance Properties
258 [DefaultValue (ItemActivation.Standard)]
259 public ItemActivation Activation {
260 get { return activation; }
262 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
263 value != ItemActivation.TwoClick) {
264 throw new InvalidEnumArgumentException (string.Format
265 ("Enum argument value '{0}' is not valid for Activation", value));
272 [DefaultValue (ListViewAlignment.Top)]
274 public ListViewAlignment Alignment {
275 get { return alignment; }
277 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
278 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
279 throw new InvalidEnumArgumentException (string.Format
280 ("Enum argument value '{0}' is not valid for Alignment", value));
283 if (this.alignment != value) {
285 // alignment does not matter in Details/List views
286 if (this.view == View.LargeIcon ||
287 this.View == View.SmallIcon)
293 [DefaultValue (false)]
294 public bool AllowColumnReorder {
295 get { return allow_column_reorder; }
296 set { allow_column_reorder = value; }
299 [DefaultValue (true)]
300 public bool AutoArrange {
301 get { return auto_arrange; }
303 if (auto_arrange != value) {
304 auto_arrange = value;
305 // autoarrange does not matter in Details/List views
306 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
312 public override Color BackColor {
314 if (background_color.IsEmpty)
315 return ThemeEngine.Current.ColorWindow;
317 return background_color;
319 set { background_color = value; }
323 [EditorBrowsable (EditorBrowsableState.Never)]
324 public override Image BackgroundImage {
325 get { return base.BackgroundImage; }
326 set { base.BackgroundImage = value; }
329 [DefaultValue (BorderStyle.Fixed3D)]
331 public BorderStyle BorderStyle {
332 get { return InternalBorderStyle; }
333 set { InternalBorderStyle = value; }
336 [DefaultValue (false)]
337 public bool CheckBoxes {
338 get { return check_boxes; }
340 if (check_boxes != value) {
342 if (value && View == View.Tile)
343 throw new NotSupportedException ("CheckBoxes are not"
344 + " supported in Tile view. Choose a different"
345 + " view or set CheckBoxes to false.");
355 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
356 public CheckedIndexCollection CheckedIndices {
357 get { return checked_indices; }
361 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
362 public CheckedListViewItemCollection CheckedItems {
363 get { return checked_items; }
366 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
368 [MergableProperty (false)]
369 public ColumnHeaderCollection Columns {
370 get { return columns; }
374 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
375 public ListViewItem FocusedItem {
381 public override Color ForeColor {
383 if (foreground_color.IsEmpty)
384 return ThemeEngine.Current.ColorWindowText;
386 return foreground_color;
388 set { foreground_color = value; }
391 [DefaultValue (false)]
392 public bool FullRowSelect {
393 get { return full_row_select; }
394 set { full_row_select = value; }
397 [DefaultValue (false)]
398 public bool GridLines {
399 get { return grid_lines; }
401 if (grid_lines != value) {
408 [DefaultValue (ColumnHeaderStyle.Clickable)]
409 public ColumnHeaderStyle HeaderStyle {
410 get { return header_style; }
412 if (header_style == value)
416 case ColumnHeaderStyle.Clickable:
417 case ColumnHeaderStyle.Nonclickable:
418 case ColumnHeaderStyle.None:
421 throw new InvalidEnumArgumentException (string.Format
422 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
425 header_style = value;
426 if (view == View.Details)
431 [DefaultValue (true)]
432 public bool HideSelection {
433 get { return hide_selection; }
435 if (hide_selection != value) {
436 hide_selection = value;
442 [DefaultValue (false)]
443 public bool HoverSelection {
444 get { return hover_selection; }
445 set { hover_selection = value; }
448 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
450 [MergableProperty (false)]
451 public ListViewItemCollection Items {
452 get { return items; }
455 [DefaultValue (false)]
456 public bool LabelEdit {
457 get { return label_edit; }
458 set { label_edit = value; }
461 [DefaultValue (true)]
463 public bool LabelWrap {
464 get { return label_wrap; }
466 if (label_wrap != value) {
473 [DefaultValue (null)]
474 public ImageList LargeImageList {
475 get { return large_image_list; }
477 large_image_list = value;
483 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
484 public IComparer ListViewItemSorter {
486 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
491 if (item_sorter != value) {
498 [DefaultValue (true)]
499 public bool MultiSelect {
500 get { return multiselect; }
501 set { multiselect = value; }
504 [DefaultValue (true)]
505 public bool Scrollable {
506 get { return scrollable; }
508 if (scrollable != value) {
516 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
517 public SelectedIndexCollection SelectedIndices {
518 get { return selected_indices; }
522 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
523 public SelectedListViewItemCollection SelectedItems {
524 get { return selected_items; }
529 public bool ShowGroups {
530 get { return show_groups; }
533 if (show_groups != value)
541 [LocalizableAttribute(true)]
542 public ListViewGroupCollection Groups {
543 get { return groups; }
547 [DefaultValue (null)]
548 public ImageList SmallImageList {
549 get { return small_image_list; }
551 small_image_list = value;
556 [DefaultValue (SortOrder.None)]
557 public SortOrder Sorting {
558 get { return sort_order; }
560 if (!Enum.IsDefined (typeof (SortOrder), value)) {
561 throw new InvalidEnumArgumentException ("value", (int) value,
565 if (sort_order == value)
570 if (value == SortOrder.None) {
571 if (item_sorter != null) {
572 // ListViewItemSorter should never be reset for SmallIcon
573 // and LargeIcon view
574 if (View != View.SmallIcon && View != View.LargeIcon)
578 // in .NET 1.1, only internal IComparer would be
580 if (item_sorter is ItemComparer)
586 if (item_sorter == null)
587 item_sorter = new ItemComparer (value);
588 if (item_sorter is ItemComparer) {
590 item_sorter = new ItemComparer (value);
592 // in .NET 1.1, the sort order is not updated for
593 // SmallIcon and LargeIcon views if no custom IComparer
595 if (View != View.SmallIcon && View != View.LargeIcon)
596 item_sorter = new ItemComparer (value);
604 [DefaultValue (null)]
605 public ImageList StateImageList {
606 get { return state_image_list; }
608 state_image_list = value;
615 [EditorBrowsable (EditorBrowsableState.Never)]
616 public override string Text {
617 get { return base.Text; }
619 if (value == base.Text)
628 public Size TileSize {
633 if (value.Width <= 0 || value.Height <= 0)
634 throw new ArgumentOutOfRangeException ("value");
643 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
644 public ListViewItem TopItem {
647 if (this.items.Count == 0)
649 // if contents are not scrolled
650 // it is the first item
651 else if (h_marker == 0 && v_marker == 0)
652 return this.items [0];
653 // do a hit test for the scrolled position
655 foreach (ListViewItem item in this.items) {
656 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
665 [MonoTODO("Implement")]
666 public bool UseCompatibleStateImageBehavior {
676 [DefaultValue (View.LargeIcon)]
680 if (!Enum.IsDefined (typeof (View), value))
681 throw new InvalidEnumArgumentException ("value", (int) value,
686 if (CheckBoxes && value == View.Tile)
687 throw new NotSupportedException ("CheckBoxes are not"
688 + " supported in Tile view. Choose a different"
689 + " view or set CheckBoxes to false.");
692 h_scroll.Value = v_scroll.Value = 0;
698 #endregion // Public Instance Properties
700 #region Internal Methods Properties
702 internal int FirstVisibleIndex {
705 if (this.items.Count == 0)
708 if (h_marker == 0 && v_marker == 0)
711 foreach (ListViewItem item in this.items) {
712 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
721 internal int LastVisibleIndex {
723 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
724 if (View == View.List || Alignment == ListViewAlignment.Left) {
725 if (Items[i].Bounds.X > ClientRectangle.Right)
728 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
733 return Items.Count - 1;
737 internal void OnSelectedIndexChanged ()
740 OnSelectedIndexChanged (EventArgs.Empty);
743 internal int TotalWidth {
744 get { return Math.Max (this.Width, this.layout_wd); }
747 internal int TotalHeight {
748 get { return Math.Max (this.Height, this.layout_ht); }
751 internal void Redraw (bool recalculate)
753 // Avoid calculations when control is being updated
758 CalculateListView (this.alignment);
763 const int text_padding = 5;
765 internal Size GetChildColumnSize (int index)
767 Size ret_size = Size.Empty;
768 ColumnHeader col = this.columns [index];
770 if (col.Width == -2) { // autosize = max(items, columnheader)
771 Size size = Size.Ceiling (this.DeviceContext.MeasureString
772 (col.Text, this.Font));
773 size.Width += text_padding;
774 ret_size = BiggestItem (index);
775 if (size.Width > ret_size.Width)
778 else { // -1 and all the values < -2 are put under one category
779 ret_size = BiggestItem (index);
780 // fall back to empty columns' width if no subitem is available for a column
781 if (ret_size.IsEmpty) {
782 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
783 if (col.Text.Length > 0)
784 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
785 (col.Text, this.Font)).Height;
787 ret_size.Height = this.Font.Height;
791 ret_size.Height += text_padding;
793 // adjust the size for icon and checkbox for 0th column
795 ret_size.Width += (this.CheckBoxSize.Width + 4);
796 if (this.small_image_list != null)
797 ret_size.Width += this.small_image_list.ImageSize.Width;
802 // Returns the size of biggest item text in a column.
803 private Size BiggestItem (int col)
805 Size temp = Size.Empty;
806 Size ret_size = Size.Empty;
808 // 0th column holds the item text, we check the size of
809 // the various subitems falling in that column and get
810 // the biggest one's size.
811 foreach (ListViewItem item in items) {
812 if (col >= item.SubItems.Count)
815 temp = Size.Ceiling (this.DeviceContext.MeasureString
816 (item.SubItems [col].Text, this.Font));
817 if (temp.Width > ret_size.Width)
821 // adjustment for space
822 if (!ret_size.IsEmpty)
828 const int max_wrap_padding = 38;
830 // Sets the size of the biggest item text as per the view
831 private void CalcTextSize ()
833 // clear the old value
834 text_size = Size.Empty;
836 if (items.Count == 0)
839 text_size = BiggestItem (0);
841 if (view == View.LargeIcon && this.label_wrap) {
842 Size temp = Size.Empty;
843 if (this.check_boxes)
844 temp.Width += 2 * this.CheckBoxSize.Width;
845 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
846 temp.Width += icon_w + max_wrap_padding;
847 // wrapping is done for two lines only
848 if (text_size.Width > temp.Width) {
849 text_size.Width = temp.Width;
850 text_size.Height *= 2;
853 else if (view == View.List) {
854 // in list view max text shown in determined by the
855 // control width, even if scolling is enabled.
856 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
857 if (this.small_image_list != null)
858 max_wd -= this.small_image_list.ImageSize.Width;
860 if (text_size.Width > max_wd)
861 text_size.Width = max_wd;
864 // we do the default settings, if we have got 0's
865 if (text_size.Height <= 0)
866 text_size.Height = this.Font.Height;
867 if (text_size.Width <= 0)
868 text_size.Width = this.Width;
871 text_size.Width += 4;
872 text_size.Height += 2;
875 private void Scroll (ScrollBar scrollbar, int delta)
877 if (delta == 0 || !scrollbar.Visible)
881 if (scrollbar == h_scroll)
882 max = h_scroll.Maximum - item_control.Width;
884 max = v_scroll.Maximum - item_control.Height;
886 int val = scrollbar.Value + delta;
889 else if (val < scrollbar.Minimum)
890 val = scrollbar.Minimum;
891 scrollbar.Value = val;
894 private void CalculateScrollBars ()
896 Rectangle client_area = ClientRectangle;
898 if (!this.scrollable || this.items.Count <= 0) {
899 h_scroll.Visible = false;
900 v_scroll.Visible = false;
901 item_control.Location = new Point (0, header_control.Height);
902 item_control.Height = ClientRectangle.Width - header_control.Height;
903 item_control.Width = ClientRectangle.Width;
904 header_control.Width = ClientRectangle.Width;
908 // Don't calculate if the view is not displayable
909 if (client_area.Height < 0 || client_area.Width < 0)
912 // making a scroll bar visible might make
913 // other scroll bar visible
914 if (layout_wd > client_area.Right) {
915 h_scroll.Visible = true;
916 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
917 v_scroll.Visible = true;
919 v_scroll.Visible = false;
920 } else if (layout_ht > client_area.Bottom) {
921 v_scroll.Visible = true;
922 if ((layout_wd + v_scroll.Width) > client_area.Right)
923 h_scroll.Visible = true;
925 h_scroll.Visible = false;
927 h_scroll.Visible = false;
928 v_scroll.Visible = false;
931 item_control.Height = ClientRectangle.Height - header_control.Height;
933 if (h_scroll.is_visible) {
934 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
935 h_scroll.Minimum = 0;
937 // if v_scroll is visible, adjust the maximum of the
938 // h_scroll to account for the width of v_scroll
939 if (v_scroll.Visible) {
940 h_scroll.Maximum = layout_wd + v_scroll.Width;
941 h_scroll.Width = client_area.Width - v_scroll.Width;
944 h_scroll.Maximum = layout_wd;
945 h_scroll.Width = client_area.Width;
948 h_scroll.LargeChange = client_area.Width;
949 h_scroll.SmallChange = Font.Height;
950 item_control.Height -= h_scroll.Height;
953 if (header_control.is_visible)
954 header_control.Width = ClientRectangle.Width;
955 item_control.Width = ClientRectangle.Width;
957 if (v_scroll.is_visible) {
958 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
959 v_scroll.Minimum = 0;
961 // if h_scroll is visible, adjust the maximum of the
962 // v_scroll to account for the height of h_scroll
963 if (h_scroll.Visible) {
964 v_scroll.Maximum = layout_ht + h_scroll.Height;
965 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
967 v_scroll.Maximum = layout_ht;
968 v_scroll.Height = client_area.Height;
971 v_scroll.LargeChange = client_area.Height;
972 v_scroll.SmallChange = Font.Height;
973 if (header_control.Visible)
974 header_control.Width -= v_scroll.Width;
975 item_control.Width -= v_scroll.Width;
979 ColumnHeader GetReorderedColumn (int index)
981 if (reordered_column_indices == null)
982 return Columns [index];
984 return Columns [reordered_column_indices [index]];
987 void ReorderColumn (ColumnHeader col, int index)
990 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
992 ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
996 header_control.Invalidate ();
997 item_control.Invalidate ();
1002 if (reordered_column_indices == null) {
1003 reordered_column_indices = new int [Columns.Count];
1004 for (int i = 0; i < Columns.Count; i++)
1005 reordered_column_indices [i] = i;
1008 if (reordered_column_indices [index] == col.Index)
1011 int[] curr = reordered_column_indices;
1012 int[] result = new int [Columns.Count];
1014 for (int i = 0; i < Columns.Count; i++) {
1015 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
1019 result [i] = col.Index;
1021 result [i] = curr [curr_idx++];
1024 reordered_column_indices = result;
1026 header_control.Invalidate ();
1027 item_control.Invalidate ();
1030 Size LargeIconItemSize {
1032 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1033 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1034 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
1035 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1036 return new Size (w, h);
1040 Size SmallIconItemSize {
1042 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1043 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1044 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
1045 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1046 return new Size (w, h);
1053 // Calculate tile size if needed
1054 // It appears that using Font.Size instead of a SizeF value can give us
1055 // a slightly better approach to the proportions defined in .Net
1056 if (tile_size == Size.Empty) {
1057 int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1058 int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1059 int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1060 int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1062 tile_size = new Size (w, h);
1072 ListViewItem[,] item_matrix;
1074 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1076 header_control.Visible = false;
1077 header_control.Size = Size.Empty;
1078 item_control.Visible = true;
1079 item_control.Location = Point.Empty;
1081 if (items.Count == 0)
1084 Size sz = item_size;
1085 Rectangle area = ClientRectangle;
1088 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
1091 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1093 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
1096 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1099 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1100 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
1101 item_matrix = new ListViewItem [rows, cols];
1104 foreach (ListViewItem item in items) {
1105 int x = col * (sz.Width + x_spacing);
1106 int y = row * (sz.Height + y_spacing);
1107 item.Location = new Point (x, y);
1111 item_matrix [row, col] = item;
1113 if (++row == rows) {
1118 if (++col == cols) {
1125 item_control.Size = new Size (layout_wd, layout_ht);
1128 void LayoutHeader ()
1131 for (int i = 0; i < Columns.Count; i++) {
1132 ColumnHeader col = GetReorderedColumn (i);
1135 col.CalcColumnHeader ();
1139 if (x < ClientRectangle.Width)
1140 x = ClientRectangle.Width;
1142 if (header_style == ColumnHeaderStyle.None) {
1143 header_control.Visible = false;
1144 header_control.Size = Size.Empty;
1146 header_control.Width = x;
1147 header_control.Height = columns [0].Ht;
1148 header_control.Visible = true;
1152 void LayoutDetails ()
1154 if (columns.Count == 0) {
1155 header_control.Visible = false;
1156 item_control.Visible = false;
1162 item_control.Visible = true;
1163 item_control.Location = new Point (0, header_control.Height);
1166 if (items.Count > 0) {
1167 foreach (ListViewItem item in items) {
1169 item.Location = new Point (0, y);
1170 y += item.Bounds.Height + 2;
1173 // some space for bottom gridline
1178 layout_wd = Math.Max (header_control.Width, item_control.Width);
1179 layout_ht = y + header_control.Height;
1182 private void CalculateListView (ListViewAlignment align)
1191 case View.SmallIcon:
1192 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left, 4, 2);
1195 case View.LargeIcon:
1196 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
1197 ThemeEngine.Current.ListViewHorizontalSpacing,
1198 ThemeEngine.Current.ListViewVerticalSpacing);
1202 LayoutIcons (SmallIconItemSize, true, 4, 2);
1206 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left,
1207 ThemeEngine.Current.ListViewHorizontalSpacing,
1208 ThemeEngine.Current.ListViewVerticalSpacing);
1213 CalculateScrollBars ();
1216 private bool KeySearchString (KeyEventArgs ke)
1218 int current_tickcnt = Environment.TickCount;
1219 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1220 keysearch_text = string.Empty;
1223 keysearch_text += (char) ke.KeyData;
1224 keysearch_tickcnt = current_tickcnt;
1226 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1229 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1230 CompareOptions.IgnoreCase)) {
1231 SetFocusedItem (Items [i]);
1232 items [i].Selected = true;
1236 i = (i + 1 < Items.Count) ? i+1 : 0;
1244 int GetAdjustedIndex (Keys key)
1248 if (View == View.Details) {
1250 result = FocusedItem.Index - 1;
1251 else if (key == Keys.Down) {
1252 result = FocusedItem.Index + 1;
1253 if (result == items.Count)
1259 int row = FocusedItem.row;
1260 int col = FocusedItem.col;
1266 return item_matrix [row, col - 1].Index;
1269 if (col == (cols - 1))
1271 while (item_matrix [row, col + 1] == null) {
1276 return item_matrix [row, col + 1].Index;
1281 return item_matrix [row - 1, col].Index;
1284 if (row == (rows - 1) || row == Items.Count - 1)
1286 while (item_matrix [row + 1, col] == null) {
1291 return item_matrix [row + 1, col].Index;
1298 ListViewItem selection_start;
1300 private bool SelectItems (ArrayList sel_items)
1302 bool changed = false;
1303 ArrayList curr_items = SelectedItems.List;
1304 foreach (ListViewItem item in curr_items)
1305 if (!sel_items.Contains (item)) {
1306 item.Selected = false;
1309 foreach (ListViewItem item in sel_items)
1310 if (!item.Selected) {
1311 item.Selected = true;
1317 private void UpdateMultiSelection (int index)
1319 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1320 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1321 ListViewItem item = items [index];
1323 if (shift_pressed && selection_start != null) {
1324 ArrayList list = new ArrayList ();
1325 int start = Math.Min (selection_start.Index, index);
1326 int end = Math.Max (selection_start.Index, index);
1327 if (View == View.Details) {
1328 for (int i = start; i <= end; i++)
1329 list.Add (items [i]);
1331 int left = Math.Min (items [start].col, items [end].col);
1332 int right = Math.Max (items [start].col, items [end].col);
1333 int top = Math.Min (items [start].row, items [end].row);
1334 int bottom = Math.Max (items [start].row, items [end].row);
1335 foreach (ListViewItem curr in items)
1336 if (curr.row >= top && curr.row <= bottom &&
1337 curr.col >= left && curr.col <= right)
1340 if (SelectItems (list))
1341 OnSelectedIndexChanged (EventArgs.Empty);
1342 } else if (ctrl_pressed) {
1343 item.Selected = !item.Selected;
1344 selection_start = item;
1345 OnSelectedIndexChanged (EventArgs.Empty);
1347 SelectedItems.Clear ();
1348 item.Selected = true;
1349 selection_start = item;
1350 OnSelectedIndexChanged (EventArgs.Empty);
1354 internal override bool InternalPreProcessMessage (ref Message msg)
1356 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
1357 Keys key_data = (Keys)msg.WParam.ToInt32();
1358 if (HandleNavKeys (key_data))
1361 return base.InternalPreProcessMessage (ref msg);
1364 bool HandleNavKeys (Keys key_data)
1366 if (Items.Count == 0 || !item_control.Visible)
1369 if (FocusedItem == null)
1370 SetFocusedItem (Items [0]);
1374 SelectIndex (Items.Count - 1);
1385 SelectIndex (GetAdjustedIndex (key_data));
1395 void SelectIndex (int index)
1401 UpdateMultiSelection (index);
1402 else if (!items [index].Selected) {
1403 items [index].Selected = true;
1404 OnSelectedIndexChanged (EventArgs.Empty);
1407 SetFocusedItem (items [index]);
1408 EnsureVisible (index);
1411 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1413 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1416 ke.Handled = KeySearchString (ke);
1419 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
1421 Point loc = PointToClient (Control.MousePosition);
1422 return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
1425 internal class ItemControl : Control {
1428 ListViewItem clicked_item;
1429 ListViewItem last_clicked_item;
1430 bool hover_processed = false;
1431 bool checking = false;
1433 ListViewLabelEditTextBox edit_text_box;
1434 internal ListViewItem edit_item;
1435 LabelEditEventArgs edit_args;
1437 public ItemControl (ListView owner)
1440 DoubleClick += new EventHandler(ItemsDoubleClick);
1441 MouseDown += new MouseEventHandler(ItemsMouseDown);
1442 MouseMove += new MouseEventHandler(ItemsMouseMove);
1443 MouseHover += new EventHandler(ItemsMouseHover);
1444 MouseUp += new MouseEventHandler(ItemsMouseUp);
1447 void ItemsDoubleClick (object sender, EventArgs e)
1449 if (owner.activation == ItemActivation.Standard)
1450 owner.OnItemActivate (EventArgs.Empty);
1460 BoxSelect box_select_mode = BoxSelect.None;
1461 ArrayList prev_selection;
1462 Point box_select_start;
1464 Rectangle box_select_rect;
1465 internal Rectangle BoxSelectRectangle {
1466 get { return box_select_rect; }
1468 if (box_select_rect == value)
1471 InvalidateBoxSelectRect ();
1472 box_select_rect = value;
1473 InvalidateBoxSelectRect ();
1477 void InvalidateBoxSelectRect ()
1479 if (BoxSelectRectangle.Size.IsEmpty)
1482 Rectangle edge = BoxSelectRectangle;
1488 edge.Y = BoxSelectRectangle.Bottom - 1;
1490 edge.Y = BoxSelectRectangle.Y - 1;
1492 edge.Height = BoxSelectRectangle.Height + 2;
1494 edge.X = BoxSelectRectangle.Right - 1;
1498 private Rectangle CalculateBoxSelectRectangle (Point pt)
1500 int left = Math.Min (box_select_start.X, pt.X);
1501 int right = Math.Max (box_select_start.X, pt.X);
1502 int top = Math.Min (box_select_start.Y, pt.Y);
1503 int bottom = Math.Max (box_select_start.Y, pt.Y);
1504 return Rectangle.FromLTRB (left, top, right, bottom);
1507 ArrayList BoxSelectedItems {
1509 ArrayList result = new ArrayList ();
1510 foreach (ListViewItem item in owner.Items) {
1511 Rectangle r = item.Bounds;
1513 r.Y += r.Height / 4;
1516 if (BoxSelectRectangle.IntersectsWith (r))
1523 private bool PerformBoxSelection (Point pt)
1525 if (box_select_mode == BoxSelect.None)
1528 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1530 ArrayList box_items = BoxSelectedItems;
1534 switch (box_select_mode) {
1536 case BoxSelect.Normal:
1540 case BoxSelect.Control:
1541 items = new ArrayList ();
1542 foreach (ListViewItem item in prev_selection)
1543 if (!box_items.Contains (item))
1545 foreach (ListViewItem item in box_items)
1546 if (!prev_selection.Contains (item))
1550 case BoxSelect.Shift:
1552 foreach (ListViewItem item in box_items)
1553 prev_selection.Remove (item);
1554 foreach (ListViewItem item in prev_selection)
1559 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1563 owner.SelectItems (items);
1569 private void ToggleCheckState (ListViewItem item)
1571 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1572 item.Checked = !item.Checked;
1573 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1575 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1576 owner.OnItemCheck (ice);
1579 private void ItemsMouseDown (object sender, MouseEventArgs me)
1581 if (owner.items.Count == 0) {
1582 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
1586 Point pt = new Point (me.X, me.Y);
1587 foreach (ListViewItem item in owner.items) {
1588 if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
1590 ToggleCheckState (item);
1591 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
1595 if (owner.View == View.Details && !owner.FullRowSelect) {
1596 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1597 clicked_item = item;
1601 if (item.Bounds.Contains (pt)) {
1602 clicked_item = item;
1609 if (clicked_item != null) {
1610 owner.SetFocusedItem (clicked_item);
1611 bool changed = !clicked_item.Selected;
1612 if (owner.MultiSelect)
1613 owner.UpdateMultiSelection (clicked_item.Index);
1615 clicked_item.Selected = true;
1618 owner.OnSelectedIndexChanged (EventArgs.Empty);
1620 // Raise double click if the item was clicked. On MS the
1621 // double click is only raised if you double click an item
1622 if (me.Clicks > 1) {
1623 owner.OnDoubleClick (EventArgs.Empty);
1624 if (owner.CheckBoxes)
1625 ToggleCheckState (clicked_item);
1626 } else if (me.Clicks == 1) {
1627 owner.OnClick (EventArgs.Empty);
1628 if (owner.LabelEdit && !changed)
1629 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
1632 if (owner.MultiSelect) {
1633 Keys mods = XplatUI.State.ModifierKeys;
1634 if ((mods & Keys.Shift) != 0)
1635 box_select_mode = BoxSelect.Shift;
1636 else if ((mods & Keys.Control) != 0)
1637 box_select_mode = BoxSelect.Control;
1639 box_select_mode = BoxSelect.Normal;
1640 box_select_start = pt;
1641 prev_selection = owner.SelectedItems.List;
1642 } else if (owner.SelectedItems.Count > 0) {
1643 owner.SelectedItems.Clear ();
1644 owner.OnSelectedIndexChanged (EventArgs.Empty);
1648 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
1651 private void ItemsMouseMove (object sender, MouseEventArgs me)
1653 bool done = PerformBoxSelection (new Point (me.X, me.Y));
1655 if (!done && owner.HoverSelection && hover_processed) {
1657 Point pt = PointToClient (Control.MousePosition);
1658 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1659 if (item != null && !item.Selected) {
1660 hover_processed = false;
1661 XplatUI.ResetMouseHover (Handle);
1665 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
1669 private void ItemsMouseHover (object sender, EventArgs e)
1671 owner.OnMouseHover(e);
1673 if (Capture || !owner.HoverSelection)
1676 hover_processed = true;
1677 Point pt = PointToClient (Control.MousePosition);
1678 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1683 item.Selected = true;
1684 owner.OnSelectedIndexChanged (new EventArgs ());
1687 private void ItemsMouseUp (object sender, MouseEventArgs me)
1690 if (owner.Items.Count == 0) {
1691 owner.OnMouseUp (owner.TranslateMouseEventArgs (me));
1695 Point pt = new Point (me.X, me.Y);
1697 Rectangle rect = Rectangle.Empty;
1698 if (clicked_item != null) {
1699 if (owner.view == View.Details && !owner.full_row_select)
1700 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1702 rect = clicked_item.Bounds;
1704 if (rect.Contains (pt)) {
1705 switch (owner.activation) {
1706 case ItemActivation.OneClick:
1707 owner.OnItemActivate (EventArgs.Empty);
1710 case ItemActivation.TwoClick:
1711 if (last_clicked_item == clicked_item) {
1712 owner.OnItemActivate (EventArgs.Empty);
1713 last_clicked_item = null;
1715 last_clicked_item = clicked_item;
1718 // DoubleClick activation is handled in another handler
1722 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1723 // Need this to clean up background clicks
1724 owner.SelectedItems.Clear ();
1725 owner.OnSelectedIndexChanged (EventArgs.Empty);
1728 clicked_item = null;
1729 box_select_start = Point.Empty;
1730 BoxSelectRectangle = Rectangle.Empty;
1731 prev_selection = null;
1732 box_select_mode = BoxSelect.None;
1734 owner.OnMouseUp (owner.TranslateMouseEventArgs (me));
1737 internal void LabelEditFinished (object sender, EventArgs e)
1739 EndEdit (edit_item);
1742 internal void BeginEdit (ListViewItem item)
1744 if (edit_item != null)
1745 EndEdit (edit_item);
1747 if (edit_text_box == null) {
1748 edit_text_box = new ListViewLabelEditTextBox ();
1749 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1750 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1751 edit_text_box.Visible = false;
1752 Controls.Add (edit_text_box);
1755 item.EnsureVisible();
1757 edit_text_box.Reset ();
1759 switch (owner.view) {
1761 case View.SmallIcon:
1763 edit_text_box.TextAlign = HorizontalAlignment.Left;
1764 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1765 SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
1766 edit_text_box.Width = (int)sizef.Width + 4;
1767 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
1768 edit_text_box.WordWrap = false;
1769 edit_text_box.Multiline = false;
1771 case View.LargeIcon:
1772 edit_text_box.TextAlign = HorizontalAlignment.Center;
1773 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1774 sizef = DeviceContext.MeasureString (item.Text, item.Font);
1775 edit_text_box.Width = (int)sizef.Width + 4;
1776 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
1777 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
1778 edit_text_box.WordWrap = true;
1779 edit_text_box.Multiline = true;
1783 edit_text_box.Text = item.Text;
1784 edit_text_box.Font = item.Font;
1785 edit_text_box.Visible = true;
1786 edit_text_box.Focus ();
1787 edit_text_box.SelectAll ();
1789 edit_args = new LabelEditEventArgs (owner.Items.IndexOf(edit_item));
1790 owner.OnBeforeLabelEdit (edit_args);
1792 if (edit_args.CancelEdit)
1798 internal void EndEdit (ListViewItem item)
1800 if (edit_text_box != null && edit_text_box.Visible) {
1801 edit_text_box.Visible = false;
1804 if (edit_item != null && edit_item == item) {
1805 owner.OnAfterLabelEdit (edit_args);
1807 if (!edit_args.CancelEdit) {
1808 if (edit_args.Label != null)
1809 edit_item.Text = edit_args.Label;
1811 edit_item.Text = edit_text_box.Text;
1820 internal override void OnPaintInternal (PaintEventArgs pe)
1822 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1825 internal override void OnGotFocusInternal (EventArgs e)
1831 internal class ListViewLabelEditTextBox : TextBox
1836 int max_height = -1;
1837 int min_height = -1;
1839 int old_number_lines = 1;
1841 SizeF text_size_one_char;
1843 public ListViewLabelEditTextBox ()
1845 min_height = DefaultSize.Height;
1846 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1849 public int MaxWidth {
1851 if (value < min_width)
1852 max_width = min_width;
1858 public int MaxHeight {
1860 if (value < min_height)
1861 max_height = min_height;
1867 public new int Width {
1877 public override Font Font {
1883 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1887 protected override void OnTextChanged (EventArgs e)
1889 SizeF text_size = DeviceContext.MeasureString (Text, Font);
1891 int new_width = (int)text_size.Width + 8;
1894 ResizeTextBoxWidth (new_width);
1896 if (Width != max_width)
1897 ResizeTextBoxWidth (new_width);
1899 int number_lines = Lines.Length;
1901 if (number_lines != old_number_lines) {
1902 int new_height = number_lines * (int)text_size_one_char.Height + 4;
1903 old_number_lines = number_lines;
1905 ResizeTextBoxHeight (new_height);
1909 base.OnTextChanged (e);
1912 protected override bool IsInputKey (Keys key_data)
1914 if ((key_data & Keys.Alt) == 0) {
1915 switch (key_data & Keys.KeyCode) {
1920 return base.IsInputKey (key_data);
1923 protected override void OnKeyDown (KeyEventArgs e)
1925 if (e.KeyCode == Keys.Return && Visible) {
1926 this.Visible = false;
1927 OnEditingFinished (e);
1931 protected override void OnLostFocus (EventArgs e)
1934 OnEditingFinished (e);
1938 protected void OnEditingFinished (EventArgs e)
1940 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
1945 private void ResizeTextBoxWidth (int new_width)
1947 if (new_width > max_width)
1948 base.Width = max_width;
1950 if (new_width >= min_width)
1951 base.Width = new_width;
1953 base.Width = min_width;
1956 private void ResizeTextBoxHeight (int new_height)
1958 if (new_height > max_height)
1959 base.Height = max_height;
1961 if (new_height >= min_height)
1962 base.Height = new_height;
1964 base.Height = min_height;
1967 public void Reset ()
1974 old_number_lines = 1;
1976 Text = String.Empty;
1981 static object EditingFinishedEvent = new object ();
1982 public event EventHandler EditingFinished {
1983 add { Events.AddHandler (EditingFinishedEvent, value); }
1984 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
1988 internal override void OnPaintInternal (PaintEventArgs pe)
1993 CalculateScrollBars ();
1996 void FocusChanged (object o, EventArgs args)
1998 if (Items.Count == 0)
2001 if (FocusedItem == null)
2002 SetFocusedItem (Items [0]);
2004 item_control.Invalidate (FocusedItem.Bounds);
2007 private void ListView_MouseWheel (object sender, MouseEventArgs me)
2009 if (Items.Count == 0)
2012 int lines = me.Delta / 120;
2019 case View.SmallIcon:
2020 Scroll (v_scroll, -Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
2022 case View.LargeIcon:
2023 Scroll (v_scroll, -(Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
2026 Scroll (h_scroll, -Items [0].Bounds.Width * lines);
2031 private void ListView_SizeChanged (object sender, EventArgs e)
2033 CalculateListView (alignment);
2036 private void SetFocusedItem (ListViewItem item)
2038 if (focused_item != null)
2039 focused_item.Focused = false;
2042 item.Focused = true;
2044 focused_item = item;
2047 private void HorizontalScroller (object sender, EventArgs e)
2049 item_control.EndEdit (item_control.edit_item);
2051 // Avoid unnecessary flickering, when button is
2052 // kept pressed at the end
2053 if (h_marker != h_scroll.Value) {
2055 int pixels = h_marker - h_scroll.Value;
2057 h_marker = h_scroll.Value;
2058 if (header_control.Visible)
2059 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
2061 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
2065 private void VerticalScroller (object sender, EventArgs e)
2067 item_control.EndEdit (item_control.edit_item);
2069 // Avoid unnecessary flickering, when button is
2070 // kept pressed at the end
2071 if (v_marker != v_scroll.Value) {
2072 int pixels = v_marker - v_scroll.Value;
2073 Rectangle area = item_control.ClientRectangle;
2074 v_marker = v_scroll.Value;
2075 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
2078 #endregion // Internal Methods Properties
2080 #region Protected Methods
2081 protected override void CreateHandle ()
2083 base.CreateHandle ();
2084 for (int i = 0; i < SelectedItems.Count; i++)
2085 OnSelectedIndexChanged (EventArgs.Empty);
2088 protected override void Dispose (bool disposing)
2091 h_scroll.Dispose ();
2092 v_scroll.Dispose ();
2094 large_image_list = null;
2095 small_image_list = null;
2096 state_image_list = null;
2099 base.Dispose (disposing);
2102 protected override bool IsInputKey (Keys keyData)
2119 return base.IsInputKey (keyData);
2122 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
2124 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
2129 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
2131 LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
2136 protected virtual void OnColumnClick (ColumnClickEventArgs e)
2138 ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
2143 protected override void OnEnabledChanged (EventArgs e)
2145 base.OnEnabledChanged (e);
2148 protected override void OnFontChanged (EventArgs e)
2150 base.OnFontChanged (e);
2154 protected override void OnHandleCreated (EventArgs e)
2156 base.OnHandleCreated (e);
2160 protected override void OnHandleDestroyed (EventArgs e)
2162 base.OnHandleDestroyed (e);
2165 protected virtual void OnItemActivate (EventArgs e)
2167 EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
2172 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
2174 EventHandler eh = (EventHandler)(Events [ItemCheckEvent]);
2179 protected virtual void OnItemDrag (ItemDragEventArgs e)
2181 EventHandler eh = (EventHandler)(Events [ItemDragEvent]);
2186 protected virtual void OnSelectedIndexChanged (EventArgs e)
2188 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
2193 protected override void OnSystemColorsChanged (EventArgs e)
2195 base.OnSystemColorsChanged (e);
2198 protected void RealizeProperties ()
2203 protected void UpdateExtendedStyles ()
2208 protected override void WndProc (ref Message m)
2210 base.WndProc (ref m);
2212 #endregion // Protected Methods
2214 #region Public Instance Methods
2215 public void ArrangeIcons ()
2217 ArrangeIcons (this.alignment);
2220 public void ArrangeIcons (ListViewAlignment alignment)
2222 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2223 if (view == View.LargeIcon || view == View.SmallIcon) {
2224 this.CalculateListView (alignment);
2225 // we have done the calculations already
2226 this.Redraw (false);
2230 public void BeginUpdate ()
2232 // flag to avoid painting
2236 public void Clear ()
2239 items.Clear (); // Redraw (true) called here
2242 public void EndUpdate ()
2244 // flag to avoid painting
2247 // probably, now we need a redraw with recalculations
2251 public void EnsureVisible (int index)
2253 if (index < 0 || index >= items.Count || scrollable == false)
2256 Rectangle view_rect = item_control.ClientRectangle;
2257 Rectangle bounds = items [index].Bounds;
2259 if (view_rect.Contains (bounds))
2262 if (bounds.Left < 0)
2263 h_scroll.Value += bounds.Left;
2264 else if (bounds.Right > view_rect.Right)
2265 h_scroll.Value += (bounds.Right - view_rect.Right);
2268 v_scroll.Value += bounds.Top;
2269 else if (bounds.Bottom > view_rect.Bottom)
2270 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
2273 public ListViewItem GetItemAt (int x, int y)
2275 foreach (ListViewItem item in items) {
2276 if (item.Bounds.Contains (x, y))
2282 public Rectangle GetItemRect (int index)
2284 return GetItemRect (index, ItemBoundsPortion.Entire);
2287 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
2289 if (index < 0 || index >= items.Count)
2290 throw new IndexOutOfRangeException ("index");
2292 return items [index].GetBounds (portion);
2300 // we need this overload to reuse the logic for sorting, while allowing
2301 // redrawing to be done by caller or have it done by this method when
2302 // sorting is really performed
2304 // ListViewItemCollection's Add and AddRange methods call this overload
2305 // with redraw set to false, as they take care of redrawing themselves
2306 // (they even want to redraw the listview if no sort is performed, as
2307 // an item was added), while ListView.Sort () only wants to redraw if
2308 // sorting was actually performed
2309 private void Sort (bool redraw)
2311 if (!IsHandleCreated || item_sorter == null) {
2315 items.Sort (item_sorter);
2320 public override string ToString ()
2322 int count = this.Items.Count;
2325 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2327 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
2329 #endregion // Public Instance Methods
2334 class HeaderControl : Control {
2337 bool column_resize_active = false;
2338 ColumnHeader resize_column;
2339 ColumnHeader clicked_column;
2340 ColumnHeader drag_column;
2342 int drag_to_index = -1;
2344 public HeaderControl (ListView owner)
2347 MouseDown += new MouseEventHandler (HeaderMouseDown);
2348 MouseMove += new MouseEventHandler (HeaderMouseMove);
2349 MouseUp += new MouseEventHandler (HeaderMouseUp);
2352 private ColumnHeader ColumnAtX (int x)
2354 Point pt = new Point (x, 0);
2355 ColumnHeader result = null;
2356 foreach (ColumnHeader col in owner.Columns) {
2357 if (col.Rect.Contains (pt)) {
2365 private int GetReorderedIndex (ColumnHeader col)
2367 if (owner.reordered_column_indices == null)
2370 for (int i = 0; i < owner.Columns.Count; i++)
2371 if (owner.reordered_column_indices [i] == col.Index)
2373 throw new Exception ("Column index missing from reordered array");
2376 private void HeaderMouseDown (object sender, MouseEventArgs me)
2378 if (resize_column != null) {
2379 column_resize_active = true;
2384 clicked_column = ColumnAtX (me.X + owner.h_marker);
2386 if (clicked_column != null) {
2388 if (owner.AllowColumnReorder) {
2390 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
2391 drag_column.Rect = clicked_column.Rect;
2392 drag_to_index = GetReorderedIndex (clicked_column);
2394 clicked_column.Pressed = true;
2395 Rectangle bounds = clicked_column.Rect;
2396 bounds.X -= owner.h_marker;
2397 Invalidate (bounds);
2404 column_resize_active = false;
2405 resize_column = null;
2407 Cursor = Cursors.Default;
2410 private void HeaderMouseMove (object sender, MouseEventArgs me)
2412 Point pt = new Point (me.X + owner.h_marker, me.Y);
2414 if (column_resize_active) {
2415 int width = pt.X - resize_column.X;
2419 if (!owner.CanProceedWithResize (resize_column, width)){
2423 resize_column.Width = width;
2427 resize_column = null;
2429 if (clicked_column != null) {
2430 if (owner.AllowColumnReorder) {
2433 r = drag_column.Rect;
2434 r.X = clicked_column.Rect.X + me.X - drag_x;
2435 drag_column.Rect = r;
2437 int x = me.X + owner.h_marker;
2438 ColumnHeader over = ColumnAtX (x);
2440 drag_to_index = owner.Columns.Count;
2441 else if (x < over.X + over.Width / 2)
2442 drag_to_index = GetReorderedIndex (over);
2444 drag_to_index = GetReorderedIndex (over) + 1;
2447 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
2448 bool pressed = clicked_column.Pressed;
2449 clicked_column.Pressed = over == clicked_column;
2450 if (clicked_column.Pressed ^ pressed) {
2451 Rectangle bounds = clicked_column.Rect;
2452 bounds.X -= owner.h_marker;
2453 Invalidate (bounds);
2459 for (int i = 0; i < owner.Columns.Count; i++) {
2460 Rectangle zone = owner.Columns [i].Rect;
2461 zone.X = zone.Right - 5;
2463 if (zone.Contains (pt)) {
2464 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
2466 resize_column = owner.Columns [i];
2471 if (resize_column == null)
2472 Cursor = Cursors.Default;
2474 Cursor = Cursors.VSplit;
2477 void HeaderMouseUp (object sender, MouseEventArgs me)
2481 if (column_resize_active) {
2482 int column_idx = resize_column.Index;
2484 owner.RaiseColumnWidthChanged (column_idx);
2488 if (clicked_column != null && clicked_column.Pressed) {
2489 clicked_column.Pressed = false;
2490 Rectangle bounds = clicked_column.Rect;
2491 bounds.X -= owner.h_marker;
2492 Invalidate (bounds);
2493 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2496 if (drag_column != null && owner.AllowColumnReorder) {
2498 if (drag_to_index > GetReorderedIndex (clicked_column))
2500 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2501 owner.ReorderColumn (clicked_column, drag_to_index);
2506 clicked_column = null;
2509 internal override void OnPaintInternal (PaintEventArgs pe)
2514 Theme theme = ThemeEngine.Current;
2515 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2517 if (drag_column == null)
2521 if (drag_to_index == owner.Columns.Count)
2522 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2524 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2525 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2528 protected override void WndProc (ref Message m)
2530 switch ((Msg)m.Msg) {
2531 case Msg.WM_SETFOCUS:
2535 base.WndProc (ref m);
2541 private class ItemComparer : IComparer {
2542 readonly SortOrder sort_order;
2544 public ItemComparer (SortOrder sortOrder)
2546 sort_order = sortOrder;
2549 public int Compare (object x, object y)
2551 ListViewItem item_x = x as ListViewItem;
2552 ListViewItem item_y = y as ListViewItem;
2553 if (sort_order == SortOrder.Ascending)
2554 return String.Compare (item_x.Text, item_y.Text);
2556 return String.Compare (item_y.Text, item_x.Text);
2560 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2562 private readonly ListView owner;
2564 #region Public Constructor
2565 public CheckedIndexCollection (ListView owner)
2569 #endregion // Public Constructor
2571 #region Public Properties
2574 get { return owner.CheckedItems.Count; }
2577 public bool IsReadOnly {
2578 get { return true; }
2581 public int this [int index] {
2583 int [] indices = GetIndices ();
2584 if (index < 0 || index >= indices.Length)
2585 throw new ArgumentOutOfRangeException ("index");
2586 return indices [index];
2590 bool ICollection.IsSynchronized {
2591 get { return false; }
2594 object ICollection.SyncRoot {
2595 get { return this; }
2598 bool IList.IsFixedSize {
2599 get { return true; }
2602 object IList.this [int index] {
2603 get { return this [index]; }
2604 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2606 #endregion // Public Properties
2608 #region Public Methods
2609 public bool Contains (int checkedIndex)
2611 int [] indices = GetIndices ();
2612 for (int i = 0; i < indices.Length; i++) {
2613 if (indices [i] == checkedIndex)
2619 public IEnumerator GetEnumerator ()
2621 int [] indices = GetIndices ();
2622 return indices.GetEnumerator ();
2625 void ICollection.CopyTo (Array dest, int index)
2627 int [] indices = GetIndices ();
2628 Array.Copy (indices, 0, dest, index, indices.Length);
2631 int IList.Add (object value)
2633 throw new NotSupportedException ("Add operation is not supported.");
2638 throw new NotSupportedException ("Clear operation is not supported.");
2641 bool IList.Contains (object checkedIndex)
2643 if (!(checkedIndex is int))
2645 return Contains ((int) checkedIndex);
2648 int IList.IndexOf (object checkedIndex)
2650 if (!(checkedIndex is int))
2652 return IndexOf ((int) checkedIndex);
2655 void IList.Insert (int index, object value)
2657 throw new NotSupportedException ("Insert operation is not supported.");
2660 void IList.Remove (object value)
2662 throw new NotSupportedException ("Remove operation is not supported.");
2665 void IList.RemoveAt (int index)
2667 throw new NotSupportedException ("RemoveAt operation is not supported.");
2670 public int IndexOf (int checkedIndex)
2672 int [] indices = GetIndices ();
2673 for (int i = 0; i < indices.Length; i++) {
2674 if (indices [i] == checkedIndex)
2679 #endregion // Public Methods
2681 private int [] GetIndices ()
2683 ArrayList checked_items = owner.CheckedItems.List;
2684 int [] indices = new int [checked_items.Count];
2685 for (int i = 0; i < checked_items.Count; i++) {
2686 ListViewItem item = (ListViewItem) checked_items [i];
2687 indices [i] = item.Index;
2691 } // CheckedIndexCollection
2693 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2695 private readonly ListView owner;
2696 private ArrayList list;
2698 #region Public Constructor
2699 public CheckedListViewItemCollection (ListView owner)
2702 this.owner.Items.Changed += new CollectionChangedHandler (
2703 ItemsCollection_Changed);
2705 #endregion // Public Constructor
2707 #region Public Properties
2711 if (!owner.CheckBoxes)
2717 public bool IsReadOnly {
2718 get { return true; }
2721 public ListViewItem this [int index] {
2723 ArrayList checked_items = List;
2724 if (index < 0 || index >= checked_items.Count)
2725 throw new ArgumentOutOfRangeException ("index");
2726 return (ListViewItem) checked_items [index];
2731 public virtual ListViewItem this [string key] {
2733 int idx = IndexOfKey (key);
2734 return idx == -1 ? null : (ListViewItem) List [idx];
2739 bool ICollection.IsSynchronized {
2740 get { return false; }
2743 object ICollection.SyncRoot {
2744 get { return this; }
2747 bool IList.IsFixedSize {
2748 get { return true; }
2751 object IList.this [int index] {
2752 get { return this [index]; }
2753 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2755 #endregion // Public Properties
2757 #region Public Methods
2758 public bool Contains (ListViewItem item)
2760 if (!owner.CheckBoxes)
2762 return List.Contains (item);
2766 public virtual bool ContainsKey (string key)
2768 return IndexOfKey (key) != -1;
2772 public void CopyTo (Array dest, int index)
2774 if (!owner.CheckBoxes)
2776 List.CopyTo (dest, index);
2779 public IEnumerator GetEnumerator ()
2781 if (!owner.CheckBoxes)
2782 return (new ListViewItem [0]).GetEnumerator ();
2783 return List.GetEnumerator ();
2786 int IList.Add (object value)
2788 throw new NotSupportedException ("Add operation is not supported.");
2793 throw new NotSupportedException ("Clear operation is not supported.");
2796 bool IList.Contains (object item)
2798 if (!(item is ListViewItem))
2800 return Contains ((ListViewItem) item);
2803 int IList.IndexOf (object item)
2805 if (!(item is ListViewItem))
2807 return IndexOf ((ListViewItem) item);
2810 void IList.Insert (int index, object value)
2812 throw new NotSupportedException ("Insert operation is not supported.");
2815 void IList.Remove (object value)
2817 throw new NotSupportedException ("Remove operation is not supported.");
2820 void IList.RemoveAt (int index)
2822 throw new NotSupportedException ("RemoveAt operation is not supported.");
2825 public int IndexOf (ListViewItem item)
2827 if (!owner.CheckBoxes)
2829 return List.IndexOf (item);
2833 public virtual int IndexOfKey (string key)
2835 if (key == null || key.Length == 0)
2838 ArrayList checked_items = List;
2839 for (int i = 0; i < checked_items.Count; i++) {
2840 ListViewItem item = (ListViewItem) checked_items [i];
2841 if (String.Compare (key, item.Name, true) == 0)
2848 #endregion // Public Methods
2850 internal ArrayList List {
2853 list = new ArrayList ();
2854 foreach (ListViewItem item in owner.Items) {
2863 internal void Reset ()
2865 // force re-population of list
2869 private void ItemsCollection_Changed ()
2873 } // CheckedListViewItemCollection
2875 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2877 internal ArrayList list;
2878 private ListView owner;
2880 #region Public Constructor
2881 public ColumnHeaderCollection (ListView owner)
2883 list = new ArrayList ();
2886 #endregion // Public Constructor
2888 #region Public Properties
2891 get { return list.Count; }
2894 public bool IsReadOnly {
2895 get { return false; }
2898 public virtual ColumnHeader this [int index] {
2900 if (index < 0 || index >= list.Count)
2901 throw new ArgumentOutOfRangeException ("index");
2902 return (ColumnHeader) list [index];
2907 public virtual ColumnHeader this [string key] {
2909 int idx = IndexOfKey (key);
2913 return (ColumnHeader) list [idx];
2918 bool ICollection.IsSynchronized {
2919 get { return true; }
2922 object ICollection.SyncRoot {
2923 get { return this; }
2926 bool IList.IsFixedSize {
2927 get { return list.IsFixedSize; }
2930 object IList.this [int index] {
2931 get { return this [index]; }
2932 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2934 #endregion // Public Properties
2936 #region Public Methods
2937 public virtual int Add (ColumnHeader value)
2940 value.SetListView (this.owner);
2941 idx = list.Add (value);
2942 if (owner.IsHandleCreated) {
2943 owner.Redraw (true);
2948 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2950 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2951 this.Add (colHeader);
2956 public virtual ColumnHeader Add (string text)
2958 return Add (String.Empty, text);
2961 public virtual ColumnHeader Add (string text, int iwidth)
2963 return Add (String.Empty, text, iwidth);
2966 public virtual ColumnHeader Add (string key, string text)
2968 ColumnHeader colHeader = new ColumnHeader ();
2969 colHeader.Name = key;
2970 colHeader.Text = text;
2975 public virtual ColumnHeader Add (string key, string text, int iwidth)
2977 return Add (key, text, iwidth, HorizontalAlignment.Left, -1);
2980 public virtual ColumnHeader Add (string key, string text, int iwidth, HorizontalAlignment textAlign, int imageIndex)
2982 ColumnHeader colHeader = new ColumnHeader (key, text, iwidth, textAlign);
2983 colHeader.ImageIndex = imageIndex;
2988 public virtual ColumnHeader Add (string key, string text, int iwidth, HorizontalAlignment textAlign, string imageKey)
2990 ColumnHeader colHeader = new ColumnHeader (key, text, iwidth, textAlign);
2991 colHeader.ImageKey = imageKey;
2997 public virtual void AddRange (ColumnHeader [] values)
2999 foreach (ColumnHeader colHeader in values) {
3000 colHeader.SetListView (this.owner);
3004 owner.Redraw (true);
3007 public virtual void Clear ()
3010 owner.Redraw (true);
3013 public bool Contains (ColumnHeader value)
3015 return list.Contains (value);
3019 public virtual bool ContainsKey (string key)
3021 return IndexOfKey (key) != -1;
3025 public IEnumerator GetEnumerator ()
3027 return list.GetEnumerator ();
3030 void ICollection.CopyTo (Array dest, int index)
3032 list.CopyTo (dest, index);
3035 int IList.Add (object value)
3037 if (! (value is ColumnHeader)) {
3038 throw new ArgumentException ("Not of type ColumnHeader", "value");
3041 return this.Add ((ColumnHeader) value);
3044 bool IList.Contains (object value)
3046 if (! (value is ColumnHeader)) {
3047 throw new ArgumentException ("Not of type ColumnHeader", "value");
3050 return this.Contains ((ColumnHeader) value);
3053 int IList.IndexOf (object value)
3055 if (! (value is ColumnHeader)) {
3056 throw new ArgumentException ("Not of type ColumnHeader", "value");
3059 return this.IndexOf ((ColumnHeader) value);
3062 void IList.Insert (int index, object value)
3064 if (! (value is ColumnHeader)) {
3065 throw new ArgumentException ("Not of type ColumnHeader", "value");
3068 this.Insert (index, (ColumnHeader) value);
3071 void IList.Remove (object value)
3073 if (! (value is ColumnHeader)) {
3074 throw new ArgumentException ("Not of type ColumnHeader", "value");
3077 this.Remove ((ColumnHeader) value);
3080 public int IndexOf (ColumnHeader value)
3082 return list.IndexOf (value);
3086 public virtual int IndexOfKey (string key)
3088 if (key == null || key.Length == 0)
3091 for (int i = 0; i < list.Count; i++) {
3092 ColumnHeader col = (ColumnHeader) list [i];
3093 if (String.Compare (key, col.Name, true) == 0)
3101 public void Insert (int index, ColumnHeader value)
3103 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
3104 // but it's really only greater.
3105 if (index < 0 || index > list.Count)
3106 throw new ArgumentOutOfRangeException ("index");
3108 value.SetListView (owner);
3109 list.Insert (index, value);
3110 owner.Redraw (true);
3114 public void Insert (int index, string text)
3116 Insert (index, String.Empty, text);
3119 public void Insert (int index, string text, int width)
3121 Insert (index, String.Empty, text, width);
3124 public void Insert (int index, string key, string text)
3126 ColumnHeader colHeader = new ColumnHeader ();
3127 colHeader.Name = key;
3128 colHeader.Text = text;
3129 Insert (index, colHeader);
3132 public void Insert (int index, string key, string text, int width)
3134 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
3135 Insert (index, colHeader);
3138 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
3140 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
3141 colHeader.ImageIndex = imageIndex;
3142 Insert (index, colHeader);
3145 public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
3147 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
3148 colHeader.ImageKey = imageKey;
3149 Insert (index, colHeader);
3153 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
3155 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
3156 this.Insert (index, colHeader);
3159 public virtual void Remove (ColumnHeader column)
3161 // TODO: Update Column internal index ?
3162 list.Remove (column);
3163 owner.Redraw (true);
3167 public virtual void RemoveByKey (string key)
3169 int idx = IndexOfKey (key);
3175 public virtual void RemoveAt (int index)
3177 if (index < 0 || index >= list.Count)
3178 throw new ArgumentOutOfRangeException ("index");
3180 // TODO: Update Column internal index ?
3181 list.RemoveAt (index);
3182 owner.Redraw (true);
3184 #endregion // Public Methods
3187 } // ColumnHeaderCollection
3189 public class ListViewItemCollection : IList, ICollection, IEnumerable
3191 private readonly ArrayList list;
3192 private readonly ListView owner;
3194 #region Public Constructor
3195 public ListViewItemCollection (ListView owner)
3197 list = new ArrayList ();
3200 #endregion // Public Constructor
3202 #region Public Properties
3205 get { return list.Count; }
3208 public bool IsReadOnly {
3209 get { return false; }
3212 public virtual ListViewItem this [int displayIndex] {
3214 if (displayIndex < 0 || displayIndex >= list.Count)
3215 throw new ArgumentOutOfRangeException ("displayIndex");
3216 return (ListViewItem) list [displayIndex];
3220 if (displayIndex < 0 || displayIndex >= list.Count)
3221 throw new ArgumentOutOfRangeException ("displayIndex");
3223 if (list.Contains (value))
3224 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
3226 if (value.ListView != null && value.ListView != owner)
3227 throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value");
3229 value.Owner = owner;
3230 list [displayIndex] = value;
3233 owner.Redraw (true);
3238 public virtual ListViewItem this [string key] {
3240 int idx = IndexOfKey (key);
3244 return (ListViewItem) list [idx];
3249 bool ICollection.IsSynchronized {
3250 get { return true; }
3253 object ICollection.SyncRoot {
3254 get { return this; }
3257 bool IList.IsFixedSize {
3258 get { return list.IsFixedSize; }
3261 object IList.this [int index] {
3262 get { return this [index]; }
3264 if (value is ListViewItem)
3265 this [index] = (ListViewItem) value;
3267 this [index] = new ListViewItem (value.ToString ());
3271 #endregion // Public Properties
3273 #region Public Methods
3274 public virtual ListViewItem Add (ListViewItem value)
3276 if (list.Contains (value))
3277 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
3279 if (value.ListView != null && value.ListView != owner)
3280 throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value");
3282 value.Owner = owner;
3285 if (this.owner != null)
3289 owner.Redraw (true);
3295 public virtual ListViewItem Add (string text)
3297 ListViewItem item = new ListViewItem (text);
3298 return this.Add (item);
3301 public virtual ListViewItem Add (string text, int imageIndex)
3303 ListViewItem item = new ListViewItem (text, imageIndex);
3304 return this.Add (item);
3308 public virtual ListViewItem Add (string text, string imageKey)
3310 ListViewItem item = new ListViewItem (text, imageKey);
3311 return this.Add (item);
3314 public virtual ListViewItem Add (string key, string text, int imageIndex)
3316 ListViewItem item = new ListViewItem (text, imageIndex);
3318 return this.Add (item);
3321 public virtual ListViewItem Add (string key, string text, string imageKey)
3323 ListViewItem item = new ListViewItem (text, imageKey);
3325 return this.Add (item);
3329 public void AddRange (ListViewItem [] values)
3332 throw new ArgumentNullException ("Argument cannot be null!", "values");
3334 foreach (ListViewItem item in values) {
3340 public void AddRange (ListViewItemCollection items)
3343 throw new ArgumentNullException ("Argument cannot be null!", "items");
3345 ListViewItem[] itemArray = new ListViewItem[items.Count];
3346 items.CopyTo (itemArray,0);
3347 this.AddRange (itemArray);
3351 public virtual void Clear ()
3353 owner.SetFocusedItem (null);
3354 owner.h_scroll.Value = owner.v_scroll.Value = 0;
3357 owner.Redraw (true);
3360 public bool Contains (ListViewItem item)
3362 return list.Contains (item);
3366 public virtual bool ContainsKey (string key)
3368 return IndexOfKey (key) != -1;
3372 public void CopyTo (Array dest, int index)
3374 list.CopyTo (dest, index);
3378 public ListViewItem [] Find (string key, bool searchAllSubitems)
3381 return new ListViewItem [0];
3383 List<ListViewItem> temp_list = new List<ListViewItem> ();
3385 for (int i = 0; i < list.Count; i++) {
3386 ListViewItem lvi = (ListViewItem) list [i];
3387 if (String.Compare (key, lvi.Name, true) == 0)
3388 temp_list.Add (lvi);
3391 ListViewItem [] retval = new ListViewItem [temp_list.Count];
3392 temp_list.CopyTo (retval);
3398 public IEnumerator GetEnumerator ()
3400 return list.GetEnumerator ();
3403 int IList.Add (object item)
3408 if (item is ListViewItem) {
3409 li = (ListViewItem) item;
3410 if (list.Contains (li))
3411 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3413 if (li.ListView != null && li.ListView != owner)
3414 throw new ArgumentException ("Cannot add or insert the item '" + li.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item");
3417 li = new ListViewItem (item.ToString ());
3420 result = list.Add (li);
3422 owner.Redraw (true);
3427 bool IList.Contains (object item)
3429 return list.Contains (item);
3432 int IList.IndexOf (object item)
3434 return list.IndexOf (item);
3437 void IList.Insert (int index, object item)
3439 if (item is ListViewItem)
3440 this.Insert (index, (ListViewItem) item);
3442 this.Insert (index, item.ToString ());
3445 void IList.Remove (object item)
3447 Remove ((ListViewItem) item);
3450 public int IndexOf (ListViewItem item)
3452 return list.IndexOf (item);
3456 public virtual int IndexOfKey (string key)
3458 if (key == null || key.Length == 0)
3461 for (int i = 0; i < list.Count; i++) {
3462 ListViewItem lvi = (ListViewItem) list [i];
3463 if (String.Compare (key, lvi.Name, true) == 0)
3471 public ListViewItem Insert (int index, ListViewItem item)
3473 if (index < 0 || index > list.Count)
3474 throw new ArgumentOutOfRangeException ("index");
3476 if (list.Contains (item))
3477 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3479 if (item.ListView != null && item.ListView != owner)
3480 throw new ArgumentException ("Cannot add or insert the item '" + item.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item");
3483 list.Insert (index, item);
3485 owner.Redraw (true);
3489 public ListViewItem Insert (int index, string text)
3491 return this.Insert (index, new ListViewItem (text));
3494 public ListViewItem Insert (int index, string text, int imageIndex)
3496 return this.Insert (index, new ListViewItem (text, imageIndex));
3500 public ListViewItem Insert (int index, string key, string text, int imageIndex)
3502 ListViewItem lvi = new ListViewItem (text, imageIndex);
3504 return Insert (index, lvi);
3508 public virtual void Remove (ListViewItem item)
3510 if (!list.Contains (item))
3513 bool selection_changed = owner.SelectedItems.Contains (item);
3516 owner.Redraw (true);
3517 if (selection_changed)
3518 owner.OnSelectedIndexChanged (EventArgs.Empty);
3521 public virtual void RemoveAt (int index)
3523 if (index < 0 || index >= Count)
3524 throw new ArgumentOutOfRangeException ("index");
3525 bool selection_changed = owner.SelectedIndices.Contains (index);
3526 list.RemoveAt (index);
3528 owner.Redraw (false);
3529 if (selection_changed)
3530 owner.OnSelectedIndexChanged (EventArgs.Empty);
3534 public virtual void RemoveByKey (string key)
3536 int idx = IndexOfKey (key);
3542 #endregion // Public Methods
3544 internal event CollectionChangedHandler Changed;
3546 internal void Sort (IComparer comparer)
3548 list.Sort (comparer);
3552 internal void OnChange ()
3554 if (Changed != null)
3557 } // ListViewItemCollection
3559 public class SelectedIndexCollection : IList, ICollection, IEnumerable
3561 private readonly ListView owner;
3563 #region Public Constructor
3564 public SelectedIndexCollection (ListView owner)
3568 #endregion // Public Constructor
3570 #region Public Properties
3574 return owner.SelectedItems.Count;
3578 public bool IsReadOnly {
3588 public int this [int index] {
3590 int [] indices = GetIndices ();
3591 if (index < 0 || index >= indices.Length)
3592 throw new ArgumentOutOfRangeException ("index");
3593 return indices [index];
3597 bool ICollection.IsSynchronized {
3598 get { return false; }
3601 object ICollection.SyncRoot {
3602 get { return this; }
3605 bool IList.IsFixedSize {
3615 object IList.this [int index] {
3616 get { return this [index]; }
3617 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3619 #endregion // Public Properties
3621 #region Public Methods
3623 public int Add (int itemIndex)
3625 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
3626 throw new ArgumentOutOfRangeException ("index");
3628 owner.Items [itemIndex].Selected = true;
3629 if (!owner.IsHandleCreated)
3632 return owner.SelectedItems.Count;
3635 public void Clear ()
3637 owner.SelectedItems.Clear ();
3640 public bool Contains (int selectedIndex)
3642 int [] indices = GetIndices ();
3643 for (int i = 0; i < indices.Length; i++) {
3644 if (indices [i] == selectedIndex)
3650 public void CopyTo (Array dest, int index)
3652 int [] indices = GetIndices ();
3653 Array.Copy (indices, 0, dest, index, indices.Length);
3656 public IEnumerator GetEnumerator ()
3658 int [] indices = GetIndices ();
3659 return indices.GetEnumerator ();
3662 int IList.Add (object value)
3664 throw new NotSupportedException ("Add operation is not supported.");
3669 throw new NotSupportedException ("Clear operation is not supported.");
3672 bool IList.Contains (object selectedIndex)
3674 if (!(selectedIndex is int))
3676 return Contains ((int) selectedIndex);
3679 int IList.IndexOf (object selectedIndex)
3681 if (!(selectedIndex is int))
3683 return IndexOf ((int) selectedIndex);
3686 void IList.Insert (int index, object value)
3688 throw new NotSupportedException ("Insert operation is not supported.");
3691 void IList.Remove (object value)
3693 throw new NotSupportedException ("Remove operation is not supported.");
3696 void IList.RemoveAt (int index)
3698 throw new NotSupportedException ("RemoveAt operation is not supported.");
3701 public int IndexOf (int selectedIndex)
3703 int [] indices = GetIndices ();
3704 for (int i = 0; i < indices.Length; i++) {
3705 if (indices [i] == selectedIndex)
3712 public void Remove (int itemIndex)
3714 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
3715 throw new ArgumentOutOfRangeException ("itemIndex");
3717 owner.Items [itemIndex].Selected = false;
3720 #endregion // Public Methods
3722 private int [] GetIndices ()
3724 ArrayList selected_items = owner.SelectedItems.List;
3725 int [] indices = new int [selected_items.Count];
3726 for (int i = 0; i < selected_items.Count; i++) {
3727 ListViewItem item = (ListViewItem) selected_items [i];
3728 indices [i] = item.Index;
3732 } // SelectedIndexCollection
3734 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
3736 private readonly ListView owner;
3737 private ArrayList list;
3739 #region Public Constructor
3740 public SelectedListViewItemCollection (ListView owner)
3743 this.owner.Items.Changed += new CollectionChangedHandler (
3744 ItemsCollection_Changed);
3746 #endregion // Public Constructor
3748 #region Public Properties
3752 if (!owner.IsHandleCreated)
3758 public bool IsReadOnly {
3759 get { return true; }
3762 public ListViewItem this [int index] {
3764 ArrayList selected_items = List;
3765 if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
3766 throw new ArgumentOutOfRangeException ("index");
3767 return (ListViewItem) selected_items [index];
3772 public virtual ListViewItem this [string key] {
3774 int idx = IndexOfKey (key);
3778 return (ListViewItem) List [idx];
3783 bool ICollection.IsSynchronized {
3784 get { return false; }
3787 object ICollection.SyncRoot {
3788 get { return this; }
3791 bool IList.IsFixedSize {
3792 get { return true; }
3795 object IList.this [int index] {
3796 get { return this [index]; }
3797 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3799 #endregion // Public Properties
3801 #region Public Methods
3802 public void Clear ()
3804 if (!owner.IsHandleCreated)
3807 foreach (ListViewItem item in List)
3808 item.Selected = false;
3811 public bool Contains (ListViewItem item)
3813 if (!owner.IsHandleCreated)
3815 return List.Contains (item);
3819 public virtual bool ContainsKey (string key)
3821 return IndexOfKey (key) != -1;
3825 public void CopyTo (Array dest, int index)
3827 if (!owner.IsHandleCreated)
3829 List.CopyTo (dest, index);
3832 public IEnumerator GetEnumerator ()
3834 if (!owner.IsHandleCreated)
3835 return (new ListViewItem [0]).GetEnumerator ();
3836 return List.GetEnumerator ();
3839 int IList.Add (object value)
3841 throw new NotSupportedException ("Add operation is not supported.");
3844 bool IList.Contains (object item)
3846 if (!(item is ListViewItem))
3848 return Contains ((ListViewItem) item);
3851 int IList.IndexOf (object item)
3853 if (!(item is ListViewItem))
3855 return IndexOf ((ListViewItem) item);
3858 void IList.Insert (int index, object value)
3860 throw new NotSupportedException ("Insert operation is not supported.");
3863 void IList.Remove (object value)
3865 throw new NotSupportedException ("Remove operation is not supported.");
3868 void IList.RemoveAt (int index)
3870 throw new NotSupportedException ("RemoveAt operation is not supported.");
3873 public int IndexOf (ListViewItem item)
3875 if (!owner.IsHandleCreated)
3877 return List.IndexOf (item);
3881 public virtual int IndexOfKey (string key)
3883 if (!owner.IsHandleCreated || key == null || key.Length == 0)
3886 ArrayList selected_items = List;
3887 for (int i = 0; i < selected_items.Count; i++) {
3888 ListViewItem item = (ListViewItem) selected_items [i];
3889 if (String.Compare (item.Name, key, true) == 0)
3896 #endregion // Public Methods
3898 internal ArrayList List {
3901 list = new ArrayList ();
3902 foreach (ListViewItem item in owner.Items) {
3911 internal void Reset ()
3913 // force re-population of list
3917 private void ItemsCollection_Changed ()
3921 } // SelectedListViewItemCollection
3923 internal delegate void CollectionChangedHandler ();
3925 #endregion // Subclasses
3927 protected override void OnResize (EventArgs e)
3932 protected override void OnMouseLeave (EventArgs e)
3934 base.OnMouseLeave (e);
3938 // ColumnReorder event
3940 static object ColumnReorderedEvent = new object ();
3941 public event ColumnReorderedEventHandler ColumnReordered {
3942 add { Events.AddHandler (ColumnReorderedEvent, value); }
3943 remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
3946 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
3948 ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
3955 // ColumnWidthChanged
3957 static object ColumnWidthChangedEvent = new object ();
3958 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
3959 add { Events.AddHandler (ColumnWidthChangedEvent, value); }
3960 remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
3963 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
3965 ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
3970 void RaiseColumnWidthChanged (int resize_column)
3972 ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
3974 OnColumnWidthChanged (n);
3978 // ColumnWidthChanging
3980 static object ColumnWidthChangingEvent = new object ();
3981 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
3982 add { Events.AddHandler (ColumnWidthChangingEvent, value); }
3983 remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
3986 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
3988 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
3994 // 2.0 profile based implementation
3996 bool CanProceedWithResize (ColumnHeader col, int width)
3998 ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
4002 ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
4003 cwceh (this, changing);
4004 return !changing.Cancel;
4008 // 1.0 profile based implementation
4010 bool CanProceedWithResize (ColumnHeader col, int width)
4015 void RaiseColumnWidthChanged (int resize_column)