1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
23 // Ravindra Kumar (rkumar@novell.com)
24 // Jordi Mas i Hernandez, jordi@ximian.com
25 // Mike Kestner (mkestner@novell.com)
28 // - Feedback for item activation, change in cursor types as mouse moves.
37 using System.Collections;
38 using System.ComponentModel;
39 using System.ComponentModel.Design;
41 using System.Runtime.InteropServices;
42 using System.Globalization;
44 namespace System.Windows.Forms
46 [DefaultEvent ("SelectedIndexChanged")]
47 [DefaultProperty ("Items")]
48 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
49 public class ListView : Control
51 private ItemActivation activation = ItemActivation.Standard;
52 private ListViewAlignment alignment = ListViewAlignment.Top;
53 private bool allow_column_reorder = false;
54 private bool auto_arrange = true;
55 private bool check_boxes = false;
56 private CheckedIndexCollection checked_indices;
57 private CheckedListViewItemCollection checked_items;
58 private ColumnHeaderCollection columns;
59 internal ListViewItem focused_item;
60 private bool full_row_select = false;
61 private bool grid_lines = false;
62 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
63 private bool hide_selection = true;
64 private bool hover_selection = false;
65 private IComparer item_sorter;
66 private ListViewItemCollection items;
67 private bool label_edit = false;
68 private bool label_wrap = true;
69 private bool multiselect = true;
70 private bool scrollable = true;
71 private SelectedIndexCollection selected_indices;
72 private SelectedListViewItemCollection selected_items;
73 private SortOrder sort_order = SortOrder.None;
74 private ImageList state_image_list;
75 private bool updating = false;
76 private View view = View.LargeIcon;
77 private int layout_wd; // We might draw more than our client area
78 private int layout_ht; // therefore we need to have these two.
79 //private TextBox editor; // Used for editing an item text
80 HeaderControl header_control;
81 internal ItemControl item_control;
82 internal ScrollBar h_scroll; // used for scrolling horizontally
83 internal ScrollBar v_scroll; // used for scrolling vertically
84 internal int h_marker; // Position markers for scrolling
85 internal int v_marker;
86 private int keysearch_tickcnt;
87 private string keysearch_text;
88 static private readonly int keysearch_keydelay = 1000;
89 private int[] reordered_column_indices;
92 internal ImageList large_image_list;
93 internal ImageList small_image_list;
94 internal Size text_size = Size.Empty;
97 public event LabelEditEventHandler AfterLabelEdit;
100 [EditorBrowsable (EditorBrowsableState.Never)]
101 public new event EventHandler BackgroundImageChanged {
102 add { base.BackgroundImageChanged += value; }
103 remove { base.BackgroundImageChanged -= value; }
106 public event LabelEditEventHandler BeforeLabelEdit;
107 public event ColumnClickEventHandler ColumnClick;
108 public event EventHandler ItemActivate;
109 public event ItemCheckEventHandler ItemCheck;
110 public event ItemDragEventHandler ItemDrag;
113 [EditorBrowsable (EditorBrowsableState.Never)]
114 public new event PaintEventHandler Paint {
115 add { base.Paint += value; }
116 remove { base.Paint -= value; }
119 public event EventHandler SelectedIndexChanged;
122 [EditorBrowsable (EditorBrowsableState.Never)]
123 public new event EventHandler TextChanged {
124 add { base.TextChanged += value; }
125 remove { base.TextChanged -= value; }
130 #region Public Constructors
133 background_color = ThemeEngine.Current.ColorWindow;
134 checked_indices = new CheckedIndexCollection (this);
135 checked_items = new CheckedListViewItemCollection (this);
136 columns = new ColumnHeaderCollection (this);
137 foreground_color = SystemColors.WindowText;
138 items = new ListViewItemCollection (this);
139 selected_indices = new SelectedIndexCollection (this);
140 selected_items = new SelectedListViewItemCollection (this);
142 border_style = BorderStyle.Fixed3D;
144 header_control = new HeaderControl (this);
145 header_control.Visible = false;
146 item_control = new ItemControl (this);
147 item_control.Visible = true;
149 h_scroll = new HScrollBar ();
150 v_scroll = new VScrollBar ();
151 h_marker = v_marker = 0;
152 keysearch_tickcnt = 0;
154 // scroll bars are disabled initially
155 h_scroll.Visible = false;
156 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
157 v_scroll.Visible = false;
158 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
161 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
162 base.Paint += new PaintEventHandler (ListView_Paint);
163 SizeChanged += new EventHandler (ListView_SizeChanged);
165 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
167 #endregion // Public Constructors
169 #region Private Internal Properties
170 internal Size CheckBoxSize {
172 if (this.check_boxes) {
173 if (this.state_image_list != null)
174 return this.state_image_list.ImageSize;
176 return ThemeEngine.Current.ListViewCheckBoxSize;
182 internal bool CanMultiselect {
184 if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
191 #endregion // Private Internal Properties
193 #region Protected Properties
194 protected override CreateParams CreateParams {
195 get { return base.CreateParams; }
198 protected override Size DefaultSize {
199 get { return ThemeEngine.Current.ListViewDefaultSize; }
201 #endregion // Protected Properties
203 #region Public Instance Properties
204 [DefaultValue (ItemActivation.Standard)]
205 public ItemActivation Activation {
206 get { return activation; }
208 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
209 value != ItemActivation.TwoClick) {
210 throw new InvalidEnumArgumentException (string.Format
211 ("Enum argument value '{0}' is not valid for Activation", value));
218 [DefaultValue (ListViewAlignment.Top)]
220 public ListViewAlignment Alignment {
221 get { return alignment; }
223 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
224 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
225 throw new InvalidEnumArgumentException (string.Format
226 ("Enum argument value '{0}' is not valid for Alignment", value));
229 if (this.alignment != value) {
231 // alignment does not matter in Details/List views
232 if (this.view == View.LargeIcon ||
233 this.View == View.SmallIcon)
239 [DefaultValue (false)]
240 public bool AllowColumnReorder {
241 get { return allow_column_reorder; }
242 set { allow_column_reorder = value; }
245 [DefaultValue (true)]
246 public bool AutoArrange {
247 get { return auto_arrange; }
249 if (auto_arrange != value) {
250 auto_arrange = value;
251 // autoarrange does not matter in Details/List views
252 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
258 public override Color BackColor {
260 if (background_color.IsEmpty)
261 return ThemeEngine.Current.ColorWindow;
263 return background_color;
265 set { background_color = value; }
269 [EditorBrowsable (EditorBrowsableState.Never)]
270 public override Image BackgroundImage {
271 get { return background_image; }
273 if (value == background_image)
276 background_image = value;
277 OnBackgroundImageChanged (EventArgs.Empty);
281 [DefaultValue (BorderStyle.Fixed3D)]
283 public BorderStyle BorderStyle {
284 get { return InternalBorderStyle; }
285 set { InternalBorderStyle = value; }
288 [DefaultValue (false)]
289 public bool CheckBoxes {
290 get { return check_boxes; }
292 if (check_boxes != value) {
300 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
301 public CheckedIndexCollection CheckedIndices {
302 get { return checked_indices; }
306 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
307 public CheckedListViewItemCollection CheckedItems {
308 get { return checked_items; }
311 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
313 [MergableProperty (false)]
314 public ColumnHeaderCollection Columns {
315 get { return columns; }
319 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
320 public ListViewItem FocusedItem {
322 if (focused_item == null && Focused && items.Count > 0)
323 focused_item = items [0];
328 public override Color ForeColor {
330 if (foreground_color.IsEmpty)
331 return ThemeEngine.Current.ColorWindowText;
333 return foreground_color;
335 set { foreground_color = value; }
338 [DefaultValue (false)]
339 public bool FullRowSelect {
340 get { return full_row_select; }
341 set { full_row_select = value; }
344 [DefaultValue (false)]
345 public bool GridLines {
346 get { return grid_lines; }
348 if (grid_lines != value) {
355 [DefaultValue (ColumnHeaderStyle.Clickable)]
356 public ColumnHeaderStyle HeaderStyle {
357 get { return header_style; }
359 if (header_style == value)
363 case ColumnHeaderStyle.Clickable:
364 case ColumnHeaderStyle.Nonclickable:
365 case ColumnHeaderStyle.None:
368 throw new InvalidEnumArgumentException (string.Format
369 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
372 header_style = value;
373 if (view == View.Details)
378 [DefaultValue (true)]
379 public bool HideSelection {
380 get { return hide_selection; }
382 if (hide_selection != value) {
383 hide_selection = value;
389 [DefaultValue (false)]
390 public bool HoverSelection {
391 get { return hover_selection; }
392 set { hover_selection = value; }
395 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
397 [MergableProperty (false)]
398 public ListViewItemCollection Items {
399 get { return items; }
402 [DefaultValue (false)]
403 public bool LabelEdit {
404 get { return label_edit; }
405 set { label_edit = value; }
408 [DefaultValue (true)]
410 public bool LabelWrap {
411 get { return label_wrap; }
413 if (label_wrap != value) {
420 [DefaultValue (null)]
421 public ImageList LargeImageList {
422 get { return large_image_list; }
424 large_image_list = value;
430 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
431 public IComparer ListViewItemSorter {
432 get { return item_sorter; }
433 set { item_sorter = value; }
436 [DefaultValue (true)]
437 public bool MultiSelect {
438 get { return multiselect; }
439 set { multiselect = value; }
442 [DefaultValue (true)]
443 public bool Scrollable {
444 get { return scrollable; }
446 if (scrollable != value) {
454 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
455 public SelectedIndexCollection SelectedIndices {
456 get { return selected_indices; }
460 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
461 public SelectedListViewItemCollection SelectedItems {
462 get { return selected_items; }
465 [DefaultValue (null)]
466 public ImageList SmallImageList {
467 get { return small_image_list; }
469 small_image_list = value;
474 [DefaultValue (SortOrder.None)]
475 public SortOrder Sorting {
476 get { return sort_order; }
478 if (value != SortOrder.Ascending && value != SortOrder.Descending &&
479 value != SortOrder.None) {
480 throw new InvalidEnumArgumentException (string.Format
481 ("Enum argument value '{0}' is not valid for Sorting", value));
484 if (sort_order != value) {
491 [DefaultValue (null)]
492 public ImageList StateImageList {
493 get { return state_image_list; }
495 state_image_list = value;
502 [EditorBrowsable (EditorBrowsableState.Never)]
503 public override string Text {
512 OnTextChanged (EventArgs.Empty);
517 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
518 public ListViewItem TopItem {
521 if (this.items.Count == 0)
523 // if contents are not scrolled
524 // it is the first item
525 else if (h_marker == 0 && v_marker == 0)
526 return this.items [0];
527 // do a hit test for the scrolled position
529 foreach (ListViewItem item in this.items) {
530 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
538 [DefaultValue (View.LargeIcon)]
542 if (value != View.Details && value != View.LargeIcon &&
543 value != View.List && value != View.SmallIcon ) {
544 throw new InvalidEnumArgumentException (string.Format
545 ("Enum argument value '{0}' is not valid for View", value));
549 h_scroll.Value = v_scroll.Value = 0;
555 #endregion // Public Instance Properties
557 #region Internal Methods Properties
559 internal int FirstVisibleIndex {
562 if (this.items.Count == 0)
565 if (h_marker == 0 && v_marker == 0)
568 foreach (ListViewItem item in this.items) {
569 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
578 internal int LastVisibleIndex {
580 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
581 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
585 return Items.Count - 1;
589 internal int TotalWidth {
590 get { return Math.Max (this.Width, this.layout_wd); }
593 internal int TotalHeight {
594 get { return Math.Max (this.Height, this.layout_ht); }
597 internal void Redraw (bool recalculate)
599 // Avoid calculations when control is being updated
604 CalculateListView (this.alignment);
609 internal Size GetChildColumnSize (int index)
611 Size ret_size = Size.Empty;
612 ColumnHeader col = this.columns [index];
614 if (col.Width == -2) { // autosize = max(items, columnheader)
615 Size size = Size.Ceiling (this.DeviceContext.MeasureString
616 (col.Text, this.Font));
617 ret_size = BiggestItem (index);
618 if (size.Width > ret_size.Width)
621 else { // -1 and all the values < -2 are put under one category
622 ret_size = BiggestItem (index);
623 // fall back to empty columns' width if no subitem is available for a column
624 if (ret_size.IsEmpty) {
625 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
626 if (col.Text.Length > 0)
627 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
628 (col.Text, this.Font)).Height;
630 ret_size.Height = this.Font.Height;
634 // adjust the size for icon and checkbox for 0th column
636 ret_size.Width += (this.CheckBoxSize.Width + 4);
637 if (this.small_image_list != null)
638 ret_size.Width += this.small_image_list.ImageSize.Width;
643 // Returns the size of biggest item text in a column.
644 private Size BiggestItem (int col)
646 Size temp = Size.Empty;
647 Size ret_size = Size.Empty;
649 // 0th column holds the item text, we check the size of
650 // the various subitems falling in that column and get
651 // the biggest one's size.
652 foreach (ListViewItem item in items) {
653 if (col >= item.SubItems.Count)
656 temp = Size.Ceiling (this.DeviceContext.MeasureString
657 (item.SubItems [col].Text, this.Font));
658 if (temp.Width > ret_size.Width)
662 // adjustment for space
663 if (!ret_size.IsEmpty)
669 // Sets the size of the biggest item text as per the view
670 private void CalcTextSize ()
672 // clear the old value
673 text_size = Size.Empty;
675 if (items.Count == 0)
678 text_size = BiggestItem (0);
680 if (view == View.LargeIcon && this.label_wrap) {
681 Size temp = Size.Empty;
682 if (this.check_boxes)
683 temp.Width += 2 * this.CheckBoxSize.Width;
684 if (large_image_list != null)
685 temp.Width += large_image_list.ImageSize.Width;
688 // wrapping is done for two lines only
689 if (text_size.Width > temp.Width) {
690 text_size.Width = temp.Width;
691 text_size.Height *= 2;
694 else if (view == View.List) {
695 // in list view max text shown in determined by the
696 // control width, even if scolling is enabled.
697 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
698 if (this.small_image_list != null)
699 max_wd -= this.small_image_list.ImageSize.Width;
701 if (text_size.Width > max_wd)
702 text_size.Width = max_wd;
705 // we do the default settings, if we have got 0's
706 if (text_size.Height <= 0)
707 text_size.Height = this.Font.Height;
708 if (text_size.Width <= 0)
709 text_size.Width = this.Width;
712 text_size.Width += 4;
713 text_size.Height += 2;
716 private void Scroll (ScrollBar scrollbar, int delta)
718 if (delta == 0 || !scrollbar.Visible)
722 if (scrollbar == h_scroll)
723 max = h_scroll.Maximum - item_control.Width;
725 max = v_scroll.Maximum - item_control.Height;
727 int val = scrollbar.Value + delta;
730 else if (val < scrollbar.Minimum)
731 val = scrollbar.Minimum;
732 scrollbar.Value = val;
735 private void CalculateScrollBars ()
737 Rectangle client_area = ClientRectangle;
739 if (!this.scrollable || this.items.Count <= 0) {
740 h_scroll.Visible = false;
741 v_scroll.Visible = false;
745 // making a scroll bar visible might make
746 // other scroll bar visible
747 if (layout_wd > client_area.Right) {
748 h_scroll.Visible = true;
749 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
750 v_scroll.Visible = true;
752 v_scroll.Visible = false;
753 } else if (layout_ht > client_area.Bottom) {
754 v_scroll.Visible = true;
755 if ((layout_wd + v_scroll.Width) > client_area.Right)
756 h_scroll.Visible = true;
758 h_scroll.Visible = false;
760 h_scroll.Visible = false;
761 v_scroll.Visible = false;
764 item_control.Height = ClientRectangle.Height - header_control.Height;
766 if (h_scroll.Visible) {
767 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
768 h_scroll.Minimum = 0;
770 // if v_scroll is visible, adjust the maximum of the
771 // h_scroll to account for the width of v_scroll
772 if (v_scroll.Visible) {
773 h_scroll.Maximum = layout_wd + v_scroll.Width;
774 h_scroll.Width = client_area.Width - v_scroll.Width;
777 h_scroll.Maximum = layout_wd;
778 h_scroll.Width = client_area.Width;
781 h_scroll.LargeChange = client_area.Width;
782 h_scroll.SmallChange = Font.Height;
783 item_control.Height -= h_scroll.Height;
786 if (header_control.Visible)
787 header_control.Width = ClientRectangle.Width;
788 item_control.Width = ClientRectangle.Width;
790 if (v_scroll.Visible) {
791 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
792 v_scroll.Minimum = 0;
794 // if h_scroll is visible, adjust the maximum of the
795 // v_scroll to account for the height of h_scroll
796 if (h_scroll.Visible) {
797 v_scroll.Maximum = layout_ht + h_scroll.Height;
798 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
800 v_scroll.Maximum = layout_ht;
801 v_scroll.Height = client_area.Height;
804 v_scroll.LargeChange = client_area.Height;
805 v_scroll.SmallChange = Font.Height;
806 if (header_control.Visible)
807 header_control.Width -= v_scroll.Width;
808 item_control.Width -= v_scroll.Width;
812 ColumnHeader GetReorderedColumn (int index)
814 if (reordered_column_indices == null)
815 return Columns [index];
817 return Columns [reordered_column_indices [index]];
820 void ReorderColumn (ColumnHeader col, int index)
822 if (reordered_column_indices == null) {
823 reordered_column_indices = new int [Columns.Count];
824 for (int i = 0; i < Columns.Count; i++)
825 reordered_column_indices [i] = i;
828 if (reordered_column_indices [index] == col.Index)
831 int[] curr = reordered_column_indices;
832 int[] result = new int [Columns.Count];
834 for (int i = 0; i < Columns.Count; i++) {
835 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
839 result [i] = col.Index;
841 result [i] = curr [curr_idx++];
844 reordered_column_indices = result;
846 header_control.Invalidate ();
847 item_control.Invalidate ();
850 Size LargeIconItemSize {
852 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
853 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
854 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
855 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
856 return new Size (w, h);
860 Size SmallIconItemSize {
862 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
863 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
864 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
865 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
866 return new Size (w, h);
872 ListViewItem[,] item_matrix;
874 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
876 header_control.Visible = false;
877 header_control.Size = Size.Empty;
878 item_control.Location = Point.Empty;
880 if (items.Count == 0)
883 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
885 Rectangle area = ClientRectangle;
888 rows = (int) Math.Floor ((double)area.Height / (double)(sz.Height + y_spacing));
891 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
893 cols = (int) Math.Floor ((double)area.Width / (double)(sz.Width + x_spacing));
896 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
899 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
900 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
901 item_matrix = new ListViewItem [rows, cols];
904 foreach (ListViewItem item in items) {
905 int x = col * (sz.Width + x_spacing);
906 int y = row * (sz.Height + y_spacing);
907 item.Location = new Point (x, y);
911 item_matrix [row, col] = item;
925 item_control.Size = new Size (layout_wd, layout_ht);
930 if (columns.Count == 0 || header_style == ColumnHeaderStyle.None) {
931 header_control.Visible = false;
932 header_control.Size = Size.Empty;
937 for (int i = 0; i < Columns.Count; i++) {
938 ColumnHeader col = GetReorderedColumn (i);
941 col.CalcColumnHeader ();
945 header_control.Width = x;
946 header_control.Height = columns [0].Ht;
947 header_control.Visible = true;
950 void LayoutDetails ()
954 item_control.Location = new Point (0, header_control.Height);
957 if (items.Count > 0) {
958 foreach (ListViewItem item in items) {
960 item.Location = new Point (0, y);
961 y += item.Bounds.Height + 2;
964 // some space for bottom gridline
969 layout_wd = Math.Max (header_control.Width, item_control.Width);
970 layout_ht = y + header_control.Height;
973 private void CalculateListView (ListViewAlignment align)
983 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
987 LayoutIcons (true, alignment == ListViewAlignment.Left,
988 ThemeEngine.Current.ListViewHorizontalSpacing,
989 ThemeEngine.Current.ListViewVerticalSpacing);
993 LayoutIcons (false, true, 4, 2);
997 CalculateScrollBars ();
1000 internal void UpdateSelection (ListViewItem item)
1002 if (item.Selected) {
1004 if (!CanMultiselect && SelectedItems.Count > 0) {
1005 SelectedItems.Clear ();
1006 SelectedIndices.list.Clear ();
1009 if (!SelectedItems.Contains (item)) {
1010 SelectedItems.list.Add (item);
1011 SelectedIndices.list.Add (item.Index);
1014 SelectedItems.list.Remove (item);
1015 SelectedIndices.list.Remove (item.Index);
1019 private bool KeySearchString (KeyEventArgs ke)
1021 int current_tickcnt = Environment.TickCount;
1022 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1023 keysearch_text = string.Empty;
1026 keysearch_text += (char) ke.KeyData;
1027 keysearch_tickcnt = current_tickcnt;
1029 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1032 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1033 CompareOptions.IgnoreCase)) {
1034 SetFocusedItem (Items [i]);
1035 items [i].Selected = true;
1039 i = (i + 1 < Items.Count) ? i+1 : 0;
1047 int GetAdjustedIndex (Keys key)
1051 if (View == View.Details) {
1053 result = FocusedItem.Index - 1;
1054 else if (key == Keys.Down) {
1055 result = FocusedItem.Index + 1;
1056 if (result == items.Count)
1062 int row = FocusedItem.row;
1063 int col = FocusedItem.col;
1069 return item_matrix [row, col - 1].Index;
1072 if (col == (cols - 1))
1074 while (item_matrix [row, col + 1] == null)
1076 return item_matrix [row, col + 1].Index;
1081 return item_matrix [row - 1, col].Index;
1084 if (row == (rows - 1))
1086 while (item_matrix [row + 1, col] == null)
1088 return item_matrix [row + 1, col].Index;
1095 ListViewItem selection_start;
1097 private void SelectItems (ArrayList sel_items)
1099 SelectedItems.Clear ();
1100 SelectedIndices.list.Clear ();
1101 foreach (ListViewItem item in sel_items)
1102 item.Selected = true;
1105 private void UpdateMultiSelection (int index)
1107 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1108 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1109 ListViewItem item = items [index];
1111 if (shift_pressed && selection_start != null) {
1112 ArrayList list = new ArrayList ();
1113 int start = Math.Min (selection_start.Index, index);
1114 int end = Math.Max (selection_start.Index, index);
1115 if (View == View.Details) {
1116 for (int i = start; i <= end; i++)
1117 list.Add (items [i]);
1119 int left = Math.Min (items [start].col, items [end].col);
1120 int right = Math.Max (items [start].col, items [end].col);
1121 int top = Math.Min (items [start].row, items [end].row);
1122 int bottom = Math.Max (items [start].row, items [end].row);
1123 foreach (ListViewItem curr in items)
1124 if (curr.row >= top && curr.row <= bottom &&
1125 curr.col >= left && curr.col <= right)
1129 } else if (!ctrl_pressed) {
1130 SelectedItems.Clear ();
1131 SelectedIndices.list.Clear ();
1132 item.Selected = true;
1133 selection_start = item;
1137 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1139 if (ke.Handled || Items.Count == 0)
1145 switch (ke.KeyCode) {
1148 index = Items.Count - 1;
1159 index = GetAdjustedIndex (ke.KeyCode);
1163 ke.Handled = KeySearchString (ke);
1171 UpdateMultiSelection (index);
1173 items [index].Selected = true;
1175 SetFocusedItem (items [index]);
1176 EnsureVisible (index);
1180 internal class ItemControl : Control {
1183 ListViewItem clicked_item;
1184 ListViewItem last_clicked_item;
1185 bool hover_processed = false;
1187 public ItemControl (ListView owner)
1190 DoubleClick += new EventHandler(ItemsDoubleClick);
1191 KeyDown += new KeyEventHandler (ItemsKeyDown);
1192 KeyUp += new KeyEventHandler (ItemsKeyUp);
1193 MouseDown += new MouseEventHandler(ItemsMouseDown);
1194 MouseMove += new MouseEventHandler(ItemsMouseMove);
1195 MouseHover += new EventHandler(ItemsMouseHover);
1196 MouseUp += new MouseEventHandler(ItemsMouseUp);
1197 MouseWheel += new MouseEventHandler(ItemsMouseWheel);
1198 Paint += new PaintEventHandler (ItemsPaint);
1201 void ItemsDoubleClick (object sender, EventArgs e)
1203 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1204 owner.ItemActivate (this, e);
1207 void ItemsKeyDown (object sender, KeyEventArgs args)
1209 owner.OnKeyDown (args);
1212 void ItemsKeyUp (object sender, KeyEventArgs args)
1214 owner.OnKeyUp (args);
1217 private void ItemsMouseDown (object sender, MouseEventArgs me)
1219 if (owner.items.Count == 0)
1222 Point pt = new Point (me.X, me.Y);
1223 foreach (ListViewItem item in owner.items) {
1224 if (item.CheckRectReal.Contains (pt)) {
1225 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1226 item.Checked = !item.Checked;
1228 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1230 // Raise the ItemCheck event
1231 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1232 owner.OnItemCheck (ice);
1236 if (owner.View == View.Details && !owner.FullRowSelect) {
1237 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1238 clicked_item = item;
1242 if (item.Bounds.Contains (pt)) {
1243 clicked_item = item;
1249 owner.SetFocusedItem (clicked_item);
1251 if (clicked_item != null) {
1252 bool changed = !clicked_item.Selected;
1253 if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
1254 owner.UpdateMultiSelection (clicked_item.Index);
1256 clicked_item.Selected = true;
1259 owner.OnSelectedIndexChanged (EventArgs.Empty);
1261 // Raise double click if the item was clicked. On MS the
1262 // double click is only raised if you double click an item
1263 if (me.Clicks > 1 && clicked_item != null)
1264 owner.OnDoubleClick (EventArgs.Empty);
1265 else if (me.Clicks == 1 && clicked_item != null)
1266 owner.OnClick (EventArgs.Empty);
1267 } else if (owner.selected_indices.Count > 0) {
1268 // Raise the event if there was at least one item
1269 // selected and the user click on a dead area (unselecting all)
1270 owner.SelectedItems.Clear ();
1271 owner.SelectedIndices.list.Clear ();
1272 owner.OnSelectedIndexChanged (EventArgs.Empty);
1276 private void ItemsMouseMove (object sender, MouseEventArgs me)
1278 if (owner.HoverSelection && hover_processed) {
1280 Point pt = PointToClient (Control.MousePosition);
1281 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1282 if (item == null || item.Selected)
1285 hover_processed = false;
1286 XplatUI.ResetMouseHover (Handle);
1291 private void ItemsMouseHover (object sender, EventArgs e)
1293 if (Capture || !owner.HoverSelection)
1296 hover_processed = true;
1297 Point pt = PointToClient (Control.MousePosition);
1298 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1303 item.Selected = true;
1304 owner.OnSelectedIndexChanged (new EventArgs ());
1307 private void ItemsMouseUp (object sender, MouseEventArgs me)
1310 if (owner.Items.Count == 0)
1313 Point pt = new Point (me.X, me.Y);
1315 Rectangle rect = Rectangle.Empty;
1316 if (clicked_item != null) {
1317 if (owner.view == View.Details && !owner.full_row_select)
1318 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1320 rect = clicked_item.Bounds;
1322 if (rect.Contains (pt)) {
1323 switch (owner.activation) {
1324 case ItemActivation.OneClick:
1325 owner.OnItemActivate (EventArgs.Empty);
1328 case ItemActivation.TwoClick:
1329 if (last_clicked_item == clicked_item) {
1330 owner.OnItemActivate (EventArgs.Empty);
1331 last_clicked_item = null;
1333 last_clicked_item = clicked_item;
1336 // DoubleClick activation is handled in another handler
1342 clicked_item = null;
1345 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1347 if (owner.Items.Count == 0)
1350 int lines = me.Delta / 120;
1355 switch (owner.View) {
1357 case View.SmallIcon:
1358 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1360 case View.LargeIcon:
1361 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1364 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1369 private void ItemsPaint (object sender, PaintEventArgs pe)
1371 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1375 private void ListView_Paint (object sender, PaintEventArgs pe)
1377 if (Width <= 0 || Height <= 0 || !Visible || updating)
1380 CalculateScrollBars ();
1383 private void ListView_SizeChanged (object sender, EventArgs e)
1385 CalculateListView (alignment);
1388 private void SetFocusedItem (ListViewItem item)
1390 if (focused_item != null)
1391 focused_item.Focused = false;
1394 item.Focused = true;
1396 focused_item = item;
1399 private void HorizontalScroller (object sender, EventArgs e)
1401 // Avoid unnecessary flickering, when button is
1402 // kept pressed at the end
1403 if (h_marker != h_scroll.Value) {
1405 int pixels = h_marker - h_scroll.Value;
1407 h_marker = h_scroll.Value;
1408 if (header_control.Visible)
1409 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1411 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1415 private void VerticalScroller (object sender, EventArgs e)
1417 // Avoid unnecessary flickering, when button is
1418 // kept pressed at the end
1419 if (v_marker != v_scroll.Value) {
1420 int pixels = v_marker - v_scroll.Value;
1421 Rectangle area = item_control.ClientRectangle;
1422 v_marker = v_scroll.Value;
1423 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1426 #endregion // Internal Methods Properties
1428 #region Protected Methods
1429 protected override void CreateHandle ()
1431 base.CreateHandle ();
1434 protected override void Dispose (bool disposing)
1437 h_scroll.Dispose ();
1438 v_scroll.Dispose ();
1440 large_image_list = null;
1441 small_image_list = null;
1442 state_image_list = null;
1445 base.Dispose (disposing);
1448 protected override bool IsInputKey (Keys keyData)
1465 return base.IsInputKey (keyData);
1468 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1470 if (AfterLabelEdit != null)
1471 AfterLabelEdit (this, e);
1474 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1476 if (BeforeLabelEdit != null)
1477 BeforeLabelEdit (this, e);
1480 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1482 if (ColumnClick != null)
1483 ColumnClick (this, e);
1486 protected override void OnEnabledChanged (EventArgs e)
1488 base.OnEnabledChanged (e);
1491 protected override void OnFontChanged (EventArgs e)
1493 base.OnFontChanged (e);
1497 protected override void OnHandleCreated (EventArgs e)
1499 base.OnHandleCreated (e);
1501 Controls.AddImplicit (header_control);
1502 Controls.AddImplicit (item_control);
1503 Controls.AddImplicit (this.v_scroll);
1504 Controls.AddImplicit (this.h_scroll);
1508 protected override void OnHandleDestroyed (EventArgs e)
1510 base.OnHandleDestroyed (e);
1513 protected virtual void OnItemActivate (EventArgs e)
1515 if (ItemActivate != null)
1516 ItemActivate (this, e);
1519 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1521 if (ItemCheck != null)
1522 ItemCheck (this, ice);
1525 protected virtual void OnItemDrag (ItemDragEventArgs e)
1527 if (ItemDrag != null)
1531 protected virtual void OnSelectedIndexChanged (EventArgs e)
1533 if (SelectedIndexChanged != null)
1534 SelectedIndexChanged (this, e);
1537 protected override void OnSystemColorsChanged (EventArgs e)
1539 base.OnSystemColorsChanged (e);
1542 protected void RealizeProperties ()
1547 protected void UpdateExtendedStyles ()
1552 protected override void WndProc (ref Message m)
1554 base.WndProc (ref m);
1556 #endregion // Protected Methods
1558 #region Public Instance Methods
1559 public void ArrangeIcons ()
1561 ArrangeIcons (this.alignment);
1564 public void ArrangeIcons (ListViewAlignment alignment)
1566 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1567 if (view == View.LargeIcon || view == View.SmallIcon) {
1568 this.CalculateListView (alignment);
1569 // we have done the calculations already
1570 this.Redraw (false);
1574 public void BeginUpdate ()
1576 // flag to avoid painting
1580 public void Clear ()
1583 items.Clear (); // Redraw (true) called here
1586 public void EndUpdate ()
1588 // flag to avoid painting
1591 // probably, now we need a redraw with recalculations
1595 public void EnsureVisible (int index)
1597 if (index < 0 || index >= items.Count || scrollable == false)
1600 Rectangle view_rect = item_control.ClientRectangle;
1601 Rectangle bounds = items [index].Bounds;
1603 if (view_rect.Contains (bounds))
1606 if (bounds.Left < 0)
1607 h_scroll.Value += bounds.Left;
1608 else if (bounds.Right > view_rect.Right)
1609 h_scroll.Value += (bounds.Right - view_rect.Right);
1612 v_scroll.Value += bounds.Top;
1613 else if (bounds.Bottom > view_rect.Bottom)
1614 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1617 public ListViewItem GetItemAt (int x, int y)
1619 foreach (ListViewItem item in items) {
1620 if (item.Bounds.Contains (x, y))
1626 public Rectangle GetItemRect (int index)
1628 return GetItemRect (index, ItemBoundsPortion.Entire);
1631 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1633 if (index < 0 || index >= items.Count)
1634 throw new IndexOutOfRangeException ("Invalid Index");
1636 return items [index].GetBounds (portion);
1641 if (sort_order != SortOrder.None)
1642 items.list.Sort (item_sorter);
1644 if (sort_order == SortOrder.Descending)
1645 items.list.Reverse ();
1650 public override string ToString ()
1652 int count = this.Items.Count;
1655 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1657 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1659 #endregion // Public Instance Methods
1664 class HeaderControl : Control {
1667 bool column_resize_active = false;
1668 ColumnHeader resize_column;
1669 ColumnHeader clicked_column;
1670 ColumnHeader drag_column;
1672 int drag_to_index = -1;
1674 public HeaderControl (ListView owner)
1677 MouseDown += new MouseEventHandler (HeaderMouseDown);
1678 MouseMove += new MouseEventHandler (HeaderMouseMove);
1679 MouseUp += new MouseEventHandler (HeaderMouseUp);
1680 Paint += new PaintEventHandler (HeaderPaint);
1683 private ColumnHeader ColumnAtX (int x)
1685 Point pt = new Point (x, 0);
1686 ColumnHeader result = null;
1687 foreach (ColumnHeader col in owner.Columns) {
1688 if (col.Rect.Contains (pt)) {
1696 private int GetReorderedIndex (ColumnHeader col)
1698 if (owner.reordered_column_indices == null)
1701 for (int i = 0; i < owner.Columns.Count; i++)
1702 if (owner.reordered_column_indices [i] == col.Index)
1704 throw new Exception ("Column index missing from reordered array");
1707 private void HeaderMouseDown (object sender, MouseEventArgs me)
1709 if (resize_column != null) {
1710 column_resize_active = true;
1715 clicked_column = ColumnAtX (me.X + owner.h_marker);
1717 if (clicked_column != null) {
1719 if (owner.AllowColumnReorder) {
1721 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1722 drag_column.column_rect = clicked_column.Rect;
1723 drag_to_index = GetReorderedIndex (clicked_column);
1725 clicked_column.pressed = true;
1726 Rectangle bounds = clicked_column.Rect;
1727 bounds.X -= owner.h_marker;
1728 Invalidate (bounds);
1733 private void HeaderMouseMove (object sender, MouseEventArgs me)
1735 Point pt = new Point (me.X + owner.h_marker, me.Y);
1737 if (column_resize_active) {
1738 resize_column.Width = pt.X - resize_column.X;
1739 if (resize_column.Width < 0)
1740 resize_column.Width = 0;
1744 resize_column = null;
1746 if (clicked_column != null) {
1747 if (owner.AllowColumnReorder) {
1750 r = drag_column.column_rect;
1751 r.X = clicked_column.Rect.X + me.X - drag_x;
1752 drag_column.column_rect = r;
1754 int x = me.X + owner.h_marker;
1755 ColumnHeader over = ColumnAtX (x);
1756 if (x < over.X + over.Width / 2)
1757 drag_to_index = GetReorderedIndex (over);
1759 drag_to_index = GetReorderedIndex (over) + 1;
1762 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1763 bool pressed = clicked_column.pressed;
1764 clicked_column.pressed = over == clicked_column;
1765 if (clicked_column.pressed ^ pressed) {
1766 Rectangle bounds = clicked_column.Rect;
1767 bounds.X -= owner.h_marker;
1768 Invalidate (bounds);
1774 for (int i = 0; i < owner.Columns.Count; i++) {
1775 Rectangle zone = owner.Columns [i].Rect;
1776 zone.X = zone.Right - 5;
1778 if (zone.Contains (pt)) {
1779 resize_column = owner.Columns [i];
1784 if (resize_column == null)
1785 Cursor = Cursors.Default;
1787 Cursor = Cursors.VSplit;
1790 void HeaderMouseUp (object sender, MouseEventArgs me)
1794 if (column_resize_active) {
1795 column_resize_active = false;
1796 resize_column = null;
1797 Cursor = Cursors.Default;
1801 if (clicked_column != null && clicked_column.pressed) {
1802 clicked_column.pressed = false;
1803 Rectangle bounds = clicked_column.Rect;
1804 bounds.X -= owner.h_marker;
1805 Invalidate (bounds);
1806 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
1809 if (drag_column != null && owner.AllowColumnReorder) {
1811 if (drag_to_index > GetReorderedIndex (clicked_column))
1813 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
1814 owner.ReorderColumn (clicked_column, drag_to_index);
1819 clicked_column = null;
1822 void HeaderPaint (object sender, PaintEventArgs pe)
1824 if (Width <= 0 || Height <= 0 || !Visible || owner.updating)
1827 Theme theme = ThemeEngine.Current;
1828 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
1830 if (drag_column == null)
1834 if (drag_to_index == owner.Columns.Count)
1835 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
1837 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
1838 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
1843 public class CheckedIndexCollection : IList, ICollection, IEnumerable
1845 internal ArrayList list;
1846 private ListView owner;
1848 #region Public Constructor
1849 public CheckedIndexCollection (ListView owner)
1851 list = new ArrayList ();
1854 #endregion // Public Constructor
1856 #region Public Properties
1858 int ICollection.Count {
1859 get { return list.Count; }
1862 bool IList.IsReadOnly {
1863 get { return true; }
1866 public int this [int index] {
1868 if (index < 0 || index >= list.Count)
1869 throw new ArgumentOutOfRangeException ("Index out of range.");
1870 return (int) list [index];
1874 bool ICollection.IsSynchronized {
1875 get { return false; }
1878 object ICollection.SyncRoot {
1879 get { return this; }
1882 bool IList.IsFixedSize {
1883 get { return true; }
1886 object IList.this [int index] {
1887 get { return this [index]; }
1888 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1890 #endregion // Public Properties
1892 #region Public Methods
1893 public bool Contains (int checkedIndex)
1895 return list.Contains (checkedIndex);
1898 IEnumerator IEnumerable.GetEnumerator ()
1900 return list.GetEnumerator ();
1903 void ICollection.CopyTo (Array dest, int index)
1905 list.CopyTo (dest, index);
1908 int IList.Add (object value)
1910 throw new NotSupportedException ("Add operation is not supported.");
1915 throw new NotSupportedException ("Clear operation is not supported.");
1918 bool IList.Contains (object checkedIndex)
1920 return list.Contains (checkedIndex);
1923 int IList.IndexOf (object checkedIndex)
1925 return list.IndexOf (checkedIndex);
1928 void IList.Insert (int index, object value)
1930 throw new NotSupportedException ("Insert operation is not supported.");
1933 void IList.Remove (object value)
1935 throw new NotSupportedException ("Remove operation is not supported.");
1938 void IList.RemoveAt (int index)
1940 throw new NotSupportedException ("RemoveAt operation is not supported.");
1943 public int IndexOf (int checkedIndex)
1945 return list.IndexOf (checkedIndex);
1947 #endregion // Public Methods
1949 } // CheckedIndexCollection
1951 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
1953 internal ArrayList list;
1954 private ListView owner;
1956 #region Public Constructor
1957 public CheckedListViewItemCollection (ListView owner)
1959 list = new ArrayList ();
1962 #endregion // Public Constructor
1964 #region Public Properties
1967 get { return list.Count; }
1970 public bool IsReadOnly {
1971 get { return true; }
1974 public ListViewItem this [int index] {
1976 if (index < 0 || index >= list.Count)
1977 throw new ArgumentOutOfRangeException ("Index out of range.");
1978 return (ListViewItem) list [index];
1982 bool ICollection.IsSynchronized {
1983 get { return list.IsSynchronized; }
1986 object ICollection.SyncRoot {
1987 get { return this; }
1990 bool IList.IsFixedSize {
1991 get { return true; }
1994 object IList.this [int index] {
1995 get { return this [index]; }
1996 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1998 #endregion // Public Properties
2000 #region Public Methods
2001 public bool Contains (ListViewItem item)
2003 return list.Contains (item);
2006 void ICollection.CopyTo (Array dest, int index)
2008 list.CopyTo (dest, index);
2011 public IEnumerator GetEnumerator ()
2013 return list.GetEnumerator ();
2016 int IList.Add (object value)
2018 throw new NotSupportedException ("Add operation is not supported.");
2023 throw new NotSupportedException ("Clear operation is not supported.");
2026 bool IList.Contains (object item)
2028 return list.Contains (item);
2031 int IList.IndexOf (object item)
2033 return list.IndexOf (item);
2036 void IList.Insert (int index, object value)
2038 throw new NotSupportedException ("Insert operation is not supported.");
2041 void IList.Remove (object value)
2043 throw new NotSupportedException ("Remove operation is not supported.");
2046 void IList.RemoveAt (int index)
2048 throw new NotSupportedException ("RemoveAt operation is not supported.");
2051 public int IndexOf (ListViewItem item)
2053 return list.IndexOf (item);
2055 #endregion // Public Methods
2057 } // CheckedListViewItemCollection
2059 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2061 internal ArrayList list;
2062 private ListView owner;
2064 #region Public Constructor
2065 public ColumnHeaderCollection (ListView owner)
2067 list = new ArrayList ();
2070 #endregion // Public Constructor
2072 #region Public Properties
2075 get { return list.Count; }
2078 public bool IsReadOnly {
2079 get { return false; }
2082 public virtual ColumnHeader this [int index] {
2084 if (index < 0 || index >= list.Count)
2085 throw new ArgumentOutOfRangeException ("Index out of range.");
2086 return (ColumnHeader) list [index];
2090 bool ICollection.IsSynchronized {
2091 get { return true; }
2094 object ICollection.SyncRoot {
2095 get { return this; }
2098 bool IList.IsFixedSize {
2099 get { return list.IsFixedSize; }
2102 object IList.this [int index] {
2103 get { return this [index]; }
2104 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2106 #endregion // Public Properties
2108 #region Public Methods
2109 public virtual int Add (ColumnHeader value)
2112 value.owner = this.owner;
2113 idx = list.Add (value);
2114 owner.Redraw (true);
2118 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2120 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2121 this.Add (colHeader);
2125 public virtual void AddRange (ColumnHeader [] values)
2127 foreach (ColumnHeader colHeader in values) {
2128 colHeader.owner = this.owner;
2132 owner.Redraw (true);
2135 public virtual void Clear ()
2138 owner.Redraw (true);
2141 public bool Contains (ColumnHeader value)
2143 return list.Contains (value);
2146 public IEnumerator GetEnumerator ()
2148 return list.GetEnumerator ();
2151 public void CopyTo (Array dest, int index)
2153 list.CopyTo (dest, index);
2156 int IList.Add (object value)
2158 if (! (value is ColumnHeader)) {
2159 throw new ArgumentException ("Not of type ColumnHeader", "value");
2162 return this.Add ((ColumnHeader) value);
2165 bool IList.Contains (object value)
2167 if (! (value is ColumnHeader)) {
2168 throw new ArgumentException ("Not of type ColumnHeader", "value");
2171 return this.Contains ((ColumnHeader) value);
2174 int IList.IndexOf (object value)
2176 if (! (value is ColumnHeader)) {
2177 throw new ArgumentException ("Not of type ColumnHeader", "value");
2180 return this.IndexOf ((ColumnHeader) value);
2183 void IList.Insert (int index, object value)
2185 if (! (value is ColumnHeader)) {
2186 throw new ArgumentException ("Not of type ColumnHeader", "value");
2189 this.Insert (index, (ColumnHeader) value);
2192 void IList.Remove (object value)
2194 if (! (value is ColumnHeader)) {
2195 throw new ArgumentException ("Not of type ColumnHeader", "value");
2198 this.Remove ((ColumnHeader) value);
2201 public int IndexOf (ColumnHeader value)
2203 return list.IndexOf (value);
2206 public void Insert (int index, ColumnHeader value)
2208 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2209 // but it's really only greater.
2210 if (index < 0 || index > list.Count)
2211 throw new ArgumentOutOfRangeException ("Index out of range.");
2213 value.owner = this.owner;
2214 list.Insert (index, value);
2215 owner.Redraw (true);
2218 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2220 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2221 this.Insert (index, colHeader);
2224 public virtual void Remove (ColumnHeader column)
2226 // TODO: Update Column internal index ?
2227 list.Remove (column);
2228 owner.Redraw (true);
2231 public virtual void RemoveAt (int index)
2233 if (index < 0 || index >= list.Count)
2234 throw new ArgumentOutOfRangeException ("Index out of range.");
2236 // TODO: Update Column internal index ?
2237 list.RemoveAt (index);
2238 owner.Redraw (true);
2240 #endregion // Public Methods
2243 } // ColumnHeaderCollection
2245 public class ListViewItemCollection : IList, ICollection, IEnumerable
2247 internal ArrayList list;
2248 private ListView owner;
2250 #region Public Constructor
2251 public ListViewItemCollection (ListView owner)
2253 list = new ArrayList ();
2256 #endregion // Public Constructor
2258 #region Public Properties
2261 get { return list.Count; }
2264 public bool IsReadOnly {
2265 get { return false; }
2268 public virtual ListViewItem this [int displayIndex] {
2270 if (displayIndex < 0 || displayIndex >= list.Count)
2271 throw new ArgumentOutOfRangeException ("Index out of range.");
2272 return (ListViewItem) list [displayIndex];
2276 if (displayIndex < 0 || displayIndex >= list.Count)
2277 throw new ArgumentOutOfRangeException ("Index out of range.");
2279 if (list.Contains (value))
2280 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2282 value.Owner = owner;
2283 list [displayIndex] = value;
2285 owner.Redraw (true);
2289 bool ICollection.IsSynchronized {
2290 get { return true; }
2293 object ICollection.SyncRoot {
2294 get { return this; }
2297 bool IList.IsFixedSize {
2298 get { return list.IsFixedSize; }
2301 object IList.this [int index] {
2302 get { return this [index]; }
2304 if (value is ListViewItem)
2305 this [index] = (ListViewItem) value;
2307 this [index] = new ListViewItem (value.ToString ());
2310 #endregion // Public Properties
2312 #region Public Methods
2313 public virtual ListViewItem Add (ListViewItem value)
2315 if (list.Contains (value))
2316 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2318 value.Owner = owner;
2321 if (owner.Sorting != SortOrder.None)
2324 owner.Redraw (true);
2329 public virtual ListViewItem Add (string text)
2331 ListViewItem item = new ListViewItem (text);
2332 return this.Add (item);
2335 public virtual ListViewItem Add (string text, int imageIndex)
2337 ListViewItem item = new ListViewItem (text, imageIndex);
2338 return this.Add (item);
2341 public void AddRange (ListViewItem [] values)
2344 owner.SelectedItems.list.Clear ();
2345 owner.SelectedIndices.list.Clear ();
2346 owner.CheckedItems.list.Clear ();
2347 owner.CheckedIndices.list.Clear ();
2349 foreach (ListViewItem item in values) {
2354 if (owner.Sorting != SortOrder.None)
2357 owner.Redraw (true);
2360 public virtual void Clear ()
2362 owner.SetFocusedItem (null);
2363 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2365 owner.SelectedItems.list.Clear ();
2366 owner.SelectedIndices.list.Clear ();
2367 owner.CheckedItems.list.Clear ();
2368 owner.CheckedIndices.list.Clear ();
2369 owner.Redraw (true);
2372 public bool Contains (ListViewItem item)
2374 return list.Contains (item);
2377 void ICollection.CopyTo (Array dest, int index)
2379 list.CopyTo (dest, index);
2382 public IEnumerator GetEnumerator ()
2384 return list.GetEnumerator ();
2387 int IList.Add (object item)
2392 if (item is ListViewItem) {
2393 li = (ListViewItem) item;
2394 if (list.Contains (li))
2395 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2398 li = new ListViewItem (item.ToString ());
2401 result = list.Add (li);
2402 owner.Redraw (true);
2407 bool IList.Contains (object item)
2409 return list.Contains (item);
2412 int IList.IndexOf (object item)
2414 return list.IndexOf (item);
2417 void IList.Insert (int index, object item)
2419 if (item is ListViewItem)
2420 this.Insert (index, (ListViewItem) item);
2422 this.Insert (index, item.ToString ());
2425 void IList.Remove (object item)
2427 Remove ((ListViewItem) item);
2430 public int IndexOf (ListViewItem item)
2432 return list.IndexOf (item);
2435 public ListViewItem Insert (int index, ListViewItem item)
2437 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2438 // but it's really only greater.
2439 if (index < 0 || index > list.Count)
2440 throw new ArgumentOutOfRangeException ("Index out of range.");
2442 if (list.Contains (item))
2443 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2446 list.Insert (index, item);
2447 owner.Redraw (true);
2451 public ListViewItem Insert (int index, string text)
2453 return this.Insert (index, new ListViewItem (text));
2456 public ListViewItem Insert (int index, string text, int imageIndex)
2458 return this.Insert (index, new ListViewItem (text, imageIndex));
2461 public virtual void Remove (ListViewItem item)
2463 if (!list.Contains (item))
2466 owner.SelectedItems.list.Remove (item);
2467 owner.SelectedIndices.list.Remove (item.Index);
2468 owner.CheckedItems.list.Remove (item);
2469 owner.CheckedIndices.list.Remove (item.Index);
2471 owner.Redraw (true);
2474 public virtual void RemoveAt (int index)
2476 if (index < 0 || index >= list.Count)
2477 throw new ArgumentOutOfRangeException ("Index out of range.");
2479 list.RemoveAt (index);
2480 owner.SelectedItems.list.RemoveAt (index);
2481 owner.SelectedIndices.list.RemoveAt (index);
2482 owner.CheckedItems.list.RemoveAt (index);
2483 owner.CheckedIndices.list.RemoveAt (index);
2484 owner.Redraw (false);
2486 #endregion // Public Methods
2488 } // ListViewItemCollection
2490 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2492 internal ArrayList list;
2493 private ListView owner;
2495 #region Public Constructor
2496 public SelectedIndexCollection (ListView owner)
2498 list = new ArrayList ();
2501 #endregion // Public Constructor
2503 #region Public Properties
2506 get { return list.Count; }
2509 public bool IsReadOnly {
2510 get { return true; }
2513 public int this [int index] {
2515 if (index < 0 || index >= list.Count)
2516 throw new ArgumentOutOfRangeException ("Index out of range.");
2517 return (int) list [index];
2521 bool ICollection.IsSynchronized {
2522 get { return list.IsSynchronized; }
2525 object ICollection.SyncRoot {
2526 get { return this; }
2529 bool IList.IsFixedSize {
2530 get { return true; }
2533 object IList.this [int index] {
2534 get { return this [index]; }
2535 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2537 #endregion // Public Properties
2539 #region Public Methods
2540 public bool Contains (int selectedIndex)
2542 return list.Contains (selectedIndex);
2545 public void CopyTo (Array dest, int index)
2547 list.CopyTo (dest, index);
2550 public IEnumerator GetEnumerator ()
2552 return list.GetEnumerator ();
2555 int IList.Add (object value)
2557 throw new NotSupportedException ("Add operation is not supported.");
2562 throw new NotSupportedException ("Clear operation is not supported.");
2565 bool IList.Contains (object selectedIndex)
2567 return list.Contains (selectedIndex);
2570 int IList.IndexOf (object selectedIndex)
2572 return list.IndexOf (selectedIndex);
2575 void IList.Insert (int index, object value)
2577 throw new NotSupportedException ("Insert operation is not supported.");
2580 void IList.Remove (object value)
2582 throw new NotSupportedException ("Remove operation is not supported.");
2585 void IList.RemoveAt (int index)
2587 throw new NotSupportedException ("RemoveAt operation is not supported.");
2590 public int IndexOf (int selectedIndex)
2592 return list.IndexOf (selectedIndex);
2594 #endregion // Public Methods
2596 } // SelectedIndexCollection
2598 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2600 internal ArrayList list;
2601 private ListView owner;
2603 #region Public Constructor
2604 public SelectedListViewItemCollection (ListView owner)
2606 list = new ArrayList ();
2609 #endregion // Public Constructor
2611 #region Public Properties
2614 get { return list.Count; }
2617 public bool IsReadOnly {
2618 get { return true; }
2621 public ListViewItem this [int index] {
2623 if (index < 0 || index >= list.Count)
2624 throw new ArgumentOutOfRangeException ("Index out of range.");
2625 return (ListViewItem) list [index];
2629 bool ICollection.IsSynchronized {
2630 get { return list.IsSynchronized; }
2633 object ICollection.SyncRoot {
2634 get { return this; }
2637 bool IList.IsFixedSize {
2638 get { return true; }
2641 object IList.this [int index] {
2642 get { return this [index]; }
2643 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2645 #endregion // Public Properties
2647 #region Public Methods
2648 public void Clear ()
2650 ArrayList copy = (ArrayList) list.Clone ();
2651 for (int i = 0; i < copy.Count; i++)
2652 ((ListViewItem) copy [i]).Selected = false;
2657 public bool Contains (ListViewItem item)
2659 return list.Contains (item);
2662 public void CopyTo (Array dest, int index)
2664 list.CopyTo (dest, index);
2667 public IEnumerator GetEnumerator ()
2669 return list.GetEnumerator ();
2672 int IList.Add (object value)
2674 throw new NotSupportedException ("Add operation is not supported.");
2677 bool IList.Contains (object item)
2679 return list.Contains (item);
2682 int IList.IndexOf (object item)
2684 return list.IndexOf (item);
2687 void IList.Insert (int index, object value)
2689 throw new NotSupportedException ("Insert operation is not supported.");
2692 void IList.Remove (object value)
2694 throw new NotSupportedException ("Remove operation is not supported.");
2697 void IList.RemoveAt (int index)
2699 throw new NotSupportedException ("RemoveAt operation is not supported.");
2702 public int IndexOf (ListViewItem item)
2704 return list.IndexOf (item);
2706 #endregion // Public Methods
2708 } // SelectedListViewItemCollection
2710 #endregion // Subclasses