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-2006 Novell, Inc.
23 // Jordi Mas i Hernandez, jordi@ximian.com
24 // Mike Kestner <mkestner@novell.com>
31 using System.Collections;
32 using System.ComponentModel;
33 using System.ComponentModel.Design;
34 using System.ComponentModel.Design.Serialization;
35 using System.Globalization;
36 using System.Reflection;
37 using System.Runtime.InteropServices;
40 using System.Collections.Generic;
43 namespace System.Windows.Forms
45 [DefaultProperty("Items")]
46 [DefaultEvent("SelectedIndexChanged")]
47 [Designer ("System.Windows.Forms.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
49 [DefaultBindingProperty ("SelectedValue")]
50 [ClassInterface (ClassInterfaceType.AutoDispatch)]
53 public class ListBox : ListControl
55 public const int DefaultItemHeight = 13;
56 public const int NoMatches = -1;
58 internal enum ItemNavigation
70 Hashtable item_heights;
71 private int item_height = -1;
72 private int column_width = 0;
73 private int requested_height;
74 private DrawMode draw_mode = DrawMode.Normal;
75 private int horizontal_extent = 0;
76 private bool horizontal_scrollbar = false;
77 private bool integral_height = true;
78 private bool multicolumn = false;
79 private bool scroll_always_visible = false;
80 private SelectedIndexCollection selected_indices;
81 private SelectedObjectCollection selected_items;
82 private SelectionMode selection_mode = SelectionMode.One;
83 private bool sorted = false;
84 private bool use_tabstops = true;
85 private int column_width_internal = 120;
86 private ImplicitVScrollBar vscrollbar;
87 private ImplicitHScrollBar hscrollbar;
88 private int hbar_offset;
89 private bool suspend_layout;
90 private bool ctrl_pressed = false;
91 private bool shift_pressed = false;
92 private bool explicit_item_height = false;
93 private int top_index = 0;
94 private int last_visible_index = 0;
95 private Rectangle items_area;
96 private int focused_item = -1;
97 private ObjectCollection items;
99 private IntegerCollection custom_tab_offsets;
100 private Padding padding;
101 private bool use_custom_tab_offsets;
106 items = CreateItemCollection ();
107 selected_indices = new SelectedIndexCollection (this);
108 selected_items = new SelectedObjectCollection (this);
110 requested_height = bounds.Height;
111 InternalBorderStyle = BorderStyle.Fixed3D;
112 BackColor = ThemeEngine.Current.ColorWindow;
114 /* Vertical scrollbar */
115 vscrollbar = new ImplicitVScrollBar ();
116 vscrollbar.Minimum = 0;
117 vscrollbar.SmallChange = 1;
118 vscrollbar.LargeChange = 1;
119 vscrollbar.Maximum = 0;
120 vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent);
121 vscrollbar.Visible = false;
123 /* Horizontal scrollbar */
124 hscrollbar = new ImplicitHScrollBar ();
125 hscrollbar.Minimum = 0;
126 hscrollbar.SmallChange = 1;
127 hscrollbar.LargeChange = 1;
128 hscrollbar.Maximum = 0;
129 hscrollbar.Visible = false;
130 hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent);
132 Controls.AddImplicit (vscrollbar);
133 Controls.AddImplicit (hscrollbar);
136 MouseDown += new MouseEventHandler (OnMouseDownLB);
137 MouseMove += new MouseEventHandler (OnMouseMoveLB);
138 MouseUp += new MouseEventHandler (OnMouseUpLB);
139 MouseWheel += new MouseEventHandler (OnMouseWheelLB);
140 KeyDown += new KeyEventHandler (OnKeyDownLB);
141 KeyUp += new KeyEventHandler (OnKeyUpLB);
142 GotFocus += new EventHandler (OnGotFocus);
143 LostFocus += new EventHandler (OnLostFocus);
145 SetStyle (ControlStyles.UserPaint, false);
148 custom_tab_offsets = new IntegerCollection (this);
153 static object DrawItemEvent = new object ();
154 static object MeasureItemEvent = new object ();
155 static object SelectedIndexChangedEvent = new object ();
158 [EditorBrowsable (EditorBrowsableState.Never)]
159 public new event EventHandler BackgroundImageChanged {
160 add { base.BackgroundImageChanged += value; }
161 remove { base.BackgroundImageChanged -= value; }
166 [EditorBrowsable (EditorBrowsableState.Never)]
167 public new event EventHandler BackgroundImageLayoutChanged {
168 add { base.BackgroundImageLayoutChanged += value; }
169 remove { base.BackgroundImageLayoutChanged -= value; }
173 [EditorBrowsable (EditorBrowsableState.Always)]
176 [EditorBrowsable (EditorBrowsableState.Advanced)]
178 public new event EventHandler Click {
179 add { base.Click += value; }
180 remove { base.Click -= value; }
183 public event DrawItemEventHandler DrawItem {
184 add { Events.AddHandler (DrawItemEvent, value); }
185 remove { Events.RemoveHandler (DrawItemEvent, value); }
188 public event MeasureItemEventHandler MeasureItem {
189 add { Events.AddHandler (MeasureItemEvent, value); }
190 remove { Events.RemoveHandler (MeasureItemEvent, value); }
195 [EditorBrowsable (EditorBrowsableState.Always)]
196 public new event MouseEventHandler MouseClick {
197 add { base.MouseClick += value; }
198 remove { base.MouseClick -= value; }
202 [EditorBrowsable (EditorBrowsableState.Never)]
203 public new event EventHandler PaddingChanged {
204 add { base.PaddingChanged += value; }
205 remove { base.PaddingChanged -= value; }
210 [EditorBrowsable (EditorBrowsableState.Never)]
211 public new event PaintEventHandler Paint {
212 add { base.Paint += value; }
213 remove { base.Paint -= value; }
216 public event EventHandler SelectedIndexChanged {
217 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
218 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
222 [EditorBrowsable (EditorBrowsableState.Advanced)]
223 public new event EventHandler TextChanged {
224 add { base.TextChanged += value; }
225 remove { base.TextChanged -= value; }
229 #region Public Properties
230 public override Color BackColor {
231 get { return base.BackColor; }
233 if (base.BackColor == value)
236 base.BackColor = value;
237 base.Refresh (); // Careful. Calling the base method is not the same that calling
238 } // the overriden one that refresh also all the items
242 [EditorBrowsable (EditorBrowsableState.Never)]
243 public override Image BackgroundImage {
244 get { return base.BackgroundImage; }
246 base.BackgroundImage = value;
253 [EditorBrowsable (EditorBrowsableState.Never)]
254 public override ImageLayout BackgroundImageLayout {
255 get { return base.BackgroundImageLayout; }
256 set { base.BackgroundImageLayout = value; }
260 [DefaultValue (BorderStyle.Fixed3D)]
262 public BorderStyle BorderStyle {
263 get { return InternalBorderStyle; }
265 InternalBorderStyle = value;
266 UpdateListBoxBounds ();
272 public int ColumnWidth {
273 get { return column_width; }
276 throw new ArgumentException ("A value less than zero is assigned to the property.");
278 column_width = value;
281 ColumnWidthInternal = 120;
283 ColumnWidthInternal = value;
289 protected override CreateParams CreateParams {
290 get { return base.CreateParams;}
295 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
296 public IntegerCollection CustomTabOffsets {
297 get { return custom_tab_offsets; }
301 protected override Size DefaultSize {
302 get { return new Size (120, 96); }
305 [RefreshProperties(RefreshProperties.Repaint)]
306 [DefaultValue (DrawMode.Normal)]
307 public virtual DrawMode DrawMode {
308 get { return draw_mode; }
310 if (!Enum.IsDefined (typeof (DrawMode), value))
311 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
313 if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
314 throw new ArgumentException ("Cannot have variable height and multicolumn");
316 if (draw_mode == value)
321 if (draw_mode == DrawMode.OwnerDrawVariable)
322 item_heights = new Hashtable ();
331 public override Font Font {
332 get { return base.Font; }
333 set { base.Font = value; }
337 public override Color ForeColor {
338 get { return base.ForeColor; }
340 if (base.ForeColor == value)
343 base.ForeColor = value;
350 public int HorizontalExtent {
351 get { return horizontal_extent; }
353 if (horizontal_extent == value)
356 horizontal_extent = value;
361 [DefaultValue (false)]
363 public bool HorizontalScrollbar {
364 get { return horizontal_scrollbar; }
366 if (horizontal_scrollbar == value)
369 horizontal_scrollbar = value;
375 [DefaultValue (true)]
377 [RefreshProperties(RefreshProperties.Repaint)]
378 public bool IntegralHeight {
379 get { return integral_height; }
381 if (integral_height == value)
384 integral_height = value;
385 UpdateListBoxBounds ();
391 [RefreshProperties(RefreshProperties.Repaint)]
392 public virtual int ItemHeight {
394 if (item_height == -1) {
395 SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
396 item_height = (int) sz.Height;
402 throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
404 explicit_item_height = true;
405 if (item_height == value)
410 UpdateListBoxBounds ();
415 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
417 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
419 [MergableProperty (false)]
421 public ObjectCollection Items {
422 get { return items; }
425 [DefaultValue (false)]
426 public bool MultiColumn {
427 get { return multicolumn; }
429 if (multicolumn == value)
432 if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
433 throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
443 [EditorBrowsable (EditorBrowsableState.Never)]
444 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
445 public new Padding Padding {
446 get { return padding; }
447 set { padding = value; }
452 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
453 [EditorBrowsable (EditorBrowsableState.Advanced)]
454 public int PreferredHeight {
457 if (draw_mode == DrawMode.Normal)
458 itemsHeight = FontHeight * items.Count;
459 else if (draw_mode == DrawMode.OwnerDrawFixed)
460 itemsHeight = ItemHeight * items.Count;
461 else if (draw_mode == DrawMode.OwnerDrawVariable) {
462 for (int i = 0; i < items.Count; i++)
463 itemsHeight += (int) item_heights [Items [i]];
470 public override RightToLeft RightToLeft {
471 get { return base.RightToLeft; }
473 base.RightToLeft = value;
474 if (base.RightToLeft == RightToLeft.Yes)
475 StringFormat.Alignment = StringAlignment.Far;
477 StringFormat.Alignment = StringAlignment.Near;
482 // Only affects the Vertical ScrollBar
483 [DefaultValue (false)]
485 public bool ScrollAlwaysVisible {
486 get { return scroll_always_visible; }
488 if (scroll_always_visible == value)
491 scroll_always_visible = value;
498 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
499 public override int SelectedIndex {
501 if (selected_indices == null)
504 return selected_indices.Count > 0 ? selected_indices [0] : -1;
507 if (value < -1 || value >= Items.Count)
508 throw new ArgumentOutOfRangeException ("Index of out range");
510 if (SelectionMode == SelectionMode.None)
511 throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
514 selected_indices.Clear ();
516 selected_indices.Add (value);
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 public SelectedIndexCollection SelectedIndices {
523 get { return selected_indices; }
528 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
529 public object SelectedItem {
531 if (SelectedItems.Count > 0)
532 return SelectedItems[0];
537 if (value != null && !Items.Contains (value))
538 return; // FIXME: this is probably an exception
540 SelectedIndex = value == null ? - 1 : Items.IndexOf (value);
545 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
546 public SelectedObjectCollection SelectedItems {
547 get {return selected_items;}
550 [DefaultValue (SelectionMode.One)]
551 public virtual SelectionMode SelectionMode {
552 get { return selection_mode; }
554 if (!Enum.IsDefined (typeof (SelectionMode), value))
555 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
557 if (selection_mode == value)
560 selection_mode = value;
562 switch (selection_mode) {
563 case SelectionMode.None:
564 SelectedIndices.Clear ();
567 case SelectionMode.One:
568 // FIXME: Probably this can be improved
569 ArrayList old_selection = (ArrayList) SelectedIndices.List.Clone ();
570 for (int i = 1; i < old_selection.Count; i++)
571 SelectedIndices.Remove ((int)old_selection [i]);
580 [DefaultValue (false)]
582 get { return sorted; }
595 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
596 [EditorBrowsable (EditorBrowsableState.Advanced)]
597 public override string Text {
599 if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
600 return GetItemText (SelectedItem);
608 if (SelectionMode == SelectionMode.None)
613 index = FindStringExact (value);
618 SelectedIndex = index;
623 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
624 public int TopIndex {
625 get { return top_index; }
627 if (value == top_index)
630 if (value < 0 || value >= Items.Count)
641 [DefaultValue (false)]
642 public bool UseCustomTabOffsets {
643 get { return use_custom_tab_offsets; }
645 if (use_custom_tab_offsets != value) {
646 use_custom_tab_offsets = value;
647 CalculateTabStops ();
652 [DefaultValue (true)]
653 public bool UseTabStops {
654 get { return use_tabstops; }
656 if (use_tabstops == value)
659 use_tabstops = value;
660 CalculateTabStops ();
665 protected override bool AllowSelection {
667 return SelectionMode != SelectionMode.None;
672 #endregion Public Properties
674 #region Private Properties
676 private int ColumnWidthInternal {
677 get { return column_width_internal; }
678 set { column_width_internal = value; }
681 private int row_count = 1;
682 private int RowCount {
684 return MultiColumn ? row_count : Items.Count;
688 #endregion Private Properties
690 #region Public Methods
692 [Obsolete ("this method has been deprecated")]
694 protected virtual void AddItemsCore (object[] value)
696 Items.AddRange (value);
699 public void BeginUpdate ()
701 suspend_layout = true;
704 public void ClearSelected ()
706 selected_indices.Clear ();
709 protected virtual ObjectCollection CreateItemCollection ()
711 return new ObjectCollection (this);
714 public void EndUpdate ()
716 suspend_layout = false;
721 public int FindString (String s)
723 return FindString (s, -1);
726 public int FindString (string s, int startIndex)
728 if (Items.Count == 0)
729 return -1; // No exception throwing if empty
731 if (startIndex < -1 || startIndex >= Items.Count)
732 throw new ArgumentOutOfRangeException ("Index of out range");
734 startIndex = (startIndex == Items.Count - 1) ? 0 : startIndex + 1;
738 string text = GetItemText (Items [i]);
739 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (text, s,
740 CompareOptions.IgnoreCase))
743 i = (i == Items.Count - 1) ? 0 : i + 1;
751 public int FindStringExact (string s)
753 return FindStringExact (s, -1);
756 public int FindStringExact (string s, int startIndex)
758 if (Items.Count == 0)
759 return -1; // No exception throwing if empty
761 if (startIndex < -1 || startIndex >= Items.Count)
762 throw new ArgumentOutOfRangeException ("Index of out range");
764 startIndex = (startIndex + 1 == Items.Count) ? 0 : startIndex + 1;
768 if (String.Compare (GetItemText (Items[i]), s, true) == 0)
771 i = (i + 1 == Items.Count) ? 0 : i + 1;
779 public int GetItemHeight (int index)
781 if (index < 0 || index >= Items.Count)
782 throw new ArgumentOutOfRangeException ("Index of out range");
784 if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
786 object o = Items [index];
787 if (item_heights.Contains (o))
788 return (int) item_heights [o];
790 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
791 OnMeasureItem (args);
792 item_heights [o] = args.ItemHeight;
793 return args.ItemHeight;
799 public Rectangle GetItemRectangle (int index)
801 if (index < 0 || index >= Items.Count)
802 throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
804 Rectangle rect = new Rectangle ();
807 int col = index / RowCount;
808 rect.Y = ((index - top_index) % RowCount) * ItemHeight;
809 rect.X = col * ColumnWidthInternal;
810 rect.Height = ItemHeight;
811 rect.Width = ColumnWidthInternal;
814 rect.Height = GetItemHeight (index);
815 rect.Width = items_area.Width;
817 if (DrawMode == DrawMode.OwnerDrawVariable) {
819 if (index >= top_index) {
820 for (int i = top_index; i < index; i++) {
821 rect.Y += GetItemHeight (i);
824 for (int i = index; i < top_index; i++) {
825 rect.Y -= GetItemHeight (i);
829 rect.Y = ItemHeight * (index - top_index);
833 if (this is CheckedListBox)
840 [EditorBrowsable (EditorBrowsableState.Advanced)]
841 protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
843 bounds.Height = requested_height;
845 return base.GetScaledBounds (bounds, factor, specified);
849 public bool GetSelected (int index)
851 if (index < 0 || index >= Items.Count)
852 throw new ArgumentOutOfRangeException ("Index of out range");
854 return SelectedIndices.Contains (index);
857 public int IndexFromPoint (Point p)
859 return IndexFromPoint (p.X, p.Y);
862 // Only returns visible points
863 public int IndexFromPoint (int x, int y)
866 if (Items.Count == 0) {
870 for (int i = top_index; i <= last_visible_index; i++) {
871 if (GetItemRectangle (i).Contains (x,y) == true)
878 protected override void OnChangeUICues (UICuesEventArgs e)
880 base.OnChangeUICues (e);
883 protected override void OnDataSourceChanged (EventArgs e)
885 base.OnDataSourceChanged (e);
888 if (DataSource == null || DataManager == null) {
891 SelectedIndex = DataManager.Position;
895 protected override void OnDisplayMemberChanged (EventArgs e)
897 base.OnDisplayMemberChanged (e);
899 if (DataManager == null || !IsHandleCreated)
906 protected virtual void OnDrawItem (DrawItemEventArgs e)
909 case DrawMode.OwnerDrawFixed:
910 case DrawMode.OwnerDrawVariable:
911 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
918 ThemeEngine.Current.DrawListBoxItem (this, e);
923 protected override void OnFontChanged (EventArgs e)
925 base.OnFontChanged (e);
928 StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
930 if (explicit_item_height) {
933 SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
934 item_height = (int) sz.Height;
936 UpdateListBoxBounds ();
941 protected override void OnHandleCreated (EventArgs e)
943 base.OnHandleCreated (e);
946 UpdateListBoxBounds ();
949 EnsureVisible (focused_item);
952 protected override void OnHandleDestroyed (EventArgs e)
954 base.OnHandleDestroyed (e);
957 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
959 if (draw_mode != DrawMode.OwnerDrawVariable)
962 MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
967 protected override void OnParentChanged (EventArgs e)
969 base.OnParentChanged (e);
972 protected override void OnResize (EventArgs e)
975 if (canvas_size.IsEmpty || MultiColumn)
981 protected override void OnSelectedIndexChanged (EventArgs e)
983 base.OnSelectedIndexChanged (e);
985 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
990 protected override void OnSelectedValueChanged (EventArgs e)
992 base.OnSelectedValueChanged (e);
995 public override void Refresh ()
997 if (draw_mode == DrawMode.OwnerDrawVariable)
998 item_heights.Clear ();
1003 protected override void RefreshItem (int index)
1005 if (index < 0 || index >= Items.Count)
1006 throw new ArgumentOutOfRangeException ("Index of out range");
1008 if (draw_mode == DrawMode.OwnerDrawVariable)
1009 item_heights.Remove (Items [index]);
1013 protected override void RefreshItems ()
1015 for (int i = 0; i < Items.Count; i++) {
1020 public override void ResetBackColor ()
1022 base.ResetBackColor ();
1025 public override void ResetForeColor ()
1027 base.ResetForeColor ();
1030 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
1032 base.ScaleControl (factor, specified);
1036 private int SnapHeightToIntegral (int height)
1040 switch (border_style) {
1041 case BorderStyle.Fixed3D:
1042 border = ThemeEngine.Current.Border3DSize.Height;
1044 case BorderStyle.FixedSingle:
1045 border = ThemeEngine.Current.BorderSize.Height;
1047 case BorderStyle.None:
1053 height -= (2 * border);
1054 height -= height % ItemHeight;
1055 height += (2 * border);
1060 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1062 if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
1063 requested_height = height;
1065 if (IntegralHeight && IsHandleCreated)
1066 height = SnapHeightToIntegral (height);
1068 base.SetBoundsCore (x, y, width, height, specified);
1069 UpdateScrollBars ();
1070 last_visible_index = LastVisibleItem ();
1073 protected override void SetItemCore (int index, object value)
1075 if (index < 0 || index >= Items.Count)
1078 Items[index] = value;
1081 protected override void SetItemsCore (IList value)
1086 Items.AddRange (value);
1092 public void SetSelected (int index, bool value)
1094 if (index < 0 || index >= Items.Count)
1095 throw new ArgumentOutOfRangeException ("Index of out range");
1097 if (SelectionMode == SelectionMode.None)
1098 throw new InvalidOperationException ();
1101 SelectedIndices.Add (index);
1103 SelectedIndices.Remove (index);
1106 protected virtual void Sort ()
1112 // Sometimes we could need to Sort, and request a Refresh
1113 // in a different place, to not have the painting done twice
1115 void Sort (bool paint)
1117 if (Items.Count == 0)
1126 public override string ToString ()
1128 return base.ToString ();
1131 protected virtual void WmReflectCommand (ref Message m)
1135 protected override void WndProc (ref Message m)
1137 base.WndProc (ref m);
1140 #endregion Public Methods
1142 #region Private Methods
1144 private void CalculateTabStops ()
1148 if (use_custom_tab_offsets) {
1149 float[] f = new float[custom_tab_offsets.Count];
1150 custom_tab_offsets.CopyTo (f, 0);
1151 StringFormat.SetTabStops (0, f);
1155 StringFormat.SetTabStops (0, new float[] { (float)(Font.Height * 3.7) });
1157 StringFormat.SetTabStops (0, new float[0]);
1162 private Size canvas_size;
1164 private void LayoutListBox ()
1166 if (!IsHandleCreated || suspend_layout)
1170 LayoutMultiColumn ();
1172 LayoutSingleColumn ();
1174 UpdateScrollBars ();
1175 last_visible_index = LastVisibleItem ();
1178 private void LayoutSingleColumn ()
1183 case DrawMode.OwnerDrawVariable:
1185 width = HorizontalExtent;
1186 for (int i = 0; i < Items.Count; i++) {
1187 height += GetItemHeight (i);
1191 case DrawMode.OwnerDrawFixed:
1192 height = Items.Count * ItemHeight;
1193 width = HorizontalExtent;
1196 case DrawMode.Normal:
1198 height = Items.Count * ItemHeight;
1200 for (int i = 0; i < Items.Count; i++) {
1201 SizeF sz = TextRenderer.MeasureString (GetItemText (Items[i]), Font);
1202 int t = (int)sz.Width;
1204 if (this is CheckedListBox)
1213 canvas_size = new Size (width, height);
1216 private void LayoutMultiColumn ()
1218 int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0);
1219 row_count = Math.Max (1, usable_height / ItemHeight);
1221 int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1222 Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1223 if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) {
1224 usable_height = ClientRectangle.Height - hscrollbar.Height;
1225 row_count = Math.Max (1, usable_height / ItemHeight);
1226 cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1227 sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1232 internal void Draw (Rectangle clip, Graphics dc)
1234 Theme theme = ThemeEngine.Current;
1236 if (hscrollbar.Visible && vscrollbar.Visible) {
1237 // Paint the dead space in the bottom right corner
1238 Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height);
1239 if (rect.IntersectsWith (clip))
1240 dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect);
1243 dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area);
1245 if (Items.Count == 0)
1248 for (int i = top_index; i <= last_visible_index; i++) {
1249 Rectangle rect = GetItemDisplayRectangle (i, top_index);
1251 if (!clip.IntersectsWith (rect))
1254 DrawItemState state = DrawItemState.None;
1256 if (SelectedIndices.Contains (i))
1257 state |= DrawItemState.Selected;
1259 if (has_focus && FocusedItem == i)
1260 state |= DrawItemState.Focus;
1262 if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) {
1263 rect.X -= hscrollbar.Value;
1264 rect.Width += hscrollbar.Value;
1267 OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, ForeColor, BackColor));
1271 // Converts a GetItemRectangle to a one that we can display
1272 internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
1274 Rectangle item_rect;
1275 Rectangle first_item_rect = GetItemRectangle (first_displayble);
1276 item_rect = GetItemRectangle (index);
1277 item_rect.X -= first_item_rect.X;
1278 item_rect.Y -= first_item_rect.Y;
1280 // Subtract the checkboxes from the width
1281 if (this is CheckedListBox)
1282 item_rect.Width -= 14;
1288 private void HorizontalScrollEvent (object sender, EventArgs e)
1291 int top_item = top_index;
1292 int last_item = last_visible_index;
1294 top_index = RowCount * hscrollbar.Value;
1295 last_visible_index = LastVisibleItem ();
1297 if (top_item != top_index || last_item != last_visible_index)
1298 Invalidate (items_area);
1301 int old_offset = hbar_offset;
1302 hbar_offset = hscrollbar.Value;
1304 if (hbar_offset < 0)
1307 if (IsHandleCreated)
1308 XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false);
1312 // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
1313 // has screen coordinates
1314 private int IndexAtClientPoint (int x, int y)
1316 if (Items.Count == 0)
1321 else if (x > ClientRectangle.Right)
1322 x = ClientRectangle.Right;
1326 else if (y > ClientRectangle.Bottom)
1327 y = ClientRectangle.Bottom;
1329 for (int i = top_index; i <= last_visible_index; i++)
1330 if (GetItemDisplayRectangle (i, top_index).Contains (x, y))
1336 internal override bool IsInputCharInternal (char charCode)
1341 private int LastVisibleItem ()
1343 Rectangle item_rect;
1344 int top_y = items_area.Y + items_area.Height;
1347 if (top_index >= Items.Count)
1350 for (i = top_index; i < Items.Count; i++) {
1351 item_rect = GetItemDisplayRectangle (i, top_index);
1353 if (item_rect.X > items_area.Width)
1356 if (item_rect.Y + item_rect.Height > top_y)
1363 private void UpdateTopItem ()
1366 int col = top_index / RowCount;
1368 if (col > hscrollbar.Maximum)
1369 hscrollbar.Value = hscrollbar.Maximum;
1371 hscrollbar.Value = col;
1373 int val = vscrollbar.Value;
1374 if (top_index > vscrollbar.Maximum)
1375 vscrollbar.Value = vscrollbar.Maximum;
1377 vscrollbar.Value = top_index;
1378 Scroll (vscrollbar, vscrollbar.Value - top_index);
1379 if (IsHandleCreated)
1380 XplatUI.ScrollWindow (Handle, items_area, 0, ItemHeight * (val - vscrollbar.Value), false);
1384 // Navigates to the indicated item and returns the new item
1385 private int NavigateItemVisually (ItemNavigation navigation)
1387 int page_size, columns, selected_index = -1;
1390 columns = items_area.Width / ColumnWidthInternal;
1391 page_size = columns * RowCount;
1392 if (page_size == 0) {
1393 page_size = RowCount;
1396 page_size = items_area.Height / ItemHeight;
1399 switch (navigation) {
1401 case ItemNavigation.PreviousColumn: {
1402 if (SelectedIndex - RowCount < 0) {
1406 if (SelectedIndex - RowCount < top_index) {
1407 top_index = SelectedIndex - RowCount;
1411 selected_index = SelectedIndex - RowCount;
1415 case ItemNavigation.NextColumn: {
1416 if (SelectedIndex + RowCount >= Items.Count) {
1420 if (SelectedIndex + RowCount > last_visible_index) {
1421 top_index = SelectedIndex;
1425 selected_index = SelectedIndex + RowCount;
1429 case ItemNavigation.First: {
1436 case ItemNavigation.Last: {
1438 int rows = items_area.Height / ItemHeight;
1441 selected_index = Items.Count - 1;
1444 if (Items.Count < rows) {
1446 selected_index = Items.Count - 1;
1449 top_index = Items.Count - rows;
1450 selected_index = Items.Count - 1;
1456 case ItemNavigation.Next: {
1457 if (FocusedItem == Items.Count - 1)
1461 selected_index = FocusedItem + 1;
1466 ArrayList heights = new ArrayList ();
1467 if (draw_mode == DrawMode.OwnerDrawVariable) {
1468 for (int i = top_index; i <= FocusedItem + 1; i++) {
1469 int h = GetItemHeight (i);
1474 bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight;
1477 if (bottom >= items_area.Height) {
1478 int overhang = bottom - items_area.Height;
1481 if (draw_mode == DrawMode.OwnerDrawVariable)
1482 while (overhang > 0)
1483 overhang -= (int) heights [offset];
1485 offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight);
1486 top_index += offset;
1489 selected_index = FocusedItem + 1;
1493 case ItemNavigation.Previous: {
1494 if (FocusedItem > 0) {
1495 if (FocusedItem - 1 < top_index) {
1499 selected_index = FocusedItem - 1;
1504 case ItemNavigation.NextPage: {
1505 if (Items.Count < page_size) {
1506 NavigateItemVisually (ItemNavigation.Last);
1510 if (FocusedItem + page_size - 1 >= Items.Count) {
1511 top_index = Items.Count - page_size;
1513 selected_index = Items.Count - 1;
1516 if (FocusedItem + page_size - 1 > last_visible_index) {
1517 top_index = FocusedItem;
1521 selected_index = FocusedItem + page_size - 1;
1527 case ItemNavigation.PreviousPage: {
1529 int rows = items_area.Height / ItemHeight;
1530 if (FocusedItem - (rows - 1) <= 0) {
1536 if (SelectedIndex - (rows - 1) < top_index) {
1537 top_index = FocusedItem - (rows - 1);
1541 selected_index = FocusedItem - (rows - 1);
1550 return selected_index;
1554 private void OnGotFocus (object sender, EventArgs e)
1556 if (Items.Count == 0)
1559 if (FocusedItem == -1)
1562 InvalidateItem (FocusedItem);
1565 private void OnLostFocus (object sender, EventArgs e)
1567 if (FocusedItem != -1)
1568 InvalidateItem (FocusedItem);
1571 private bool KeySearch (Keys key)
1573 char c = (char) key;
1574 if (!Char.IsLetterOrDigit (c))
1577 int idx = FindString (c.ToString (), SelectedIndex);
1578 if (idx != ListBox.NoMatches)
1579 SelectedIndex = idx;
1584 internal void OnKeyDownLB (object sender, KeyEventArgs e)
1588 if (Items.Count == 0)
1591 if (KeySearch (e.KeyCode))
1594 switch (e.KeyCode) {
1596 case Keys.ControlKey:
1597 ctrl_pressed = true;
1601 shift_pressed = true;
1605 new_item = NavigateItemVisually (ItemNavigation.First);
1609 new_item = NavigateItemVisually (ItemNavigation.Last);
1613 new_item = NavigateItemVisually (ItemNavigation.Previous);
1617 new_item = NavigateItemVisually (ItemNavigation.Next);
1621 new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
1625 new_item = NavigateItemVisually (ItemNavigation.NextPage);
1629 if (multicolumn == true) {
1630 new_item = NavigateItemVisually (ItemNavigation.NextColumn);
1635 if (multicolumn == true) {
1636 new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
1641 if (selection_mode == SelectionMode.MultiSimple) {
1642 SelectedItemFromNavigation (FocusedItem);
1651 if (new_item != -1) {
1652 FocusedItem = new_item;
1653 if (selection_mode != SelectionMode.MultiSimple && selection_mode != SelectionMode.None) {
1654 SelectedItemFromNavigation (new_item);
1659 private void OnKeyUpLB (object sender, KeyEventArgs e)
1661 switch (e.KeyCode) {
1662 case Keys.ControlKey:
1663 ctrl_pressed = false;
1666 shift_pressed = false;
1673 internal void InvalidateItem (int index)
1675 if (!IsHandleCreated)
1677 Rectangle bounds = GetItemDisplayRectangle (index, top_index);
1678 if (ClientRectangle.IntersectsWith (bounds))
1679 Invalidate (bounds);
1682 internal virtual void OnItemClick (int index)
1684 OnSelectedIndexChanged (EventArgs.Empty);
1685 OnSelectedValueChanged (EventArgs.Empty);
1689 int[] prev_selection;
1690 bool button_pressed = false;
1692 private void SelectExtended (int index)
1696 ArrayList new_selection = new ArrayList ();
1697 int start = anchor < index ? anchor : index;
1698 int end = anchor > index ? anchor : index;
1699 for (int i = start; i <= end; i++)
1700 new_selection.Add (i);
1703 foreach (int i in prev_selection)
1704 if (!selected_indices.Contains (i))
1705 new_selection.Add (i);
1707 // Need to make a copy since we can't enumerate and modify the collection
1709 ArrayList sel_indices = (ArrayList) selected_indices.List.Clone ();
1710 foreach (int i in sel_indices)
1711 if (!new_selection.Contains (i))
1712 selected_indices.Remove (i);
1714 foreach (int i in new_selection)
1715 if (!sel_indices.Contains (i))
1716 selected_indices.Add (i);
1720 private void OnMouseDownLB (object sender, MouseEventArgs e)
1722 // Only do stuff with the left mouse button
1723 if ((e.Button & MouseButtons.Left) == 0)
1726 int index = IndexAtClientPoint (e.X, e.Y);
1730 switch (SelectionMode) {
1731 case SelectionMode.One:
1732 SelectedIndex = index;
1735 case SelectionMode.MultiSimple:
1736 if (SelectedIndices.Contains (index))
1737 SelectedIndices.Remove (index);
1739 SelectedIndices.Add (index);
1742 case SelectionMode.MultiExtended:
1743 shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1744 ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1747 prev_selection = new int [SelectedIndices.Count];
1748 SelectedIndices.CopyTo (prev_selection, 0);
1750 SelectedIndices.Clear ();
1755 SelectExtended (index);
1758 case SelectionMode.None:
1764 button_pressed = true;
1765 FocusedItem = index;
1768 private void OnMouseMoveLB (object sender, MouseEventArgs e)
1770 if (!button_pressed)
1773 int index = IndexAtClientPoint (e.X, e.Y);
1775 switch (SelectionMode) {
1776 case SelectionMode.One:
1777 SelectedIndex = index;
1780 case SelectionMode.MultiSimple:
1783 case SelectionMode.MultiExtended:
1784 SelectExtended (index);
1787 case SelectionMode.None:
1793 FocusedItem = index;
1796 private void OnMouseUpLB (object sender, MouseEventArgs e)
1798 // Only do stuff with the left mouse button
1799 if ((e.Button & MouseButtons.Left) == 0)
1803 OnDoubleClick (EventArgs.Empty);
1805 OnMouseDoubleClick (e);
1808 else if (e.Clicks == 1) {
1809 OnClick (EventArgs.Empty);
1815 if (!button_pressed)
1818 int index = IndexAtClientPoint (e.X, e.Y);
1819 OnItemClick (index);
1820 button_pressed = ctrl_pressed = shift_pressed = false;
1823 private void Scroll (ScrollBar scrollbar, int delta)
1825 if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled)
1829 if (scrollbar == hscrollbar)
1830 max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1;
1832 max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1;
1834 int val = scrollbar.Value + delta;
1837 else if (val < scrollbar.Minimum)
1838 val = scrollbar.Minimum;
1839 scrollbar.Value = val;
1842 private void OnMouseWheelLB (object sender, MouseEventArgs me)
1844 if (Items.Count == 0)
1847 int lines = me.Delta / 120;
1850 Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines);
1852 Scroll (vscrollbar, -lines);
1855 internal override void OnPaintInternal (PaintEventArgs pevent)
1860 Draw (pevent.ClipRectangle, pevent.Graphics);
1863 internal void RepositionScrollBars ()
1865 if (vscrollbar.is_visible) {
1866 vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height);
1867 vscrollbar.Location = new Point (items_area.Width, 0);
1870 if (hscrollbar.is_visible) {
1871 hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height);
1872 hscrollbar.Location = new Point (0, items_area.Height);
1876 // An item navigation operation (mouse or keyboard) has caused to select a new item
1877 internal void SelectedItemFromNavigation (int index)
1879 switch (SelectionMode) {
1880 case SelectionMode.None: // Do nothing
1882 case SelectionMode.One: {
1883 SelectedIndex = index;
1886 case SelectionMode.MultiSimple: {
1887 if (SelectedIndex == -1) {
1888 SelectedIndex = index;
1891 if (SelectedIndices.Contains (index))
1892 SelectedIndices.Remove (index);
1894 SelectedIndices.AddCore (index);
1896 OnSelectedIndexChanged (EventArgs.Empty);
1897 OnSelectedValueChanged (EventArgs.Empty);
1903 case SelectionMode.MultiExtended: {
1904 if (SelectedIndex == -1) {
1905 SelectedIndex = index;
1908 if (ctrl_pressed == false && shift_pressed == false) {
1909 SelectedIndices.Clear ();
1912 if (shift_pressed == true) {
1913 ShiftSelection (index);
1914 } else { // ctrl_pressed or single item
1915 SelectedIndices.AddCore (index);
1919 OnSelectedIndexChanged (EventArgs.Empty);
1920 OnSelectedValueChanged (EventArgs.Empty);
1930 private void ShiftSelection (int index)
1932 int shorter_item = -1, dist = Items.Count + 1, cur_dist;
1934 foreach (int idx in selected_indices) {
1936 cur_dist = idx - index;
1938 cur_dist = index - idx;
1941 if (cur_dist < dist) {
1947 if (shorter_item != -1) {
1950 if (shorter_item > index) {
1954 start = shorter_item;
1958 selected_indices.Clear ();
1959 for (int idx = start; idx <= end; idx++) {
1960 selected_indices.AddCore (idx);
1965 internal int FocusedItem {
1966 get { return focused_item; }
1968 if (focused_item == value)
1971 int prev = focused_item;
1973 focused_item = value;
1975 if (has_focus == false)
1979 InvalidateItem (prev);
1982 InvalidateItem (value);
1986 StringFormat string_format;
1987 internal StringFormat StringFormat {
1989 if (string_format == null) {
1990 string_format = new StringFormat ();
1991 if (RightToLeft == RightToLeft.Yes)
1992 string_format.Alignment = StringAlignment.Far;
1994 string_format.Alignment = StringAlignment.Near;
1995 CalculateTabStops ();
1997 return string_format;
2001 internal virtual void CollectionChanged ()
2006 if (Items.Count == 0) {
2007 selected_indices.List.Clear ();
2011 if (Items.Count <= focused_item)
2012 focused_item = Items.Count - 1;
2014 if (!IsHandleCreated || suspend_layout)
2022 void EnsureVisible (int index)
2024 if (!IsHandleCreated || index == -1)
2027 if (index < top_index) {
2031 } else if (!multicolumn) {
2032 int rows = items_area.Height / ItemHeight;
2033 if (index >= (top_index + rows))
2034 top_index = index - rows + 1;
2038 int rows = Math.Max (1, items_area.Height / ItemHeight);
2039 int cols = Math.Max (1, items_area.Width / ColumnWidthInternal);
2041 if (index >= (top_index + (rows * cols))) {
2042 int incolumn = index / rows;
2043 top_index = (incolumn - (cols - 1)) * rows;
2051 private void UpdateListBoxBounds ()
2053 if (IsHandleCreated)
2054 SetBoundsInternal (bounds.X, bounds.Y, bounds.Width, IntegralHeight ? SnapHeightToIntegral (requested_height) : requested_height, BoundsSpecified.None);
2057 private void UpdateScrollBars ()
2059 items_area = ClientRectangle;
2060 if (UpdateHorizontalScrollBar ()) {
2061 items_area.Height -= hscrollbar.Height;
2062 if (UpdateVerticalScrollBar ()) {
2063 items_area.Width -= vscrollbar.Width;
2064 UpdateHorizontalScrollBar ();
2066 } else if (UpdateVerticalScrollBar ()) {
2067 items_area.Width -= vscrollbar.Width;
2068 if (UpdateHorizontalScrollBar ()) {
2069 items_area.Height -= hscrollbar.Height;
2070 UpdateVerticalScrollBar ();
2074 RepositionScrollBars ();
2077 /* Determines if the horizontal scrollbar has to be displyed */
2078 private bool UpdateHorizontalScrollBar ()
2081 bool enabled = true;
2084 if (canvas_size.Width > items_area.Width) {
2086 hscrollbar.Maximum = canvas_size.Width / ColumnWidthInternal - 1;
2087 } else if (ScrollAlwaysVisible == true) {
2090 hscrollbar.Maximum = 0;
2092 } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) {
2094 hscrollbar.Maximum = canvas_size.Width;
2095 hscrollbar.LargeChange = Math.Max (0, items_area.Width);
2096 } else if (horizontal_scrollbar) {
2099 hscrollbar.Maximum = 0;
2102 hbar_offset = hscrollbar.Value;
2103 hscrollbar.Enabled = enabled;
2104 hscrollbar.Visible = show;
2109 /* Determines if the vertical scrollbar has to be displyed */
2110 private bool UpdateVerticalScrollBar ()
2112 if (MultiColumn || (Items.Count == 0 && !scroll_always_visible)) {
2113 vscrollbar.Visible = false;
2115 } else if (Items.Count == 0) {
2116 vscrollbar.Visible = true;
2117 vscrollbar.Enabled = false;
2118 vscrollbar.Maximum = 0;
2123 bool enabled = true;
2124 if (canvas_size.Height > items_area.Height) {
2126 vscrollbar.Maximum = Items.Count - 1;
2127 vscrollbar.LargeChange = Math.Max (items_area.Height / ItemHeight, 0);
2128 } else if (ScrollAlwaysVisible) {
2131 vscrollbar.Maximum = 0;
2134 vscrollbar.Enabled = enabled;
2135 vscrollbar.Visible = show;
2141 private void VerticalScrollEvent (object sender, EventArgs e)
2143 int top_item = top_index;
2145 top_index = /*row_count + */ vscrollbar.Value;
2146 last_visible_index = LastVisibleItem ();
2148 int delta = (top_item - top_index) * ItemHeight;
2149 if (DrawMode == DrawMode.OwnerDrawVariable) {
2152 if (top_index < top_item)
2153 for (int i = top_index; i < top_item; i++)
2154 delta += GetItemHeight (i);
2156 for (int i = top_item; i < top_index; i++)
2157 delta -= GetItemHeight (i);
2160 if (IsHandleCreated)
2161 XplatUI.ScrollWindow (Handle, items_area, 0, delta, false);
2164 #endregion Private Methods
2167 public class IntegerCollection : IList, ICollection, IEnumerable
2169 private ListBox owner;
2170 private List<int> list;
2172 #region Public Constructor
2173 public IntegerCollection (ListBox owner)
2176 list = new List<int> ();
2180 #region Public Properties
2183 get { return list.Count; }
2186 public int this [int index] {
2187 get { return list[index]; }
2188 set { list[index] = value; owner.CalculateTabStops (); }
2192 #region Public Methods
2193 public int Add (int item)
2195 // This collection does not allow duplicates
2196 if (!list.Contains (item)) {
2199 owner.CalculateTabStops ();
2202 return list.IndexOf (item);
2205 public void AddRange (int[] items)
2207 foreach (int i in items)
2208 if (!list.Contains (i))
2214 public void AddRange (IntegerCollection value)
2216 foreach (int i in value)
2217 if (!list.Contains (i))
2223 public void Clear ()
2226 owner.CalculateTabStops ();
2229 public bool Contains (int item)
2231 return list.Contains (item);
2234 public void CopyTo (Array destination, int index)
2236 for (int i = index; i < list.Count; i++)
2237 destination.SetValue (list[i], i);
2240 public int IndexOf (int item)
2242 return list.IndexOf (item);
2245 public void Remove (int item)
2249 owner.CalculateTabStops ();
2252 public void RemoveAt (int index)
2254 list.RemoveAt (index);
2256 owner.CalculateTabStops ();
2260 #region IEnumerable Members
2261 IEnumerator IEnumerable.GetEnumerator ()
2263 return list.GetEnumerator ();
2267 #region IList Members
2268 int IList.Add (object item)
2270 return Add ((int) item);
2278 bool IList.Contains (object item)
2280 return Contains ((int) item);
2283 int IList.IndexOf (object item)
2285 return IndexOf ((int) item);
2288 void IList.Insert (int index, object value)
2290 throw new Exception ("The method or operation is not implemented.");
2293 bool IList.IsFixedSize
2295 get { return false; }
2298 bool IList.IsReadOnly
2300 get { return false; }
2303 void IList.Remove (object value)
2305 Remove ((int)value);
2308 void IList.RemoveAt (int index)
2313 object IList.this[int index] {
2314 get { return this[index]; }
2315 set { this[index] = (int)value; }
2319 #region ICollection Members
2320 bool ICollection.IsSynchronized
2322 get { throw new Exception ("The method or operation is not implemented."); }
2325 object ICollection.SyncRoot
2327 get { throw new Exception ("The method or operation is not implemented."); }
2333 [ListBindable (false)]
2334 public class ObjectCollection : IList, ICollection, IEnumerable
2336 internal class ListObjectComparer : IComparer
2338 public int Compare (object a, object b)
2340 string str1 = a.ToString ();
2341 string str2 = b.ToString ();
2342 return str1.CompareTo (str2);
2346 private ListBox owner;
2347 internal ArrayList object_items = new ArrayList ();
2349 public ObjectCollection (ListBox owner)
2354 public ObjectCollection (ListBox owner, object[] value)
2360 public ObjectCollection (ListBox owner, ObjectCollection value)
2366 #region Public Properties
2368 get { return object_items.Count; }
2371 public bool IsReadOnly {
2372 get { return false; }
2376 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2377 public virtual object this [int index] {
2379 if (index < 0 || index >= Count)
2380 throw new ArgumentOutOfRangeException ("Index of out range");
2382 return object_items[index];
2385 if (index < 0 || index >= Count)
2386 throw new ArgumentOutOfRangeException ("Index of out range");
2388 throw new ArgumentNullException ("value");
2390 object_items[index] = value;
2391 owner.CollectionChanged ();
2395 bool ICollection.IsSynchronized {
2396 get { return false; }
2399 object ICollection.SyncRoot {
2400 get { return this; }
2403 bool IList.IsFixedSize {
2404 get { return false; }
2407 #endregion Public Properties
2409 #region Public Methods
2410 public int Add (object item)
2414 idx = AddItem (item);
2415 owner.CollectionChanged ();
2419 public void AddRange (object[] items)
2422 throw new ArgumentNullException ("items");
2424 foreach (object mi in items)
2427 owner.CollectionChanged ();
2430 public void AddRange (ObjectCollection value)
2433 throw new ArgumentNullException ("value");
2435 foreach (object mi in value)
2438 owner.CollectionChanged ();
2441 internal void AddRange (IList list)
2443 foreach (object mi in list)
2446 owner.CollectionChanged ();
2449 public virtual void Clear ()
2451 owner.selected_indices.Clear ();
2452 object_items.Clear ();
2453 owner.CollectionChanged ();
2455 public bool Contains (object value)
2458 throw new ArgumentNullException ("value");
2460 return object_items.Contains (value);
2464 public void CopyTo (object[] destination, int arrayIndex)
2466 object [] dest = destination;
2468 public void CopyTo (object [] dest, int arrayIndex)
2471 object_items.CopyTo (dest, arrayIndex);
2475 void ICollection.CopyTo (Array destination, int index)
2477 Array dest = destination;
2479 void ICollection.CopyTo (Array dest, int index)
2482 object_items.CopyTo (dest, index);
2485 public IEnumerator GetEnumerator ()
2487 return object_items.GetEnumerator ();
2490 int IList.Add (object item)
2495 public int IndexOf (object value)
2498 throw new ArgumentNullException ("value");
2500 return object_items.IndexOf (value);
2503 public void Insert (int index, object item)
2505 if (index < 0 || index > Count)
2506 throw new ArgumentOutOfRangeException ("Index of out range");
2508 throw new ArgumentNullException ("item");
2510 owner.BeginUpdate ();
2511 object_items.Insert (index, item);
2512 owner.CollectionChanged ();
2516 public void Remove (object value)
2521 RemoveAt (IndexOf (value));
2524 public void RemoveAt (int index)
2526 if (index < 0 || index >= Count)
2527 throw new ArgumentOutOfRangeException ("Index of out range");
2529 owner.selected_indices.Remove (index);
2530 object_items.RemoveAt (index);
2531 owner.CollectionChanged ();
2533 #endregion Public Methods
2535 #region Private Methods
2536 internal int AddItem (object item)
2539 throw new ArgumentNullException ("item");
2541 int cnt = object_items.Count;
2542 object_items.Add (item);
2546 internal void Sort ()
2548 object_items.Sort (new ListObjectComparer ());
2551 #endregion Private Methods
2554 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2556 private ListBox owner;
2557 ArrayList selection;
2558 bool sorting_needed; // Selection state retrieval is done sorted - we do it lazyly
2560 public SelectedIndexCollection (ListBox owner)
2563 selection = new ArrayList ();
2566 #region Public Properties
2569 get { return selection.Count; }
2572 public bool IsReadOnly {
2573 get { return true; }
2576 public int this [int index] {
2578 if (index < 0 || index >= Count)
2579 throw new ArgumentOutOfRangeException ("Index of out range");
2582 return (int)selection [index];
2586 bool ICollection.IsSynchronized {
2587 get { return true; }
2590 bool IList.IsFixedSize{
2591 get { return true; }
2594 object ICollection.SyncRoot {
2595 get { return selection; }
2598 #endregion Public Properties
2600 #region Public Methods
2606 void Add (int index)
2608 if (AddCore (index)) {
2609 owner.OnSelectedIndexChanged (EventArgs.Empty);
2610 owner.OnSelectedValueChanged (EventArgs.Empty);
2614 // Need to separate selection logic from events,
2615 // since selection changes using keys/mouse handle them their own way
2616 internal bool AddCore (int index)
2618 if (selection.Contains (index))
2621 if (index == -1) // Weird MS behaviour
2623 if (index < -1 || index >= owner.Items.Count)
2624 throw new ArgumentOutOfRangeException ("index");
2625 if (owner.selection_mode == SelectionMode.None)
2626 throw new InvalidOperationException ("Cannot call this method when selection mode is SelectionMode.None");
2628 if (owner.selection_mode == SelectionMode.One && Count > 0) // Unselect previously selected item
2629 RemoveCore ((int)selection [0]);
2631 selection.Add (index);
2632 sorting_needed = true;
2633 owner.EnsureVisible (index);
2634 owner.FocusedItem = index;
2635 owner.InvalidateItem (index);
2647 if (selection.Count == 0)
2650 foreach (int index in selection)
2651 owner.InvalidateItem (index);
2654 owner.OnSelectedIndexChanged (EventArgs.Empty);
2655 owner.OnSelectedValueChanged (EventArgs.Empty);
2658 public bool Contains (int selectedIndex)
2660 foreach (int index in selection)
2661 if (index == selectedIndex)
2667 public void CopyTo (Array destination, int index)
2669 Array dest = destination;
2671 public void CopyTo (Array dest, int index)
2675 selection.CopyTo (dest, index);
2678 public IEnumerator GetEnumerator ()
2681 return selection.GetEnumerator ();
2684 // FIXME: Probably we can avoid sorting when calling
2685 // IndexOf (imagine a scenario where multiple removal of items
2692 void Remove (int index)
2694 // Separate logic from events here too
2695 if (RemoveCore (index)) {
2696 owner.OnSelectedIndexChanged (EventArgs.Empty);
2697 owner.OnSelectedValueChanged (EventArgs.Empty);
2701 internal bool RemoveCore (int index)
2703 int idx = IndexOf (index);
2707 selection.RemoveAt (idx);
2708 owner.InvalidateItem (index);
2713 int IList.Add (object value)
2715 throw new NotSupportedException ();
2720 throw new NotSupportedException ();
2723 bool IList.Contains (object selectedIndex)
2725 return Contains ((int)selectedIndex);
2728 int IList.IndexOf (object selectedIndex)
2730 return IndexOf ((int) selectedIndex);
2733 void IList.Insert (int index, object value)
2735 throw new NotSupportedException ();
2738 void IList.Remove (object value)
2740 throw new NotSupportedException ();
2743 void IList.RemoveAt (int index)
2745 throw new NotSupportedException ();
2748 object IList.this[int index]{
2749 get { return this [index]; }
2750 set {throw new NotImplementedException (); }
2753 public int IndexOf (int selectedIndex)
2757 for (int i = 0; i < selection.Count; i++)
2758 if ((int)selection [i] == selectedIndex)
2763 #endregion Public Methods
2764 internal ArrayList List {
2773 if (sorting_needed) {
2774 sorting_needed = false;
2780 public class SelectedObjectCollection : IList, ICollection, IEnumerable
2782 private ListBox owner;
2784 public SelectedObjectCollection (ListBox owner)
2789 #region Public Properties
2791 get { return owner.selected_indices.Count; }
2794 public bool IsReadOnly {
2795 get { return true; }
2799 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2800 public object this [int index] {
2802 if (index < 0 || index >= Count)
2803 throw new ArgumentOutOfRangeException ("Index of out range");
2805 return owner.items [owner.selected_indices [index]];
2807 set {throw new NotSupportedException ();}
2810 bool ICollection.IsSynchronized {
2811 get { return true; }
2814 object ICollection.SyncRoot {
2815 get { return this; }
2818 bool IList.IsFixedSize {
2819 get { return true; }
2822 #endregion Public Properties
2824 #region Public Methods
2826 public void Add (object value)
2828 if (owner.selection_mode == SelectionMode.None)
2829 throw new ArgumentException ("Cannot call this method if SelectionMode is SelectionMode.None");
2831 int idx = owner.items.IndexOf (value);
2835 owner.selected_indices.Add (idx);
2838 public void Clear ()
2840 owner.selected_indices.Clear ();
2844 public bool Contains (object selectedObject)
2846 int idx = owner.items.IndexOf (selectedObject);
2847 return idx == -1 ? false : owner.selected_indices.Contains (idx);
2851 public void CopyTo (Array destination, int index)
2853 Array dest = destination;
2855 public void CopyTo (Array dest, int index)
2858 for (int i = 0; i < Count; i++)
2859 dest.SetValue (this [i], index++);
2863 public void Remove (object value)
2868 int idx = owner.items.IndexOf (value);
2872 owner.selected_indices.Remove (idx);
2876 int IList.Add (object value)
2878 throw new NotSupportedException ();
2883 throw new NotSupportedException ();
2886 void IList.Insert (int index, object value)
2888 throw new NotSupportedException ();
2891 void IList.Remove (object value)
2893 throw new NotSupportedException ();
2896 void IList.RemoveAt (int index)
2898 throw new NotSupportedException ();
2901 public int IndexOf (object selectedObject)
2903 int idx = owner.items.IndexOf (selectedObject);
2904 return idx == -1 ? -1 : owner.selected_indices.IndexOf (idx);
2907 public IEnumerator GetEnumerator ()
2909 //FIXME: write an enumerator that uses selection.GetEnumerator
2910 // so that invalidation is write on selection changes
2911 object [] items = new object [Count];
2912 for (int i = 0; i < Count; i++) {
2913 items [i] = owner.items [owner.selected_indices [i]];
2916 return items.GetEnumerator ();
2919 #endregion Public Methods