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 base.BackgroundImage; }
307 set { base.BackgroundImage = value; }
310 [DefaultValue (BorderStyle
.Fixed3D
)]
312 public BorderStyle BorderStyle
{
313 get { return InternalBorderStyle; }
314 set { InternalBorderStyle = value; }
317 [DefaultValue (false)]
318 public bool CheckBoxes
{
319 get { return check_boxes; }
321 if (check_boxes
!= value) {
323 if (value && View
== View
.Tile
)
324 throw new NotSupportedException ("CheckBoxes are not"
325 + " supported in Tile view. Choose a different"
326 + " view or set CheckBoxes to false.");
336 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
337 public CheckedIndexCollection CheckedIndices
{
338 get { return checked_indices; }
342 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
343 public CheckedListViewItemCollection CheckedItems
{
344 get { return checked_items; }
347 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
349 [MergableProperty (false)]
350 public ColumnHeaderCollection Columns
{
351 get { return columns; }
355 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
356 public ListViewItem FocusedItem
{
362 public override Color ForeColor
{
364 if (foreground_color
.IsEmpty
)
365 return ThemeEngine
.Current
.ColorWindowText
;
367 return foreground_color
;
369 set { foreground_color = value; }
372 [DefaultValue (false)]
373 public bool FullRowSelect
{
374 get { return full_row_select; }
375 set { full_row_select = value; }
378 [DefaultValue (false)]
379 public bool GridLines
{
380 get { return grid_lines; }
382 if (grid_lines
!= value) {
389 [DefaultValue (ColumnHeaderStyle
.Clickable
)]
390 public ColumnHeaderStyle HeaderStyle
{
391 get { return header_style; }
393 if (header_style
== value)
397 case ColumnHeaderStyle
.Clickable
:
398 case ColumnHeaderStyle
.Nonclickable
:
399 case ColumnHeaderStyle
.None
:
402 throw new InvalidEnumArgumentException (string.Format
403 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
406 header_style
= value;
407 if (view
== View
.Details
)
412 [DefaultValue (true)]
413 public bool HideSelection
{
414 get { return hide_selection; }
416 if (hide_selection
!= value) {
417 hide_selection
= value;
423 [DefaultValue (false)]
424 public bool HoverSelection
{
425 get { return hover_selection; }
426 set { hover_selection = value; }
429 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
431 [MergableProperty (false)]
432 public ListViewItemCollection Items
{
433 get { return items; }
436 [DefaultValue (false)]
437 public bool LabelEdit
{
438 get { return label_edit; }
439 set { label_edit = value; }
442 [DefaultValue (true)]
444 public bool LabelWrap
{
445 get { return label_wrap; }
447 if (label_wrap
!= value) {
454 [DefaultValue (null)]
455 public ImageList LargeImageList
{
456 get { return large_image_list; }
458 large_image_list
= value;
464 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
465 public IComparer ListViewItemSorter
{
467 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
&& item_sorter
is ItemComparer
)
472 if (item_sorter
!= value) {
479 [DefaultValue (true)]
480 public bool MultiSelect
{
481 get { return multiselect; }
482 set { multiselect = value; }
485 [DefaultValue (true)]
486 public bool Scrollable
{
487 get { return scrollable; }
489 if (scrollable
!= value) {
497 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
498 public SelectedIndexCollection SelectedIndices
{
499 get { return selected_indices; }
503 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
504 public SelectedListViewItemCollection SelectedItems
{
505 get { return selected_items; }
509 [MonoTODO("Implement")]
510 public bool ShowGroups
{
520 [DefaultValue (null)]
521 public ImageList SmallImageList
{
522 get { return small_image_list; }
524 small_image_list
= value;
529 [DefaultValue (SortOrder
.None
)]
530 public SortOrder Sorting
{
531 get { return sort_order; }
533 if (!Enum
.IsDefined (typeof (SortOrder
), value)) {
534 throw new InvalidEnumArgumentException ("value", (int) value,
538 if (sort_order
== value)
543 if (value == SortOrder
.None
) {
544 if (item_sorter
!= null) {
545 // ListViewItemSorter should never be reset for SmallIcon
546 // and LargeIcon view
547 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
)
551 // in .NET 1.1, only internal IComparer would be
553 if (item_sorter
is ItemComparer
)
559 if (item_sorter
== null)
560 item_sorter
= new ItemComparer (value);
561 if (item_sorter
is ItemComparer
) {
563 item_sorter
= new ItemComparer (value);
565 // in .NET 1.1, the sort order is not updated for
566 // SmallIcon and LargeIcon views if no custom IComparer
568 if (View
!= View
.SmallIcon
&& View
!= View
.LargeIcon
)
569 item_sorter
= new ItemComparer (value);
577 [DefaultValue (null)]
578 public ImageList StateImageList
{
579 get { return state_image_list; }
581 state_image_list
= value;
588 [EditorBrowsable (EditorBrowsableState
.Never
)]
589 public override string Text
{
590 get { return base.Text; }
592 if (value == base.Text
)
601 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
602 public ListViewItem TopItem
{
605 if (this.items
.Count
== 0)
607 // if contents are not scrolled
608 // it is the first item
609 else if (h_marker
== 0 && v_marker
== 0)
610 return this.items
[0];
611 // do a hit test for the scrolled position
613 foreach (ListViewItem item
in this.items
) {
614 if (item
.Bounds
.X
>= 0 && item
.Bounds
.Y
>= 0)
623 [MonoTODO("Implement")]
624 public bool UseCompatibleStateImageBehavior
{
634 [DefaultValue (View
.LargeIcon
)]
638 if (!Enum
.IsDefined (typeof (View
), value))
639 throw new InvalidEnumArgumentException ("value", (int) value,
644 if (CheckBoxes
&& value == View
.Tile
)
645 throw new NotSupportedException ("CheckBoxes are not"
646 + " supported in Tile view. Choose a different"
647 + " view or set CheckBoxes to false.");
650 h_scroll
.Value
= v_scroll
.Value
= 0;
656 #endregion // Public Instance Properties
658 #region Internal Methods Properties
660 internal int FirstVisibleIndex
{
663 if (this.items
.Count
== 0)
666 if (h_marker
== 0 && v_marker
== 0)
669 foreach (ListViewItem item
in this.items
) {
670 if (item
.Bounds
.Right
>= 0 && item
.Bounds
.Bottom
>= 0)
679 internal int LastVisibleIndex
{
681 for (int i
= FirstVisibleIndex
; i
< Items
.Count
; i
++) {
682 if (View
== View
.List
|| Alignment
== ListViewAlignment
.Left
) {
683 if (Items
[i
].Bounds
.X
> ClientRectangle
.Right
)
686 if (Items
[i
].Bounds
.Y
> ClientRectangle
.Bottom
)
691 return Items
.Count
- 1;
695 internal void OnSelectedIndexChanged ()
698 OnSelectedIndexChanged (EventArgs
.Empty
);
701 internal int TotalWidth
{
702 get { return Math.Max (this.Width, this.layout_wd); }
705 internal int TotalHeight
{
706 get { return Math.Max (this.Height, this.layout_ht); }
709 internal void Redraw (bool recalculate
)
711 // Avoid calculations when control is being updated
716 CalculateListView (this.alignment
);
721 internal Size
GetChildColumnSize (int index
)
723 Size ret_size
= Size
.Empty
;
724 ColumnHeader col
= this.columns
[index
];
726 if (col
.Width
== -2) { // autosize = max(items, columnheader)
727 Size size
= Size
.Ceiling (this.DeviceContext
.MeasureString
728 (col
.Text
, this.Font
));
729 ret_size
= BiggestItem (index
);
730 if (size
.Width
> ret_size
.Width
)
733 else { // -1 and all the values < -2 are put under one category
734 ret_size
= BiggestItem (index
);
735 // fall back to empty columns' width if no subitem is available for a column
736 if (ret_size
.IsEmpty
) {
737 ret_size
.Width
= ThemeEngine
.Current
.ListViewEmptyColumnWidth
;
738 if (col
.Text
.Length
> 0)
739 ret_size
.Height
= Size
.Ceiling (this.DeviceContext
.MeasureString
740 (col
.Text
, this.Font
)).Height
;
742 ret_size
.Height
= this.Font
.Height
;
746 // adjust the size for icon and checkbox for 0th column
748 ret_size
.Width
+= (this.CheckBoxSize
.Width
+ 4);
749 if (this.small_image_list
!= null)
750 ret_size
.Width
+= this.small_image_list
.ImageSize
.Width
;
755 // Returns the size of biggest item text in a column.
756 private Size
BiggestItem (int col
)
758 Size temp
= Size
.Empty
;
759 Size ret_size
= Size
.Empty
;
761 // 0th column holds the item text, we check the size of
762 // the various subitems falling in that column and get
763 // the biggest one's size.
764 foreach (ListViewItem item
in items
) {
765 if (col
>= item
.SubItems
.Count
)
768 temp
= Size
.Ceiling (this.DeviceContext
.MeasureString
769 (item
.SubItems
[col
].Text
, this.Font
));
770 if (temp
.Width
> ret_size
.Width
)
774 // adjustment for space
775 if (!ret_size
.IsEmpty
)
781 const int max_wrap_padding
= 38;
783 // Sets the size of the biggest item text as per the view
784 private void CalcTextSize ()
786 // clear the old value
787 text_size
= Size
.Empty
;
789 if (items
.Count
== 0)
792 text_size
= BiggestItem (0);
794 if (view
== View
.LargeIcon
&& this.label_wrap
) {
795 Size temp
= Size
.Empty
;
796 if (this.check_boxes
)
797 temp
.Width
+= 2 * this.CheckBoxSize
.Width
;
798 int icon_w
= LargeImageList
== null ? 12 : LargeImageList
.ImageSize
.Width
;
799 temp
.Width
+= icon_w
+ max_wrap_padding
;
800 // wrapping is done for two lines only
801 if (text_size
.Width
> temp
.Width
) {
802 text_size
.Width
= temp
.Width
;
803 text_size
.Height
*= 2;
806 else if (view
== View
.List
) {
807 // in list view max text shown in determined by the
808 // control width, even if scolling is enabled.
809 int max_wd
= this.Width
- (this.CheckBoxSize
.Width
- 2);
810 if (this.small_image_list
!= null)
811 max_wd
-= this.small_image_list
.ImageSize
.Width
;
813 if (text_size
.Width
> max_wd
)
814 text_size
.Width
= max_wd
;
817 // we do the default settings, if we have got 0's
818 if (text_size
.Height
<= 0)
819 text_size
.Height
= this.Font
.Height
;
820 if (text_size
.Width
<= 0)
821 text_size
.Width
= this.Width
;
824 text_size
.Width
+= 4;
825 text_size
.Height
+= 2;
828 private void Scroll (ScrollBar scrollbar
, int delta
)
830 if (delta
== 0 || !scrollbar
.Visible
)
834 if (scrollbar
== h_scroll
)
835 max
= h_scroll
.Maximum
- item_control
.Width
;
837 max
= v_scroll
.Maximum
- item_control
.Height
;
839 int val
= scrollbar
.Value
+ delta
;
842 else if (val
< scrollbar
.Minimum
)
843 val
= scrollbar
.Minimum
;
844 scrollbar
.Value
= val
;
847 private void CalculateScrollBars ()
849 Rectangle client_area
= ClientRectangle
;
851 if (!this.scrollable
|| this.items
.Count
<= 0) {
852 h_scroll
.Visible
= false;
853 v_scroll
.Visible
= false;
854 item_control
.Location
= new Point (0, header_control
.Height
);
855 item_control
.Height
= ClientRectangle
.Width
- header_control
.Height
;
856 item_control
.Width
= ClientRectangle
.Width
;
857 header_control
.Width
= ClientRectangle
.Width
;
861 // Don't calculate if the view is not displayable
862 if (client_area
.Height
< 0 || client_area
.Width
< 0)
865 // making a scroll bar visible might make
866 // other scroll bar visible
867 if (layout_wd
> client_area
.Right
) {
868 h_scroll
.Visible
= true;
869 if ((layout_ht
+ h_scroll
.Height
) > client_area
.Bottom
)
870 v_scroll
.Visible
= true;
872 v_scroll
.Visible
= false;
873 } else if (layout_ht
> client_area
.Bottom
) {
874 v_scroll
.Visible
= true;
875 if ((layout_wd
+ v_scroll
.Width
) > client_area
.Right
)
876 h_scroll
.Visible
= true;
878 h_scroll
.Visible
= false;
880 h_scroll
.Visible
= false;
881 v_scroll
.Visible
= false;
884 item_control
.Height
= ClientRectangle
.Height
- header_control
.Height
;
886 if (h_scroll
.Visible
) {
887 h_scroll
.Location
= new Point (client_area
.X
, client_area
.Bottom
- h_scroll
.Height
);
888 h_scroll
.Minimum
= 0;
890 // if v_scroll is visible, adjust the maximum of the
891 // h_scroll to account for the width of v_scroll
892 if (v_scroll
.Visible
) {
893 h_scroll
.Maximum
= layout_wd
+ v_scroll
.Width
;
894 h_scroll
.Width
= client_area
.Width
- v_scroll
.Width
;
897 h_scroll
.Maximum
= layout_wd
;
898 h_scroll
.Width
= client_area
.Width
;
901 h_scroll
.LargeChange
= client_area
.Width
;
902 h_scroll
.SmallChange
= Font
.Height
;
903 item_control
.Height
-= h_scroll
.Height
;
906 if (header_control
.Visible
)
907 header_control
.Width
= ClientRectangle
.Width
;
908 item_control
.Width
= ClientRectangle
.Width
;
910 if (v_scroll
.Visible
) {
911 v_scroll
.Location
= new Point (client_area
.Right
- v_scroll
.Width
, client_area
.Y
);
912 v_scroll
.Minimum
= 0;
914 // if h_scroll is visible, adjust the maximum of the
915 // v_scroll to account for the height of h_scroll
916 if (h_scroll
.Visible
) {
917 v_scroll
.Maximum
= layout_ht
+ h_scroll
.Height
;
918 v_scroll
.Height
= client_area
.Height
; // - h_scroll.Height already done
920 v_scroll
.Maximum
= layout_ht
;
921 v_scroll
.Height
= client_area
.Height
;
924 v_scroll
.LargeChange
= client_area
.Height
;
925 v_scroll
.SmallChange
= Font
.Height
;
926 if (header_control
.Visible
)
927 header_control
.Width
-= v_scroll
.Width
;
928 item_control
.Width
-= v_scroll
.Width
;
932 ColumnHeader
GetReorderedColumn (int index
)
934 if (reordered_column_indices
== null)
935 return Columns
[index
];
937 return Columns
[reordered_column_indices
[index
]];
940 void ReorderColumn (ColumnHeader col
, int index
)
942 if (reordered_column_indices
== null) {
943 reordered_column_indices
= new int [Columns
.Count
];
944 for (int i
= 0; i
< Columns
.Count
; i
++)
945 reordered_column_indices
[i
] = i
;
948 if (reordered_column_indices
[index
] == col
.Index
)
951 int[] curr
= reordered_column_indices
;
952 int[] result
= new int [Columns
.Count
];
954 for (int i
= 0; i
< Columns
.Count
; i
++) {
955 if (curr_idx
< Columns
.Count
&& curr
[curr_idx
] == col
.Index
)
959 result
[i
] = col
.Index
;
961 result
[i
] = curr
[curr_idx
++];
964 reordered_column_indices
= result
;
966 header_control
.Invalidate ();
967 item_control
.Invalidate ();
970 Size LargeIconItemSize
{
972 int image_w
= LargeImageList
== null ? 12 : LargeImageList
.ImageSize
.Width
;
973 int image_h
= LargeImageList
== null ? 2 : LargeImageList
.ImageSize
.Height
;
974 int w
= CheckBoxSize
.Width
+ 2 + Math
.Max (text_size
.Width
, image_w
);
975 int h
= text_size
.Height
+ 2 + Math
.Max (CheckBoxSize
.Height
, image_h
);
976 return new Size (w
, h
);
980 Size SmallIconItemSize
{
982 int image_w
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Width
;
983 int image_h
= SmallImageList
== null ? 0 : SmallImageList
.ImageSize
.Height
;
984 int w
= text_size
.Width
+ 2 + CheckBoxSize
.Width
+ image_w
;
985 int h
= Math
.Max (text_size
.Height
, Math
.Max (CheckBoxSize
.Height
, image_h
));
986 return new Size (w
, h
);
992 ListViewItem
[,] item_matrix
;
994 void LayoutIcons (bool large_icons
, bool left_aligned
, int x_spacing
, int y_spacing
)
996 header_control
.Visible
= false;
997 header_control
.Size
= Size
.Empty
;
998 item_control
.Visible
= true;
999 item_control
.Location
= Point
.Empty
;
1001 if (items
.Count
== 0)
1004 Size sz
= large_icons
? LargeIconItemSize
: SmallIconItemSize
;
1006 Rectangle area
= ClientRectangle
;
1009 rows
= (int) Math
.Floor ((double)(area
.Height
- h_scroll
.Height
+ y_spacing
) / (double)(sz
.Height
+ y_spacing
));
1012 cols
= (int) Math
.Ceiling ((double)items
.Count
/ (double)rows
);
1014 cols
= (int) Math
.Floor ((double)(area
.Width
- v_scroll
.Width
+ x_spacing
) / (double)(sz
.Width
+ x_spacing
));
1017 rows
= (int) Math
.Ceiling ((double)items
.Count
/ (double)cols
);
1020 layout_ht
= rows
* (sz
.Height
+ y_spacing
) - y_spacing
;
1021 layout_wd
= cols
* (sz
.Width
+ x_spacing
) - x_spacing
;
1022 item_matrix
= new ListViewItem
[rows
, cols
];
1025 foreach (ListViewItem item
in items
) {
1026 int x
= col
* (sz
.Width
+ x_spacing
);
1027 int y
= row
* (sz
.Height
+ y_spacing
);
1028 item
.Location
= new Point (x
, y
);
1032 item_matrix
[row
, col
] = item
;
1034 if (++row
== rows
) {
1039 if (++col
== cols
) {
1046 item_control
.Size
= new Size (layout_wd
, layout_ht
);
1049 void LayoutHeader ()
1052 for (int i
= 0; i
< Columns
.Count
; i
++) {
1053 ColumnHeader col
= GetReorderedColumn (i
);
1056 col
.CalcColumnHeader ();
1060 if (x
< ClientRectangle
.Width
)
1061 x
= ClientRectangle
.Width
;
1063 if (header_style
== ColumnHeaderStyle
.None
) {
1064 header_control
.Visible
= false;
1065 header_control
.Size
= Size
.Empty
;
1067 header_control
.Width
= x
;
1068 header_control
.Height
= columns
[0].Ht
;
1069 header_control
.Visible
= true;
1073 void LayoutDetails ()
1075 if (columns
.Count
== 0) {
1076 header_control
.Visible
= false;
1077 item_control
.Visible
= false;
1083 item_control
.Visible
= true;
1084 item_control
.Location
= new Point (0, header_control
.Height
);
1087 if (items
.Count
> 0) {
1088 foreach (ListViewItem item
in items
) {
1090 item
.Location
= new Point (0, y
);
1091 y
+= item
.Bounds
.Height
+ 2;
1094 // some space for bottom gridline
1099 layout_wd
= Math
.Max (header_control
.Width
, item_control
.Width
);
1100 layout_ht
= y
+ header_control
.Height
;
1103 private void CalculateListView (ListViewAlignment align
)
1112 case View
.SmallIcon
:
1113 LayoutIcons (false, alignment
== ListViewAlignment
.Left
, 4, 2);
1116 case View
.LargeIcon
:
1117 LayoutIcons (true, alignment
== ListViewAlignment
.Left
,
1118 ThemeEngine
.Current
.ListViewHorizontalSpacing
,
1119 ThemeEngine
.Current
.ListViewVerticalSpacing
);
1123 LayoutIcons (false, true, 4, 2);
1127 CalculateScrollBars ();
1130 private bool KeySearchString (KeyEventArgs ke
)
1132 int current_tickcnt
= Environment
.TickCount
;
1133 if (keysearch_tickcnt
> 0 && current_tickcnt
- keysearch_tickcnt
> keysearch_keydelay
) {
1134 keysearch_text
= string.Empty
;
1137 keysearch_text
+= (char) ke
.KeyData
;
1138 keysearch_tickcnt
= current_tickcnt
;
1140 int start
= FocusedItem
== null ? 0 : FocusedItem
.Index
;
1143 if (CultureInfo
.CurrentCulture
.CompareInfo
.IsPrefix (Items
[i
].Text
, keysearch_text
,
1144 CompareOptions
.IgnoreCase
)) {
1145 SetFocusedItem (Items
[i
]);
1146 items
[i
].Selected
= true;
1150 i
= (i
+ 1 < Items
.Count
) ? i
+1 : 0;
1158 int GetAdjustedIndex (Keys key
)
1162 if (View
== View
.Details
) {
1164 result
= FocusedItem
.Index
- 1;
1165 else if (key
== Keys
.Down
) {
1166 result
= FocusedItem
.Index
+ 1;
1167 if (result
== items
.Count
)
1173 int row
= FocusedItem
.row
;
1174 int col
= FocusedItem
.col
;
1180 return item_matrix
[row
, col
- 1].Index
;
1183 if (col
== (cols
- 1))
1185 while (item_matrix
[row
, col
+ 1] == null)
1187 return item_matrix
[row
, col
+ 1].Index
;
1192 return item_matrix
[row
- 1, col
].Index
;
1195 if (row
== (rows
- 1) || row
== Items
.Count
- 1)
1197 while (item_matrix
[row
+ 1, col
] == null)
1199 return item_matrix
[row
+ 1, col
].Index
;
1206 ListViewItem selection_start
;
1208 private bool SelectItems (ArrayList sel_items
)
1210 bool changed
= false;
1211 ArrayList curr_items
= SelectedItems
.List
;
1212 foreach (ListViewItem item
in curr_items
)
1213 if (!sel_items
.Contains (item
)) {
1214 item
.Selected
= false;
1217 foreach (ListViewItem item
in sel_items
)
1218 if (!item
.Selected
) {
1219 item
.Selected
= true;
1225 private void UpdateMultiSelection (int index
)
1227 bool shift_pressed
= (XplatUI
.State
.ModifierKeys
& Keys
.Shift
) != 0;
1228 bool ctrl_pressed
= (XplatUI
.State
.ModifierKeys
& Keys
.Control
) != 0;
1229 ListViewItem item
= items
[index
];
1231 if (shift_pressed
&& selection_start
!= null) {
1232 ArrayList list
= new ArrayList ();
1233 int start
= Math
.Min (selection_start
.Index
, index
);
1234 int end
= Math
.Max (selection_start
.Index
, index
);
1235 if (View
== View
.Details
) {
1236 for (int i
= start
; i
<= end
; i
++)
1237 list
.Add (items
[i
]);
1239 int left
= Math
.Min (items
[start
].col
, items
[end
].col
);
1240 int right
= Math
.Max (items
[start
].col
, items
[end
].col
);
1241 int top
= Math
.Min (items
[start
].row
, items
[end
].row
);
1242 int bottom
= Math
.Max (items
[start
].row
, items
[end
].row
);
1243 foreach (ListViewItem curr
in items
)
1244 if (curr
.row
>= top
&& curr
.row
<= bottom
&&
1245 curr
.col
>= left
&& curr
.col
<= right
)
1248 if (SelectItems (list
))
1249 OnSelectedIndexChanged (EventArgs
.Empty
);
1250 } else if (ctrl_pressed
) {
1251 item
.Selected
= !item
.Selected
;
1252 selection_start
= item
;
1253 OnSelectedIndexChanged (EventArgs
.Empty
);
1255 SelectedItems
.Clear ();
1256 item
.Selected
= true;
1257 selection_start
= item
;
1258 OnSelectedIndexChanged (EventArgs
.Empty
);
1262 internal override bool InternalPreProcessMessage (ref Message msg
)
1264 if (msg
.Msg
== (int)Msg
.WM_KEYDOWN
) {
1265 Keys key_data
= (Keys
)msg
.WParam
.ToInt32();
1266 if (HandleNavKeys (key_data
))
1269 return base.InternalPreProcessMessage (ref msg
);
1272 bool HandleNavKeys (Keys key_data
)
1274 if (Items
.Count
== 0 || !item_control
.Visible
)
1277 if (FocusedItem
== null)
1278 SetFocusedItem (Items
[0]);
1282 SelectIndex (Items
.Count
- 1);
1293 SelectIndex (GetAdjustedIndex (key_data
));
1303 void SelectIndex (int index
)
1309 UpdateMultiSelection (index
);
1310 else if (!items
[index
].Selected
) {
1311 items
[index
].Selected
= true;
1312 OnSelectedIndexChanged (EventArgs
.Empty
);
1315 SetFocusedItem (items
[index
]);
1316 EnsureVisible (index
);
1319 private void ListView_KeyDown (object sender
, KeyEventArgs ke
)
1321 if (ke
.Handled
|| Items
.Count
== 0 || !item_control
.Visible
)
1324 ke
.Handled
= KeySearchString (ke
);
1327 internal class ItemControl
: Control
{
1330 ListViewItem clicked_item
;
1331 ListViewItem last_clicked_item
;
1332 bool hover_processed
= false;
1333 bool checking
= false;
1335 ListViewLabelEditTextBox edit_text_box
;
1336 internal ListViewItem edit_item
;
1337 LabelEditEventArgs edit_args
;
1339 public ItemControl (ListView owner
)
1342 DoubleClick
+= new EventHandler(ItemsDoubleClick
);
1343 MouseDown
+= new MouseEventHandler(ItemsMouseDown
);
1344 MouseMove
+= new MouseEventHandler(ItemsMouseMove
);
1345 MouseHover
+= new EventHandler(ItemsMouseHover
);
1346 MouseUp
+= new MouseEventHandler(ItemsMouseUp
);
1349 void ItemsDoubleClick (object sender
, EventArgs e
)
1351 if (owner
.activation
== ItemActivation
.Standard
)
1352 owner
.OnItemActivate (EventArgs
.Empty
);
1362 BoxSelect box_select_mode
= BoxSelect
.None
;
1363 ArrayList prev_selection
;
1364 Point box_select_start
;
1366 Rectangle box_select_rect
;
1367 internal Rectangle BoxSelectRectangle
{
1368 get { return box_select_rect; }
1370 if (box_select_rect
== value)
1373 InvalidateBoxSelectRect ();
1374 box_select_rect
= value;
1375 InvalidateBoxSelectRect ();
1379 void InvalidateBoxSelectRect ()
1381 if (BoxSelectRectangle
.Size
.IsEmpty
)
1384 Rectangle edge
= BoxSelectRectangle
;
1390 edge
.Y
= BoxSelectRectangle
.Bottom
- 1;
1392 edge
.Y
= BoxSelectRectangle
.Y
- 1;
1394 edge
.Height
= BoxSelectRectangle
.Height
+ 2;
1396 edge
.X
= BoxSelectRectangle
.Right
- 1;
1400 private Rectangle
CalculateBoxSelectRectangle (Point pt
)
1402 int left
= Math
.Min (box_select_start
.X
, pt
.X
);
1403 int right
= Math
.Max (box_select_start
.X
, pt
.X
);
1404 int top
= Math
.Min (box_select_start
.Y
, pt
.Y
);
1405 int bottom
= Math
.Max (box_select_start
.Y
, pt
.Y
);
1406 return Rectangle
.FromLTRB (left
, top
, right
, bottom
);
1409 ArrayList BoxSelectedItems
{
1411 ArrayList result
= new ArrayList ();
1412 foreach (ListViewItem item
in owner
.Items
) {
1413 Rectangle r
= item
.Bounds
;
1415 r
.Y
+= r
.Height
/ 4;
1418 if (BoxSelectRectangle
.IntersectsWith (r
))
1425 private bool PerformBoxSelection (Point pt
)
1427 if (box_select_mode
== BoxSelect
.None
)
1430 BoxSelectRectangle
= CalculateBoxSelectRectangle (pt
);
1432 ArrayList box_items
= BoxSelectedItems
;
1436 switch (box_select_mode
) {
1438 case BoxSelect
.Normal
:
1442 case BoxSelect
.Control
:
1443 items
= new ArrayList ();
1444 foreach (ListViewItem item
in prev_selection
)
1445 if (!box_items
.Contains (item
))
1447 foreach (ListViewItem item
in box_items
)
1448 if (!prev_selection
.Contains (item
))
1452 case BoxSelect
.Shift
:
1454 foreach (ListViewItem item
in box_items
)
1455 prev_selection
.Remove (item
);
1456 foreach (ListViewItem item
in prev_selection
)
1461 throw new Exception ("Unexpected Selection mode: " + box_select_mode
);
1465 owner
.SelectItems (items
);
1471 private void ToggleCheckState (ListViewItem item
)
1473 CheckState curr_state
= item
.Checked
? CheckState
.Checked
: CheckState
.Unchecked
;
1474 item
.Checked
= !item
.Checked
;
1475 CheckState new_state
= item
.Checked
? CheckState
.Checked
: CheckState
.Unchecked
;
1477 ItemCheckEventArgs ice
= new ItemCheckEventArgs (item
.Index
, curr_state
, new_state
);
1478 owner
.OnItemCheck (ice
);
1481 private void ItemsMouseDown (object sender
, MouseEventArgs me
)
1483 if (owner
.items
.Count
== 0)
1486 Point pt
= new Point (me
.X
, me
.Y
);
1487 foreach (ListViewItem item
in owner
.items
) {
1488 if (me
.Clicks
== 1 && item
.CheckRectReal
.Contains (pt
)) {
1492 ToggleCheckState (item
);
1496 if (owner
.View
== View
.Details
&& !owner
.FullRowSelect
) {
1497 if (item
.GetBounds (ItemBoundsPortion
.Label
).Contains (pt
)) {
1498 clicked_item
= item
;
1502 if (item
.Bounds
.Contains (pt
)) {
1503 clicked_item
= item
;
1510 if (clicked_item
!= null) {
1511 owner
.SetFocusedItem (clicked_item
);
1512 bool changed
= !clicked_item
.Selected
;
1513 if (owner
.MultiSelect
)
1514 owner
.UpdateMultiSelection (clicked_item
.Index
);
1516 clicked_item
.Selected
= true;
1519 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
1521 // Raise double click if the item was clicked. On MS the
1522 // double click is only raised if you double click an item
1523 if (me
.Clicks
> 1) {
1524 owner
.OnDoubleClick (EventArgs
.Empty
);
1525 if (owner
.CheckBoxes
)
1526 ToggleCheckState (clicked_item
);
1527 } else if (me
.Clicks
== 1) {
1528 owner
.OnClick (EventArgs
.Empty
);
1529 if (owner
.LabelEdit
&& !changed
)
1530 BeginEdit (clicked_item
); // this is probably not the correct place to execute BeginEdit
1533 if (owner
.MultiSelect
) {
1534 Keys mods
= XplatUI
.State
.ModifierKeys
;
1535 if ((mods
& Keys
.Shift
) != 0)
1536 box_select_mode
= BoxSelect
.Shift
;
1537 else if ((mods
& Keys
.Control
) != 0)
1538 box_select_mode
= BoxSelect
.Control
;
1540 box_select_mode
= BoxSelect
.Normal
;
1541 box_select_start
= pt
;
1542 prev_selection
= owner
.SelectedItems
.List
;
1543 } else if (owner
.SelectedItems
.Count
> 0) {
1544 owner
.SelectedItems
.Clear ();
1545 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
1550 private void ItemsMouseMove (object sender
, MouseEventArgs me
)
1552 if (PerformBoxSelection (new Point (me
.X
, me
.Y
)))
1555 if (owner
.HoverSelection
&& hover_processed
) {
1557 Point pt
= PointToClient (Control
.MousePosition
);
1558 ListViewItem item
= owner
.GetItemAt (pt
.X
, pt
.Y
);
1559 if (item
== null || item
.Selected
)
1562 hover_processed
= false;
1563 XplatUI
.ResetMouseHover (Handle
);
1568 private void ItemsMouseHover (object sender
, EventArgs e
)
1570 if (Capture
|| !owner
.HoverSelection
)
1573 hover_processed
= true;
1574 Point pt
= PointToClient (Control
.MousePosition
);
1575 ListViewItem item
= owner
.GetItemAt (pt
.X
, pt
.Y
);
1580 item
.Selected
= true;
1581 owner
.OnSelectedIndexChanged (new EventArgs ());
1584 private void ItemsMouseUp (object sender
, MouseEventArgs me
)
1587 if (owner
.Items
.Count
== 0)
1590 Point pt
= new Point (me
.X
, me
.Y
);
1592 Rectangle rect
= Rectangle
.Empty
;
1593 if (clicked_item
!= null) {
1594 if (owner
.view
== View
.Details
&& !owner
.full_row_select
)
1595 rect
= clicked_item
.GetBounds (ItemBoundsPortion
.Label
);
1597 rect
= clicked_item
.Bounds
;
1599 if (rect
.Contains (pt
)) {
1600 switch (owner
.activation
) {
1601 case ItemActivation
.OneClick
:
1602 owner
.OnItemActivate (EventArgs
.Empty
);
1605 case ItemActivation
.TwoClick
:
1606 if (last_clicked_item
== clicked_item
) {
1607 owner
.OnItemActivate (EventArgs
.Empty
);
1608 last_clicked_item
= null;
1610 last_clicked_item
= clicked_item
;
1613 // DoubleClick activation is handled in another handler
1617 } else if (!checking
&& owner
.SelectedItems
.Count
> 0 && BoxSelectRectangle
.Size
.IsEmpty
) {
1618 // Need this to clean up background clicks
1619 owner
.SelectedItems
.Clear ();
1620 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
1623 clicked_item
= null;
1624 box_select_start
= Point
.Empty
;
1625 BoxSelectRectangle
= Rectangle
.Empty
;
1626 prev_selection
= null;
1627 box_select_mode
= BoxSelect
.None
;
1631 internal void LabelEditFinished (object sender
, EventArgs e
)
1633 EndEdit (edit_item
);
1636 internal void BeginEdit (ListViewItem item
)
1638 if (edit_item
!= null)
1639 EndEdit (edit_item
);
1641 if (edit_text_box
== null) {
1642 edit_text_box
= new ListViewLabelEditTextBox ();
1643 edit_text_box
.BorderStyle
= BorderStyle
.FixedSingle
;
1644 edit_text_box
.EditingFinished
+= new EventHandler (LabelEditFinished
);
1645 edit_text_box
.Visible
= false;
1646 Controls
.Add (edit_text_box
);
1649 item
.EnsureVisible();
1651 edit_text_box
.Reset ();
1653 switch (owner
.view
) {
1655 case View
.SmallIcon
:
1657 edit_text_box
.TextAlign
= HorizontalAlignment
.Left
;
1658 edit_text_box
.Bounds
= item
.GetBounds (ItemBoundsPortion
.Label
);
1659 SizeF sizef
= DeviceContext
.MeasureString (item
.Text
, item
.Font
);
1660 edit_text_box
.Width
= (int)sizef
.Width
+ 4;
1661 edit_text_box
.MaxWidth
= owner
.ClientRectangle
.Width
- edit_text_box
.Bounds
.X
;
1662 edit_text_box
.WordWrap
= false;
1663 edit_text_box
.Multiline
= false;
1665 case View
.LargeIcon
:
1666 edit_text_box
.TextAlign
= HorizontalAlignment
.Center
;
1667 edit_text_box
.Bounds
= item
.GetBounds (ItemBoundsPortion
.Label
);
1668 sizef
= DeviceContext
.MeasureString (item
.Text
, item
.Font
);
1669 edit_text_box
.Width
= (int)sizef
.Width
+ 4;
1670 edit_text_box
.MaxWidth
= item
.GetBounds(ItemBoundsPortion
.Entire
).Width
;
1671 edit_text_box
.MaxHeight
= owner
.ClientRectangle
.Height
- edit_text_box
.Bounds
.Y
;
1672 edit_text_box
.WordWrap
= true;
1673 edit_text_box
.Multiline
= true;
1677 edit_text_box
.Text
= item
.Text
;
1678 edit_text_box
.Font
= item
.Font
;
1679 edit_text_box
.Visible
= true;
1680 edit_text_box
.Focus ();
1681 edit_text_box
.SelectAll ();
1683 edit_args
= new LabelEditEventArgs (owner
.Items
.IndexOf(edit_item
));
1684 owner
.OnBeforeLabelEdit (edit_args
);
1686 if (edit_args
.CancelEdit
)
1692 internal void EndEdit (ListViewItem item
)
1694 if (edit_text_box
!= null && edit_text_box
.Visible
) {
1695 edit_text_box
.Visible
= false;
1698 if (edit_item
!= null && edit_item
== item
) {
1699 owner
.OnAfterLabelEdit (edit_args
);
1701 if (!edit_args
.CancelEdit
) {
1702 if (edit_args
.Label
!= null)
1703 edit_item
.Text
= edit_args
.Label
;
1705 edit_item
.Text
= edit_text_box
.Text
;
1714 internal override void OnPaintInternal (PaintEventArgs pe
)
1716 ThemeEngine
.Current
.DrawListViewItems (pe
.Graphics
, pe
.ClipRectangle
, owner
);
1719 internal override void OnGotFocusInternal (EventArgs e
)
1725 internal class ListViewLabelEditTextBox
: TextBox
1730 int max_height
= -1;
1731 int min_height
= -1;
1733 int old_number_lines
= 1;
1735 SizeF text_size_one_char
;
1737 public ListViewLabelEditTextBox ()
1739 min_height
= DefaultSize
.Height
;
1740 text_size_one_char
= DeviceContext
.MeasureString ("B", Font
);
1743 public int MaxWidth
{
1745 if (value < min_width
)
1746 max_width
= min_width
;
1752 public int MaxHeight
{
1754 if (value < min_height
)
1755 max_height
= min_height
;
1761 public new int Width
{
1771 public override Font Font
{
1777 text_size_one_char
= DeviceContext
.MeasureString ("B", Font
);
1781 protected override void OnTextChanged (EventArgs e
)
1783 SizeF text_size
= DeviceContext
.MeasureString (Text
, Font
);
1785 int new_width
= (int)text_size
.Width
+ 8;
1788 ResizeTextBoxWidth (new_width
);
1790 if (Width
!= max_width
)
1791 ResizeTextBoxWidth (new_width
);
1793 int number_lines
= Lines
.Length
;
1795 if (number_lines
!= old_number_lines
) {
1796 int new_height
= number_lines
* (int)text_size_one_char
.Height
+ 4;
1797 old_number_lines
= number_lines
;
1799 ResizeTextBoxHeight (new_height
);
1803 base.OnTextChanged (e
);
1806 protected override bool IsInputKey (Keys key_data
)
1808 if ((key_data
& Keys
.Alt
) == 0) {
1809 switch (key_data
& Keys
.KeyCode
) {
1814 return base.IsInputKey (key_data
);
1817 protected override void OnKeyDown (KeyEventArgs e
)
1819 if (e
.KeyCode
== Keys
.Return
&& Visible
) {
1820 this.Visible
= false;
1821 OnEditingFinished (e
);
1825 protected override void OnLostFocus (EventArgs e
)
1828 OnEditingFinished (e
);
1832 protected void OnEditingFinished (EventArgs e
)
1834 EventHandler eh
= (EventHandler
)(Events
[EditingFinishedEvent
]);
1839 private void ResizeTextBoxWidth (int new_width
)
1841 if (new_width
> max_width
)
1842 base.Width
= max_width
;
1844 if (new_width
>= min_width
)
1845 base.Width
= new_width
;
1847 base.Width
= min_width
;
1850 private void ResizeTextBoxHeight (int new_height
)
1852 if (new_height
> max_height
)
1853 base.Height
= max_height
;
1855 if (new_height
>= min_height
)
1856 base.Height
= new_height
;
1858 base.Height
= min_height
;
1861 public void Reset ()
1868 old_number_lines
= 1;
1870 Text
= String
.Empty
;
1875 static object EditingFinishedEvent
= new object ();
1876 public event EventHandler EditingFinished
{
1877 add { Events.AddHandler (EditingFinishedEvent, value); }
1878 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
1882 internal override void OnPaintInternal (PaintEventArgs pe
)
1887 CalculateScrollBars ();
1890 void FocusChanged (object o
, EventArgs args
)
1892 if (Items
.Count
== 0)
1895 if (FocusedItem
== null)
1896 SetFocusedItem (Items
[0]);
1898 item_control
.Invalidate (FocusedItem
.Bounds
);
1901 private void ListView_MouseWheel (object sender
, MouseEventArgs me
)
1903 if (Items
.Count
== 0)
1906 int lines
= me
.Delta
/ 120;
1913 case View
.SmallIcon
:
1914 Scroll (v_scroll
, -Items
[0].Bounds
.Height
* SystemInformation
.MouseWheelScrollLines
* lines
);
1916 case View
.LargeIcon
:
1917 Scroll (v_scroll
, -(Items
[0].Bounds
.Height
+ ThemeEngine
.Current
.ListViewVerticalSpacing
) * lines
);
1920 Scroll (h_scroll
, -Items
[0].Bounds
.Width
* lines
);
1925 private void ListView_SizeChanged (object sender
, EventArgs e
)
1927 CalculateListView (alignment
);
1930 private void SetFocusedItem (ListViewItem item
)
1932 if (focused_item
!= null)
1933 focused_item
.Focused
= false;
1936 item
.Focused
= true;
1938 focused_item
= item
;
1941 private void HorizontalScroller (object sender
, EventArgs e
)
1943 item_control
.EndEdit (item_control
.edit_item
);
1945 // Avoid unnecessary flickering, when button is
1946 // kept pressed at the end
1947 if (h_marker
!= h_scroll
.Value
) {
1949 int pixels
= h_marker
- h_scroll
.Value
;
1951 h_marker
= h_scroll
.Value
;
1952 if (header_control
.Visible
)
1953 XplatUI
.ScrollWindow (header_control
.Handle
, pixels
, 0, false);
1955 XplatUI
.ScrollWindow (item_control
.Handle
, pixels
, 0, false);
1959 private void VerticalScroller (object sender
, EventArgs e
)
1961 item_control
.EndEdit (item_control
.edit_item
);
1963 // Avoid unnecessary flickering, when button is
1964 // kept pressed at the end
1965 if (v_marker
!= v_scroll
.Value
) {
1966 int pixels
= v_marker
- v_scroll
.Value
;
1967 Rectangle area
= item_control
.ClientRectangle
;
1968 v_marker
= v_scroll
.Value
;
1969 XplatUI
.ScrollWindow (item_control
.Handle
, area
, 0, pixels
, false);
1972 #endregion // Internal Methods Properties
1974 #region Protected Methods
1975 protected override void CreateHandle ()
1977 base.CreateHandle ();
1978 for (int i
= 0; i
< SelectedItems
.Count
; i
++)
1979 OnSelectedIndexChanged (EventArgs
.Empty
);
1982 protected override void Dispose (bool disposing
)
1985 h_scroll
.Dispose ();
1986 v_scroll
.Dispose ();
1988 large_image_list
= null;
1989 small_image_list
= null;
1990 state_image_list
= null;
1993 base.Dispose (disposing
);
1996 protected override bool IsInputKey (Keys keyData
)
2013 return base.IsInputKey (keyData
);
2016 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e
)
2018 LabelEditEventHandler eh
= (LabelEditEventHandler
)(Events
[AfterLabelEditEvent
]);
2023 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e
)
2025 LabelEditEventHandler eh
= (LabelEditEventHandler
)(Events
[BeforeLabelEditEvent
]);
2030 protected virtual void OnColumnClick (ColumnClickEventArgs e
)
2032 ColumnClickEventHandler eh
= (ColumnClickEventHandler
)(Events
[ColumnClickEvent
]);
2037 protected override void OnEnabledChanged (EventArgs e
)
2039 base.OnEnabledChanged (e
);
2042 protected override void OnFontChanged (EventArgs e
)
2044 base.OnFontChanged (e
);
2048 protected override void OnHandleCreated (EventArgs e
)
2050 base.OnHandleCreated (e
);
2054 protected override void OnHandleDestroyed (EventArgs e
)
2056 base.OnHandleDestroyed (e
);
2059 protected virtual void OnItemActivate (EventArgs e
)
2061 EventHandler eh
= (EventHandler
)(Events
[ItemActivateEvent
]);
2066 protected virtual void OnItemCheck (ItemCheckEventArgs ice
)
2068 EventHandler eh
= (EventHandler
)(Events
[ItemCheckEvent
]);
2073 protected virtual void OnItemDrag (ItemDragEventArgs e
)
2075 EventHandler eh
= (EventHandler
)(Events
[ItemDragEvent
]);
2080 protected virtual void OnSelectedIndexChanged (EventArgs e
)
2082 EventHandler eh
= (EventHandler
)(Events
[SelectedIndexChangedEvent
]);
2087 protected override void OnSystemColorsChanged (EventArgs e
)
2089 base.OnSystemColorsChanged (e
);
2092 protected void RealizeProperties ()
2097 protected void UpdateExtendedStyles ()
2102 protected override void WndProc (ref Message m
)
2104 base.WndProc (ref m
);
2106 #endregion // Protected Methods
2108 #region Public Instance Methods
2109 public void ArrangeIcons ()
2111 ArrangeIcons (this.alignment
);
2114 public void ArrangeIcons (ListViewAlignment alignment
)
2116 // Icons are arranged only if view is set to LargeIcon or SmallIcon
2117 if (view
== View
.LargeIcon
|| view
== View
.SmallIcon
) {
2118 this.CalculateListView (alignment
);
2119 // we have done the calculations already
2120 this.Redraw (false);
2124 public void BeginUpdate ()
2126 // flag to avoid painting
2130 public void Clear ()
2133 items
.Clear (); // Redraw (true) called here
2136 public void EndUpdate ()
2138 // flag to avoid painting
2141 // probably, now we need a redraw with recalculations
2145 public void EnsureVisible (int index
)
2147 if (index
< 0 || index
>= items
.Count
|| scrollable
== false)
2150 Rectangle view_rect
= item_control
.ClientRectangle
;
2151 Rectangle bounds
= items
[index
].Bounds
;
2153 if (view_rect
.Contains (bounds
))
2156 if (bounds
.Left
< 0)
2157 h_scroll
.Value
+= bounds
.Left
;
2158 else if (bounds
.Right
> view_rect
.Right
)
2159 h_scroll
.Value
+= (bounds
.Right
- view_rect
.Right
);
2162 v_scroll
.Value
+= bounds
.Top
;
2163 else if (bounds
.Bottom
> view_rect
.Bottom
)
2164 v_scroll
.Value
+= (bounds
.Bottom
- view_rect
.Bottom
);
2167 public ListViewItem
GetItemAt (int x
, int y
)
2169 foreach (ListViewItem item
in items
) {
2170 if (item
.Bounds
.Contains (x
, y
))
2176 public Rectangle
GetItemRect (int index
)
2178 return GetItemRect (index
, ItemBoundsPortion
.Entire
);
2181 public Rectangle
GetItemRect (int index
, ItemBoundsPortion portion
)
2183 if (index
< 0 || index
>= items
.Count
)
2184 throw new IndexOutOfRangeException ("index");
2186 return items
[index
].GetBounds (portion
);
2194 // we need this overload to reuse the logic for sorting, while allowing
2195 // redrawing to be done by caller or have it done by this method when
2196 // sorting is really performed
2198 // ListViewItemCollection's Add and AddRange methods call this overload
2199 // with redraw set to false, as they take care of redrawing themselves
2200 // (they even want to redraw the listview if no sort is performed, as
2201 // an item was added), while ListView.Sort () only wants to redraw if
2202 // sorting was actually performed
2203 private void Sort (bool redraw
)
2205 if (!IsHandleCreated
|| item_sorter
== null) {
2209 items
.Sort (item_sorter
);
2214 public override string ToString ()
2216 int count
= this.Items
.Count
;
2219 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
2221 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count
, this.Items
[0].ToString ());
2223 #endregion // Public Instance Methods
2228 class HeaderControl
: Control
{
2231 bool column_resize_active
= false;
2232 ColumnHeader resize_column
;
2233 ColumnHeader clicked_column
;
2234 ColumnHeader drag_column
;
2236 int drag_to_index
= -1;
2238 public HeaderControl (ListView owner
)
2241 MouseDown
+= new MouseEventHandler (HeaderMouseDown
);
2242 MouseMove
+= new MouseEventHandler (HeaderMouseMove
);
2243 MouseUp
+= new MouseEventHandler (HeaderMouseUp
);
2246 private ColumnHeader
ColumnAtX (int x
)
2248 Point pt
= new Point (x
, 0);
2249 ColumnHeader result
= null;
2250 foreach (ColumnHeader col
in owner
.Columns
) {
2251 if (col
.Rect
.Contains (pt
)) {
2259 private int GetReorderedIndex (ColumnHeader col
)
2261 if (owner
.reordered_column_indices
== null)
2264 for (int i
= 0; i
< owner
.Columns
.Count
; i
++)
2265 if (owner
.reordered_column_indices
[i
] == col
.Index
)
2267 throw new Exception ("Column index missing from reordered array");
2270 private void HeaderMouseDown (object sender
, MouseEventArgs me
)
2272 if (resize_column
!= null) {
2273 column_resize_active
= true;
2278 clicked_column
= ColumnAtX (me
.X
+ owner
.h_marker
);
2280 if (clicked_column
!= null) {
2282 if (owner
.AllowColumnReorder
) {
2284 drag_column
= (ColumnHeader
) (clicked_column
as ICloneable
).Clone ();
2285 drag_column
.column_rect
= clicked_column
.Rect
;
2286 drag_to_index
= GetReorderedIndex (clicked_column
);
2288 clicked_column
.pressed
= true;
2289 Rectangle bounds
= clicked_column
.Rect
;
2290 bounds
.X
-= owner
.h_marker
;
2291 Invalidate (bounds
);
2296 private void HeaderMouseMove (object sender
, MouseEventArgs me
)
2298 Point pt
= new Point (me
.X
+ owner
.h_marker
, me
.Y
);
2300 if (column_resize_active
) {
2301 resize_column
.Width
= pt
.X
- resize_column
.X
;
2302 if (resize_column
.Width
< 0)
2303 resize_column
.Width
= 0;
2307 resize_column
= null;
2309 if (clicked_column
!= null) {
2310 if (owner
.AllowColumnReorder
) {
2313 r
= drag_column
.column_rect
;
2314 r
.X
= clicked_column
.Rect
.X
+ me
.X
- drag_x
;
2315 drag_column
.column_rect
= r
;
2317 int x
= me
.X
+ owner
.h_marker
;
2318 ColumnHeader over
= ColumnAtX (x
);
2320 drag_to_index
= owner
.Columns
.Count
;
2321 else if (x
< over
.X
+ over
.Width
/ 2)
2322 drag_to_index
= GetReorderedIndex (over
);
2324 drag_to_index
= GetReorderedIndex (over
) + 1;
2327 ColumnHeader over
= ColumnAtX (me
.X
+ owner
.h_marker
);
2328 bool pressed
= clicked_column
.pressed
;
2329 clicked_column
.pressed
= over
== clicked_column
;
2330 if (clicked_column
.pressed ^ pressed
) {
2331 Rectangle bounds
= clicked_column
.Rect
;
2332 bounds
.X
-= owner
.h_marker
;
2333 Invalidate (bounds
);
2339 for (int i
= 0; i
< owner
.Columns
.Count
; i
++) {
2340 Rectangle zone
= owner
.Columns
[i
].Rect
;
2341 zone
.X
= zone
.Right
- 5;
2343 if (zone
.Contains (pt
)) {
2344 if (i
< owner
.Columns
.Count
- 1 && owner
.Columns
[i
+ 1].Width
== 0)
2346 resize_column
= owner
.Columns
[i
];
2351 if (resize_column
== null)
2352 Cursor
= Cursors
.Default
;
2354 Cursor
= Cursors
.VSplit
;
2357 void HeaderMouseUp (object sender
, MouseEventArgs me
)
2361 if (column_resize_active
) {
2362 column_resize_active
= false;
2363 resize_column
= null;
2364 Cursor
= Cursors
.Default
;
2368 if (clicked_column
!= null && clicked_column
.pressed
) {
2369 clicked_column
.pressed
= false;
2370 Rectangle bounds
= clicked_column
.Rect
;
2371 bounds
.X
-= owner
.h_marker
;
2372 Invalidate (bounds
);
2373 owner
.OnColumnClick (new ColumnClickEventArgs (clicked_column
.Index
));
2376 if (drag_column
!= null && owner
.AllowColumnReorder
) {
2378 if (drag_to_index
> GetReorderedIndex (clicked_column
))
2380 if (owner
.GetReorderedColumn (drag_to_index
) != clicked_column
)
2381 owner
.ReorderColumn (clicked_column
, drag_to_index
);
2386 clicked_column
= null;
2389 internal override void OnPaintInternal (PaintEventArgs pe
)
2394 Theme theme
= ThemeEngine
.Current
;
2395 theme
.DrawListViewHeader (pe
.Graphics
, pe
.ClipRectangle
, this.owner
);
2397 if (drag_column
== null)
2401 if (drag_to_index
== owner
.Columns
.Count
)
2402 target_x
= owner
.GetReorderedColumn (drag_to_index
- 1).Rect
.Right
- owner
.h_marker
;
2404 target_x
= owner
.GetReorderedColumn (drag_to_index
).Rect
.X
- owner
.h_marker
;
2405 theme
.DrawListViewHeaderDragDetails (pe
.Graphics
, owner
, drag_column
, target_x
);
2408 protected override void WndProc (ref Message m
)
2410 switch ((Msg
)m
.Msg
) {
2411 case Msg
.WM_SETFOCUS
:
2415 base.WndProc (ref m
);
2421 private class ItemComparer
: IComparer
{
2422 readonly SortOrder sort_order
;
2424 public ItemComparer (SortOrder sortOrder
)
2426 sort_order
= sortOrder
;
2429 public int Compare (object x
, object y
)
2431 ListViewItem item_x
= x
as ListViewItem
;
2432 ListViewItem item_y
= y
as ListViewItem
;
2433 if (sort_order
== SortOrder
.Ascending
)
2434 return String
.Compare (item_x
.Text
, item_y
.Text
);
2436 return String
.Compare (item_y
.Text
, item_x
.Text
);
2440 public class CheckedIndexCollection
: IList
, ICollection
, IEnumerable
2442 private readonly ListView owner
;
2444 #region Public Constructor
2445 public CheckedIndexCollection (ListView owner
)
2449 #endregion // Public Constructor
2451 #region Public Properties
2454 get { return owner.CheckedItems.Count; }
2457 public bool IsReadOnly
{
2458 get { return true; }
2461 public int this [int index
] {
2463 int [] indices
= GetIndices ();
2464 if (index
< 0 || index
>= indices
.Length
)
2465 throw new ArgumentOutOfRangeException ("index");
2466 return indices
[index
];
2470 bool ICollection
.IsSynchronized
{
2471 get { return false; }
2474 object ICollection
.SyncRoot
{
2475 get { return this; }
2478 bool IList
.IsFixedSize
{
2479 get { return true; }
2482 object IList
.this [int index
] {
2483 get { return this [index]; }
2484 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2486 #endregion // Public Properties
2488 #region Public Methods
2489 public bool Contains (int checkedIndex
)
2491 int [] indices
= GetIndices ();
2492 for (int i
= 0; i
< indices
.Length
; i
++) {
2493 if (indices
[i
] == checkedIndex
)
2499 public IEnumerator
GetEnumerator ()
2501 int [] indices
= GetIndices ();
2502 return indices
.GetEnumerator ();
2505 void ICollection
.CopyTo (Array dest
, int index
)
2507 int [] indices
= GetIndices ();
2508 Array
.Copy (indices
, 0, dest
, index
, indices
.Length
);
2511 int IList
.Add (object value)
2513 throw new NotSupportedException ("Add operation is not supported.");
2518 throw new NotSupportedException ("Clear operation is not supported.");
2521 bool IList
.Contains (object checkedIndex
)
2523 if (!(checkedIndex
is int))
2525 return Contains ((int) checkedIndex
);
2528 int IList
.IndexOf (object checkedIndex
)
2530 if (!(checkedIndex
is int))
2532 return IndexOf ((int) checkedIndex
);
2535 void IList
.Insert (int index
, object value)
2537 throw new NotSupportedException ("Insert operation is not supported.");
2540 void IList
.Remove (object value)
2542 throw new NotSupportedException ("Remove operation is not supported.");
2545 void IList
.RemoveAt (int index
)
2547 throw new NotSupportedException ("RemoveAt operation is not supported.");
2550 public int IndexOf (int checkedIndex
)
2552 int [] indices
= GetIndices ();
2553 for (int i
= 0; i
< indices
.Length
; i
++) {
2554 if (indices
[i
] == checkedIndex
)
2559 #endregion // Public Methods
2561 private int [] GetIndices ()
2563 ArrayList checked_items
= owner
.CheckedItems
.List
;
2564 int [] indices
= new int [checked_items
.Count
];
2565 for (int i
= 0; i
< checked_items
.Count
; i
++) {
2566 ListViewItem item
= (ListViewItem
) checked_items
[i
];
2567 indices
[i
] = item
.Index
;
2571 } // CheckedIndexCollection
2573 public class CheckedListViewItemCollection
: IList
, ICollection
, IEnumerable
2575 private readonly ListView owner
;
2576 private ArrayList list
;
2578 #region Public Constructor
2579 public CheckedListViewItemCollection (ListView owner
)
2582 this.owner
.Items
.Changed
+= new CollectionChangedHandler (
2583 ItemsCollection_Changed
);
2585 #endregion // Public Constructor
2587 #region Public Properties
2591 if (!owner
.CheckBoxes
)
2597 public bool IsReadOnly
{
2598 get { return true; }
2601 public ListViewItem
this [int index
] {
2603 ArrayList checked_items
= List
;
2604 if (index
< 0 || index
>= checked_items
.Count
)
2605 throw new ArgumentOutOfRangeException ("index");
2606 return (ListViewItem
) checked_items
[index
];
2610 bool ICollection
.IsSynchronized
{
2611 get { return false; }
2614 object ICollection
.SyncRoot
{
2615 get { return this; }
2618 bool IList
.IsFixedSize
{
2619 get { return true; }
2622 object IList
.this [int index
] {
2623 get { return this [index]; }
2624 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2626 #endregion // Public Properties
2628 #region Public Methods
2629 public bool Contains (ListViewItem item
)
2631 if (!owner
.CheckBoxes
)
2633 return List
.Contains (item
);
2636 public void CopyTo (Array dest
, int index
)
2638 if (!owner
.CheckBoxes
)
2640 List
.CopyTo (dest
, index
);
2643 public IEnumerator
GetEnumerator ()
2645 if (!owner
.CheckBoxes
)
2646 return (new ListViewItem
[0]).GetEnumerator ();
2647 return List
.GetEnumerator ();
2650 int IList
.Add (object value)
2652 throw new NotSupportedException ("Add operation is not supported.");
2657 throw new NotSupportedException ("Clear operation is not supported.");
2660 bool IList
.Contains (object item
)
2662 if (!(item
is ListViewItem
))
2664 return Contains ((ListViewItem
) item
);
2667 int IList
.IndexOf (object item
)
2669 if (!(item
is ListViewItem
))
2671 return IndexOf ((ListViewItem
) item
);
2674 void IList
.Insert (int index
, object value)
2676 throw new NotSupportedException ("Insert operation is not supported.");
2679 void IList
.Remove (object value)
2681 throw new NotSupportedException ("Remove operation is not supported.");
2684 void IList
.RemoveAt (int index
)
2686 throw new NotSupportedException ("RemoveAt operation is not supported.");
2689 public int IndexOf (ListViewItem item
)
2691 if (!owner
.CheckBoxes
)
2693 return List
.IndexOf (item
);
2695 #endregion // Public Methods
2697 internal ArrayList List
{
2700 list
= new ArrayList ();
2701 foreach (ListViewItem item
in owner
.Items
) {
2710 internal void Reset ()
2712 // force re-population of list
2716 private void ItemsCollection_Changed ()
2720 } // CheckedListViewItemCollection
2722 public class ColumnHeaderCollection
: IList
, ICollection
, IEnumerable
2724 internal ArrayList list
;
2725 private ListView owner
;
2727 #region Public Constructor
2728 public ColumnHeaderCollection (ListView owner
)
2730 list
= new ArrayList ();
2733 #endregion // Public Constructor
2735 #region Public Properties
2738 get { return list.Count; }
2741 public bool IsReadOnly
{
2742 get { return false; }
2745 public virtual ColumnHeader
this [int index
] {
2747 if (index
< 0 || index
>= list
.Count
)
2748 throw new ArgumentOutOfRangeException ("index");
2749 return (ColumnHeader
) list
[index
];
2753 bool ICollection
.IsSynchronized
{
2754 get { return true; }
2757 object ICollection
.SyncRoot
{
2758 get { return this; }
2761 bool IList
.IsFixedSize
{
2762 get { return list.IsFixedSize; }
2765 object IList
.this [int index
] {
2766 get { return this [index]; }
2767 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2769 #endregion // Public Properties
2771 #region Public Methods
2772 public virtual int Add (ColumnHeader
value)
2775 value.owner
= this.owner
;
2776 idx
= list
.Add (value);
2777 if (owner
.IsHandleCreated
) {
2778 owner
.Redraw (true);
2783 public virtual ColumnHeader
Add (string str
, int width
, HorizontalAlignment textAlign
)
2785 ColumnHeader colHeader
= new ColumnHeader (this.owner
, str
, textAlign
, width
);
2786 this.Add (colHeader
);
2790 public virtual void AddRange (ColumnHeader
[] values
)
2792 foreach (ColumnHeader colHeader
in values
) {
2793 colHeader
.owner
= this.owner
;
2797 owner
.Redraw (true);
2800 public virtual void Clear ()
2803 owner
.Redraw (true);
2806 public bool Contains (ColumnHeader
value)
2808 return list
.Contains (value);
2811 public IEnumerator
GetEnumerator ()
2813 return list
.GetEnumerator ();
2816 void ICollection
.CopyTo (Array dest
, int index
)
2818 list
.CopyTo (dest
, index
);
2821 int IList
.Add (object value)
2823 if (! (value is ColumnHeader
)) {
2824 throw new ArgumentException ("Not of type ColumnHeader", "value");
2827 return this.Add ((ColumnHeader
) value);
2830 bool IList
.Contains (object value)
2832 if (! (value is ColumnHeader
)) {
2833 throw new ArgumentException ("Not of type ColumnHeader", "value");
2836 return this.Contains ((ColumnHeader
) value);
2839 int IList
.IndexOf (object value)
2841 if (! (value is ColumnHeader
)) {
2842 throw new ArgumentException ("Not of type ColumnHeader", "value");
2845 return this.IndexOf ((ColumnHeader
) value);
2848 void IList
.Insert (int index
, object value)
2850 if (! (value is ColumnHeader
)) {
2851 throw new ArgumentException ("Not of type ColumnHeader", "value");
2854 this.Insert (index
, (ColumnHeader
) value);
2857 void IList
.Remove (object value)
2859 if (! (value is ColumnHeader
)) {
2860 throw new ArgumentException ("Not of type ColumnHeader", "value");
2863 this.Remove ((ColumnHeader
) value);
2866 public int IndexOf (ColumnHeader
value)
2868 return list
.IndexOf (value);
2871 public void Insert (int index
, ColumnHeader
value)
2873 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2874 // but it's really only greater.
2875 if (index
< 0 || index
> list
.Count
)
2876 throw new ArgumentOutOfRangeException ("index");
2878 value.owner
= this.owner
;
2879 list
.Insert (index
, value);
2880 owner
.Redraw (true);
2883 public void Insert (int index
, string str
, int width
, HorizontalAlignment textAlign
)
2885 ColumnHeader colHeader
= new ColumnHeader (this.owner
, str
, textAlign
, width
);
2886 this.Insert (index
, colHeader
);
2889 public virtual void Remove (ColumnHeader column
)
2891 // TODO: Update Column internal index ?
2892 list
.Remove (column
);
2893 owner
.Redraw (true);
2896 public virtual void RemoveAt (int index
)
2898 if (index
< 0 || index
>= list
.Count
)
2899 throw new ArgumentOutOfRangeException ("index");
2901 // TODO: Update Column internal index ?
2902 list
.RemoveAt (index
);
2903 owner
.Redraw (true);
2905 #endregion // Public Methods
2908 } // ColumnHeaderCollection
2910 public class ListViewItemCollection
: IList
, ICollection
, IEnumerable
2912 private readonly ArrayList list
;
2913 private readonly ListView owner
;
2915 #region Public Constructor
2916 public ListViewItemCollection (ListView owner
)
2918 list
= new ArrayList ();
2921 #endregion // Public Constructor
2923 #region Public Properties
2926 get { return list.Count; }
2929 public bool IsReadOnly
{
2930 get { return false; }
2933 public virtual ListViewItem
this [int displayIndex
] {
2935 if (displayIndex
< 0 || displayIndex
>= list
.Count
)
2936 throw new ArgumentOutOfRangeException ("displayIndex");
2937 return (ListViewItem
) list
[displayIndex
];
2941 if (displayIndex
< 0 || displayIndex
>= list
.Count
)
2942 throw new ArgumentOutOfRangeException ("displayIndex");
2944 if (list
.Contains (value))
2945 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2947 value.Owner
= owner
;
2948 list
[displayIndex
] = value;
2951 owner
.Redraw (true);
2955 bool ICollection
.IsSynchronized
{
2956 get { return true; }
2959 object ICollection
.SyncRoot
{
2960 get { return this; }
2963 bool IList
.IsFixedSize
{
2964 get { return list.IsFixedSize; }
2967 object IList
.this [int index
] {
2968 get { return this [index]; }
2970 if (value is ListViewItem
)
2971 this [index
] = (ListViewItem
) value;
2973 this [index
] = new ListViewItem (value.ToString ());
2977 #endregion // Public Properties
2979 #region Public Methods
2980 public virtual ListViewItem
Add (ListViewItem
value)
2982 if (list
.Contains (value))
2983 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2985 value.Owner
= owner
;
2990 owner
.Redraw (true);
2994 public virtual ListViewItem
Add (string text
)
2996 ListViewItem item
= new ListViewItem (text
);
2997 return this.Add (item
);
3000 public virtual ListViewItem
Add (string text
, int imageIndex
)
3002 ListViewItem item
= new ListViewItem (text
, imageIndex
);
3003 return this.Add (item
);
3006 public void AddRange (ListViewItem
[] values
)
3010 foreach (ListViewItem item
in values
) {
3017 owner
.Redraw (true);
3020 public virtual void Clear ()
3022 owner
.SetFocusedItem (null);
3023 owner
.h_scroll
.Value
= owner
.v_scroll
.Value
= 0;
3026 owner
.Redraw (true);
3029 public bool Contains (ListViewItem item
)
3031 return list
.Contains (item
);
3034 public void CopyTo (Array dest
, int index
)
3036 list
.CopyTo (dest
, index
);
3039 public IEnumerator
GetEnumerator ()
3041 return list
.GetEnumerator ();
3044 int IList
.Add (object item
)
3049 if (item
is ListViewItem
) {
3050 li
= (ListViewItem
) item
;
3051 if (list
.Contains (li
))
3052 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3055 li
= new ListViewItem (item
.ToString ());
3058 result
= list
.Add (li
);
3060 owner
.Redraw (true);
3065 bool IList
.Contains (object item
)
3067 return list
.Contains (item
);
3070 int IList
.IndexOf (object item
)
3072 return list
.IndexOf (item
);
3075 void IList
.Insert (int index
, object item
)
3077 if (item
is ListViewItem
)
3078 this.Insert (index
, (ListViewItem
) item
);
3080 this.Insert (index
, item
.ToString ());
3083 void IList
.Remove (object item
)
3085 Remove ((ListViewItem
) item
);
3088 public int IndexOf (ListViewItem item
)
3090 return list
.IndexOf (item
);
3093 public ListViewItem
Insert (int index
, ListViewItem item
)
3095 if (index
< 0 || index
> list
.Count
)
3096 throw new ArgumentOutOfRangeException ("index");
3098 if (list
.Contains (item
))
3099 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
3102 list
.Insert (index
, item
);
3104 owner
.Redraw (true);
3108 public ListViewItem
Insert (int index
, string text
)
3110 return this.Insert (index
, new ListViewItem (text
));
3113 public ListViewItem
Insert (int index
, string text
, int imageIndex
)
3115 return this.Insert (index
, new ListViewItem (text
, imageIndex
));
3118 public virtual void Remove (ListViewItem item
)
3120 if (!list
.Contains (item
))
3123 bool selection_changed
= owner
.SelectedItems
.Contains (item
);
3126 owner
.Redraw (true);
3127 if (selection_changed
)
3128 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
3131 public virtual void RemoveAt (int index
)
3133 if (index
< 0 || index
>= Count
)
3134 throw new ArgumentOutOfRangeException ("index");
3135 bool selection_changed
= owner
.SelectedIndices
.Contains (index
);
3136 list
.RemoveAt (index
);
3138 owner
.Redraw (false);
3139 if (selection_changed
)
3140 owner
.OnSelectedIndexChanged (EventArgs
.Empty
);
3142 #endregion // Public Methods
3144 internal event CollectionChangedHandler Changed
;
3146 internal void Sort (IComparer comparer
)
3148 list
.Sort (comparer
);
3152 internal void OnChange ()
3154 if (Changed
!= null)
3157 } // ListViewItemCollection
3159 public class SelectedIndexCollection
: IList
, ICollection
, IEnumerable
3161 private readonly ListView owner
;
3163 #region Public Constructor
3164 public SelectedIndexCollection (ListView owner
)
3168 #endregion // Public Constructor
3170 #region Public Properties
3174 return owner
.SelectedItems
.Count
;
3178 public bool IsReadOnly
{
3179 get { return true; }
3182 public int this [int index
] {
3184 int [] indices
= GetIndices ();
3185 if (index
< 0 || index
>= indices
.Length
)
3186 throw new ArgumentOutOfRangeException ("index");
3187 return indices
[index
];
3191 bool ICollection
.IsSynchronized
{
3192 get { return false; }
3195 object ICollection
.SyncRoot
{
3196 get { return this; }
3199 bool IList
.IsFixedSize
{
3200 get { return true; }
3203 object IList
.this [int index
] {
3204 get { return this [index]; }
3205 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3207 #endregion // Public Properties
3209 #region Public Methods
3210 public bool Contains (int selectedIndex
)
3212 int [] indices
= GetIndices ();
3213 for (int i
= 0; i
< indices
.Length
; i
++) {
3214 if (indices
[i
] == selectedIndex
)
3220 public void CopyTo (Array dest
, int index
)
3222 int [] indices
= GetIndices ();
3223 Array
.Copy (indices
, 0, dest
, index
, indices
.Length
);
3226 public IEnumerator
GetEnumerator ()
3228 int [] indices
= GetIndices ();
3229 return indices
.GetEnumerator ();
3232 int IList
.Add (object value)
3234 throw new NotSupportedException ("Add operation is not supported.");
3239 throw new NotSupportedException ("Clear operation is not supported.");
3242 bool IList
.Contains (object selectedIndex
)
3244 if (!(selectedIndex
is int))
3246 return Contains ((int) selectedIndex
);
3249 int IList
.IndexOf (object selectedIndex
)
3251 if (!(selectedIndex
is int))
3253 return IndexOf ((int) selectedIndex
);
3256 void IList
.Insert (int index
, object value)
3258 throw new NotSupportedException ("Insert operation is not supported.");
3261 void IList
.Remove (object value)
3263 throw new NotSupportedException ("Remove operation is not supported.");
3266 void IList
.RemoveAt (int index
)
3268 throw new NotSupportedException ("RemoveAt operation is not supported.");
3271 public int IndexOf (int selectedIndex
)
3273 int [] indices
= GetIndices ();
3274 for (int i
= 0; i
< indices
.Length
; i
++) {
3275 if (indices
[i
] == selectedIndex
)
3280 #endregion // Public Methods
3282 private int [] GetIndices ()
3284 ArrayList selected_items
= owner
.SelectedItems
.List
;
3285 int [] indices
= new int [selected_items
.Count
];
3286 for (int i
= 0; i
< selected_items
.Count
; i
++) {
3287 ListViewItem item
= (ListViewItem
) selected_items
[i
];
3288 indices
[i
] = item
.Index
;
3292 } // SelectedIndexCollection
3294 public class SelectedListViewItemCollection
: IList
, ICollection
, IEnumerable
3296 private readonly ListView owner
;
3297 private ArrayList list
;
3299 #region Public Constructor
3300 public SelectedListViewItemCollection (ListView owner
)
3303 this.owner
.Items
.Changed
+= new CollectionChangedHandler (
3304 ItemsCollection_Changed
);
3306 #endregion // Public Constructor
3308 #region Public Properties
3312 if (!owner
.IsHandleCreated
)
3318 public bool IsReadOnly
{
3319 get { return true; }
3322 public ListViewItem
this [int index
] {
3324 ArrayList selected_items
= List
;
3325 if (!owner
.IsHandleCreated
|| index
< 0 || index
>= selected_items
.Count
)
3326 throw new ArgumentOutOfRangeException ("index");
3327 return (ListViewItem
) selected_items
[index
];
3331 bool ICollection
.IsSynchronized
{
3332 get { return false; }
3335 object ICollection
.SyncRoot
{
3336 get { return this; }
3339 bool IList
.IsFixedSize
{
3340 get { return true; }
3343 object IList
.this [int index
] {
3344 get { return this [index]; }
3345 set { throw new NotSupportedException ("SetItem operation is not supported."); }
3347 #endregion // Public Properties
3349 #region Public Methods
3350 public void Clear ()
3352 if (!owner
.IsHandleCreated
)
3355 foreach (ListViewItem item
in List
)
3356 item
.Selected
= false;
3359 public bool Contains (ListViewItem item
)
3361 if (!owner
.IsHandleCreated
)
3363 return List
.Contains (item
);
3366 public void CopyTo (Array dest
, int index
)
3368 if (!owner
.IsHandleCreated
)
3370 List
.CopyTo (dest
, index
);
3373 public IEnumerator
GetEnumerator ()
3375 if (!owner
.IsHandleCreated
)
3376 return (new ListViewItem
[0]).GetEnumerator ();
3377 return List
.GetEnumerator ();
3380 int IList
.Add (object value)
3382 throw new NotSupportedException ("Add operation is not supported.");
3385 bool IList
.Contains (object item
)
3387 if (!(item
is ListViewItem
))
3389 return Contains ((ListViewItem
) item
);
3392 int IList
.IndexOf (object item
)
3394 if (!(item
is ListViewItem
))
3396 return IndexOf ((ListViewItem
) item
);
3399 void IList
.Insert (int index
, object value)
3401 throw new NotSupportedException ("Insert operation is not supported.");
3404 void IList
.Remove (object value)
3406 throw new NotSupportedException ("Remove operation is not supported.");
3409 void IList
.RemoveAt (int index
)
3411 throw new NotSupportedException ("RemoveAt operation is not supported.");
3414 public int IndexOf (ListViewItem item
)
3416 if (!owner
.IsHandleCreated
)
3418 return List
.IndexOf (item
);
3420 #endregion // Public Methods
3422 internal ArrayList List
{
3425 list
= new ArrayList ();
3426 foreach (ListViewItem item
in owner
.Items
) {
3435 internal void Reset ()
3437 // force re-population of list
3441 private void ItemsCollection_Changed ()
3445 } // SelectedListViewItemCollection
3447 internal delegate void CollectionChangedHandler ();
3449 #endregion // Subclasses