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 static object AfterLabelEditEvent
= new object ();
97 static object BeforeLabelEditEvent
= new object ();
98 static object ColumnClickEvent
= new object ();
99 static object ItemActivateEvent
= new object ();
100 static object ItemCheckEvent
= new object ();
101 static object ItemDragEvent
= new object ();
102 static object SelectedIndexChangedEvent
= new object ();
104 public event LabelEditEventHandler AfterLabelEdit
{
105 add { Events.AddHandler (AfterLabelEditEvent, value); }
106 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
110 [EditorBrowsable (EditorBrowsableState
.Never
)]
111 public new event EventHandler BackgroundImageChanged
{
112 add { base.BackgroundImageChanged += value; }
113 remove { base.BackgroundImageChanged -= value; }
116 public event LabelEditEventHandler BeforeLabelEdit
{
117 add { Events.AddHandler (BeforeLabelEditEvent, value); }
118 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
121 public event ColumnClickEventHandler ColumnClick
{
122 add { Events.AddHandler (ColumnClickEvent, value); }
123 remove { Events.RemoveHandler (ColumnClickEvent, value); }
126 public event EventHandler ItemActivate
{
127 add { Events.AddHandler (ItemActivateEvent, value); }
128 remove { Events.RemoveHandler (ItemActivateEvent, value); }
131 public event ItemCheckEventHandler ItemCheck
{
132 add { Events.AddHandler (ItemCheckEvent, value); }
133 remove { Events.RemoveHandler (ItemCheckEvent, value); }
136 public event ItemDragEventHandler ItemDrag
{
137 add { Events.AddHandler (ItemDragEvent, value); }
138 remove { Events.RemoveHandler (ItemDragEvent, value); }
142 [EditorBrowsable (EditorBrowsableState
.Never
)]
143 public new event PaintEventHandler Paint
{
144 add { base.Paint += value; }
145 remove { base.Paint -= value; }
148 public event EventHandler SelectedIndexChanged
{
149 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
150 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
154 [EditorBrowsable (EditorBrowsableState
.Never
)]
155 public new event EventHandler TextChanged
{
156 add { base.TextChanged += value; }
157 remove { base.TextChanged -= value; }
162 #region Public Constructors
165 background_color
= ThemeEngine
.Current
.ColorWindow
;
166 items
= new ListViewItemCollection (this);
167 checked_indices
= new CheckedIndexCollection (this);
168 checked_items
= new CheckedListViewItemCollection (this);
169 columns
= new ColumnHeaderCollection (this);
170 foreground_color
= SystemColors
.WindowText
;
171 selected_indices
= new SelectedIndexCollection (this);
172 selected_items
= new SelectedListViewItemCollection (this);
174 border_style
= BorderStyle
.Fixed3D
;
176 header_control
= new HeaderControl (this);
177 header_control
.Visible
= false;
178 Controls
.AddImplicit (header_control
);
180 item_control
= new ItemControl (this);
181 Controls
.AddImplicit (item_control
);
183 h_scroll
= new ImplicitHScrollBar ();
184 Controls
.AddImplicit (this.h_scroll
);
186 v_scroll
= new ImplicitVScrollBar ();
187 Controls
.AddImplicit (this.v_scroll
);
189 h_marker
= v_marker
= 0;
190 keysearch_tickcnt
= 0;
192 // scroll bars are disabled initially
193 h_scroll
.Visible
= false;
194 h_scroll
.ValueChanged
+= new EventHandler(HorizontalScroller
);
195 v_scroll
.Visible
= false;
196 v_scroll
.ValueChanged
+= new EventHandler(VerticalScroller
);
199 base.KeyDown
+= new KeyEventHandler(ListView_KeyDown
);
200 SizeChanged
+= new EventHandler (ListView_SizeChanged
);
201 GotFocus
+= new EventHandler (FocusChanged
);
202 LostFocus
+= new EventHandler (FocusChanged
);
203 MouseWheel
+= new MouseEventHandler(ListView_MouseWheel
);
205 this.SetStyle (ControlStyles
.UserPaint
| ControlStyles
.StandardClick
207 | ControlStyles
.UseTextForAccessibility
211 #endregion // Public Constructors
213 #region Private Internal Properties
214 internal Size CheckBoxSize
{
216 if (this.check_boxes
) {
217 if (this.state_image_list
!= null)
218 return this.state_image_list
.ImageSize
;
220 return ThemeEngine
.Current
.ListViewCheckBoxSize
;
226 #endregion // Private Internal Properties
228 #region Protected Properties
229 protected override CreateParams CreateParams
{
230 get { return base.CreateParams; }
233 protected override Size DefaultSize
{
234 get { return ThemeEngine.Current.ListViewDefaultSize; }
236 #endregion // Protected Properties
238 #region Public Instance Properties
239 [DefaultValue (ItemActivation
.Standard
)]
240 public ItemActivation Activation
{
241 get { return activation; }
243 if (value != ItemActivation
.Standard
&& value != ItemActivation
.OneClick
&&
244 value != ItemActivation
.TwoClick
) {
245 throw new InvalidEnumArgumentException (string.Format
246 ("Enum argument value '{0}' is not valid for Activation", value));
253 [DefaultValue (ListViewAlignment
.Top
)]
255 public ListViewAlignment Alignment
{
256 get { return alignment; }
258 if (value != ListViewAlignment
.Default
&& value != ListViewAlignment
.Left
&&
259 value != ListViewAlignment
.SnapToGrid
&& value != ListViewAlignment
.Top
) {
260 throw new InvalidEnumArgumentException (string.Format
261 ("Enum argument value '{0}' is not valid for Alignment", value));
264 if (this.alignment
!= value) {
266 // alignment does not matter in Details/List views
267 if (this.view
== View
.LargeIcon
||
268 this.View
== View
.SmallIcon
)
274 [DefaultValue (false)]
275 public bool AllowColumnReorder
{
276 get { return allow_column_reorder; }
277 set { allow_column_reorder = value; }
280 [DefaultValue (true)]
281 public bool AutoArrange
{
282 get { return auto_arrange; }
284 if (auto_arrange
!= value) {
285 auto_arrange
= value;
286 // autoarrange does not matter in Details/List views
287 if (this.view
== View
.LargeIcon
|| this.View
== View
.SmallIcon
)
293 public override Color BackColor
{
295 if (background_color
.IsEmpty
)
296 return ThemeEngine
.Current
.ColorWindow
;
298 return background_color
;
300 set { background_color = value; }
304 [EditorBrowsable (EditorBrowsableState
.Never
)]
305 public override Image BackgroundImage
{
306 get { return background_image; }
308 if (value == background_image
)
311 background_image
= value;
312 OnBackgroundImageChanged (EventArgs
.Empty
);
316 [DefaultValue (BorderStyle
.Fixed3D
)]
318 public BorderStyle BorderStyle
{
319 get { return InternalBorderStyle; }
320 set { InternalBorderStyle = value; }
323 [DefaultValue (false)]
324 public bool CheckBoxes
{
325 get { return check_boxes; }
327 if (check_boxes
!= value) {
329 if (value && View
== View
.Tile
)
330 throw new NotSupportedException ("CheckBoxes are not"
331 + " supported in Tile view. Choose a different"
332 + " view or set CheckBoxes to false.");
342 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
343 public CheckedIndexCollection CheckedIndices
{
344 get { return checked_indices; }
348 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
349 public CheckedListViewItemCollection CheckedItems
{
350 get { return checked_items; }
353 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
355 [MergableProperty (false)]
356 public ColumnHeaderCollection Columns
{
357 get { return columns; }
361 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
362 public ListViewItem FocusedItem
{
368 public override Color ForeColor
{
370 if (foreground_color
.IsEmpty
)
371 return ThemeEngine
.Current
.ColorWindowText
;
373 return foreground_color
;
375 set { foreground_color = value; }
378 [DefaultValue (false)]
379 public bool FullRowSelect
{
380 get { return full_row_select; }
381 set { full_row_select = value; }
384 [DefaultValue (false)]
385 public bool GridLines
{
386 get { return grid_lines; }
388 if (grid_lines
!= value) {
395 [DefaultValue (ColumnHeaderStyle
.Clickable
)]
396 public ColumnHeaderStyle HeaderStyle
{
397 get { return header_style; }
399 if (header_style
== value)
403 case ColumnHeaderStyle
.Clickable
:
404 case ColumnHeaderStyle
.Nonclickable
:
405 case ColumnHeaderStyle
.None
:
408 throw new InvalidEnumArgumentException (string.Format
409 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
412 header_style
= value;
413 if (view
== View
.Details
)
418 [DefaultValue (true)]
419 public bool HideSelection
{
420 get { return hide_selection; }
422 if (hide_selection
!= value) {
423 hide_selection
= value;
429 [DefaultValue (false)]
430 public bool HoverSelection
{
431 get { return hover_selection; }
432 set { hover_selection = value; }
435 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
437 [MergableProperty (false)]
438 public ListViewItemCollection Items
{
439 get { return items; }
442 [DefaultValue (false)]
443 public bool LabelEdit
{
444 get { return label_edit; }
445 set { label_edit = value; }
448 [DefaultValue (true)]
450 public bool LabelWrap
{
451 get { return label_wrap; }
453 if (label_wrap
!= value) {
460 [DefaultValue (null)]
461 public ImageList LargeImageList
{
462 get { return large_image_list; }
464 large_image_list
= value;
470 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
471 public IComparer ListViewItemSorter
{
473 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
&& item_sorter
is ItemComparer
)
478 if (item_sorter
!= value) {
485 [DefaultValue (true)]
486 public bool MultiSelect
{
487 get { return multiselect; }
488 set { multiselect = value; }
491 [DefaultValue (true)]
492 public bool Scrollable
{
493 get { return scrollable; }
495 if (scrollable
!= value) {
503 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
504 public SelectedIndexCollection SelectedIndices
{
505 get { return selected_indices; }
509 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
510 public SelectedListViewItemCollection SelectedItems
{
511 get { return selected_items; }
515 [MonoTODO("Implement")]
516 public bool ShowGroups
{
526 [DefaultValue (null)]
527 public ImageList SmallImageList
{
528 get { return small_image_list; }
530 small_image_list
= value;
535 [DefaultValue (SortOrder
.None
)]
536 public SortOrder Sorting
{
537 get { return sort_order; }
539 if (!Enum
.IsDefined (typeof (SortOrder
), value)) {
540 throw new InvalidEnumArgumentException ("value", (int) value,
544 if (sort_order
== value)
549 if (value == SortOrder
.None
) {
550 if (item_sorter
!= null) {
551 // ListViewItemSorter should never be reset for SmallIcon
552 // and LargeIcon view
553 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
)
557 // in .NET 1.1, only internal IComparer would be
559 if (item_sorter
is ItemComparer
)
565 if (item_sorter
== null)
566 item_sorter
= new ItemComparer (value);
567 if (item_sorter
is ItemComparer
) {
569 item_sorter
= new ItemComparer (value);
571 // in .NET 1.1, the sort order is not updated for
572 // SmallIcon and LargeIcon views if no custom IComparer
574 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
)
575 item_sorter
= new ItemComparer (value);
583 [DefaultValue (null)]
584 public ImageList StateImageList
{
585 get { return state_image_list; }
587 state_image_list
= value;
594 [EditorBrowsable (EditorBrowsableState
.Never
)]
595 public override string Text
{
596 get { return base.Text; }
598 if (value == base.Text
)
607 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
608 public ListViewItem TopItem
{
611 if (this.items
.Count
== 0)
613 // if contents are not scrolled
614 // it is the first item
615 else if (h_marker
== 0 && v_marker
== 0)
616 return this.items
[0];
617 // do a hit test for the scrolled position
619 foreach (ListViewItem item
in this.items
) {
620 if (item
.Bounds
.X
>= 0 && item
.Bounds
.Y
>= 0)
629 [MonoTODO("Implement")]
630 public bool UseCompatibleStateImageBehavior
{
640 [DefaultValue (View
.LargeIcon
)]
644 if (!Enum
.IsDefined (typeof (View
), value))
645 throw new InvalidEnumArgumentException ("value", (int) value,
650 if (CheckBoxes
&& value == View
.Tile
)
651 throw new NotSupportedException ("CheckBoxes are not"
652 + " supported in Tile view. Choose a different"
653 + " view or set CheckBoxes to false.");
656 h_scroll
.Value
= v_scroll
.Value
= 0;
662 #endregion // Public Instance Properties
664 #region Internal Methods Properties
666 internal int FirstVisibleIndex
{
669 if (this.items
.Count
== 0)
672 if (h_marker
== 0 && v_marker
== 0)
675 foreach (ListViewItem item
in this.items
) {
676 if (item
.Bounds
.Right
>= 0 && item
.Bounds
.Bottom
>= 0)
685 internal int LastVisibleIndex
{
687 for (int i
= FirstVisibleIndex
; i
< Items
.Count
; i
++) {
688 if (View
== View
.List
|| Alignment
== ListViewAlignment
.Left
) {
689 if (Items
[i
].Bounds
.X
> ClientRectangle
.Right
)
692 if (Items
[i
].Bounds
.Y
> ClientRectangle
.Bottom
)
697 return Items
.Count
- 1;
701 internal void OnSelectedIndexChanged ()
704 OnSelectedIndexChanged (EventArgs
.Empty
);
707 internal int TotalWidth
{
708 get { return Math.Max (this.Width, this.layout_wd); }
711 internal int TotalHeight
{
712 get { return Math.Max (this.Height, this.layout_ht); }
715 internal void Redraw (bool recalculate
)
717 // Avoid calculations when control is being updated
722 CalculateListView (this.alignment
);
727 internal Size
GetChildColumnSize (int index
)
729 Size ret_size
= Size
.Empty
;
730 ColumnHeader col
= this.columns
[index
];
732 if (col
.Width
== -2) { // autosize = max(items, columnheader)
733 Size size
= Size
.Ceiling (this.DeviceContext
.MeasureString
734 (col
.Text
, this.Font
));
735 ret_size
= BiggestItem (index
);
736 if (size
.Width
> ret_size
.Width
)
739 else { // -1 and all the values < -2 are put under one category
740 ret_size
= BiggestItem (index
);
741 // fall back to empty columns' width if no subitem is available for a column
742 if (ret_size
.IsEmpty
) {
743 ret_size
.Width
= ThemeEngine
.Current
.ListViewEmptyColumnWidth
;
744 if (col
.Text
.Length
> 0)
745 ret_size
.Height
= Size
.Ceiling (this.DeviceContext
.MeasureString
746 (col
.Text
, this.Font
)).Height
;
748 ret_size
.Height
= this.Font
.Height
;
752 // adjust the size for icon and checkbox for 0th column
754 ret_size
.Width
+= (this.CheckBoxSize
.Width
+ 4);
755 if (this.small_image_list
!= null)
756 ret_size
.Width
+= this.small_image_list
.ImageSize
.Width
;
761 // Returns the size of biggest item text in a column.
762 private Size
BiggestItem (int col
)
764 Size temp
= Size
.Empty
;
765 Size ret_size
= Size
.Empty
;
767 // 0th column holds the item text, we check the size of
768 // the various subitems falling in that column and get
769 // the biggest one's size.
770 foreach (ListViewItem item
in items
) {
771 if (col
>= item
.SubItems
.Count
)
774 temp
= Size
.Ceiling (this.DeviceContext
.MeasureString
775 (item
.SubItems
[col
].Text
, this.Font
));
776 if (temp
.Width
> ret_size
.Width
)
780 // adjustment for space
781 if (!ret_size
.IsEmpty
)
787 const int max_wrap_padding
= 38;
789 // Sets the size of the biggest item text as per the view
790 private void CalcTextSize ()
792 // clear the old value
793 text_size
= Size
.Empty
;
795 if (items
.Count
== 0)
798 text_size
= BiggestItem (0);
800 if (view
== View
.LargeIcon
&& this.label_wrap
) {
801 Size temp
= Size
.Empty
;
802 if (this.check_boxes
)
803 temp
.Width
+= 2 * this.CheckBoxSize
.Width
;
804 int icon_w
= LargeImageList
== null ? 12 : LargeImageList
.ImageSize
.Width
;
805 temp
.Width
+= icon_w
+ max_wrap_padding
;
806 // wrapping is done for two lines only
807 if (text_size
.Width
> temp
.Width
) {
808 text_size
.Width
= temp
.Width
;
809 text_size
.Height
*= 2;
812 else if (view
== View
.List
) {
813 // in list view max text shown in determined by the
814 // control width, even if scolling is enabled.
815 int max_wd
= this.Width
- (this.CheckBoxSize
.Width
- 2);
816 if (this.small_image_list
!= null)
817 max_wd
-= this.small_image_list
.ImageSize
.Width
;
819 if (text_size
.Width
> max_wd
)
820 text_size
.Width
= max_wd
;
823 // we do the default settings, if we have got 0's
824 if (text_size
.Height
<= 0)
825 text_size
.Height
= this.Font
.Height
;
826 if (text_size
.Width
<= 0)
827 text_size
.Width
= this.Width
;
830 text_size
.Width
+= 4;
831 text_size
.Height
+= 2;
834 private void Scroll (ScrollBar scrollbar
, int delta
)
836 if (delta
== 0 || !scrollbar
.Visible
)
840 if (scrollbar
== h_scroll
)
841 max
= h_scroll
.Maximum
- item_control
.Width
;
843 max
= v_scroll
.Maximum
- item_control
.Height
;
845 int val
= scrollbar
.Value
+ delta
;
848 else if (val
< scrollbar
.Minimum
)
849 val
= scrollbar
.Minimum
;
850 scrollbar
.Value
= val
;
853 private void CalculateScrollBars ()
855 Rectangle client_area
= ClientRectangle
;
857 if (!this.scrollable
|| this.items
.Count
<= 0) {
858 h_scroll
.Visible
= false;
859 v_scroll
.Visible
= false;
860 item_control
.Location
= new Point (0, header_control
.Height
);
861 item_control
.Height
= ClientRectangle
.Width
- header_control
.Height
;
862 item_control
.Width
= ClientRectangle
.Width
;
863 header_control
.Width
= ClientRectangle
.Width
;
867 // Don't calculate if the view is not displayable
868 if (client_area
.Height
< 0 || client_area
.Width
< 0)
871 // making a scroll bar visible might make
872 // other scroll bar visible
873 if (layout_wd
> client_area
.Right
) {
874 h_scroll
.Visible
= true;
875 if ((layout_ht
+ h_scroll
.Height
) > client_area
.Bottom
)
876 v_scroll
.Visible
= true;
878 v_scroll
.Visible
= false;
879 } else if (layout_ht
> client_area
.Bottom
) {
880 v_scroll
.Visible
= true;
881 if ((layout_wd
+ v_scroll
.Width
) > client_area
.Right
)
882 h_scroll
.Visible
= true;
884 h_scroll
.Visible
= false;
886 h_scroll
.Visible
= false;
887 v_scroll
.Visible
= false;
890 item_control
.Height
= ClientRectangle
.Height
- header_control
.Height
;
892 if (h_scroll
.is_visible
) {
893 h_scroll
.Location
= new Point (client_area
.X
, client_area
.Bottom
- h_scroll
.Height
);
894 h_scroll
.Minimum
= 0;
896 // if v_scroll is visible, adjust the maximum of the
897 // h_scroll to account for the width of v_scroll
898 if (v_scroll
.Visible
) {
899 h_scroll
.Maximum
= layout_wd
+ v_scroll
.Width
;
900 h_scroll
.Width
= client_area
.Width
- v_scroll
.Width
;
903 h_scroll
.Maximum
= layout_wd
;
904 h_scroll
.Width
= client_area
.Width
;
907 h_scroll
.LargeChange
= client_area
.Width
;
908 h_scroll
.SmallChange
= Font
.Height
;
909 item_control
.Height
-= h_scroll
.Height
;
912 if (header_control
.is_visible
)
913 header_control
.Width
= ClientRectangle
.Width
;
914 item_control
.Width
= ClientRectangle
.Width
;
916 if (v_scroll
.is_visible
) {
917 v_scroll
.Location
= new Point (client_area
.Right
- v_scroll
.Width
, client_area
.Y
);
918 v_scroll
.Minimum
= 0;
920 // if h_scroll is visible, adjust the maximum of the
921 // v_scroll to account for the height of h_scroll
922 if (h_scroll
.Visible
) {
923 v_scroll
.Maximum
= layout_ht
+ h_scroll
.Height
;
924 v_scroll
.Height
= client_area
.Height
; // - h_scroll.Height already done
926 v_scroll
.Maximum
= layout_ht
;
927 v_scroll
.Height
= client_area
.Height
;
930 v_scroll
.LargeChange
= client_area
.Height
;
931 v_scroll
.SmallChange
= Font
.Height
;
932 if (header_control
.Visible
)
933 header_control
.Width
-= v_scroll
.Width
;
934 item_control
.Width
-= v_scroll
.Width
;
938 ColumnHeader
GetReorderedColumn (int index
)
940 if (reordered_column_indices
== null)
941 return Columns
[index
];
943 return Columns
[reordered_column_indices
[index
]];
946 void ReorderColumn (ColumnHeader col
, int index
)
948 if (reordered_column_indices
== null) {
949 reordered_column_indices
= new int [Columns
.Count
];
950 for (int i
= 0; i
< Columns
.Count
; i
++)
951 reordered_column_indices
[i
] = i
;
954 if (reordered_column_indices
[index
] == col
.Index
)
957 int[] curr
= reordered_column_indices
;
958 int[] result
= new int [Columns
.Count
];
960 for (int i
= 0; i
< Columns
.Count
; i
++) {
961 if (curr_idx
< Columns
.Count
&& curr
[curr_idx
] == col
.Index
)
965 result
[i
] = col
.Index
;
967 result
[i
] = curr
[curr_idx
++];
970 reordered_column_indices
= result
;
972 header_control
.Invalidate ();
973 item_control
.Invalidate ();
976 Size LargeIconItemSize
{
978 int image_w
= LargeImageList
== null ? 12 : LargeImageList
.ImageSize
.Width
;
979 int image_h
= LargeImageList
== null ? 2 : LargeImageList
.ImageSize
.Height
;
980 int w
= CheckBoxSize
.Width
+ 2 + Math
.Max (text_size
.Width
, image_w
);
981 int h
= text_size
.Height
+ 2 + Math
.Max (CheckBoxSize
.Height
, image_h
);
982 return new Size (w
, h
);
986 Size SmallIconItemSize
{
988 int image_w
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Width
;
989 int image_h
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Height
;
990 int w
= text_size
.Width
+ 2 + CheckBoxSize
.Width
+ image_w
;
991 int h
= Math
.Max (text_size
.Height
, Math
.Max (CheckBoxSize
.Height
, image_h
));
992 return new Size (w
, h
);
998 ListViewItem
[,] item_matrix
;
1000 void LayoutIcons (bool large_icons
, bool left_aligned
, int x_spacing
, int y_spacing
)
1002 header_control
.Visible
= false;
1003 header_control
.Size
= Size
.Empty
;
1004 item_control
.Visible
= true;
1005 item_control
.Location
= Point
.Empty
;
1007 if (items
.Count
== 0)
1010 Size sz
= large_icons
? LargeIconItemSize
: SmallIconItemSize
;
1012 Rectangle area
= ClientRectangle
;
1015 rows
= (int) Math
.Floor ((double)(area
.Height
- h_scroll
.Height
+ y_spacing
) / (double)(sz
.Height
+ y_spacing
));
1018 cols
= (int) Math
.Ceiling ((double)items
.Count
/ (double)rows
);
1020 cols
= (int) Math
.Floor ((double)(area
.Width
- v_scroll
.Width
+ x_spacing
) / (double)(sz
.Width
+ x_spacing
));
1023 rows
= (int) Math
.Ceiling ((double)items
.Count
/ (double)cols
);
1026 layout_ht
= rows
* (sz
.Height
+ y_spacing
) - y_spacing
;
1027 layout_wd
= cols
* (sz
.Width
+ x_spacing
) - x_spacing
;
1028 item_matrix
= new ListViewItem
[rows
, cols
];
1031 foreach (ListViewItem item
in items
) {
1032 int x
= col
* (sz
.Width
+ x_spacing
);
1033 int y
= row
* (sz
.Height
+ y_spacing
);
1034 item
.Location
= new Point (x
, y
);
1038 item_matrix
[row
, col
] = item
;
1040 if (++row
== rows
) {
1045 if (++col
== cols
) {
1052 item_control
.Size
= new Size (layout_wd
, layout_ht
);
1055 void LayoutHeader ()
1058 for (int i
= 0; i
< Columns
.Count
; i
++) {
1059 ColumnHeader col
= GetReorderedColumn (i
);
1062 col
.CalcColumnHeader ();
1066 if (x
< ClientRectangle
.Width
)
1067 x
= ClientRectangle
.Width
;
1069 if (header_style
== ColumnHeaderStyle
.None
) {
1070 header_control
.Visible
= false;
1071 header_control
.Size
= Size
.Empty
;
1073 header_control
.Width
= x
;
1074 header_control
.Height
= columns
[0].Ht
;
1075 header_control
.Visible
= true;
1079 void LayoutDetails ()
1081 if (columns
.Count
== 0) {
1082 header_control
.Visible
= false;
1083 item_control
.Visible
= false;
1089 item_control
.Visible
= true;
1090 item_control
.Location
= new Point (0, header_control
.Height
);
1093 if (items
.Count
> 0) {
1094 foreach (ListViewItem item
in items
) {
1096 item
.Location
= new Point (0, y
);
1097 y
+= item
.Bounds
.Height
+ 2;
1100 // some space for bottom gridline
1105 layout_wd
= Math
.Max (header_control
.Width
, item_control
.Width
);
1106 layout_ht
= y
+ header_control
.Height
;
1109 private void CalculateListView (ListViewAlignment align
)
1118 case View
.SmallIcon
:
1119 LayoutIcons (false, alignment
== ListViewAlignment
.Left
, 4, 2);
1122 case View
.LargeIcon
:
1123 LayoutIcons (true, alignment
== ListViewAlignment
.Left
,
1124 ThemeEngine
.Current
.ListViewHorizontalSpacing
,
1125 ThemeEngine
.Current
.ListViewVerticalSpacing
);
1129 LayoutIcons (false, true, 4, 2);
1133 CalculateScrollBars ();
1136 private bool KeySearchString (KeyEventArgs ke
)
1138 int current_tickcnt
= Environment
.TickCount
;
1139 if (keysearch_tickcnt
> 0 && current_tickcnt
- keysearch_tickcnt
> keysearch_keydelay
) {
1140 keysearch_text
= string.Empty
;
1143 keysearch_text
+= (char) ke
.KeyData
;
1144 keysearch_tickcnt
= current_tickcnt
;
1146 int start
= FocusedItem
== null ? 0 : FocusedItem
.Index
;
1149 if (CultureInfo
.CurrentCulture
.CompareInfo
.IsPrefix (Items
[i
].Text
, keysearch_text
,
1150 CompareOptions
.IgnoreCase
)) {
1151 SetFocusedItem (Items
[i
]);
1152 items
[i
].Selected
= true;
1156 i
= (i
+ 1 < Items
.Count
) ? i
+1 : 0;
1164 int GetAdjustedIndex (Keys key
)
1168 if (View
== View
.Details
) {
1170 result
= FocusedItem
.Index
- 1;
1171 else if (key
== Keys
.Down
) {
1172 result
= FocusedItem
.Index
+ 1;
1173 if (result
== items
.Count
)
1179 int row
= FocusedItem
.row
;
1180 int col
= FocusedItem
.col
;
1186 return item_matrix
[row
, col
- 1].Index
;
1189 if (col
== (cols
- 1))
1191 while (item_matrix
[row
, col
+ 1] == null)
1193 return item_matrix
[row
, col
+ 1].Index
;
1198 return item_matrix
[row
- 1, col
].Index
;
1201 if (row
== (rows
- 1) || row
== Items
.Count
- 1)
1203 while (item_matrix
[row
+ 1, col
] == null)
1205 return item_matrix
[row
+ 1, col
].Index
;
1212 ListViewItem selection_start
;
1214 private bool SelectItems (ArrayList sel_items
)
1216 bool changed
= false;
1217 ArrayList curr_items
= SelectedItems
.List
;
1218 foreach (ListViewItem item
in curr_items
)
1219 if (!sel_items
.Contains (item
)) {
1220 item
.Selected
= false;
1223 foreach (ListViewItem item
in sel_items
)
1224 if (!item
.Selected
) {
1225 item
.Selected
= true;
1231 private void UpdateMultiSelection (int index
)
1233 bool shift_pressed
= (XplatUI
.State
.ModifierKeys
& Keys
.Shift
) != 0;
1234 bool ctrl_pressed
= (XplatUI
.State
.ModifierKeys
& Keys
.Control
) != 0;
1235 ListViewItem item
= items
[index
];
1237 if (shift_pressed
&& selection_start
!= null) {
1238 ArrayList list
= new ArrayList ();
1239 int start
= Math
.Min (selection_start
.Index
, index
);
1240 int end
= Math
.Max (selection_start
.Index
, index
);
1241 if (View
== View
.Details
) {
1242 for (int i
= start
; i
<= end
; i
++)
1243 list
.Add (items
[i
]);
1245 int left
= Math
.Min (items
[start
].col
, items
[end
].col
);
1246 int right
= Math
.Max (items
[start
].col
, items
[end
].col
);
1247 int top
= Math
.Min (items
[start
].row
, items
[end
].row
);
1248 int bottom
= Math
.Max (items
[start
].row
, items
[end
].row
);
1249 foreach (ListViewItem curr
in items
)
1250 if (curr
.row
>= top
&& curr
.row
<= bottom
&&
1251 curr
.col
>= left
&& curr
.col
<= right
)
1254 if (SelectItems (list
))
1255 OnSelectedIndexChanged (EventArgs
.Empty
);
1256 } else if (ctrl_pressed
) {
1257 item
.Selected
= !item
.Selected
;
1258 selection_start
= item
;
1259 OnSelectedIndexChanged (EventArgs
.Empty
);
1261 SelectedItems
.Clear ();
1262 item
.Selected
= true;
1263 selection_start
= item
;
1264 OnSelectedIndexChanged (EventArgs
.Empty
);
1268 internal override bool InternalPreProcessMessage (ref Message msg
)
1270 if (msg
.Msg
== (int)Msg
.WM_KEYDOWN
) {
1271 Keys key_data
= (Keys
)msg
.WParam
.ToInt32();
1272 if (HandleNavKeys (key_data
))
1275 return base.InternalPreProcessMessage (ref msg
);
1278 bool HandleNavKeys (Keys key_data
)
1280 if (Items
.Count
== 0 || !item_control
.Visible
)
1283 if (FocusedItem
== null)
1284 SetFocusedItem (Items
[0]);
1288 SelectIndex (Items
.Count
- 1);
1299 SelectIndex (GetAdjustedIndex (key_data
));
1309 void SelectIndex (int index
)
1315 UpdateMultiSelection (index
);
1316 else if (!items
[index
].Selected
) {
1317 items
[index
].Selected
= true;
1318 OnSelectedIndexChanged (EventArgs
.Empty
);
1321 SetFocusedItem (items
[index
]);
1322 EnsureVisible (index
);
1325 private void ListView_KeyDown (object sender
, KeyEventArgs ke
)
1327 if (ke
.Handled
|| Items
.Count
== 0 || !item_control
.Visible
)
1330 ke
.Handled
= KeySearchString (ke
);
1333 internal class ItemControl
: Control
{
1336 ListViewItem clicked_item
;
1337 ListViewItem last_clicked_item
;
1338 bool hover_processed
= false;
1339 bool checking
= false;
1341 ListViewLabelEditTextBox edit_text_box
;
1342 internal ListViewItem edit_item
;
1343 LabelEditEventArgs edit_args
;
1345 public ItemControl (ListView owner
)
1348 DoubleClick
+= new EventHandler(ItemsDoubleClick
);
1349 MouseDown
+= new MouseEventHandler(ItemsMouseDown
);
1350 MouseMove
+= new MouseEventHandler(ItemsMouseMove
);
1351 MouseHover
+= new EventHandler(ItemsMouseHover
);
1352 MouseUp
+= new MouseEventHandler(ItemsMouseUp
);
1355 void ItemsDoubleClick (object sender
, EventArgs e
)
1357 if (owner
.activation
== ItemActivation
.Standard
)
1358 owner
.OnItemActivate (EventArgs
.Empty
);
1368 BoxSelect box_select_mode
= BoxSelect
.None
;
1369 ArrayList prev_selection
;
1370 Point box_select_start
;
1372 Rectangle box_select_rect
;
1373 internal Rectangle BoxSelectRectangle
{
1374 get { return box_select_rect; }
1376 if (box_select_rect
== value)
1379 InvalidateBoxSelectRect ();
1380 box_select_rect
= value;
1381 InvalidateBoxSelectRect ();
1385 void InvalidateBoxSelectRect ()
1387 if (BoxSelectRectangle
.Size
.IsEmpty
)
1390 Rectangle edge
= BoxSelectRectangle
;
1396 edge
.Y
= BoxSelectRectangle
.Bottom
- 1;
1398 edge
.Y
= BoxSelectRectangle
.Y
- 1;
1400 edge
.Height
= BoxSelectRectangle
.Height
+ 2;
1402 edge
.X
= BoxSelectRectangle
.Right
- 1;
1406 private Rectangle
CalculateBoxSelectRectangle (Point pt
)
1408 int left
= Math
.Min (box_select_start
.X
, pt
.X
);
1409 int right
= Math
.Max (box_select_start
.X
, pt
.X
);
1410 int top
= Math
.Min (box_select_start
.Y
, pt
.Y
);
1411 int bottom
= Math
.Max (box_select_start
.Y
, pt
.Y
);
1412 return Rectangle
.FromLTRB (left
, top
, right
, bottom
);
1415 ArrayList BoxSelectedItems
{
1417 ArrayList result
= new ArrayList ();
1418 foreach (ListViewItem item
in owner
.Items
) {
1419 Rectangle r
= item
.Bounds
;
1421 r
.Y
+= r
.Height
/ 4;
1424 if (BoxSelectRectangle
.IntersectsWith (r
))
1431 private bool PerformBoxSelection (Point pt
)
1433 if (box_select_mode
== BoxSelect
.None
)
1436 BoxSelectRectangle
= CalculateBoxSelectRectangle (pt
);
1438 ArrayList box_items
= BoxSelectedItems
;
1442 switch (box_select_mode
) {
1444 case BoxSelect
.Normal
:
1448 case BoxSelect
.Control
:
1449 items
= new ArrayList ();
1450 foreach (ListViewItem item
in prev_selection
)
1451 if (!box_items
.Contains (item
))
1453 foreach (ListViewItem item
in box_items
)
1454 if (!prev_selection
.Contains (item
))
1458 case BoxSelect
.Shift
:
1460 foreach (ListViewItem item
in box_items
)
1461 prev_selection
.Remove (item
);
1462 foreach (ListViewItem item
in prev_selection
)
1467 throw new Exception ("Unexpected Selection mode: " + box_select_mode
);
1471 owner
.SelectItems (items
);
1477 private void ToggleCheckState (ListViewItem item
)
1479 CheckState curr_state
= item
.Checked
? CheckState
.Checked
: CheckState
.Unchecked
;
1480 item
.Checked
= !item
.Checked
;
1481 CheckState new_state
= item
.Checked
? CheckState
.Checked
: CheckState
.Unchecked
;
1483 ItemCheckEventArgs ice
= new ItemCheckEventArgs (item
.Index
, curr_state
, new_state
);
1484 owner
.OnItemCheck (ice
);
1487 private void ItemsMouseDown (object sender
, MouseEventArgs me
)
1489 if (owner
.items
.Count
== 0)
1492 Point pt
= new Point (me
.X
, me
.Y
);
1493 foreach (ListViewItem item
in owner
.items
) {
1494 if (me
.Clicks
== 1 && item
.CheckRectReal
.Contains (pt
)) {
1498 ToggleCheckState (item
);
1502 if (owner
.View
== View
.Details
&& !owner
.FullRowSelect
) {
1503 if (item
.GetBounds (ItemBoundsPortion
.Label
).Contains (pt
)) {
1504 clicked_item
= item
;
1508 if (item
.Bounds
.Contains (pt
)) {
1509 clicked_item
= item
;
1516 if (clicked_item
!= null) {
1517 owner
.SetFocusedItem (clicked_item
);
1518 bool changed
= !clicked_item
.Selected
;
1519 if (owner
.MultiSelect
)
1520 owner
.UpdateMultiSelection (clicked_item
.Index
);
1522 clicked_item
.Selected
= true;
1525 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
1527 // Raise double click if the item was clicked. On MS the
1528 // double click is only raised if you double click an item
1529 if (me
.Clicks
> 1) {
1530 owner
.OnDoubleClick (EventArgs
.Empty
);
1531 if (owner
.CheckBoxes
)
1532 ToggleCheckState (clicked_item
);
1533 } else if (me
.Clicks
== 1) {
1534 owner
.OnClick (EventArgs
.Empty
);
1535 if (owner
.LabelEdit
&& !changed
)
1536 BeginEdit (clicked_item
); // this is probably not the correct place to execute BeginEdit
1539 if (owner
.MultiSelect
) {
1540 Keys mods
= XplatUI
.State
.ModifierKeys
;
1541 if ((mods
& Keys
.Shift
) != 0)
1542 box_select_mode
= BoxSelect
.Shift
;
1543 else if ((mods
& Keys
.Control
) != 0)
1544 box_select_mode
= BoxSelect
.Control
;
1546 box_select_mode
= BoxSelect
.Normal
;
1547 box_select_start
= pt
;
1548 prev_selection
= owner
.SelectedItems
.List
;
1549 } else if (owner
.SelectedItems
.Count
> 0) {
1550 owner
.SelectedItems
.Clear ();
1551 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
1556 private void ItemsMouseMove (object sender
, MouseEventArgs me
)
1558 if (PerformBoxSelection (new Point (me
.X
, me
.Y
)))
1561 if (owner
.HoverSelection
&& hover_processed
) {
1563 Point pt
= PointToClient (Control
.MousePosition
);
1564 ListViewItem item
= owner
.GetItemAt (pt
.X
, pt
.Y
);
1565 if (item
== null || item
.Selected
)
1568 hover_processed
= false;
1569 XplatUI
.ResetMouseHover (Handle
);
1574 private void ItemsMouseHover (object sender
, EventArgs e
)
1576 if (Capture
|| !owner
.HoverSelection
)
1579 hover_processed
= true;
1580 Point pt
= PointToClient (Control
.MousePosition
);
1581 ListViewItem item
= owner
.GetItemAt (pt
.X
, pt
.Y
);
1586 item
.Selected
= true;
1587 owner
.OnSelectedIndexChanged (new EventArgs ());
1590 private void ItemsMouseUp (object sender
, MouseEventArgs me
)
1593 if (owner
.Items
.Count
== 0)
1596 Point pt
= new Point (me
.X
, me
.Y
);
1598 Rectangle rect
= Rectangle
.Empty
;
1599 if (clicked_item
!= null) {
1600 if (owner
.view
== View
.Details
&& !owner
.full_row_select
)
1601 rect
= clicked_item
.GetBounds (ItemBoundsPortion
.Label
);
1603 rect
= clicked_item
.Bounds
;
1605 if (rect
.Contains (pt
)) {
1606 switch (owner
.activation
) {
1607 case ItemActivation
.OneClick
:
1608 owner
.OnItemActivate (EventArgs
.Empty
);
1611 case ItemActivation
.TwoClick
:
1612 if (last_clicked_item
== clicked_item
) {
1613 owner
.OnItemActivate (EventArgs
.Empty
);
1614 last_clicked_item
= null;
1616 last_clicked_item
= clicked_item
;
1619 // DoubleClick activation is handled in another handler
1623 } else if (!checking
&& owner
.SelectedItems
.Count
> 0 && BoxSelectRectangle
.Size
.IsEmpty
) {
1624 // Need this to clean up background clicks
1625 owner
.SelectedItems
.Clear ();
1626 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
1629 clicked_item
= null;
1630 box_select_start
= Point
.Empty
;
1631 BoxSelectRectangle
= Rectangle
.Empty
;
1632 prev_selection
= null;
1633 box_select_mode
= BoxSelect
.None
;
1637 internal void LabelEditFinished (object sender
, EventArgs e
)
1639 EndEdit (edit_item
);
1642 internal void BeginEdit (ListViewItem item
)
1644 if (edit_item
!= null)
1645 EndEdit (edit_item
);
1647 if (edit_text_box
== null) {
1648 edit_text_box
= new ListViewLabelEditTextBox ();
1649 edit_text_box
.BorderStyle
= BorderStyle
.FixedSingle
;
1650 edit_text_box
.EditingFinished
+= new EventHandler (LabelEditFinished
);
1651 edit_text_box
.Visible
= false;
1652 Controls
.Add (edit_text_box
);
1655 item
.EnsureVisible();
1657 edit_text_box
.Reset ();
1659 switch (owner
.view
) {
1661 case View
.SmallIcon
:
1663 edit_text_box
.TextAlign
= HorizontalAlignment
.Left
;
1664 edit_text_box
.Bounds
= item
.GetBounds (ItemBoundsPortion
.Label
);
1665 SizeF sizef
= DeviceContext
.MeasureString (item
.Text
, item
.Font
);
1666 edit_text_box
.Width
= (int)sizef
.Width
+ 4;
1667 edit_text_box
.MaxWidth
= owner
.ClientRectangle
.Width
- edit_text_box
.Bounds
.X
;
1668 edit_text_box
.WordWrap
= false;
1669 edit_text_box
.Multiline
= false;
1671 case View
.LargeIcon
:
1672 edit_text_box
.TextAlign
= HorizontalAlignment
.Center
;
1673 edit_text_box
.Bounds
= item
.GetBounds (ItemBoundsPortion
.Label
);
1674 sizef
= DeviceContext
.MeasureString (item
.Text
, item
.Font
);
1675 edit_text_box
.Width
= (int)sizef
.Width
+ 4;
1676 edit_text_box
.MaxWidth
= item
.GetBounds(ItemBoundsPortion
.Entire
).Width
;
1677 edit_text_box
.MaxHeight
= owner
.ClientRectangle
.Height
- edit_text_box
.Bounds
.Y
;
1678 edit_text_box
.WordWrap
= true;
1679 edit_text_box
.Multiline
= true;
1683 edit_text_box
.Text
= item
.Text
;
1684 edit_text_box
.Font
= item
.Font
;
1685 edit_text_box
.Visible
= true;
1686 edit_text_box
.Focus ();
1687 edit_text_box
.SelectAll ();
1689 edit_args
= new LabelEditEventArgs (owner
.Items
.IndexOf(edit_item
));
1690 owner
.OnBeforeLabelEdit (edit_args
);
1692 if (edit_args
.CancelEdit
)
1698 internal void EndEdit (ListViewItem item
)
1700 if (edit_text_box
!= null && edit_text_box
.Visible
) {
1701 edit_text_box
.Visible
= false;
1704 if (edit_item
!= null && edit_item
== item
) {
1705 owner
.OnAfterLabelEdit (edit_args
);
1707 if (!edit_args
.CancelEdit
) {
1708 if (edit_args
.Label
!= null)
1709 edit_item
.Text
= edit_args
.Label
;
1711 edit_item
.Text
= edit_text_box
.Text
;
1720 internal override void OnPaintInternal (PaintEventArgs pe
)
1722 ThemeEngine
.Current
.DrawListViewItems (pe
.Graphics
, pe
.ClipRectangle
, owner
);
1725 internal override void OnGotFocusInternal (EventArgs e
)
1731 internal class ListViewLabelEditTextBox
: TextBox
1736 int max_height
= -1;
1737 int min_height
= -1;
1739 int old_number_lines
= 1;
1741 SizeF text_size_one_char
;
1743 public ListViewLabelEditTextBox ()
1745 min_height
= DefaultSize
.Height
;
1746 text_size_one_char
= DeviceContext
.MeasureString ("B", Font
);
1749 public int MaxWidth
{
1751 if (value < min_width
)
1752 max_width
= min_width
;
1758 public int MaxHeight
{
1760 if (value < min_height
)
1761 max_height
= min_height
;
1767 public new int Width
{
1777 public override Font Font
{
1783 text_size_one_char
= DeviceContext
.MeasureString ("B", Font
);
1787 protected override void OnTextChanged (EventArgs e
)
1789 SizeF text_size
= DeviceContext
.MeasureString (Text
, Font
);
1791 int new_width
= (int)text_size
.Width
+ 8;
1794 ResizeTextBoxWidth (new_width
);
1796 if (Width
!= max_width
)
1797 ResizeTextBoxWidth (new_width
);
1799 int number_lines
= Lines
.Length
;
1801 if (number_lines
!= old_number_lines
) {
1802 int new_height
= number_lines
* (int)text_size_one_char
.Height
+ 4;
1803 old_number_lines
= number_lines
;
1805 ResizeTextBoxHeight (new_height
);
1809 base.OnTextChanged (e
);
1812 protected override bool IsInputKey (Keys key_data
)
1814 if ((key_data
& Keys
.Alt
) == 0) {
1815 switch (key_data
& Keys
.KeyCode
) {
1820 return base.IsInputKey (key_data
);
1823 protected override void OnKeyDown (KeyEventArgs e
)
1825 if (e
.KeyCode
== Keys
.Return
&& Visible
) {
1826 this.Visible
= false;
1827 OnEditingFinished (e
);
1831 protected override void OnLostFocus (EventArgs e
)
1834 OnEditingFinished (e
);
1838 protected void OnEditingFinished (EventArgs e
)
1840 EventHandler eh
= (EventHandler
)(Events
[EditingFinishedEvent
]);
1845 private void ResizeTextBoxWidth (int new_width
)
1847 if (new_width
> max_width
)
1848 base.Width
= max_width
;
1850 if (new_width
>= min_width
)
1851 base.Width
= new_width
;
1853 base.Width
= min_width
;
1856 private void ResizeTextBoxHeight (int new_height
)
1858 if (new_height
> max_height
)
1859 base.Height
= max_height
;
1861 if (new_height
>= min_height
)
1862 base.Height
= new_height
;
1864 base.Height
= min_height
;
1867 public void Reset ()
1874 old_number_lines
= 1;
1876 Text
= String
.Empty
;
1881 static object EditingFinishedEvent
= new object ();
1882 public event EventHandler EditingFinished
{
1883 add { Events.AddHandler (EditingFinishedEvent, value); }
1884 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
1888 internal override void OnPaintInternal (PaintEventArgs pe
)
1893 CalculateScrollBars ();
1896 void FocusChanged (object o
, EventArgs args
)
1898 if (Items
.Count
== 0)
1901 if (FocusedItem
== null)
1902 SetFocusedItem (Items
[0]);
1904 item_control
.Invalidate (FocusedItem
.Bounds
);
1907 private void ListView_MouseWheel (object sender
, MouseEventArgs me
)
1909 if (Items
.Count
== 0)
1912 int lines
= me
.Delta
/ 120;
1919 case View
.SmallIcon
:
1920 Scroll (v_scroll
, -Items
[0].Bounds
.Height
* SystemInformation
.MouseWheelScrollLines
* lines
);
1922 case View
.LargeIcon
:
1923 Scroll (v_scroll
, -(Items
[0].Bounds
.Height
+ ThemeEngine
.Current
.ListViewVerticalSpacing
) * lines
);
1926 Scroll (h_scroll
, -Items
[0].Bounds
.Width
* lines
);
1931 private void ListView_SizeChanged (object sender
, EventArgs e
)
1933 CalculateListView (alignment
);
1936 private void SetFocusedItem (ListViewItem item
)
1938 if (focused_item
!= null)
1939 focused_item
.Focused
= false;
1942 item
.Focused
= true;
1944 focused_item
= item
;
1947 private void HorizontalScroller (object sender
, EventArgs e
)
1949 item_control
.EndEdit (item_control
.edit_item
);
1951 // Avoid unnecessary flickering, when button is
1952 // kept pressed at the end
1953 if (h_marker
!= h_scroll
.Value
) {
1955 int pixels
= h_marker
- h_scroll
.Value
;
1957 h_marker
= h_scroll
.Value
;
1958 if (header_control
.Visible
)
1959 XplatUI
.ScrollWindow (header_control
.Handle
, pixels
, 0, false);
1961 XplatUI
.ScrollWindow (item_control
.Handle
, pixels
, 0, false);
1965 private void VerticalScroller (object sender
, EventArgs e
)
1967 item_control
.EndEdit (item_control
.edit_item
);
1969 // Avoid unnecessary flickering, when button is
1970 // kept pressed at the end
1971 if (v_marker
!= v_scroll
.Value
) {
1972 int pixels
= v_marker
- v_scroll
.Value
;
1973 Rectangle area
= item_control
.ClientRectangle
;
1974 v_marker
= v_scroll
.Value
;
1975 XplatUI
.ScrollWindow (item_control
.Handle
, area
, 0, pixels
, false);
1978 #endregion // Internal Methods Properties
1980 #region Protected Methods
1981 protected override void CreateHandle ()
1983 base.CreateHandle ();
1984 for (int i
= 0; i
< SelectedItems
.Count
; i
++)
1985 OnSelectedIndexChanged (EventArgs
.Empty
);
1988 protected override void Dispose (bool disposing
)
1991 h_scroll
.Dispose ();
1992 v_scroll
.Dispose ();
1994 large_image_list
= null;
1995 small_image_list
= null;
1996 state_image_list
= null;
1999 base.Dispose (disposing
);
2002 protected override bool IsInputKey (Keys keyData
)
2019 return base.IsInputKey (keyData
);
2022 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e
)
2024 LabelEditEventHandler eh
= (LabelEditEventHandler
)(Events
[AfterLabelEditEvent
]);
2029 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e
)
2031 LabelEditEventHandler eh
= (LabelEditEventHandler
)(Events
[BeforeLabelEditEvent
]);
2036 protected virtual void OnColumnClick (ColumnClickEventArgs e
)
2038 ColumnClickEventHandler eh
= (ColumnClickEventHandler
)(Events
[ColumnClickEvent
]);
2043 protected override void OnEnabledChanged (EventArgs e
)
2045 base.OnEnabledChanged (e
);
2048 protected override void OnFontChanged (EventArgs e
)
2050 base.OnFontChanged (e
);
2054 protected override void OnHandleCreated (EventArgs e
)
2056 base.OnHandleCreated (e
);
2060 protected override void OnHandleDestroyed (EventArgs e
)
2062 base.OnHandleDestroyed (e
);
2065 protected virtual void OnItemActivate (EventArgs e
)
2067 EventHandler eh
= (EventHandler
)(Events
[ItemActivateEvent
]);
2072 protected virtual void OnItemCheck (ItemCheckEventArgs ice
)
2074 EventHandler eh
= (EventHandler
)(Events
[ItemCheckEvent
]);
2079 protected virtual void OnItemDrag (ItemDragEventArgs e
)
2081 EventHandler eh
= (EventHandler
)(Events
[ItemDragEvent
]);
2086 protected virtual void OnSelectedIndexChanged (EventArgs e
)
2088 EventHandler eh
= (EventHandler
)(Events
[SelectedIndexChangedEvent
]);
2093 protected override void OnSystemColorsChanged (EventArgs e
)
2095 base.OnSystemColorsChanged (e
);
2098 protected void RealizeProperties ()
2103 protected void UpdateExtendedStyles ()
2108 protected override void WndProc (ref Message m
)
2110 base.WndProc (ref m
);
2112 #endregion // Protected Methods
2114 #region Public Instance Methods
2115 public void ArrangeIcons ()
2117 ArrangeIcons (this.alignment
);
2120 public void ArrangeIcons (ListViewAlignment alignment
)
2122 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2123 if (view
== View
.LargeIcon
|| view
== View
.SmallIcon
) {
2124 this.CalculateListView (alignment
);
2125 // we have done the calculations already
2126 this.Redraw (false);
2130 public void BeginUpdate ()
2132 // flag to avoid painting
2136 public void Clear ()
2139 items
.Clear (); // Redraw (true) called here
2142 public void EndUpdate ()
2144 // flag to avoid painting
2147 // probably, now we need a redraw with recalculations
2151 public void EnsureVisible (int index
)
2153 if (index
< 0 || index
>= items
.Count
|| scrollable
== false)
2156 Rectangle view_rect
= item_control
.ClientRectangle
;
2157 Rectangle bounds
= items
[index
].Bounds
;
2159 if (view_rect
.Contains (bounds
))
2162 if (bounds
.Left
< 0)
2163 h_scroll
.Value
+= bounds
.Left
;
2164 else if (bounds
.Right
> view_rect
.Right
)
2165 h_scroll
.Value
+= (bounds
.Right
- view_rect
.Right
);
2168 v_scroll
.Value
+= bounds
.Top
;
2169 else if (bounds
.Bottom
> view_rect
.Bottom
)
2170 v_scroll
.Value
+= (bounds
.Bottom
- view_rect
.Bottom
);
2173 public ListViewItem
GetItemAt (int x
, int y
)
2175 foreach (ListViewItem item
in items
) {
2176 if (item
.Bounds
.Contains (x
, y
))
2182 public Rectangle
GetItemRect (int index
)
2184 return GetItemRect (index
, ItemBoundsPortion
.Entire
);
2187 public Rectangle
GetItemRect (int index
, ItemBoundsPortion portion
)
2189 if (index
< 0 || index
>= items
.Count
)
2190 throw new IndexOutOfRangeException ("index");
2192 return items
[index
].GetBounds (portion
);
2200 // we need this overload to reuse the logic for sorting, while allowing
2201 // redrawing to be done by caller or have it done by this method when
2202 // sorting is really performed
2204 // ListViewItemCollection's Add and AddRange methods call this overload
2205 // with redraw set to false, as they take care of redrawing themselves
2206 // (they even want to redraw the listview if no sort is performed, as
2207 // an item was added), while ListView.Sort () only wants to redraw if
2208 // sorting was actually performed
2209 private void Sort (bool redraw
)
2211 if (!IsHandleCreated
|| item_sorter
== null) {
2215 items
.Sort (item_sorter
);
2220 public override string ToString ()
2222 int count
= this.Items
.Count
;
2225 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2227 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count
, this.Items
[0].ToString ());
2229 #endregion // Public Instance Methods
2234 class HeaderControl
: Control
{
2237 bool column_resize_active
= false;
2238 ColumnHeader resize_column
;
2239 ColumnHeader clicked_column
;
2240 ColumnHeader drag_column
;
2242 int drag_to_index
= -1;
2244 public HeaderControl (ListView owner
)
2247 MouseDown
+= new MouseEventHandler (HeaderMouseDown
);
2248 MouseMove
+= new MouseEventHandler (HeaderMouseMove
);
2249 MouseUp
+= new MouseEventHandler (HeaderMouseUp
);
2252 private ColumnHeader
ColumnAtX (int x
)
2254 Point pt
= new Point (x
, 0);
2255 ColumnHeader result
= null;
2256 foreach (ColumnHeader col
in owner
.Columns
) {
2257 if (col
.Rect
.Contains (pt
)) {
2265 private int GetReorderedIndex (ColumnHeader col
)
2267 if (owner
.reordered_column_indices
== null)
2270 for (int i
= 0; i
< owner
.Columns
.Count
; i
++)
2271 if (owner
.reordered_column_indices
[i
] == col
.Index
)
2273 throw new Exception ("Column index missing from reordered array");
2276 private void HeaderMouseDown (object sender
, MouseEventArgs me
)
2278 if (resize_column
!= null) {
2279 column_resize_active
= true;
2284 clicked_column
= ColumnAtX (me
.X
+ owner
.h_marker
);
2286 if (clicked_column
!= null) {
2288 if (owner
.AllowColumnReorder
) {
2290 drag_column
= (ColumnHeader
) (clicked_column
as ICloneable
).Clone ();
2291 drag_column
.column_rect
= clicked_column
.Rect
;
2292 drag_to_index
= GetReorderedIndex (clicked_column
);
2294 clicked_column
.pressed
= true;
2295 Rectangle bounds
= clicked_column
.Rect
;
2296 bounds
.X
-= owner
.h_marker
;
2297 Invalidate (bounds
);
2302 private void HeaderMouseMove (object sender
, MouseEventArgs me
)
2304 Point pt
= new Point (me
.X
+ owner
.h_marker
, me
.Y
);
2306 if (column_resize_active
) {
2307 resize_column
.Width
= pt
.X
- resize_column
.X
;
2308 if (resize_column
.Width
< 0)
2309 resize_column
.Width
= 0;
2313 resize_column
= null;
2315 if (clicked_column
!= null) {
2316 if (owner
.AllowColumnReorder
) {
2319 r
= drag_column
.column_rect
;
2320 r
.X
= clicked_column
.Rect
.X
+ me
.X
- drag_x
;
2321 drag_column
.column_rect
= r
;
2323 int x
= me
.X
+ owner
.h_marker
;
2324 ColumnHeader over
= ColumnAtX (x
);
2326 drag_to_index
= owner
.Columns
.Count
;
2327 else if (x
< over
.X
+ over
.Width
/ 2)
2328 drag_to_index
= GetReorderedIndex (over
);
2330 drag_to_index
= GetReorderedIndex (over
) + 1;
2333 ColumnHeader over
= ColumnAtX (me
.X
+ owner
.h_marker
);
2334 bool pressed
= clicked_column
.pressed
;
2335 clicked_column
.pressed
= over
== clicked_column
;
2336 if (clicked_column
.pressed ^ pressed
) {
2337 Rectangle bounds
= clicked_column
.Rect
;
2338 bounds
.X
-= owner
.h_marker
;
2339 Invalidate (bounds
);
2345 for (int i
= 0; i
< owner
.Columns
.Count
; i
++) {
2346 Rectangle zone
= owner
.Columns
[i
].Rect
;
2347 zone
.X
= zone
.Right
- 5;
2349 if (zone
.Contains (pt
)) {
2350 if (i
< owner
.Columns
.Count
- 1 && owner
.Columns
[i
+ 1].Width
== 0)
2352 resize_column
= owner
.Columns
[i
];
2357 if (resize_column
== null)
2358 Cursor
= Cursors
.Default
;
2360 Cursor
= Cursors
.VSplit
;
2363 void HeaderMouseUp (object sender
, MouseEventArgs me
)
2367 if (column_resize_active
) {
2368 column_resize_active
= false;
2369 resize_column
= null;
2370 Cursor
= Cursors
.Default
;
2374 if (clicked_column
!= null && clicked_column
.pressed
) {
2375 clicked_column
.pressed
= false;
2376 Rectangle bounds
= clicked_column
.Rect
;
2377 bounds
.X
-= owner
.h_marker
;
2378 Invalidate (bounds
);
2379 owner
.OnColumnClick (new ColumnClickEventArgs (clicked_column
.Index
));
2382 if (drag_column
!= null && owner
.AllowColumnReorder
) {
2384 if (drag_to_index
> GetReorderedIndex (clicked_column
))
2386 if (owner
.GetReorderedColumn (drag_to_index
) != clicked_column
)
2387 owner
.ReorderColumn (clicked_column
, drag_to_index
);
2392 clicked_column
= null;
2395 internal override void OnPaintInternal (PaintEventArgs pe
)
2400 Theme theme
= ThemeEngine
.Current
;
2401 theme
.DrawListViewHeader (pe
.Graphics
, pe
.ClipRectangle
, this.owner
);
2403 if (drag_column
== null)
2407 if (drag_to_index
== owner
.Columns
.Count
)
2408 target_x
= owner
.GetReorderedColumn (drag_to_index
- 1).Rect
.Right
- owner
.h_marker
;
2410 target_x
= owner
.GetReorderedColumn (drag_to_index
).Rect
.X
- owner
.h_marker
;
2411 theme
.DrawListViewHeaderDragDetails (pe
.Graphics
, owner
, drag_column
, target_x
);
2414 protected override void WndProc (ref Message m
)
2416 switch ((Msg
)m
.Msg
) {
2417 case Msg
.WM_SETFOCUS
:
2421 base.WndProc (ref m
);
2427 private class ItemComparer
: IComparer
{
2428 readonly SortOrder sort_order
;
2430 public ItemComparer (SortOrder sortOrder
)
2432 sort_order
= sortOrder
;
2435 public int Compare (object x
, object y
)
2437 ListViewItem item_x
= x
as ListViewItem
;
2438 ListViewItem item_y
= y
as ListViewItem
;
2439 if (sort_order
== SortOrder
.Ascending
)
2440 return String
.Compare (item_x
.Text
, item_y
.Text
);
2442 return String
.Compare (item_y
.Text
, item_x
.Text
);
2446 public class CheckedIndexCollection
: IList
, ICollection
, IEnumerable
2448 private readonly ListView owner
;
2450 #region Public Constructor
2451 public CheckedIndexCollection (ListView owner
)
2455 #endregion // Public Constructor
2457 #region Public Properties
2460 get { return owner.CheckedItems.Count; }
2463 public bool IsReadOnly
{
2464 get { return true; }
2467 public int this [int index
] {
2469 int [] indices
= GetIndices ();
2470 if (index
< 0 || index
>= indices
.Length
)
2471 throw new ArgumentOutOfRangeException ("index");
2472 return indices
[index
];
2476 bool ICollection
.IsSynchronized
{
2477 get { return false; }
2480 object ICollection
.SyncRoot
{
2481 get { return this; }
2484 bool IList
.IsFixedSize
{
2485 get { return true; }
2488 object IList
.this [int index
] {
2489 get { return this [index]; }
2490 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2492 #endregion // Public Properties
2494 #region Public Methods
2495 public bool Contains (int checkedIndex
)
2497 int [] indices
= GetIndices ();
2498 for (int i
= 0; i
< indices
.Length
; i
++) {
2499 if (indices
[i
] == checkedIndex
)
2505 public IEnumerator
GetEnumerator ()
2507 int [] indices
= GetIndices ();
2508 return indices
.GetEnumerator ();
2511 void ICollection
.CopyTo (Array dest
, int index
)
2513 int [] indices
= GetIndices ();
2514 Array
.Copy (indices
, 0, dest
, index
, indices
.Length
);
2517 int IList
.Add (object value)
2519 throw new NotSupportedException ("Add operation is not supported.");
2524 throw new NotSupportedException ("Clear operation is not supported.");
2527 bool IList
.Contains (object checkedIndex
)
2529 if (!(checkedIndex
is int))
2531 return Contains ((int) checkedIndex
);
2534 int IList
.IndexOf (object checkedIndex
)
2536 if (!(checkedIndex
is int))
2538 return IndexOf ((int) checkedIndex
);
2541 void IList
.Insert (int index
, object value)
2543 throw new NotSupportedException ("Insert operation is not supported.");
2546 void IList
.Remove (object value)
2548 throw new NotSupportedException ("Remove operation is not supported.");
2551 void IList
.RemoveAt (int index
)
2553 throw new NotSupportedException ("RemoveAt operation is not supported.");
2556 public int IndexOf (int checkedIndex
)
2558 int [] indices
= GetIndices ();
2559 for (int i
= 0; i
< indices
.Length
; i
++) {
2560 if (indices
[i
] == checkedIndex
)
2565 #endregion // Public Methods
2567 private int [] GetIndices ()
2569 ArrayList checked_items
= owner
.CheckedItems
.List
;
2570 int [] indices
= new int [checked_items
.Count
];
2571 for (int i
= 0; i
< checked_items
.Count
; i
++) {
2572 ListViewItem item
= (ListViewItem
) checked_items
[i
];
2573 indices
[i
] = item
.Index
;
2577 } // CheckedIndexCollection
2579 public class CheckedListViewItemCollection
: IList
, ICollection
, IEnumerable
2581 private readonly ListView owner
;
2582 private ArrayList list
;
2584 #region Public Constructor
2585 public CheckedListViewItemCollection (ListView owner
)
2588 this.owner
.Items
.Changed
+= new CollectionChangedHandler (
2589 ItemsCollection_Changed
);
2591 #endregion // Public Constructor
2593 #region Public Properties
2597 if (!owner
.CheckBoxes
)
2603 public bool IsReadOnly
{
2604 get { return true; }
2607 public ListViewItem
this [int index
] {
2609 ArrayList checked_items
= List
;
2610 if (index
< 0 || index
>= checked_items
.Count
)
2611 throw new ArgumentOutOfRangeException ("index");
2612 return (ListViewItem
) checked_items
[index
];
2616 bool ICollection
.IsSynchronized
{
2617 get { return false; }
2620 object ICollection
.SyncRoot
{
2621 get { return this; }
2624 bool IList
.IsFixedSize
{
2625 get { return true; }
2628 object IList
.this [int index
] {
2629 get { return this [index]; }
2630 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2632 #endregion // Public Properties
2634 #region Public Methods
2635 public bool Contains (ListViewItem item
)
2637 if (!owner
.CheckBoxes
)
2639 return List
.Contains (item
);
2642 public void CopyTo (Array dest
, int index
)
2644 if (!owner
.CheckBoxes
)
2646 List
.CopyTo (dest
, index
);
2649 public IEnumerator
GetEnumerator ()
2651 if (!owner
.CheckBoxes
)
2652 return (new ListViewItem
[0]).GetEnumerator ();
2653 return List
.GetEnumerator ();
2656 int IList
.Add (object value)
2658 throw new NotSupportedException ("Add operation is not supported.");
2663 throw new NotSupportedException ("Clear operation is not supported.");
2666 bool IList
.Contains (object item
)
2668 if (!(item
is ListViewItem
))
2670 return Contains ((ListViewItem
) item
);
2673 int IList
.IndexOf (object item
)
2675 if (!(item
is ListViewItem
))
2677 return IndexOf ((ListViewItem
) item
);
2680 void IList
.Insert (int index
, object value)
2682 throw new NotSupportedException ("Insert operation is not supported.");
2685 void IList
.Remove (object value)
2687 throw new NotSupportedException ("Remove operation is not supported.");
2690 void IList
.RemoveAt (int index
)
2692 throw new NotSupportedException ("RemoveAt operation is not supported.");
2695 public int IndexOf (ListViewItem item
)
2697 if (!owner
.CheckBoxes
)
2699 return List
.IndexOf (item
);
2701 #endregion // Public Methods
2703 internal ArrayList List
{
2706 list
= new ArrayList ();
2707 foreach (ListViewItem item
in owner
.Items
) {
2716 internal void Reset ()
2718 // force re-population of list
2722 private void ItemsCollection_Changed ()
2726 } // CheckedListViewItemCollection
2728 public class ColumnHeaderCollection
: IList
, ICollection
, IEnumerable
2730 internal ArrayList list
;
2731 private ListView owner
;
2733 #region Public Constructor
2734 public ColumnHeaderCollection (ListView owner
)
2736 list
= new ArrayList ();
2739 #endregion // Public Constructor
2741 #region Public Properties
2744 get { return list.Count; }
2747 public bool IsReadOnly
{
2748 get { return false; }
2751 public virtual ColumnHeader
this [int index
] {
2753 if (index
< 0 || index
>= list
.Count
)
2754 throw new ArgumentOutOfRangeException ("index");
2755 return (ColumnHeader
) list
[index
];
2759 bool ICollection
.IsSynchronized
{
2760 get { return true; }
2763 object ICollection
.SyncRoot
{
2764 get { return this; }
2767 bool IList
.IsFixedSize
{
2768 get { return list.IsFixedSize; }
2771 object IList
.this [int index
] {
2772 get { return this [index]; }
2773 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2775 #endregion // Public Properties
2777 #region Public Methods
2778 public virtual int Add (ColumnHeader
value)
2781 value.owner
= this.owner
;
2782 idx
= list
.Add (value);
2783 if (owner
.IsHandleCreated
) {
2784 owner
.Redraw (true);
2789 public virtual ColumnHeader
Add (string str
, int width
, HorizontalAlignment textAlign
)
2791 ColumnHeader colHeader
= new ColumnHeader (this.owner
, str
, textAlign
, width
);
2792 this.Add (colHeader
);
2796 public virtual void AddRange (ColumnHeader
[] values
)
2798 foreach (ColumnHeader colHeader
in values
) {
2799 colHeader
.owner
= this.owner
;
2803 owner
.Redraw (true);
2806 public virtual void Clear ()
2809 owner
.Redraw (true);
2812 public bool Contains (ColumnHeader
value)
2814 return list
.Contains (value);
2817 public IEnumerator
GetEnumerator ()
2819 return list
.GetEnumerator ();
2822 void ICollection
.CopyTo (Array dest
, int index
)
2824 list
.CopyTo (dest
, index
);
2827 int IList
.Add (object value)
2829 if (! (value is ColumnHeader
)) {
2830 throw new ArgumentException ("Not of type ColumnHeader", "value");
2833 return this.Add ((ColumnHeader
) value);
2836 bool IList
.Contains (object value)
2838 if (! (value is ColumnHeader
)) {
2839 throw new ArgumentException ("Not of type ColumnHeader", "value");
2842 return this.Contains ((ColumnHeader
) value);
2845 int IList
.IndexOf (object value)
2847 if (! (value is ColumnHeader
)) {
2848 throw new ArgumentException ("Not of type ColumnHeader", "value");
2851 return this.IndexOf ((ColumnHeader
) value);
2854 void IList
.Insert (int index
, object value)
2856 if (! (value is ColumnHeader
)) {
2857 throw new ArgumentException ("Not of type ColumnHeader", "value");
2860 this.Insert (index
, (ColumnHeader
) value);
2863 void IList
.Remove (object value)
2865 if (! (value is ColumnHeader
)) {
2866 throw new ArgumentException ("Not of type ColumnHeader", "value");
2869 this.Remove ((ColumnHeader
) value);
2872 public int IndexOf (ColumnHeader
value)
2874 return list
.IndexOf (value);
2877 public void Insert (int index
, ColumnHeader
value)
2879 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2880 // but it's really only greater.
2881 if (index
< 0 || index
> list
.Count
)
2882 throw new ArgumentOutOfRangeException ("index");
2884 value.owner
= this.owner
;
2885 list
.Insert (index
, value);
2886 owner
.Redraw (true);
2889 public void Insert (int index
, string str
, int width
, HorizontalAlignment textAlign
)
2891 ColumnHeader colHeader
= new ColumnHeader (this.owner
, str
, textAlign
, width
);
2892 this.Insert (index
, colHeader
);
2895 public virtual void Remove (ColumnHeader column
)
2897 // TODO: Update Column internal index ?
2898 list
.Remove (column
);
2899 owner
.Redraw (true);
2902 public virtual void RemoveAt (int index
)
2904 if (index
< 0 || index
>= list
.Count
)
2905 throw new ArgumentOutOfRangeException ("index");
2907 // TODO: Update Column internal index ?
2908 list
.RemoveAt (index
);
2909 owner
.Redraw (true);
2911 #endregion // Public Methods
2914 } // ColumnHeaderCollection
2916 public class ListViewItemCollection
: IList
, ICollection
, IEnumerable
2918 private readonly ArrayList list
;
2919 private readonly ListView owner
;
2921 #region Public Constructor
2922 public ListViewItemCollection (ListView owner
)
2924 list
= new ArrayList ();
2927 #endregion // Public Constructor
2929 #region Public Properties
2932 get { return list.Count; }
2935 public bool IsReadOnly
{
2936 get { return false; }
2939 public virtual ListViewItem
this [int displayIndex
] {
2941 if (displayIndex
< 0 || displayIndex
>= list
.Count
)
2942 throw new ArgumentOutOfRangeException ("displayIndex");
2943 return (ListViewItem
) list
[displayIndex
];
2947 if (displayIndex
< 0 || displayIndex
>= list
.Count
)
2948 throw new ArgumentOutOfRangeException ("displayIndex");
2950 if (list
.Contains (value))
2951 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2953 value.Owner
= owner
;
2954 list
[displayIndex
] = value;
2957 owner
.Redraw (true);
2961 bool ICollection
.IsSynchronized
{
2962 get { return true; }
2965 object ICollection
.SyncRoot
{
2966 get { return this; }
2969 bool IList
.IsFixedSize
{
2970 get { return list.IsFixedSize; }
2973 object IList
.this [int index
] {
2974 get { return this [index]; }
2976 if (value is ListViewItem
)
2977 this [index
] = (ListViewItem
) value;
2979 this [index
] = new ListViewItem (value.ToString ());
2983 #endregion // Public Properties
2985 #region Public Methods
2986 public virtual ListViewItem
Add (ListViewItem
value)
2988 if (list
.Contains (value))
2989 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2991 value.Owner
= owner
;
2996 owner
.Redraw (true);
3000 public virtual ListViewItem
Add (string text
)
3002 ListViewItem item
= new ListViewItem (text
);
3003 return this.Add (item
);
3006 public virtual ListViewItem
Add (string text
, int imageIndex
)
3008 ListViewItem item
= new ListViewItem (text
, imageIndex
);
3009 return this.Add (item
);
3012 public void AddRange (ListViewItem
[] values
)
3016 foreach (ListViewItem item
in values
) {
3023 owner
.Redraw (true);
3026 public virtual void Clear ()
3028 owner
.SetFocusedItem (null);
3029 owner
.h_scroll
.Value
= owner
.v_scroll
.Value
= 0;
3032 owner
.Redraw (true);
3035 public bool Contains (ListViewItem item
)
3037 return list
.Contains (item
);
3040 public void CopyTo (Array dest
, int index
)
3042 list
.CopyTo (dest
, index
);
3045 public IEnumerator
GetEnumerator ()
3047 return list
.GetEnumerator ();
3050 int IList
.Add (object item
)
3055 if (item
is ListViewItem
) {
3056 li
= (ListViewItem
) item
;
3057 if (list
.Contains (li
))
3058 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3061 li
= new ListViewItem (item
.ToString ());
3064 result
= list
.Add (li
);
3066 owner
.Redraw (true);
3071 bool IList
.Contains (object item
)
3073 return list
.Contains (item
);
3076 int IList
.IndexOf (object item
)
3078 return list
.IndexOf (item
);
3081 void IList
.Insert (int index
, object item
)
3083 if (item
is ListViewItem
)
3084 this.Insert (index
, (ListViewItem
) item
);
3086 this.Insert (index
, item
.ToString ());
3089 void IList
.Remove (object item
)
3091 Remove ((ListViewItem
) item
);
3094 public int IndexOf (ListViewItem item
)
3096 return list
.IndexOf (item
);
3099 public ListViewItem
Insert (int index
, ListViewItem item
)
3101 if (index
< 0 || index
> list
.Count
)
3102 throw new ArgumentOutOfRangeException ("index");
3104 if (list
.Contains (item
))
3105 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3108 list
.Insert (index
, item
);
3110 owner
.Redraw (true);
3114 public ListViewItem
Insert (int index
, string text
)
3116 return this.Insert (index
, new ListViewItem (text
));
3119 public ListViewItem
Insert (int index
, string text
, int imageIndex
)
3121 return this.Insert (index
, new ListViewItem (text
, imageIndex
));
3124 public virtual void Remove (ListViewItem item
)
3126 if (!list
.Contains (item
))
3129 bool selection_changed
= owner
.SelectedItems
.Contains (item
);
3132 owner
.Redraw (true);
3133 if (selection_changed
)
3134 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
3137 public virtual void RemoveAt (int index
)
3139 if (index
< 0 || index
>= Count
)
3140 throw new ArgumentOutOfRangeException ("index");
3141 bool selection_changed
= owner
.SelectedIndices
.Contains (index
);
3142 list
.RemoveAt (index
);
3144 owner
.Redraw (false);
3145 if (selection_changed
)
3146 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
3148 #endregion // Public Methods
3150 internal event CollectionChangedHandler Changed
;
3152 internal void Sort (IComparer comparer
)
3154 list
.Sort (comparer
);
3158 internal void OnChange ()
3160 if (Changed
!= null)
3163 } // ListViewItemCollection
3165 public class SelectedIndexCollection
: IList
, ICollection
, IEnumerable
3167 private readonly ListView owner
;
3169 #region Public Constructor
3170 public SelectedIndexCollection (ListView owner
)
3174 #endregion // Public Constructor
3176 #region Public Properties
3180 return owner
.SelectedItems
.Count
;
3184 public bool IsReadOnly
{
3185 get { return true; }
3188 public int this [int index
] {
3190 int [] indices
= GetIndices ();
3191 if (index
< 0 || index
>= indices
.Length
)
3192 throw new ArgumentOutOfRangeException ("index");
3193 return indices
[index
];
3197 bool ICollection
.IsSynchronized
{
3198 get { return false; }
3201 object ICollection
.SyncRoot
{
3202 get { return this; }
3205 bool IList
.IsFixedSize
{
3206 get { return true; }
3209 object IList
.this [int index
] {
3210 get { return this [index]; }
3211 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3213 #endregion // Public Properties
3215 #region Public Methods
3216 public bool Contains (int selectedIndex
)
3218 int [] indices
= GetIndices ();
3219 for (int i
= 0; i
< indices
.Length
; i
++) {
3220 if (indices
[i
] == selectedIndex
)
3226 public void CopyTo (Array dest
, int index
)
3228 int [] indices
= GetIndices ();
3229 Array
.Copy (indices
, 0, dest
, index
, indices
.Length
);
3232 public IEnumerator
GetEnumerator ()
3234 int [] indices
= GetIndices ();
3235 return indices
.GetEnumerator ();
3238 int IList
.Add (object value)
3240 throw new NotSupportedException ("Add operation is not supported.");
3245 throw new NotSupportedException ("Clear operation is not supported.");
3248 bool IList
.Contains (object selectedIndex
)
3250 if (!(selectedIndex
is int))
3252 return Contains ((int) selectedIndex
);
3255 int IList
.IndexOf (object selectedIndex
)
3257 if (!(selectedIndex
is int))
3259 return IndexOf ((int) selectedIndex
);
3262 void IList
.Insert (int index
, object value)
3264 throw new NotSupportedException ("Insert operation is not supported.");
3267 void IList
.Remove (object value)
3269 throw new NotSupportedException ("Remove operation is not supported.");
3272 void IList
.RemoveAt (int index
)
3274 throw new NotSupportedException ("RemoveAt operation is not supported.");
3277 public int IndexOf (int selectedIndex
)
3279 int [] indices
= GetIndices ();
3280 for (int i
= 0; i
< indices
.Length
; i
++) {
3281 if (indices
[i
] == selectedIndex
)
3286 #endregion // Public Methods
3288 private int [] GetIndices ()
3290 ArrayList selected_items
= owner
.SelectedItems
.List
;
3291 int [] indices
= new int [selected_items
.Count
];
3292 for (int i
= 0; i
< selected_items
.Count
; i
++) {
3293 ListViewItem item
= (ListViewItem
) selected_items
[i
];
3294 indices
[i
] = item
.Index
;
3298 } // SelectedIndexCollection
3300 public class SelectedListViewItemCollection
: IList
, ICollection
, IEnumerable
3302 private readonly ListView owner
;
3303 private ArrayList list
;
3305 #region Public Constructor
3306 public SelectedListViewItemCollection (ListView owner
)
3309 this.owner
.Items
.Changed
+= new CollectionChangedHandler (
3310 ItemsCollection_Changed
);
3312 #endregion // Public Constructor
3314 #region Public Properties
3318 if (!owner
.IsHandleCreated
)
3324 public bool IsReadOnly
{
3325 get { return true; }
3328 public ListViewItem
this [int index
] {
3330 ArrayList selected_items
= List
;
3331 if (!owner
.IsHandleCreated
|| index
< 0 || index
>= selected_items
.Count
)
3332 throw new ArgumentOutOfRangeException ("index");
3333 return (ListViewItem
) selected_items
[index
];
3337 bool ICollection
.IsSynchronized
{
3338 get { return false; }
3341 object ICollection
.SyncRoot
{
3342 get { return this; }
3345 bool IList
.IsFixedSize
{
3346 get { return true; }
3349 object IList
.this [int index
] {
3350 get { return this [index]; }
3351 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3353 #endregion // Public Properties
3355 #region Public Methods
3356 public void Clear ()
3358 if (!owner
.IsHandleCreated
)
3361 foreach (ListViewItem item
in List
)
3362 item
.Selected
= false;
3365 public bool Contains (ListViewItem item
)
3367 if (!owner
.IsHandleCreated
)
3369 return List
.Contains (item
);
3372 public void CopyTo (Array dest
, int index
)
3374 if (!owner
.IsHandleCreated
)
3376 List
.CopyTo (dest
, index
);
3379 public IEnumerator
GetEnumerator ()
3381 if (!owner
.IsHandleCreated
)
3382 return (new ListViewItem
[0]).GetEnumerator ();
3383 return List
.GetEnumerator ();
3386 int IList
.Add (object value)
3388 throw new NotSupportedException ("Add operation is not supported.");
3391 bool IList
.Contains (object item
)
3393 if (!(item
is ListViewItem
))
3395 return Contains ((ListViewItem
) item
);
3398 int IList
.IndexOf (object item
)
3400 if (!(item
is ListViewItem
))
3402 return IndexOf ((ListViewItem
) item
);
3405 void IList
.Insert (int index
, object value)
3407 throw new NotSupportedException ("Insert operation is not supported.");
3410 void IList
.Remove (object value)
3412 throw new NotSupportedException ("Remove operation is not supported.");
3415 void IList
.RemoveAt (int index
)
3417 throw new NotSupportedException ("RemoveAt operation is not supported.");
3420 public int IndexOf (ListViewItem item
)
3422 if (!owner
.IsHandleCreated
)
3424 return List
.IndexOf (item
);
3426 #endregion // Public Methods
3428 internal ArrayList List
{
3431 list
= new ArrayList ();
3432 foreach (ListViewItem item
in owner
.Items
) {
3441 internal void Reset ()
3443 // force re-population of list
3447 private void ItemsCollection_Changed ()
3451 } // SelectedListViewItemCollection
3453 internal delegate void CollectionChangedHandler ();
3455 #endregion // Subclasses