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.
36 using System.Collections;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
40 using System.Runtime.InteropServices;
41 using System.Globalization;
43 namespace System.Windows.Forms
45 [DefaultEvent ("SelectedIndexChanged")]
46 [DefaultProperty ("Items")]
47 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
48 public class ListView : Control
50 private ItemActivation activation = ItemActivation.Standard;
51 private ListViewAlignment alignment = ListViewAlignment.Top;
52 private bool allow_column_reorder = false;
53 private bool auto_arrange = true;
54 private bool check_boxes = false;
55 private readonly CheckedIndexCollection checked_indices;
56 private readonly CheckedListViewItemCollection checked_items;
57 private readonly ColumnHeaderCollection columns;
58 internal ListViewItem focused_item;
59 private bool full_row_select = false;
60 private bool grid_lines = false;
61 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
62 private bool hide_selection = true;
63 private bool hover_selection = false;
64 private IComparer item_sorter;
65 private readonly ListViewItemCollection items;
66 private bool label_edit = false;
67 private bool label_wrap = true;
68 private bool multiselect = true;
69 private bool scrollable = true;
70 private readonly SelectedIndexCollection selected_indices;
71 private readonly SelectedListViewItemCollection selected_items;
72 private SortOrder sort_order = SortOrder.None;
73 private ImageList state_image_list;
74 private bool updating = false;
75 private View view = View.LargeIcon;
76 private int layout_wd; // We might draw more than our client area
77 private int layout_ht; // therefore we need to have these two.
78 //private TextBox editor; // Used for editing an item text
79 HeaderControl header_control;
80 internal ItemControl item_control;
81 internal ScrollBar h_scroll; // used for scrolling horizontally
82 internal ScrollBar v_scroll; // used for scrolling vertically
83 internal int h_marker; // Position markers for scrolling
84 internal int v_marker;
85 private int keysearch_tickcnt;
86 private string keysearch_text;
87 static private readonly int keysearch_keydelay = 1000;
88 private int[] reordered_column_indices;
91 internal ImageList large_image_list;
92 internal ImageList small_image_list;
93 internal Size text_size = Size.Empty;
96 public event LabelEditEventHandler AfterLabelEdit;
99 [EditorBrowsable (EditorBrowsableState.Never)]
100 public new event EventHandler BackgroundImageChanged {
101 add { base.BackgroundImageChanged += value; }
102 remove { base.BackgroundImageChanged -= value; }
105 public event LabelEditEventHandler BeforeLabelEdit;
106 public event ColumnClickEventHandler ColumnClick;
107 public event EventHandler ItemActivate;
108 public event ItemCheckEventHandler ItemCheck;
109 public event ItemDragEventHandler ItemDrag;
112 [EditorBrowsable (EditorBrowsableState.Never)]
113 public new event PaintEventHandler Paint {
114 add { base.Paint += value; }
115 remove { base.Paint -= value; }
118 public event EventHandler SelectedIndexChanged;
121 [EditorBrowsable (EditorBrowsableState.Never)]
122 public new event EventHandler TextChanged {
123 add { base.TextChanged += value; }
124 remove { base.TextChanged -= value; }
129 #region Public Constructors
132 background_color = ThemeEngine.Current.ColorWindow;
133 items = new ListViewItemCollection (this);
134 checked_indices = new CheckedIndexCollection (this);
135 checked_items = new CheckedListViewItemCollection (this);
136 columns = new ColumnHeaderCollection (this);
137 foreground_color = SystemColors.WindowText;
138 selected_indices = new SelectedIndexCollection (this);
139 selected_items = new SelectedListViewItemCollection (this);
141 border_style = BorderStyle.Fixed3D;
143 header_control = new HeaderControl (this);
144 header_control.Visible = false;
145 Controls.AddImplicit (header_control);
147 item_control = new ItemControl (this);
148 Controls.AddImplicit (item_control);
150 h_scroll = new ImplicitHScrollBar ();
151 Controls.AddImplicit (this.h_scroll);
153 v_scroll = new ImplicitVScrollBar ();
154 Controls.AddImplicit (this.v_scroll);
156 h_marker = v_marker = 0;
157 keysearch_tickcnt = 0;
159 // scroll bars are disabled initially
160 h_scroll.Visible = false;
161 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
162 v_scroll.Visible = false;
163 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
166 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
167 SizeChanged += new EventHandler (ListView_SizeChanged);
168 GotFocus += new EventHandler (FocusChanged);
169 LostFocus += new EventHandler (FocusChanged);
170 MouseWheel += new MouseEventHandler(ListView_MouseWheel);
172 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
174 | ControlStyles.UseTextForAccessibility
178 #endregion // Public Constructors
180 #region Private Internal Properties
181 internal Size CheckBoxSize {
183 if (this.check_boxes) {
184 if (this.state_image_list != null)
185 return this.state_image_list.ImageSize;
187 return ThemeEngine.Current.ListViewCheckBoxSize;
193 #endregion // Private Internal Properties
195 #region Protected Properties
196 protected override CreateParams CreateParams {
197 get { return base.CreateParams; }
200 protected override Size DefaultSize {
201 get { return ThemeEngine.Current.ListViewDefaultSize; }
203 #endregion // Protected Properties
205 #region Public Instance Properties
206 [DefaultValue (ItemActivation.Standard)]
207 public ItemActivation Activation {
208 get { return activation; }
210 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
211 value != ItemActivation.TwoClick) {
212 throw new InvalidEnumArgumentException (string.Format
213 ("Enum argument value '{0}' is not valid for Activation", value));
220 [DefaultValue (ListViewAlignment.Top)]
222 public ListViewAlignment Alignment {
223 get { return alignment; }
225 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
226 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
227 throw new InvalidEnumArgumentException (string.Format
228 ("Enum argument value '{0}' is not valid for Alignment", value));
231 if (this.alignment != value) {
233 // alignment does not matter in Details/List views
234 if (this.view == View.LargeIcon ||
235 this.View == View.SmallIcon)
241 [DefaultValue (false)]
242 public bool AllowColumnReorder {
243 get { return allow_column_reorder; }
244 set { allow_column_reorder = value; }
247 [DefaultValue (true)]
248 public bool AutoArrange {
249 get { return auto_arrange; }
251 if (auto_arrange != value) {
252 auto_arrange = value;
253 // autoarrange does not matter in Details/List views
254 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
260 public override Color BackColor {
262 if (background_color.IsEmpty)
263 return ThemeEngine.Current.ColorWindow;
265 return background_color;
267 set { background_color = value; }
271 [EditorBrowsable (EditorBrowsableState.Never)]
272 public override Image BackgroundImage {
273 get { return background_image; }
275 if (value == background_image)
278 background_image = value;
279 OnBackgroundImageChanged (EventArgs.Empty);
283 [DefaultValue (BorderStyle.Fixed3D)]
285 public BorderStyle BorderStyle {
286 get { return InternalBorderStyle; }
287 set { InternalBorderStyle = value; }
290 [DefaultValue (false)]
291 public bool CheckBoxes {
292 get { return check_boxes; }
294 if (check_boxes != value) {
296 if (value && View == View.Tile)
297 throw new NotSupportedException ("CheckBoxes are not"
298 + " supported in Tile view. Choose a different"
299 + " view or set CheckBoxes to false.");
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 public CheckedIndexCollection CheckedIndices {
311 get { return checked_indices; }
315 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
316 public CheckedListViewItemCollection CheckedItems {
317 get { return checked_items; }
320 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
322 [MergableProperty (false)]
323 public ColumnHeaderCollection Columns {
324 get { return columns; }
328 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
329 public ListViewItem FocusedItem {
335 public override Color ForeColor {
337 if (foreground_color.IsEmpty)
338 return ThemeEngine.Current.ColorWindowText;
340 return foreground_color;
342 set { foreground_color = value; }
345 [DefaultValue (false)]
346 public bool FullRowSelect {
347 get { return full_row_select; }
348 set { full_row_select = value; }
351 [DefaultValue (false)]
352 public bool GridLines {
353 get { return grid_lines; }
355 if (grid_lines != value) {
362 [DefaultValue (ColumnHeaderStyle.Clickable)]
363 public ColumnHeaderStyle HeaderStyle {
364 get { return header_style; }
366 if (header_style == value)
370 case ColumnHeaderStyle.Clickable:
371 case ColumnHeaderStyle.Nonclickable:
372 case ColumnHeaderStyle.None:
375 throw new InvalidEnumArgumentException (string.Format
376 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
379 header_style = value;
380 if (view == View.Details)
385 [DefaultValue (true)]
386 public bool HideSelection {
387 get { return hide_selection; }
389 if (hide_selection != value) {
390 hide_selection = value;
396 [DefaultValue (false)]
397 public bool HoverSelection {
398 get { return hover_selection; }
399 set { hover_selection = value; }
402 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
404 [MergableProperty (false)]
405 public ListViewItemCollection Items {
406 get { return items; }
409 [DefaultValue (false)]
410 public bool LabelEdit {
411 get { return label_edit; }
412 set { label_edit = value; }
415 [DefaultValue (true)]
417 public bool LabelWrap {
418 get { return label_wrap; }
420 if (label_wrap != value) {
427 [DefaultValue (null)]
428 public ImageList LargeImageList {
429 get { return large_image_list; }
431 large_image_list = value;
437 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
438 public IComparer ListViewItemSorter {
440 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
445 if (item_sorter != value) {
452 [DefaultValue (true)]
453 public bool MultiSelect {
454 get { return multiselect; }
455 set { multiselect = value; }
458 [DefaultValue (true)]
459 public bool Scrollable {
460 get { return scrollable; }
462 if (scrollable != value) {
470 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
471 public SelectedIndexCollection SelectedIndices {
472 get { return selected_indices; }
476 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
477 public SelectedListViewItemCollection SelectedItems {
478 get { return selected_items; }
482 [MonoTODO("Implement")]
483 public bool ShowGroups {
493 [DefaultValue (null)]
494 public ImageList SmallImageList {
495 get { return small_image_list; }
497 small_image_list = value;
502 [DefaultValue (SortOrder.None)]
503 public SortOrder Sorting {
504 get { return sort_order; }
506 if (!Enum.IsDefined (typeof (SortOrder), value)) {
507 throw new InvalidEnumArgumentException ("value", (int) value,
511 if (sort_order == value)
516 if (value == SortOrder.None) {
517 if (item_sorter != null) {
518 // ListViewItemSorter should never be reset for SmallIcon
519 // and LargeIcon view
520 if (View != View.SmallIcon && View != View.LargeIcon)
524 // in .NET 1.1, only internal IComparer would be
526 if (item_sorter is ItemComparer)
532 if (item_sorter == null)
533 item_sorter = new ItemComparer (value);
534 if (item_sorter is ItemComparer) {
536 item_sorter = new ItemComparer (value);
538 // in .NET 1.1, the sort order is not updated for
539 // SmallIcon and LargeIcon views if no custom IComparer
541 if (View != View.SmallIcon && View != View.LargeIcon)
542 item_sorter = new ItemComparer (value);
550 [DefaultValue (null)]
551 public ImageList StateImageList {
552 get { return state_image_list; }
554 state_image_list = value;
561 [EditorBrowsable (EditorBrowsableState.Never)]
562 public override string Text {
571 OnTextChanged (EventArgs.Empty);
576 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
577 public ListViewItem TopItem {
580 if (this.items.Count == 0)
582 // if contents are not scrolled
583 // it is the first item
584 else if (h_marker == 0 && v_marker == 0)
585 return this.items [0];
586 // do a hit test for the scrolled position
588 foreach (ListViewItem item in this.items) {
589 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
598 [MonoTODO("Implement")]
599 public bool UseCompatibleStateImageBehavior {
609 [DefaultValue (View.LargeIcon)]
613 if (!Enum.IsDefined (typeof (View), value))
614 throw new InvalidEnumArgumentException ("value", (int) value,
619 if (CheckBoxes && value == View.Tile)
620 throw new NotSupportedException ("CheckBoxes are not"
621 + " supported in Tile view. Choose a different"
622 + " view or set CheckBoxes to false.");
625 h_scroll.Value = v_scroll.Value = 0;
631 #endregion // Public Instance Properties
633 #region Internal Methods Properties
635 internal int FirstVisibleIndex {
638 if (this.items.Count == 0)
641 if (h_marker == 0 && v_marker == 0)
644 foreach (ListViewItem item in this.items) {
645 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
654 internal int LastVisibleIndex {
656 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
657 if (View == View.List || Alignment == ListViewAlignment.Left) {
658 if (Items[i].Bounds.X > ClientRectangle.Right)
661 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
666 return Items.Count - 1;
670 internal void OnSelectedIndexChanged ()
673 OnSelectedIndexChanged (EventArgs.Empty);
676 internal int TotalWidth {
677 get { return Math.Max (this.Width, this.layout_wd); }
680 internal int TotalHeight {
681 get { return Math.Max (this.Height, this.layout_ht); }
684 internal void Redraw (bool recalculate)
686 // Avoid calculations when control is being updated
691 CalculateListView (this.alignment);
696 internal Size GetChildColumnSize (int index)
698 Size ret_size = Size.Empty;
699 ColumnHeader col = this.columns [index];
701 if (col.Width == -2) { // autosize = max(items, columnheader)
702 Size size = Size.Ceiling (this.DeviceContext.MeasureString
703 (col.Text, this.Font));
704 ret_size = BiggestItem (index);
705 if (size.Width > ret_size.Width)
708 else { // -1 and all the values < -2 are put under one category
709 ret_size = BiggestItem (index);
710 // fall back to empty columns' width if no subitem is available for a column
711 if (ret_size.IsEmpty) {
712 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
713 if (col.Text.Length > 0)
714 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
715 (col.Text, this.Font)).Height;
717 ret_size.Height = this.Font.Height;
721 // adjust the size for icon and checkbox for 0th column
723 ret_size.Width += (this.CheckBoxSize.Width + 4);
724 if (this.small_image_list != null)
725 ret_size.Width += this.small_image_list.ImageSize.Width;
730 // Returns the size of biggest item text in a column.
731 private Size BiggestItem (int col)
733 Size temp = Size.Empty;
734 Size ret_size = Size.Empty;
736 // 0th column holds the item text, we check the size of
737 // the various subitems falling in that column and get
738 // the biggest one's size.
739 foreach (ListViewItem item in items) {
740 if (col >= item.SubItems.Count)
743 temp = Size.Ceiling (this.DeviceContext.MeasureString
744 (item.SubItems [col].Text, this.Font));
745 if (temp.Width > ret_size.Width)
749 // adjustment for space
750 if (!ret_size.IsEmpty)
756 const int max_wrap_padding = 38;
758 // Sets the size of the biggest item text as per the view
759 private void CalcTextSize ()
761 // clear the old value
762 text_size = Size.Empty;
764 if (items.Count == 0)
767 text_size = BiggestItem (0);
769 if (view == View.LargeIcon && this.label_wrap) {
770 Size temp = Size.Empty;
771 if (this.check_boxes)
772 temp.Width += 2 * this.CheckBoxSize.Width;
773 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
774 temp.Width += icon_w + max_wrap_padding;
775 // wrapping is done for two lines only
776 if (text_size.Width > temp.Width) {
777 text_size.Width = temp.Width;
778 text_size.Height *= 2;
781 else if (view == View.List) {
782 // in list view max text shown in determined by the
783 // control width, even if scolling is enabled.
784 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
785 if (this.small_image_list != null)
786 max_wd -= this.small_image_list.ImageSize.Width;
788 if (text_size.Width > max_wd)
789 text_size.Width = max_wd;
792 // we do the default settings, if we have got 0's
793 if (text_size.Height <= 0)
794 text_size.Height = this.Font.Height;
795 if (text_size.Width <= 0)
796 text_size.Width = this.Width;
799 text_size.Width += 4;
800 text_size.Height += 2;
803 private void Scroll (ScrollBar scrollbar, int delta)
805 if (delta == 0 || !scrollbar.Visible)
809 if (scrollbar == h_scroll)
810 max = h_scroll.Maximum - item_control.Width;
812 max = v_scroll.Maximum - item_control.Height;
814 int val = scrollbar.Value + delta;
817 else if (val < scrollbar.Minimum)
818 val = scrollbar.Minimum;
819 scrollbar.Value = val;
822 private void CalculateScrollBars ()
824 Rectangle client_area = ClientRectangle;
826 if (!this.scrollable || this.items.Count <= 0) {
827 h_scroll.Visible = false;
828 v_scroll.Visible = false;
829 item_control.Location = new Point (0, header_control.Height);
830 item_control.Height = ClientRectangle.Width - header_control.Height;
831 item_control.Width = ClientRectangle.Width;
832 header_control.Width = ClientRectangle.Width;
836 // Don't calculate if the view is not displayable
837 if (client_area.Height < 0 || client_area.Width < 0)
840 // making a scroll bar visible might make
841 // other scroll bar visible
842 if (layout_wd > client_area.Right) {
843 h_scroll.Visible = true;
844 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
845 v_scroll.Visible = true;
847 v_scroll.Visible = false;
848 } else if (layout_ht > client_area.Bottom) {
849 v_scroll.Visible = true;
850 if ((layout_wd + v_scroll.Width) > client_area.Right)
851 h_scroll.Visible = true;
853 h_scroll.Visible = false;
855 h_scroll.Visible = false;
856 v_scroll.Visible = false;
859 item_control.Height = ClientRectangle.Height - header_control.Height;
861 if (h_scroll.is_visible) {
862 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
863 h_scroll.Minimum = 0;
865 // if v_scroll is visible, adjust the maximum of the
866 // h_scroll to account for the width of v_scroll
867 if (v_scroll.Visible) {
868 h_scroll.Maximum = layout_wd + v_scroll.Width;
869 h_scroll.Width = client_area.Width - v_scroll.Width;
872 h_scroll.Maximum = layout_wd;
873 h_scroll.Width = client_area.Width;
876 h_scroll.LargeChange = client_area.Width;
877 h_scroll.SmallChange = Font.Height;
878 item_control.Height -= h_scroll.Height;
881 if (header_control.is_visible)
882 header_control.Width = ClientRectangle.Width;
883 item_control.Width = ClientRectangle.Width;
885 if (v_scroll.is_visible) {
886 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
887 v_scroll.Minimum = 0;
889 // if h_scroll is visible, adjust the maximum of the
890 // v_scroll to account for the height of h_scroll
891 if (h_scroll.Visible) {
892 v_scroll.Maximum = layout_ht + h_scroll.Height;
893 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
895 v_scroll.Maximum = layout_ht;
896 v_scroll.Height = client_area.Height;
899 v_scroll.LargeChange = client_area.Height;
900 v_scroll.SmallChange = Font.Height;
901 if (header_control.Visible)
902 header_control.Width -= v_scroll.Width;
903 item_control.Width -= v_scroll.Width;
907 ColumnHeader GetReorderedColumn (int index)
909 if (reordered_column_indices == null)
910 return Columns [index];
912 return Columns [reordered_column_indices [index]];
915 void ReorderColumn (ColumnHeader col, int index)
917 if (reordered_column_indices == null) {
918 reordered_column_indices = new int [Columns.Count];
919 for (int i = 0; i < Columns.Count; i++)
920 reordered_column_indices [i] = i;
923 if (reordered_column_indices [index] == col.Index)
926 int[] curr = reordered_column_indices;
927 int[] result = new int [Columns.Count];
929 for (int i = 0; i < Columns.Count; i++) {
930 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
934 result [i] = col.Index;
936 result [i] = curr [curr_idx++];
939 reordered_column_indices = result;
941 header_control.Invalidate ();
942 item_control.Invalidate ();
945 Size LargeIconItemSize {
947 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
948 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
949 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
950 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
951 return new Size (w, h);
955 Size SmallIconItemSize {
957 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
958 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
959 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
960 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
961 return new Size (w, h);
967 ListViewItem[,] item_matrix;
969 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
971 header_control.Visible = false;
972 header_control.Size = Size.Empty;
973 item_control.Visible = true;
974 item_control.Location = Point.Empty;
976 if (items.Count == 0)
979 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
981 Rectangle area = ClientRectangle;
984 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
987 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
989 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
992 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
995 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
996 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
997 item_matrix = new ListViewItem [rows, cols];
1000 foreach (ListViewItem item in items) {
1001 int x = col * (sz.Width + x_spacing);
1002 int y = row * (sz.Height + y_spacing);
1003 item.Location = new Point (x, y);
1007 item_matrix [row, col] = item;
1009 if (++row == rows) {
1014 if (++col == cols) {
1021 item_control.Size = new Size (layout_wd, layout_ht);
1024 void LayoutHeader ()
1027 for (int i = 0; i < Columns.Count; i++) {
1028 ColumnHeader col = GetReorderedColumn (i);
1031 col.CalcColumnHeader ();
1035 if (x < ClientRectangle.Width)
1036 x = ClientRectangle.Width;
1038 if (header_style == ColumnHeaderStyle.None) {
1039 header_control.Visible = false;
1040 header_control.Size = Size.Empty;
1042 header_control.Width = x;
1043 header_control.Height = columns [0].Ht;
1044 header_control.Visible = true;
1048 void LayoutDetails ()
1050 if (columns.Count == 0) {
1051 header_control.Visible = false;
1052 item_control.Visible = false;
1058 item_control.Visible = true;
1059 item_control.Location = new Point (0, header_control.Height);
1062 if (items.Count > 0) {
1063 foreach (ListViewItem item in items) {
1065 item.Location = new Point (0, y);
1066 y += item.Bounds.Height + 2;
1069 // some space for bottom gridline
1074 layout_wd = Math.Max (header_control.Width, item_control.Width);
1075 layout_ht = y + header_control.Height;
1078 private void CalculateListView (ListViewAlignment align)
1087 case View.SmallIcon:
1088 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1091 case View.LargeIcon:
1092 LayoutIcons (true, alignment == ListViewAlignment.Left,
1093 ThemeEngine.Current.ListViewHorizontalSpacing,
1094 ThemeEngine.Current.ListViewVerticalSpacing);
1098 LayoutIcons (false, true, 4, 2);
1102 CalculateScrollBars ();
1107 return (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0;
1111 private bool KeySearchString (KeyEventArgs ke)
1113 int current_tickcnt = Environment.TickCount;
1114 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1115 keysearch_text = string.Empty;
1118 keysearch_text += (char) ke.KeyData;
1119 keysearch_tickcnt = current_tickcnt;
1121 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1124 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1125 CompareOptions.IgnoreCase)) {
1126 SetFocusedItem (Items [i]);
1127 items [i].Selected = true;
1131 i = (i + 1 < Items.Count) ? i+1 : 0;
1139 int GetAdjustedIndex (Keys key)
1143 if (View == View.Details) {
1145 result = FocusedItem.Index - 1;
1146 else if (key == Keys.Down) {
1147 result = FocusedItem.Index + 1;
1148 if (result == items.Count)
1154 int row = FocusedItem.row;
1155 int col = FocusedItem.col;
1161 return item_matrix [row, col - 1].Index;
1164 if (col == (cols - 1))
1166 while (item_matrix [row, col + 1] == null)
1168 return item_matrix [row, col + 1].Index;
1173 return item_matrix [row - 1, col].Index;
1176 if (row == (rows - 1) || row == Items.Count - 1)
1178 while (item_matrix [row + 1, col] == null)
1180 return item_matrix [row + 1, col].Index;
1187 ListViewItem selection_start;
1189 private bool SelectItems (ArrayList sel_items)
1191 bool changed = false;
1192 ArrayList curr_items = SelectedItems.List;
1193 foreach (ListViewItem item in curr_items)
1194 if (!sel_items.Contains (item)) {
1195 item.Selected = false;
1198 foreach (ListViewItem item in sel_items)
1199 if (!item.Selected) {
1200 item.Selected = true;
1206 private void UpdateMultiSelection (int index)
1208 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1209 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1210 ListViewItem item = items [index];
1212 if (shift_pressed && selection_start != null) {
1213 ArrayList list = new ArrayList ();
1214 int start = Math.Min (selection_start.Index, index);
1215 int end = Math.Max (selection_start.Index, index);
1216 if (View == View.Details) {
1217 for (int i = start; i <= end; i++)
1218 list.Add (items [i]);
1220 int left = Math.Min (items [start].col, items [end].col);
1221 int right = Math.Max (items [start].col, items [end].col);
1222 int top = Math.Min (items [start].row, items [end].row);
1223 int bottom = Math.Max (items [start].row, items [end].row);
1224 foreach (ListViewItem curr in items)
1225 if (curr.row >= top && curr.row <= bottom &&
1226 curr.col >= left && curr.col <= right)
1229 if (SelectItems (list))
1230 OnSelectedIndexChanged (EventArgs.Empty);
1231 } else if (ctrl_pressed) {
1232 item.Selected = !item.Selected;
1233 selection_start = item;
1234 OnSelectedIndexChanged (EventArgs.Empty);
1236 SelectedItems.Clear ();
1237 item.Selected = true;
1238 selection_start = item;
1239 OnSelectedIndexChanged (EventArgs.Empty);
1243 internal override bool InternalPreProcessMessage (ref Message msg)
1245 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
1246 Keys key_data = (Keys)msg.WParam.ToInt32();
1247 if (HandleNavKeys (key_data))
1250 return base.InternalPreProcessMessage (ref msg);
1253 bool HandleNavKeys (Keys key_data)
1255 if (Items.Count == 0 || !item_control.Visible)
1258 if (FocusedItem == null)
1259 SetFocusedItem (Items [0]);
1263 SelectIndex (Items.Count - 1);
1274 SelectIndex (GetAdjustedIndex (key_data));
1284 void SelectIndex (int index)
1290 UpdateMultiSelection (index);
1291 else if (!items [index].Selected) {
1292 items [index].Selected = true;
1293 OnSelectedIndexChanged (EventArgs.Empty);
1296 SetFocusedItem (items [index]);
1297 EnsureVisible (index);
1300 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1302 if (ke.Handled || Items.Count == 0 || !item_control.Visible)
1305 ke.Handled = KeySearchString (ke);
1308 internal class ItemControl : Control {
1311 ListViewItem clicked_item;
1312 ListViewItem last_clicked_item;
1313 bool hover_processed = false;
1314 bool checking = false;
1316 ListViewLabelEditTextBox edit_text_box;
1317 internal ListViewItem edit_item;
1318 LabelEditEventArgs edit_args;
1320 public ItemControl (ListView owner)
1323 DoubleClick += new EventHandler(ItemsDoubleClick);
1324 MouseDown += new MouseEventHandler(ItemsMouseDown);
1325 MouseMove += new MouseEventHandler(ItemsMouseMove);
1326 MouseHover += new EventHandler(ItemsMouseHover);
1327 MouseUp += new MouseEventHandler(ItemsMouseUp);
1330 void ItemsDoubleClick (object sender, EventArgs e)
1332 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1333 owner.ItemActivate (this, e);
1343 BoxSelect box_select_mode = BoxSelect.None;
1344 ArrayList prev_selection;
1345 Point box_select_start;
1347 Rectangle box_select_rect;
1348 internal Rectangle BoxSelectRectangle {
1349 get { return box_select_rect; }
1351 if (box_select_rect == value)
1354 InvalidateBoxSelectRect ();
1355 box_select_rect = value;
1356 InvalidateBoxSelectRect ();
1360 void InvalidateBoxSelectRect ()
1362 if (BoxSelectRectangle.Size.IsEmpty)
1365 Rectangle edge = BoxSelectRectangle;
1371 edge.Y = BoxSelectRectangle.Bottom - 1;
1373 edge.Y = BoxSelectRectangle.Y - 1;
1375 edge.Height = BoxSelectRectangle.Height + 2;
1377 edge.X = BoxSelectRectangle.Right - 1;
1381 private Rectangle CalculateBoxSelectRectangle (Point pt)
1383 int left = Math.Min (box_select_start.X, pt.X);
1384 int right = Math.Max (box_select_start.X, pt.X);
1385 int top = Math.Min (box_select_start.Y, pt.Y);
1386 int bottom = Math.Max (box_select_start.Y, pt.Y);
1387 return Rectangle.FromLTRB (left, top, right, bottom);
1390 ArrayList BoxSelectedItems {
1392 ArrayList result = new ArrayList ();
1393 foreach (ListViewItem item in owner.Items) {
1394 Rectangle r = item.Bounds;
1396 r.Y += r.Height / 4;
1399 if (BoxSelectRectangle.IntersectsWith (r))
1406 private bool PerformBoxSelection (Point pt)
1408 if (box_select_mode == BoxSelect.None)
1411 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1413 ArrayList box_items = BoxSelectedItems;
1417 switch (box_select_mode) {
1419 case BoxSelect.Normal:
1423 case BoxSelect.Control:
1424 items = new ArrayList ();
1425 foreach (ListViewItem item in prev_selection)
1426 if (!box_items.Contains (item))
1428 foreach (ListViewItem item in box_items)
1429 if (!prev_selection.Contains (item))
1433 case BoxSelect.Shift:
1435 foreach (ListViewItem item in box_items)
1436 prev_selection.Remove (item);
1437 foreach (ListViewItem item in prev_selection)
1442 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1446 owner.SelectItems (items);
1452 private void ToggleCheckState (ListViewItem item)
1454 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1455 item.Checked = !item.Checked;
1456 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1458 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1459 owner.OnItemCheck (ice);
1462 private void ItemsMouseDown (object sender, MouseEventArgs me)
1464 if (owner.items.Count == 0)
1467 Point pt = new Point (me.X, me.Y);
1468 foreach (ListViewItem item in owner.items) {
1469 if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
1473 ToggleCheckState (item);
1477 if (owner.View == View.Details && !owner.FullRowSelect) {
1478 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1479 clicked_item = item;
1483 if (item.Bounds.Contains (pt)) {
1484 clicked_item = item;
1491 if (clicked_item != null) {
1492 owner.SetFocusedItem (clicked_item);
1493 bool changed = !clicked_item.Selected;
1494 if (owner.MultiSelect)
1495 owner.UpdateMultiSelection (clicked_item.Index);
1497 clicked_item.Selected = true;
1500 owner.OnSelectedIndexChanged (EventArgs.Empty);
1502 // Raise double click if the item was clicked. On MS the
1503 // double click is only raised if you double click an item
1504 if (me.Clicks > 1) {
1505 owner.OnDoubleClick (EventArgs.Empty);
1506 if (owner.CheckBoxes)
1507 ToggleCheckState (clicked_item);
1508 } else if (me.Clicks == 1) {
1509 owner.OnClick (EventArgs.Empty);
1510 if (owner.LabelEdit && !changed)
1511 BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
1514 if (owner.MultiSelect) {
1515 Keys mods = XplatUI.State.ModifierKeys;
1516 if ((mods & Keys.Shift) != 0)
1517 box_select_mode = BoxSelect.Shift;
1518 else if ((mods & Keys.Control) != 0)
1519 box_select_mode = BoxSelect.Control;
1521 box_select_mode = BoxSelect.Normal;
1522 box_select_start = pt;
1523 prev_selection = owner.SelectedItems.List;
1524 } else if (owner.SelectedItems.Count > 0) {
1525 owner.SelectedItems.Clear ();
1526 owner.OnSelectedIndexChanged (EventArgs.Empty);
1531 private void ItemsMouseMove (object sender, MouseEventArgs me)
1533 if (PerformBoxSelection (new Point (me.X, me.Y)))
1536 if (owner.HoverSelection && hover_processed) {
1538 Point pt = PointToClient (Control.MousePosition);
1539 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1540 if (item == null || item.Selected)
1543 hover_processed = false;
1544 XplatUI.ResetMouseHover (Handle);
1549 private void ItemsMouseHover (object sender, EventArgs e)
1551 if (Capture || !owner.HoverSelection)
1554 hover_processed = true;
1555 Point pt = PointToClient (Control.MousePosition);
1556 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1561 item.Selected = true;
1562 owner.OnSelectedIndexChanged (new EventArgs ());
1565 private void ItemsMouseUp (object sender, MouseEventArgs me)
1568 if (owner.Items.Count == 0)
1571 Point pt = new Point (me.X, me.Y);
1573 Rectangle rect = Rectangle.Empty;
1574 if (clicked_item != null) {
1575 if (owner.view == View.Details && !owner.full_row_select)
1576 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1578 rect = clicked_item.Bounds;
1580 if (rect.Contains (pt)) {
1581 switch (owner.activation) {
1582 case ItemActivation.OneClick:
1583 owner.OnItemActivate (EventArgs.Empty);
1586 case ItemActivation.TwoClick:
1587 if (last_clicked_item == clicked_item) {
1588 owner.OnItemActivate (EventArgs.Empty);
1589 last_clicked_item = null;
1591 last_clicked_item = clicked_item;
1594 // DoubleClick activation is handled in another handler
1598 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1599 // Need this to clean up background clicks
1600 owner.SelectedItems.Clear ();
1601 owner.OnSelectedIndexChanged (EventArgs.Empty);
1604 clicked_item = null;
1605 box_select_start = Point.Empty;
1606 BoxSelectRectangle = Rectangle.Empty;
1607 prev_selection = null;
1608 box_select_mode = BoxSelect.None;
1612 internal void LabelEditFinished (object sender, EventArgs e)
1614 EndEdit (edit_item);
1617 internal void BeginEdit (ListViewItem item)
1619 if (edit_item != null)
1620 EndEdit (edit_item);
1622 if (edit_text_box == null) {
1623 edit_text_box = new ListViewLabelEditTextBox ();
1624 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1625 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1626 edit_text_box.Visible = false;
1627 Controls.Add (edit_text_box);
1630 item.EnsureVisible();
1632 edit_text_box.Reset ();
1634 switch (owner.view) {
1636 case View.SmallIcon:
1638 edit_text_box.TextAlign = HorizontalAlignment.Left;
1639 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1640 SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
1641 edit_text_box.Width = (int)sizef.Width + 4;
1642 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
1643 edit_text_box.WordWrap = false;
1644 edit_text_box.Multiline = false;
1646 case View.LargeIcon:
1647 edit_text_box.TextAlign = HorizontalAlignment.Center;
1648 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
1649 sizef = DeviceContext.MeasureString (item.Text, item.Font);
1650 edit_text_box.Width = (int)sizef.Width + 4;
1651 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
1652 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
1653 edit_text_box.WordWrap = true;
1654 edit_text_box.Multiline = true;
1658 edit_text_box.Text = item.Text;
1659 edit_text_box.Font = item.Font;
1660 edit_text_box.Visible = true;
1661 edit_text_box.Focus ();
1662 edit_text_box.SelectAll ();
1664 edit_args = new LabelEditEventArgs (owner.Items.IndexOf(edit_item));
1665 owner.OnBeforeLabelEdit (edit_args);
1667 if (edit_args.CancelEdit)
1673 internal void EndEdit (ListViewItem item)
1675 if (edit_text_box != null && edit_text_box.Visible) {
1676 edit_text_box.Visible = false;
1679 if (edit_item != null && edit_item == item) {
1680 owner.OnAfterLabelEdit (edit_args);
1682 if (!edit_args.CancelEdit) {
1683 if (edit_args.Label != null)
1684 edit_item.Text = edit_args.Label;
1686 edit_item.Text = edit_text_box.Text;
1695 internal override void OnPaintInternal (PaintEventArgs pe)
1697 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1700 internal override void OnGotFocusInternal (EventArgs e)
1706 internal class ListViewLabelEditTextBox : TextBox
1711 int max_height = -1;
1712 int min_height = -1;
1714 int old_number_lines = 1;
1716 SizeF text_size_one_char;
1718 public ListViewLabelEditTextBox ()
1720 min_height = DefaultSize.Height;
1721 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1724 public int MaxWidth {
1726 if (value < min_width)
1727 max_width = min_width;
1733 public int MaxHeight {
1735 if (value < min_height)
1736 max_height = min_height;
1742 public new int Width {
1752 public override Font Font {
1758 text_size_one_char = DeviceContext.MeasureString ("B", Font);
1762 protected override void OnTextChanged (EventArgs e)
1764 SizeF text_size = DeviceContext.MeasureString (Text, Font);
1766 int new_width = (int)text_size.Width + 8;
1769 ResizeTextBoxWidth (new_width);
1771 if (Width != max_width)
1772 ResizeTextBoxWidth (new_width);
1774 int number_lines = Lines.Length;
1776 if (number_lines != old_number_lines) {
1777 int new_height = number_lines * (int)text_size_one_char.Height + 4;
1778 old_number_lines = number_lines;
1780 ResizeTextBoxHeight (new_height);
1784 base.OnTextChanged (e);
1787 protected override bool IsInputKey (Keys key_data)
1789 if ((key_data & Keys.Alt) == 0) {
1790 switch (key_data & Keys.KeyCode) {
1795 return base.IsInputKey (key_data);
1798 protected override void OnKeyDown (KeyEventArgs e)
1800 if (e.KeyCode == Keys.Return && Visible) {
1801 this.Visible = false;
1802 OnEditingFinished (e);
1806 protected override void OnLostFocus (EventArgs e)
1809 OnEditingFinished (e);
1813 protected void OnEditingFinished (EventArgs e)
1815 if (EditingFinished != null)
1816 EditingFinished (this, EventArgs.Empty);
1819 private void ResizeTextBoxWidth (int new_width)
1821 if (new_width > max_width)
1822 base.Width = max_width;
1824 if (new_width >= min_width)
1825 base.Width = new_width;
1827 base.Width = min_width;
1830 private void ResizeTextBoxHeight (int new_height)
1832 if (new_height > max_height)
1833 base.Height = max_height;
1835 if (new_height >= min_height)
1836 base.Height = new_height;
1838 base.Height = min_height;
1841 public void Reset ()
1848 old_number_lines = 1;
1850 Text = String.Empty;
1855 public event EventHandler EditingFinished;
1858 internal override void OnPaintInternal (PaintEventArgs pe)
1863 CalculateScrollBars ();
1866 void FocusChanged (object o, EventArgs args)
1868 if (Items.Count == 0)
1871 if (FocusedItem == null)
1872 SetFocusedItem (Items [0]);
1874 item_control.Invalidate (FocusedItem.Bounds);
1877 private void ListView_MouseWheel (object sender, MouseEventArgs me)
1879 if (Items.Count == 0)
1882 int lines = me.Delta / 120;
1889 case View.SmallIcon:
1890 Scroll (v_scroll, -Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1892 case View.LargeIcon:
1893 Scroll (v_scroll, -(Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1896 Scroll (h_scroll, -Items [0].Bounds.Width * lines);
1901 private void ListView_SizeChanged (object sender, EventArgs e)
1903 CalculateListView (alignment);
1906 private void SetFocusedItem (ListViewItem item)
1908 if (focused_item != null)
1909 focused_item.Focused = false;
1912 item.Focused = true;
1914 focused_item = item;
1917 private void HorizontalScroller (object sender, EventArgs e)
1919 item_control.EndEdit (item_control.edit_item);
1921 // Avoid unnecessary flickering, when button is
1922 // kept pressed at the end
1923 if (h_marker != h_scroll.Value) {
1925 int pixels = h_marker - h_scroll.Value;
1927 h_marker = h_scroll.Value;
1928 if (header_control.Visible)
1929 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1931 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1935 private void VerticalScroller (object sender, EventArgs e)
1937 item_control.EndEdit (item_control.edit_item);
1939 // Avoid unnecessary flickering, when button is
1940 // kept pressed at the end
1941 if (v_marker != v_scroll.Value) {
1942 int pixels = v_marker - v_scroll.Value;
1943 Rectangle area = item_control.ClientRectangle;
1944 v_marker = v_scroll.Value;
1945 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1948 #endregion // Internal Methods Properties
1950 #region Protected Methods
1951 protected override void CreateHandle ()
1953 base.CreateHandle ();
1954 for (int i = 0; i < SelectedItems.Count; i++)
1955 OnSelectedIndexChanged (EventArgs.Empty);
1958 protected override void Dispose (bool disposing)
1961 h_scroll.Dispose ();
1962 v_scroll.Dispose ();
1964 large_image_list = null;
1965 small_image_list = null;
1966 state_image_list = null;
1969 base.Dispose (disposing);
1972 protected override bool IsInputKey (Keys keyData)
1989 return base.IsInputKey (keyData);
1992 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1994 if (AfterLabelEdit != null)
1995 AfterLabelEdit (this, e);
1998 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
2000 if (BeforeLabelEdit != null)
2001 BeforeLabelEdit (this, e);
2004 protected virtual void OnColumnClick (ColumnClickEventArgs e)
2006 if (ColumnClick != null)
2007 ColumnClick (this, e);
2010 protected override void OnEnabledChanged (EventArgs e)
2012 base.OnEnabledChanged (e);
2015 protected override void OnFontChanged (EventArgs e)
2017 base.OnFontChanged (e);
2021 protected override void OnHandleCreated (EventArgs e)
2023 base.OnHandleCreated (e);
2027 protected override void OnHandleDestroyed (EventArgs e)
2029 base.OnHandleDestroyed (e);
2032 protected virtual void OnItemActivate (EventArgs e)
2034 if (ItemActivate != null)
2035 ItemActivate (this, e);
2038 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
2040 if (ItemCheck != null)
2041 ItemCheck (this, ice);
2044 protected virtual void OnItemDrag (ItemDragEventArgs e)
2046 if (ItemDrag != null)
2050 protected virtual void OnSelectedIndexChanged (EventArgs e)
2052 if (SelectedIndexChanged != null)
2053 SelectedIndexChanged (this, e);
2056 protected override void OnSystemColorsChanged (EventArgs e)
2058 base.OnSystemColorsChanged (e);
2061 protected void RealizeProperties ()
2066 protected void UpdateExtendedStyles ()
2071 protected override void WndProc (ref Message m)
2073 base.WndProc (ref m);
2075 #endregion // Protected Methods
2077 #region Public Instance Methods
2078 public void ArrangeIcons ()
2080 ArrangeIcons (this.alignment);
2083 public void ArrangeIcons (ListViewAlignment alignment)
2085 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2086 if (view == View.LargeIcon || view == View.SmallIcon) {
2087 this.CalculateListView (alignment);
2088 // we have done the calculations already
2089 this.Redraw (false);
2093 public void BeginUpdate ()
2095 // flag to avoid painting
2099 public void Clear ()
2102 items.Clear (); // Redraw (true) called here
2105 public void EndUpdate ()
2107 // flag to avoid painting
2110 // probably, now we need a redraw with recalculations
2114 public void EnsureVisible (int index)
2116 if (index < 0 || index >= items.Count || scrollable == false)
2119 Rectangle view_rect = item_control.ClientRectangle;
2120 Rectangle bounds = items [index].Bounds;
2122 if (view_rect.Contains (bounds))
2125 if (bounds.Left < 0)
2126 h_scroll.Value += bounds.Left;
2127 else if (bounds.Right > view_rect.Right)
2128 h_scroll.Value += (bounds.Right - view_rect.Right);
2131 v_scroll.Value += bounds.Top;
2132 else if (bounds.Bottom > view_rect.Bottom)
2133 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
2136 public ListViewItem GetItemAt (int x, int y)
2138 foreach (ListViewItem item in items) {
2139 if (item.Bounds.Contains (x, y))
2145 public Rectangle GetItemRect (int index)
2147 return GetItemRect (index, ItemBoundsPortion.Entire);
2150 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
2152 if (index < 0 || index >= items.Count)
2153 throw new IndexOutOfRangeException ("index");
2155 return items [index].GetBounds (portion);
2163 // we need this overload to reuse the logic for sorting, while allowing
2164 // redrawing to be done by caller or have it done by this method when
2165 // sorting is really performed
2167 // ListViewItemCollection's Add and AddRange methods call this overload
2168 // with redraw set to false, as they take care of redrawing themselves
2169 // (they even want to redraw the listview if no sort is performed, as
2170 // an item was added), while ListView.Sort () only wants to redraw if
2171 // sorting was actually performed
2172 private void Sort (bool redraw)
2174 if (!IsHandleCreated || item_sorter == null) {
2178 items.Sort (item_sorter);
2183 public override string ToString ()
2185 int count = this.Items.Count;
2188 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2190 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
2192 #endregion // Public Instance Methods
2197 class HeaderControl : Control {
2200 bool column_resize_active = false;
2201 ColumnHeader resize_column;
2202 ColumnHeader clicked_column;
2203 ColumnHeader drag_column;
2205 int drag_to_index = -1;
2207 public HeaderControl (ListView owner)
2210 MouseDown += new MouseEventHandler (HeaderMouseDown);
2211 MouseMove += new MouseEventHandler (HeaderMouseMove);
2212 MouseUp += new MouseEventHandler (HeaderMouseUp);
2215 private ColumnHeader ColumnAtX (int x)
2217 Point pt = new Point (x, 0);
2218 ColumnHeader result = null;
2219 foreach (ColumnHeader col in owner.Columns) {
2220 if (col.Rect.Contains (pt)) {
2228 private int GetReorderedIndex (ColumnHeader col)
2230 if (owner.reordered_column_indices == null)
2233 for (int i = 0; i < owner.Columns.Count; i++)
2234 if (owner.reordered_column_indices [i] == col.Index)
2236 throw new Exception ("Column index missing from reordered array");
2239 private void HeaderMouseDown (object sender, MouseEventArgs me)
2241 if (resize_column != null) {
2242 column_resize_active = true;
2247 clicked_column = ColumnAtX (me.X + owner.h_marker);
2249 if (clicked_column != null) {
2251 if (owner.AllowColumnReorder) {
2253 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
2254 drag_column.column_rect = clicked_column.Rect;
2255 drag_to_index = GetReorderedIndex (clicked_column);
2257 clicked_column.pressed = true;
2258 Rectangle bounds = clicked_column.Rect;
2259 bounds.X -= owner.h_marker;
2260 Invalidate (bounds);
2265 private void HeaderMouseMove (object sender, MouseEventArgs me)
2267 Point pt = new Point (me.X + owner.h_marker, me.Y);
2269 if (column_resize_active) {
2270 resize_column.Width = pt.X - resize_column.X;
2271 if (resize_column.Width < 0)
2272 resize_column.Width = 0;
2276 resize_column = null;
2278 if (clicked_column != null) {
2279 if (owner.AllowColumnReorder) {
2282 r = drag_column.column_rect;
2283 r.X = clicked_column.Rect.X + me.X - drag_x;
2284 drag_column.column_rect = r;
2286 int x = me.X + owner.h_marker;
2287 ColumnHeader over = ColumnAtX (x);
2289 drag_to_index = owner.Columns.Count;
2290 else if (x < over.X + over.Width / 2)
2291 drag_to_index = GetReorderedIndex (over);
2293 drag_to_index = GetReorderedIndex (over) + 1;
2296 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
2297 bool pressed = clicked_column.pressed;
2298 clicked_column.pressed = over == clicked_column;
2299 if (clicked_column.pressed ^ pressed) {
2300 Rectangle bounds = clicked_column.Rect;
2301 bounds.X -= owner.h_marker;
2302 Invalidate (bounds);
2308 for (int i = 0; i < owner.Columns.Count; i++) {
2309 Rectangle zone = owner.Columns [i].Rect;
2310 zone.X = zone.Right - 5;
2312 if (zone.Contains (pt)) {
2313 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
2315 resize_column = owner.Columns [i];
2320 if (resize_column == null)
2321 Cursor = Cursors.Default;
2323 Cursor = Cursors.VSplit;
2326 void HeaderMouseUp (object sender, MouseEventArgs me)
2330 if (column_resize_active) {
2331 column_resize_active = false;
2332 resize_column = null;
2333 Cursor = Cursors.Default;
2337 if (clicked_column != null && clicked_column.pressed) {
2338 clicked_column.pressed = false;
2339 Rectangle bounds = clicked_column.Rect;
2340 bounds.X -= owner.h_marker;
2341 Invalidate (bounds);
2342 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
2345 if (drag_column != null && owner.AllowColumnReorder) {
2347 if (drag_to_index > GetReorderedIndex (clicked_column))
2349 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
2350 owner.ReorderColumn (clicked_column, drag_to_index);
2355 clicked_column = null;
2358 internal override void OnPaintInternal (PaintEventArgs pe)
2363 Theme theme = ThemeEngine.Current;
2364 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2366 if (drag_column == null)
2370 if (drag_to_index == owner.Columns.Count)
2371 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2373 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2374 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2377 protected override void WndProc (ref Message m)
2379 switch ((Msg)m.Msg) {
2380 case Msg.WM_SETFOCUS:
2384 base.WndProc (ref m);
2390 private class ItemComparer : IComparer {
2391 readonly SortOrder sort_order;
2393 public ItemComparer (SortOrder sortOrder)
2395 sort_order = sortOrder;
2398 public int Compare (object x, object y)
2400 ListViewItem item_x = x as ListViewItem;
2401 ListViewItem item_y = y as ListViewItem;
2402 if (sort_order == SortOrder.Ascending)
2403 return String.Compare (item_x.Text, item_y.Text);
2405 return String.Compare (item_y.Text, item_x.Text);
2409 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2411 private readonly ListView owner;
2413 #region Public Constructor
2414 public CheckedIndexCollection (ListView owner)
2418 #endregion // Public Constructor
2420 #region Public Properties
2423 get { return owner.CheckedItems.Count; }
2426 public bool IsReadOnly {
2427 get { return true; }
2430 public int this [int index] {
2432 int [] indices = GetIndices ();
2433 if (index < 0 || index >= indices.Length)
2434 throw new ArgumentOutOfRangeException ("index");
2435 return indices [index];
2439 bool ICollection.IsSynchronized {
2440 get { return false; }
2443 object ICollection.SyncRoot {
2444 get { return this; }
2447 bool IList.IsFixedSize {
2448 get { return true; }
2451 object IList.this [int index] {
2452 get { return this [index]; }
2453 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2455 #endregion // Public Properties
2457 #region Public Methods
2458 public bool Contains (int checkedIndex)
2460 int [] indices = GetIndices ();
2461 for (int i = 0; i < indices.Length; i++) {
2462 if (indices [i] == checkedIndex)
2468 public IEnumerator GetEnumerator ()
2470 int [] indices = GetIndices ();
2471 return indices.GetEnumerator ();
2474 void ICollection.CopyTo (Array dest, int index)
2476 int [] indices = GetIndices ();
2477 Array.Copy (indices, 0, dest, index, indices.Length);
2480 int IList.Add (object value)
2482 throw new NotSupportedException ("Add operation is not supported.");
2487 throw new NotSupportedException ("Clear operation is not supported.");
2490 bool IList.Contains (object checkedIndex)
2492 if (!(checkedIndex is int))
2494 return Contains ((int) checkedIndex);
2497 int IList.IndexOf (object checkedIndex)
2499 if (!(checkedIndex is int))
2501 return IndexOf ((int) checkedIndex);
2504 void IList.Insert (int index, object value)
2506 throw new NotSupportedException ("Insert operation is not supported.");
2509 void IList.Remove (object value)
2511 throw new NotSupportedException ("Remove operation is not supported.");
2514 void IList.RemoveAt (int index)
2516 throw new NotSupportedException ("RemoveAt operation is not supported.");
2519 public int IndexOf (int checkedIndex)
2521 int [] indices = GetIndices ();
2522 for (int i = 0; i < indices.Length; i++) {
2523 if (indices [i] == checkedIndex)
2528 #endregion // Public Methods
2530 private int [] GetIndices ()
2532 ArrayList checked_items = owner.CheckedItems.List;
2533 int [] indices = new int [checked_items.Count];
2534 for (int i = 0; i < checked_items.Count; i++) {
2535 ListViewItem item = (ListViewItem) checked_items [i];
2536 indices [i] = item.Index;
2540 } // CheckedIndexCollection
2542 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2544 private readonly ListView owner;
2545 private ArrayList list;
2547 #region Public Constructor
2548 public CheckedListViewItemCollection (ListView owner)
2551 this.owner.Items.Changed += new CollectionChangedHandler (
2552 ItemsCollection_Changed);
2554 #endregion // Public Constructor
2556 #region Public Properties
2560 if (!owner.CheckBoxes)
2566 public bool IsReadOnly {
2567 get { return true; }
2570 public ListViewItem this [int index] {
2572 ArrayList checked_items = List;
2573 if (index < 0 || index >= checked_items.Count)
2574 throw new ArgumentOutOfRangeException ("index");
2575 return (ListViewItem) checked_items [index];
2579 bool ICollection.IsSynchronized {
2580 get { return false; }
2583 object ICollection.SyncRoot {
2584 get { return this; }
2587 bool IList.IsFixedSize {
2588 get { return true; }
2591 object IList.this [int index] {
2592 get { return this [index]; }
2593 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2595 #endregion // Public Properties
2597 #region Public Methods
2598 public bool Contains (ListViewItem item)
2600 if (!owner.CheckBoxes)
2602 return List.Contains (item);
2605 public void CopyTo (Array dest, int index)
2607 if (!owner.CheckBoxes)
2609 List.CopyTo (dest, index);
2612 public IEnumerator GetEnumerator ()
2614 if (!owner.CheckBoxes)
2615 return (new ListViewItem [0]).GetEnumerator ();
2616 return List.GetEnumerator ();
2619 int IList.Add (object value)
2621 throw new NotSupportedException ("Add operation is not supported.");
2626 throw new NotSupportedException ("Clear operation is not supported.");
2629 bool IList.Contains (object item)
2631 if (!(item is ListViewItem))
2633 return Contains ((ListViewItem) item);
2636 int IList.IndexOf (object item)
2638 if (!(item is ListViewItem))
2640 return IndexOf ((ListViewItem) item);
2643 void IList.Insert (int index, object value)
2645 throw new NotSupportedException ("Insert operation is not supported.");
2648 void IList.Remove (object value)
2650 throw new NotSupportedException ("Remove operation is not supported.");
2653 void IList.RemoveAt (int index)
2655 throw new NotSupportedException ("RemoveAt operation is not supported.");
2658 public int IndexOf (ListViewItem item)
2660 if (!owner.CheckBoxes)
2662 return List.IndexOf (item);
2664 #endregion // Public Methods
2666 internal ArrayList List {
2669 list = new ArrayList ();
2670 foreach (ListViewItem item in owner.Items) {
2679 internal void Reset ()
2681 // force re-population of list
2685 private void ItemsCollection_Changed ()
2689 } // CheckedListViewItemCollection
2691 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2693 internal ArrayList list;
2694 private ListView owner;
2696 #region Public Constructor
2697 public ColumnHeaderCollection (ListView owner)
2699 list = new ArrayList ();
2702 #endregion // Public Constructor
2704 #region Public Properties
2707 get { return list.Count; }
2710 public bool IsReadOnly {
2711 get { return false; }
2714 public virtual ColumnHeader this [int index] {
2716 if (index < 0 || index >= list.Count)
2717 throw new ArgumentOutOfRangeException ("index");
2718 return (ColumnHeader) list [index];
2722 bool ICollection.IsSynchronized {
2723 get { return true; }
2726 object ICollection.SyncRoot {
2727 get { return this; }
2730 bool IList.IsFixedSize {
2731 get { return list.IsFixedSize; }
2734 object IList.this [int index] {
2735 get { return this [index]; }
2736 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2738 #endregion // Public Properties
2740 #region Public Methods
2741 public virtual int Add (ColumnHeader value)
2744 value.owner = this.owner;
2745 idx = list.Add (value);
2746 if (owner.IsHandleCreated) {
2747 owner.Redraw (true);
2752 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2754 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2755 this.Add (colHeader);
2759 public virtual void AddRange (ColumnHeader [] values)
2761 foreach (ColumnHeader colHeader in values) {
2762 colHeader.owner = this.owner;
2766 owner.Redraw (true);
2769 public virtual void Clear ()
2772 owner.Redraw (true);
2775 public bool Contains (ColumnHeader value)
2777 return list.Contains (value);
2780 public IEnumerator GetEnumerator ()
2782 return list.GetEnumerator ();
2785 void ICollection.CopyTo (Array dest, int index)
2787 list.CopyTo (dest, index);
2790 int IList.Add (object value)
2792 if (! (value is ColumnHeader)) {
2793 throw new ArgumentException ("Not of type ColumnHeader", "value");
2796 return this.Add ((ColumnHeader) value);
2799 bool IList.Contains (object value)
2801 if (! (value is ColumnHeader)) {
2802 throw new ArgumentException ("Not of type ColumnHeader", "value");
2805 return this.Contains ((ColumnHeader) value);
2808 int IList.IndexOf (object value)
2810 if (! (value is ColumnHeader)) {
2811 throw new ArgumentException ("Not of type ColumnHeader", "value");
2814 return this.IndexOf ((ColumnHeader) value);
2817 void IList.Insert (int index, object value)
2819 if (! (value is ColumnHeader)) {
2820 throw new ArgumentException ("Not of type ColumnHeader", "value");
2823 this.Insert (index, (ColumnHeader) value);
2826 void IList.Remove (object value)
2828 if (! (value is ColumnHeader)) {
2829 throw new ArgumentException ("Not of type ColumnHeader", "value");
2832 this.Remove ((ColumnHeader) value);
2835 public int IndexOf (ColumnHeader value)
2837 return list.IndexOf (value);
2840 public void Insert (int index, ColumnHeader value)
2842 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2843 // but it's really only greater.
2844 if (index < 0 || index > list.Count)
2845 throw new ArgumentOutOfRangeException ("index");
2847 value.owner = this.owner;
2848 list.Insert (index, value);
2849 owner.Redraw (true);
2852 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2854 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2855 this.Insert (index, colHeader);
2858 public virtual void Remove (ColumnHeader column)
2860 // TODO: Update Column internal index ?
2861 list.Remove (column);
2862 owner.Redraw (true);
2865 public virtual void RemoveAt (int index)
2867 if (index < 0 || index >= list.Count)
2868 throw new ArgumentOutOfRangeException ("index");
2870 // TODO: Update Column internal index ?
2871 list.RemoveAt (index);
2872 owner.Redraw (true);
2874 #endregion // Public Methods
2877 } // ColumnHeaderCollection
2879 public class ListViewItemCollection : IList, ICollection, IEnumerable
2881 private readonly ArrayList list;
2882 private readonly ListView owner;
2884 #region Public Constructor
2885 public ListViewItemCollection (ListView owner)
2887 list = new ArrayList ();
2890 #endregion // Public Constructor
2892 #region Public Properties
2895 get { return list.Count; }
2898 public bool IsReadOnly {
2899 get { return false; }
2902 public virtual ListViewItem this [int displayIndex] {
2904 if (displayIndex < 0 || displayIndex >= list.Count)
2905 throw new ArgumentOutOfRangeException ("displayIndex");
2906 return (ListViewItem) list [displayIndex];
2910 if (displayIndex < 0 || displayIndex >= list.Count)
2911 throw new ArgumentOutOfRangeException ("displayIndex");
2913 if (list.Contains (value))
2914 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2916 value.Owner = owner;
2917 list [displayIndex] = value;
2920 owner.Redraw (true);
2924 bool ICollection.IsSynchronized {
2925 get { return true; }
2928 object ICollection.SyncRoot {
2929 get { return this; }
2932 bool IList.IsFixedSize {
2933 get { return list.IsFixedSize; }
2936 object IList.this [int index] {
2937 get { return this [index]; }
2939 if (value is ListViewItem)
2940 this [index] = (ListViewItem) value;
2942 this [index] = new ListViewItem (value.ToString ());
2946 #endregion // Public Properties
2948 #region Public Methods
2949 public virtual ListViewItem Add (ListViewItem value)
2951 if (list.Contains (value))
2952 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2954 value.Owner = owner;
2959 owner.Redraw (true);
2963 public virtual ListViewItem Add (string text)
2965 ListViewItem item = new ListViewItem (text);
2966 return this.Add (item);
2969 public virtual ListViewItem Add (string text, int imageIndex)
2971 ListViewItem item = new ListViewItem (text, imageIndex);
2972 return this.Add (item);
2975 public void AddRange (ListViewItem [] values)
2979 foreach (ListViewItem item in values) {
2986 owner.Redraw (true);
2989 public virtual void Clear ()
2991 owner.SetFocusedItem (null);
2992 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2995 owner.Redraw (true);
2998 public bool Contains (ListViewItem item)
3000 return list.Contains (item);
3003 public void CopyTo (Array dest, int index)
3005 list.CopyTo (dest, index);
3008 public IEnumerator GetEnumerator ()
3010 return list.GetEnumerator ();
3013 int IList.Add (object item)
3018 if (item is ListViewItem) {
3019 li = (ListViewItem) item;
3020 if (list.Contains (li))
3021 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3024 li = new ListViewItem (item.ToString ());
3027 result = list.Add (li);
3029 owner.Redraw (true);
3034 bool IList.Contains (object item)
3036 return list.Contains (item);
3039 int IList.IndexOf (object item)
3041 return list.IndexOf (item);
3044 void IList.Insert (int index, object item)
3046 if (item is ListViewItem)
3047 this.Insert (index, (ListViewItem) item);
3049 this.Insert (index, item.ToString ());
3052 void IList.Remove (object item)
3054 Remove ((ListViewItem) item);
3057 public int IndexOf (ListViewItem item)
3059 return list.IndexOf (item);
3062 public ListViewItem Insert (int index, ListViewItem item)
3064 if (index < 0 || index > list.Count)
3065 throw new ArgumentOutOfRangeException ("index");
3067 if (list.Contains (item))
3068 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3071 list.Insert (index, item);
3073 owner.Redraw (true);
3077 public ListViewItem Insert (int index, string text)
3079 return this.Insert (index, new ListViewItem (text));
3082 public ListViewItem Insert (int index, string text, int imageIndex)
3084 return this.Insert (index, new ListViewItem (text, imageIndex));
3087 public virtual void Remove (ListViewItem item)
3089 if (!list.Contains (item))
3092 bool selection_changed = owner.SelectedItems.Contains (item);
3095 owner.Redraw (true);
3096 if (selection_changed)
3097 owner.OnSelectedIndexChanged (EventArgs.Empty);
3100 public virtual void RemoveAt (int index)
3102 if (index < 0 || index >= Count)
3103 throw new ArgumentOutOfRangeException ("index");
3104 bool selection_changed = owner.SelectedIndices.Contains (index);
3105 list.RemoveAt (index);
3107 owner.Redraw (false);
3108 if (selection_changed)
3109 owner.OnSelectedIndexChanged (EventArgs.Empty);
3111 #endregion // Public Methods
3113 internal event CollectionChangedHandler Changed;
3115 internal void Sort (IComparer comparer)
3117 list.Sort (comparer);
3121 internal void OnChange ()
3123 if (Changed != null)
3126 } // ListViewItemCollection
3128 public class SelectedIndexCollection : IList, ICollection, IEnumerable
3130 private readonly ListView owner;
3132 #region Public Constructor
3133 public SelectedIndexCollection (ListView owner)
3137 #endregion // Public Constructor
3139 #region Public Properties
3143 return owner.SelectedItems.Count;
3147 public bool IsReadOnly {
3148 get { return true; }
3151 public int this [int index] {
3153 int [] indices = GetIndices ();
3154 if (index < 0 || index >= indices.Length)
3155 throw new ArgumentOutOfRangeException ("index");
3156 return indices [index];
3160 bool ICollection.IsSynchronized {
3161 get { return false; }
3164 object ICollection.SyncRoot {
3165 get { return this; }
3168 bool IList.IsFixedSize {
3169 get { return true; }
3172 object IList.this [int index] {
3173 get { return this [index]; }
3174 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3176 #endregion // Public Properties
3178 #region Public Methods
3179 public bool Contains (int selectedIndex)
3181 int [] indices = GetIndices ();
3182 for (int i = 0; i < indices.Length; i++) {
3183 if (indices [i] == selectedIndex)
3189 public void CopyTo (Array dest, int index)
3191 int [] indices = GetIndices ();
3192 Array.Copy (indices, 0, dest, index, indices.Length);
3195 public IEnumerator GetEnumerator ()
3197 int [] indices = GetIndices ();
3198 return indices.GetEnumerator ();
3201 int IList.Add (object value)
3203 throw new NotSupportedException ("Add operation is not supported.");
3208 throw new NotSupportedException ("Clear operation is not supported.");
3211 bool IList.Contains (object selectedIndex)
3213 if (!(selectedIndex is int))
3215 return Contains ((int) selectedIndex);
3218 int IList.IndexOf (object selectedIndex)
3220 if (!(selectedIndex is int))
3222 return IndexOf ((int) selectedIndex);
3225 void IList.Insert (int index, object value)
3227 throw new NotSupportedException ("Insert operation is not supported.");
3230 void IList.Remove (object value)
3232 throw new NotSupportedException ("Remove operation is not supported.");
3235 void IList.RemoveAt (int index)
3237 throw new NotSupportedException ("RemoveAt operation is not supported.");
3240 public int IndexOf (int selectedIndex)
3242 int [] indices = GetIndices ();
3243 for (int i = 0; i < indices.Length; i++) {
3244 if (indices [i] == selectedIndex)
3249 #endregion // Public Methods
3251 private int [] GetIndices ()
3253 ArrayList selected_items = owner.SelectedItems.List;
3254 int [] indices = new int [selected_items.Count];
3255 for (int i = 0; i < selected_items.Count; i++) {
3256 ListViewItem item = (ListViewItem) selected_items [i];
3257 indices [i] = item.Index;
3261 } // SelectedIndexCollection
3263 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
3265 private readonly ListView owner;
3266 private ArrayList list;
3268 #region Public Constructor
3269 public SelectedListViewItemCollection (ListView owner)
3272 this.owner.Items.Changed += new CollectionChangedHandler (
3273 ItemsCollection_Changed);
3275 #endregion // Public Constructor
3277 #region Public Properties
3281 if (!owner.IsHandleCreated)
3287 public bool IsReadOnly {
3288 get { return true; }
3291 public ListViewItem this [int index] {
3293 ArrayList selected_items = List;
3294 if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
3295 throw new ArgumentOutOfRangeException ("index");
3296 return (ListViewItem) selected_items [index];
3300 bool ICollection.IsSynchronized {
3301 get { return false; }
3304 object ICollection.SyncRoot {
3305 get { return this; }
3308 bool IList.IsFixedSize {
3309 get { return true; }
3312 object IList.this [int index] {
3313 get { return this [index]; }
3314 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3316 #endregion // Public Properties
3318 #region Public Methods
3319 public void Clear ()
3321 if (!owner.IsHandleCreated)
3324 foreach (ListViewItem item in List)
3325 item.Selected = false;
3328 public bool Contains (ListViewItem item)
3330 if (!owner.IsHandleCreated)
3332 return List.Contains (item);
3335 public void CopyTo (Array dest, int index)
3337 if (!owner.IsHandleCreated)
3339 List.CopyTo (dest, index);
3342 public IEnumerator GetEnumerator ()
3344 if (!owner.IsHandleCreated)
3345 return (new ListViewItem [0]).GetEnumerator ();
3346 return List.GetEnumerator ();
3349 int IList.Add (object value)
3351 throw new NotSupportedException ("Add operation is not supported.");
3354 bool IList.Contains (object item)
3356 if (!(item is ListViewItem))
3358 return Contains ((ListViewItem) item);
3361 int IList.IndexOf (object item)
3363 if (!(item is ListViewItem))
3365 return IndexOf ((ListViewItem) item);
3368 void IList.Insert (int index, object value)
3370 throw new NotSupportedException ("Insert operation is not supported.");
3373 void IList.Remove (object value)
3375 throw new NotSupportedException ("Remove operation is not supported.");
3378 void IList.RemoveAt (int index)
3380 throw new NotSupportedException ("RemoveAt operation is not supported.");
3383 public int IndexOf (ListViewItem item)
3385 if (!owner.IsHandleCreated)
3387 return List.IndexOf (item);
3389 #endregion // Public Methods
3391 internal ArrayList List {
3394 list = new ArrayList ();
3395 foreach (ListViewItem item in owner.Items) {
3404 internal void Reset ()
3406 // force re-population of list
3410 private void ItemsCollection_Changed ()
3414 } // SelectedListViewItemCollection
3416 internal delegate void CollectionChangedHandler ();
3418 #endregion // Subclasses