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;
38 using System.Collections.Generic;
40 namespace System.Windows.Forms
42 [DefaultProperty("Items")]
43 [DefaultEvent("SelectedIndexChanged")]
44 [Designer ("System.Windows.Forms.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45 [DefaultBindingProperty ("SelectedValue")]
46 [ClassInterface (ClassInterfaceType.AutoDispatch)]
48 public class ListBox : ListControl
50 public const int DefaultItemHeight = 13;
51 public const int NoMatches = -1;
53 internal enum ItemNavigation
65 Hashtable item_heights;
66 private int item_height = -1;
67 private int column_width = 0;
68 private int requested_height;
69 private DrawMode draw_mode = DrawMode.Normal;
70 private int horizontal_extent = 0;
71 private bool horizontal_scrollbar = false;
72 private bool integral_height = true;
73 private bool multicolumn = false;
74 private bool scroll_always_visible = false;
75 private SelectedIndexCollection selected_indices;
76 private SelectedObjectCollection selected_items;
77 private SelectionMode selection_mode = SelectionMode.One;
78 private bool sorted = false;
79 private bool use_tabstops = true;
80 private int column_width_internal = 120;
81 private ImplicitVScrollBar vscrollbar;
82 private ImplicitHScrollBar hscrollbar;
83 private int hbar_offset;
84 private bool suspend_layout;
85 private bool ctrl_pressed = false;
86 private bool shift_pressed = false;
87 private bool explicit_item_height = false;
88 private int top_index = 0;
89 private int last_visible_index = 0;
90 private Rectangle items_area;
91 private int focused_item = -1;
92 private ObjectCollection items;
93 private IntegerCollection custom_tab_offsets;
94 private Padding padding;
95 private bool use_custom_tab_offsets;
99 items = CreateItemCollection ();
100 selected_indices = new SelectedIndexCollection (this);
101 selected_items = new SelectedObjectCollection (this);
103 requested_height = bounds.Height;
104 InternalBorderStyle = BorderStyle.Fixed3D;
105 BackColor = ThemeEngine.Current.ColorControl;
107 /* Vertical scrollbar */
108 vscrollbar = new ImplicitVScrollBar ();
109 vscrollbar.Minimum = 0;
110 vscrollbar.SmallChange = 1;
111 vscrollbar.LargeChange = 1;
112 vscrollbar.Maximum = 0;
113 vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent);
114 vscrollbar.Visible = false;
116 /* Horizontal scrollbar */
117 hscrollbar = new ImplicitHScrollBar ();
118 hscrollbar.Minimum = 0;
119 hscrollbar.SmallChange = 1;
120 hscrollbar.LargeChange = 1;
121 hscrollbar.Maximum = 0;
122 hscrollbar.Visible = false;
123 hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent);
125 Controls.AddImplicit (vscrollbar);
126 Controls.AddImplicit (hscrollbar);
129 MouseDown += new MouseEventHandler (OnMouseDownLB);
130 MouseMove += new MouseEventHandler (OnMouseMoveLB);
131 MouseUp += new MouseEventHandler (OnMouseUpLB);
132 MouseWheel += new MouseEventHandler (OnMouseWheelLB);
133 KeyUp += new KeyEventHandler (OnKeyUpLB);
134 GotFocus += new EventHandler (OnGotFocus);
135 LostFocus += new EventHandler (OnLostFocus);
137 SetStyle (ControlStyles.UserPaint, false);
139 custom_tab_offsets = new IntegerCollection (this);
143 static object DrawItemEvent = new object ();
144 static object MeasureItemEvent = new object ();
145 static object SelectedIndexChangedEvent = new object ();
148 [EditorBrowsable (EditorBrowsableState.Never)]
149 public new event EventHandler BackgroundImageChanged {
150 add { base.BackgroundImageChanged += value; }
151 remove { base.BackgroundImageChanged -= value; }
155 [EditorBrowsable (EditorBrowsableState.Never)]
156 public new event EventHandler BackgroundImageLayoutChanged {
157 add { base.BackgroundImageLayoutChanged += value; }
158 remove { base.BackgroundImageLayoutChanged -= value; }
162 [EditorBrowsable (EditorBrowsableState.Always)]
163 public new event EventHandler Click {
164 add { base.Click += value; }
165 remove { base.Click -= value; }
168 public event DrawItemEventHandler DrawItem {
169 add { Events.AddHandler (DrawItemEvent, value); }
170 remove { Events.RemoveHandler (DrawItemEvent, value); }
173 public event MeasureItemEventHandler MeasureItem {
174 add { Events.AddHandler (MeasureItemEvent, value); }
175 remove { Events.RemoveHandler (MeasureItemEvent, value); }
179 [EditorBrowsable (EditorBrowsableState.Always)]
180 public new event MouseEventHandler MouseClick {
181 add { base.MouseClick += value; }
182 remove { base.MouseClick -= value; }
186 [EditorBrowsable (EditorBrowsableState.Never)]
187 public new event EventHandler PaddingChanged {
188 add { base.PaddingChanged += value; }
189 remove { base.PaddingChanged -= value; }
193 [EditorBrowsable (EditorBrowsableState.Never)]
194 public new event PaintEventHandler Paint {
195 add { base.Paint += value; }
196 remove { base.Paint -= value; }
199 public event EventHandler SelectedIndexChanged {
200 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
201 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
205 [EditorBrowsable (EditorBrowsableState.Advanced)]
206 public new event EventHandler TextChanged {
207 add { base.TextChanged += value; }
208 remove { base.TextChanged -= value; }
212 #region UIA Framework Events
214 // We are using Reflection to add/remove internal events.
215 // Class ListProvider uses the events.
217 //Event used to generate UIA Selection Pattern
218 static object UIASelectionModeChangedEvent = new object ();
220 internal event EventHandler UIASelectionModeChanged {
221 add { Events.AddHandler (UIASelectionModeChangedEvent, value); }
222 remove { Events.RemoveHandler (UIASelectionModeChangedEvent, value); }
225 internal void OnUIASelectionModeChangedEvent ()
227 EventHandler eh = (EventHandler) Events [UIASelectionModeChangedEvent];
229 eh (this, EventArgs.Empty);
232 static object UIAFocusedItemChangedEvent = new object ();
234 internal event EventHandler UIAFocusedItemChanged {
235 add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
236 remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
239 internal void OnUIAFocusedItemChangedEvent ()
241 EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
243 eh (this, EventArgs.Empty);
245 #endregion UIA Framework Events
247 #region Public Properties
248 public override Color BackColor {
249 get { return base.BackColor; }
251 if (base.BackColor == value)
254 base.BackColor = value;
255 base.Refresh (); // Careful. Calling the base method is not the same that calling
256 } // the overriden one that refresh also all the items
260 [EditorBrowsable (EditorBrowsableState.Never)]
261 public override Image BackgroundImage {
262 get { return base.BackgroundImage; }
264 base.BackgroundImage = value;
270 [EditorBrowsable (EditorBrowsableState.Never)]
271 public override ImageLayout BackgroundImageLayout {
272 get { return base.BackgroundImageLayout; }
273 set { base.BackgroundImageLayout = value; }
276 [DefaultValue (BorderStyle.Fixed3D)]
278 public BorderStyle BorderStyle {
279 get { return InternalBorderStyle; }
281 InternalBorderStyle = value;
282 UpdateListBoxBounds ();
288 public int ColumnWidth {
289 get { return column_width; }
292 throw new ArgumentException ("A value less than zero is assigned to the property.");
294 column_width = value;
297 ColumnWidthInternal = 120;
299 ColumnWidthInternal = value;
305 protected override CreateParams CreateParams {
306 get { return base.CreateParams;}
310 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
311 public IntegerCollection CustomTabOffsets {
312 get { return custom_tab_offsets; }
315 protected override Size DefaultSize {
316 get { return new Size (120, 96); }
319 [RefreshProperties(RefreshProperties.Repaint)]
320 [DefaultValue (DrawMode.Normal)]
321 public virtual DrawMode DrawMode {
322 get { return draw_mode; }
324 if (!Enum.IsDefined (typeof (DrawMode), value))
325 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
327 if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
328 throw new ArgumentException ("Cannot have variable height and multicolumn");
330 if (draw_mode == value)
335 if (draw_mode == DrawMode.OwnerDrawVariable)
336 item_heights = new Hashtable ();
341 Parent.PerformLayout (this, "DrawMode");
346 public override Font Font {
347 get { return base.Font; }
348 set { base.Font = value; }
351 public override Color ForeColor {
352 get { return base.ForeColor; }
354 if (base.ForeColor == value)
357 base.ForeColor = value;
364 public int HorizontalExtent {
365 get { return horizontal_extent; }
367 if (horizontal_extent == value)
370 horizontal_extent = value;
375 [DefaultValue (false)]
377 public bool HorizontalScrollbar {
378 get { return horizontal_scrollbar; }
380 if (horizontal_scrollbar == value)
383 horizontal_scrollbar = value;
389 [DefaultValue (true)]
391 [RefreshProperties(RefreshProperties.Repaint)]
392 public bool IntegralHeight {
393 get { return integral_height; }
395 if (integral_height == value)
398 integral_height = value;
399 UpdateListBoxBounds ();
405 [RefreshProperties(RefreshProperties.Repaint)]
406 public virtual int ItemHeight {
408 if (item_height == -1) {
409 SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
410 item_height = (int) sz.Height;
416 throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
418 explicit_item_height = true;
419 if (item_height == value)
424 UpdateListBoxBounds ();
429 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
431 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
432 [MergableProperty (false)]
433 public ObjectCollection Items {
434 get { return items; }
437 [DefaultValue (false)]
438 public bool MultiColumn {
439 get { return multicolumn; }
441 if (multicolumn == value)
444 if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
445 throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
454 [EditorBrowsable (EditorBrowsableState.Never)]
455 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
456 public new Padding Padding {
457 get { return padding; }
458 set { padding = value; }
462 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
463 [EditorBrowsable (EditorBrowsableState.Advanced)]
464 public int PreferredHeight {
467 if (draw_mode == DrawMode.Normal)
468 itemsHeight = FontHeight * items.Count;
469 else if (draw_mode == DrawMode.OwnerDrawFixed)
470 itemsHeight = ItemHeight * items.Count;
471 else if (draw_mode == DrawMode.OwnerDrawVariable) {
472 for (int i = 0; i < items.Count; i++)
473 itemsHeight += (int) item_heights [Items [i]];
480 public override RightToLeft RightToLeft {
481 get { return base.RightToLeft; }
483 base.RightToLeft = value;
484 if (base.RightToLeft == RightToLeft.Yes)
485 StringFormat.Alignment = StringAlignment.Far;
487 StringFormat.Alignment = StringAlignment.Near;
492 // Only affects the Vertical ScrollBar
493 [DefaultValue (false)]
495 public bool ScrollAlwaysVisible {
496 get { return scroll_always_visible; }
498 if (scroll_always_visible == value)
501 scroll_always_visible = value;
508 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
509 public override int SelectedIndex {
511 if (selected_indices == null)
514 return selected_indices.Count > 0 ? selected_indices [0] : -1;
517 if (value < -1 || value >= Items.Count)
518 throw new ArgumentOutOfRangeException ("Index of out range");
520 if (SelectionMode == SelectionMode.None)
521 throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
524 selected_indices.Clear ();
526 selected_indices.Add (value);
531 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532 public SelectedIndexCollection SelectedIndices {
533 get { return selected_indices; }
538 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
539 public object SelectedItem {
541 if (SelectedItems.Count > 0)
542 return SelectedItems[0];
547 if (value != null && !Items.Contains (value))
548 return; // FIXME: this is probably an exception
550 SelectedIndex = value == null ? - 1 : Items.IndexOf (value);
555 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
556 public SelectedObjectCollection SelectedItems {
557 get {return selected_items;}
560 [DefaultValue (SelectionMode.One)]
561 public virtual SelectionMode SelectionMode {
562 get { return selection_mode; }
564 if (!Enum.IsDefined (typeof (SelectionMode), value))
565 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
567 if (selection_mode == value)
570 selection_mode = value;
572 switch (selection_mode) {
573 case SelectionMode.None:
574 SelectedIndices.Clear ();
577 case SelectionMode.One:
578 // FIXME: Probably this can be improved
579 ArrayList old_selection = (ArrayList) SelectedIndices.List.Clone ();
580 for (int i = 1; i < old_selection.Count; i++)
581 SelectedIndices.Remove ((int)old_selection [i]);
588 // UIA Framework: Generates SelectionModeChanged event.
589 OnUIASelectionModeChangedEvent ();
593 [DefaultValue (false)]
595 get { return sorted; }
608 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
609 [EditorBrowsable (EditorBrowsableState.Advanced)]
610 public override string Text {
612 if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
613 return GetItemText (SelectedItem);
621 if (SelectionMode == SelectionMode.None)
626 index = FindStringExact (value);
631 SelectedIndex = index;
636 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
637 public int TopIndex {
638 get { return top_index; }
640 if (value == top_index)
643 if (value < 0 || value >= Items.Count)
646 int page_size = (items_area.Height / ItemHeight);
648 if (Items.Count < page_size)
650 else if (!multicolumn)
651 top_index = Math.Min (value, Items.Count - page_size);
661 [DefaultValue (false)]
662 public bool UseCustomTabOffsets {
663 get { return use_custom_tab_offsets; }
665 if (use_custom_tab_offsets != value) {
666 use_custom_tab_offsets = value;
667 CalculateTabStops ();
672 [DefaultValue (true)]
673 public bool UseTabStops {
674 get { return use_tabstops; }
676 if (use_tabstops == value)
679 use_tabstops = value;
680 CalculateTabStops ();
684 protected override bool AllowSelection {
686 return SelectionMode != SelectionMode.None;
689 #endregion Public Properties
691 #region Private Properties
693 private int ColumnWidthInternal {
694 get { return column_width_internal; }
695 set { column_width_internal = value; }
698 private int row_count = 1;
699 private int RowCount {
701 return MultiColumn ? row_count : Items.Count;
705 #endregion Private Properties
707 #region UIA Framework Properties
709 internal ScrollBar UIAHScrollBar {
710 get { return hscrollbar; }
713 internal ScrollBar UIAVScrollBar {
714 get { return vscrollbar; }
717 #endregion UIA Framework Properties
719 #region Public Methods
720 [Obsolete ("this method has been deprecated")]
721 protected virtual void AddItemsCore (object[] value)
723 Items.AddRange (value);
726 public void BeginUpdate ()
728 suspend_layout = true;
731 public void ClearSelected ()
733 selected_indices.Clear ();
736 protected virtual ObjectCollection CreateItemCollection ()
738 return new ObjectCollection (this);
741 public void EndUpdate ()
743 suspend_layout = false;
748 public int FindString (String s)
750 return FindString (s, -1);
753 public int FindString (string s, int startIndex)
755 if (Items.Count == 0)
756 return -1; // No exception throwing if empty
758 if (startIndex < -1 || startIndex >= Items.Count)
759 throw new ArgumentOutOfRangeException ("Index of out range");
761 startIndex = (startIndex == Items.Count - 1) ? 0 : startIndex + 1;
765 string text = GetItemText (Items [i]);
766 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (text, s,
767 CompareOptions.IgnoreCase))
770 i = (i == Items.Count - 1) ? 0 : i + 1;
778 public int FindStringExact (string s)
780 return FindStringExact (s, -1);
783 public int FindStringExact (string s, int startIndex)
785 if (Items.Count == 0)
786 return -1; // No exception throwing if empty
788 if (startIndex < -1 || startIndex >= Items.Count)
789 throw new ArgumentOutOfRangeException ("Index of out range");
791 startIndex = (startIndex + 1 == Items.Count) ? 0 : startIndex + 1;
795 if (String.Compare (GetItemText (Items[i]), s, true) == 0)
798 i = (i + 1 == Items.Count) ? 0 : i + 1;
806 public int GetItemHeight (int index)
808 if (index < 0 || index >= Items.Count)
809 throw new ArgumentOutOfRangeException ("Index of out range");
811 if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
813 object o = Items [index];
814 if (item_heights.Contains (o))
815 return (int) item_heights [o];
817 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
818 OnMeasureItem (args);
819 item_heights [o] = args.ItemHeight;
820 return args.ItemHeight;
826 public Rectangle GetItemRectangle (int index)
828 if (index < 0 || index >= Items.Count)
829 throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
831 Rectangle rect = new Rectangle ();
834 int col = index / RowCount;
836 if (y < 0) // We convert it to valid positive value
837 y += RowCount * (top_index / RowCount);
838 rect.Y = (y % RowCount) * ItemHeight;
839 rect.X = (col - (top_index / RowCount)) * ColumnWidthInternal;
840 rect.Height = ItemHeight;
841 rect.Width = ColumnWidthInternal;
844 rect.Height = GetItemHeight (index);
845 rect.Width = items_area.Width;
847 if (DrawMode == DrawMode.OwnerDrawVariable) {
849 if (index >= top_index) {
850 for (int i = top_index; i < index; i++) {
851 rect.Y += GetItemHeight (i);
854 for (int i = index; i < top_index; i++) {
855 rect.Y -= GetItemHeight (i);
859 rect.Y = ItemHeight * (index - top_index);
863 if (this is CheckedListBox)
869 [EditorBrowsable (EditorBrowsableState.Advanced)]
870 protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
872 bounds.Height = requested_height;
874 return base.GetScaledBounds (bounds, factor, specified);
877 public bool GetSelected (int index)
879 if (index < 0 || index >= Items.Count)
880 throw new ArgumentOutOfRangeException ("Index of out range");
882 return SelectedIndices.Contains (index);
885 public int IndexFromPoint (Point p)
887 return IndexFromPoint (p.X, p.Y);
890 // Only returns visible points
891 public int IndexFromPoint (int x, int y)
894 if (Items.Count == 0) {
898 for (int i = top_index; i <= last_visible_index; i++) {
899 if (GetItemRectangle (i).Contains (x,y) == true)
906 protected override void OnChangeUICues (UICuesEventArgs e)
908 base.OnChangeUICues (e);
911 protected override void OnDataSourceChanged (EventArgs e)
913 base.OnDataSourceChanged (e);
916 if (DataSource == null || DataManager == null) {
919 SelectedIndex = DataManager.Position;
923 protected override void OnDisplayMemberChanged (EventArgs e)
925 base.OnDisplayMemberChanged (e);
927 if (DataManager == null || !IsHandleCreated)
934 protected virtual void OnDrawItem (DrawItemEventArgs e)
937 case DrawMode.OwnerDrawFixed:
938 case DrawMode.OwnerDrawVariable:
939 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
946 ThemeEngine.Current.DrawListBoxItem (this, e);
951 protected override void OnFontChanged (EventArgs e)
953 base.OnFontChanged (e);
956 StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
958 if (explicit_item_height) {
961 SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
962 item_height = (int) sz.Height;
964 UpdateListBoxBounds ();
969 protected override void OnHandleCreated (EventArgs e)
971 base.OnHandleCreated (e);
974 UpdateListBoxBounds ();
977 EnsureVisible (focused_item);
980 protected override void OnHandleDestroyed (EventArgs e)
982 base.OnHandleDestroyed (e);
985 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
987 if (draw_mode != DrawMode.OwnerDrawVariable)
990 MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
995 protected override void OnParentChanged (EventArgs e)
997 base.OnParentChanged (e);
1000 protected override void OnResize (EventArgs e)
1003 if (canvas_size.IsEmpty || MultiColumn)
1009 protected override void OnSelectedIndexChanged (EventArgs e)
1011 base.OnSelectedIndexChanged (e);
1013 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
1018 protected override void OnSelectedValueChanged (EventArgs e)
1020 base.OnSelectedValueChanged (e);
1023 public override void Refresh ()
1025 if (draw_mode == DrawMode.OwnerDrawVariable)
1026 item_heights.Clear ();
1031 protected override void RefreshItem (int index)
1033 if (index < 0 || index >= Items.Count)
1034 throw new ArgumentOutOfRangeException ("Index of out range");
1036 if (draw_mode == DrawMode.OwnerDrawVariable)
1037 item_heights.Remove (Items [index]);
1040 protected override void RefreshItems ()
1042 for (int i = 0; i < Items.Count; i++) {
1050 public override void ResetBackColor ()
1052 base.ResetBackColor ();
1055 public override void ResetForeColor ()
1057 base.ResetForeColor ();
1060 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
1062 base.ScaleControl (factor, specified);
1065 private int SnapHeightToIntegral (int height)
1069 switch (border_style) {
1070 case BorderStyle.Fixed3D:
1071 border = ThemeEngine.Current.Border3DSize.Height;
1073 case BorderStyle.FixedSingle:
1074 border = ThemeEngine.Current.BorderSize.Height;
1076 case BorderStyle.None:
1082 height -= (2 * border);
1083 height -= height % ItemHeight;
1084 height += (2 * border);
1089 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1091 if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
1092 requested_height = height;
1094 if (IntegralHeight && IsHandleCreated)
1095 height = SnapHeightToIntegral (height);
1097 base.SetBoundsCore (x, y, width, height, specified);
1098 UpdateScrollBars ();
1099 last_visible_index = LastVisibleItem ();
1102 protected override void SetItemCore (int index, object value)
1104 if (index < 0 || index >= Items.Count)
1107 Items[index] = value;
1110 protected override void SetItemsCore (IList value)
1115 Items.AddItems (value);
1121 public void SetSelected (int index, bool value)
1123 if (index < 0 || index >= Items.Count)
1124 throw new ArgumentOutOfRangeException ("Index of out range");
1126 if (SelectionMode == SelectionMode.None)
1127 throw new InvalidOperationException ();
1130 SelectedIndices.Add (index);
1132 SelectedIndices.Remove (index);
1135 protected virtual void Sort ()
1141 // Sometimes we could need to Sort, and request a Refresh
1142 // in a different place, to not have the painting done twice
1144 void Sort (bool paint)
1146 if (Items.Count == 0)
1155 public override string ToString ()
1157 return base.ToString ();
1160 protected virtual void WmReflectCommand (ref Message m)
1164 protected override void WndProc (ref Message m)
1166 if ((Msg)m.Msg == Msg.WM_KEYDOWN) {
1167 if (ProcessKeyMessage (ref m))
1168 m.Result = IntPtr.Zero;
1170 HandleKeyDown ((Keys)m.WParam.ToInt32 ());
1177 base.WndProc (ref m);
1180 #endregion Public Methods
1182 #region Private Methods
1184 private void CalculateTabStops ()
1187 if (use_custom_tab_offsets) {
1188 float[] f = new float[custom_tab_offsets.Count];
1189 custom_tab_offsets.CopyTo (f, 0);
1190 StringFormat.SetTabStops (0, f);
1193 StringFormat.SetTabStops (0, new float[] { (float)(Font.Height * 3.7) });
1195 StringFormat.SetTabStops (0, new float[0]);
1200 private Size canvas_size;
1202 private void LayoutListBox ()
1204 if (!IsHandleCreated || suspend_layout)
1208 LayoutMultiColumn ();
1210 LayoutSingleColumn ();
1212 last_visible_index = LastVisibleItem ();
1213 UpdateScrollBars ();
1216 private void LayoutSingleColumn ()
1221 case DrawMode.OwnerDrawVariable:
1223 width = HorizontalExtent;
1224 for (int i = 0; i < Items.Count; i++) {
1225 height += GetItemHeight (i);
1229 case DrawMode.OwnerDrawFixed:
1230 height = Items.Count * ItemHeight;
1231 width = HorizontalExtent;
1234 case DrawMode.Normal:
1236 height = Items.Count * ItemHeight;
1238 for (int i = 0; i < Items.Count; i++) {
1239 SizeF sz = TextRenderer.MeasureString (GetItemText (Items[i]), Font);
1240 int t = (int)sz.Width;
1242 if (this is CheckedListBox)
1251 canvas_size = new Size (width, height);
1254 private void LayoutMultiColumn ()
1256 int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0);
1257 row_count = Math.Max (1, usable_height / ItemHeight);
1259 int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1260 Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1261 if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) {
1262 usable_height = ClientRectangle.Height - hscrollbar.Height;
1263 row_count = Math.Max (1, usable_height / ItemHeight);
1264 cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1265 sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1270 internal void Draw (Rectangle clip, Graphics dc)
1272 Theme theme = ThemeEngine.Current;
1274 if (hscrollbar.Visible && vscrollbar.Visible) {
1275 // Paint the dead space in the bottom right corner
1276 Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height);
1277 if (rect.IntersectsWith (clip))
1278 dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect);
1281 dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area);
1283 if (Items.Count == 0)
1286 for (int i = top_index; i <= last_visible_index; i++) {
1287 Rectangle rect = GetItemDisplayRectangle (i, top_index);
1289 if (!clip.IntersectsWith (rect))
1292 DrawItemState state = DrawItemState.None;
1294 if (SelectedIndices.Contains (i))
1295 state |= DrawItemState.Selected;
1297 if (has_focus && FocusedItem == i)
1298 state |= DrawItemState.Focus;
1300 if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) {
1301 rect.X -= hscrollbar.Value;
1302 rect.Width += hscrollbar.Value;
1305 Color fore_color = !Enabled ? ThemeEngine.Current.ColorGrayText :
1306 (state & DrawItemState.Selected) != 0 ? ThemeEngine.Current.ColorHighlightText : ForeColor;
1307 OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, fore_color, BackColor));
1311 // Converts a GetItemRectangle to a one that we can display
1312 internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
1314 Rectangle item_rect;
1315 Rectangle first_item_rect = GetItemRectangle (first_displayble);
1316 item_rect = GetItemRectangle (index);
1317 item_rect.X -= first_item_rect.X;
1318 item_rect.Y -= first_item_rect.Y;
1320 // Subtract the checkboxes from the width
1321 if (this is CheckedListBox)
1322 item_rect.Width -= 14;
1328 private void HorizontalScrollEvent (object sender, EventArgs e)
1331 int top_item = top_index;
1332 int last_item = last_visible_index;
1334 top_index = RowCount * hscrollbar.Value;
1335 last_visible_index = LastVisibleItem ();
1337 if (top_item != top_index || last_item != last_visible_index)
1338 Invalidate (items_area);
1341 int old_offset = hbar_offset;
1342 hbar_offset = hscrollbar.Value;
1344 if (hbar_offset < 0)
1347 if (IsHandleCreated) {
1348 XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false);
1350 // Invalidate the previous selection border, to keep it properly updated.
1351 Rectangle selection_border_area = new Rectangle (items_area.Width - (hbar_offset - old_offset) - 3, 0,
1352 3, items_area.Height);
1353 Invalidate (selection_border_area);
1358 // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
1359 // has screen coordinates
1360 private int IndexAtClientPoint (int x, int y)
1362 if (Items.Count == 0)
1367 else if (x > ClientRectangle.Right)
1368 x = ClientRectangle.Right;
1372 else if (y > ClientRectangle.Bottom)
1373 y = ClientRectangle.Bottom;
1375 for (int i = top_index; i <= last_visible_index; i++)
1376 if (GetItemDisplayRectangle (i, top_index).Contains (x, y))
1382 internal override bool IsInputCharInternal (char charCode)
1387 private int LastVisibleItem ()
1389 Rectangle item_rect;
1390 int top_y = items_area.Y + items_area.Height;
1393 if (top_index >= Items.Count)
1396 for (i = top_index; i < Items.Count; i++) {
1397 item_rect = GetItemDisplayRectangle (i, top_index);
1399 if (item_rect.X > items_area.Width)
1402 if (item_rect.Y + item_rect.Height > top_y)
1409 private void UpdateTopItem ()
1412 int col = top_index / RowCount;
1414 if (col > hscrollbar.Maximum)
1415 hscrollbar.Value = hscrollbar.Maximum;
1417 hscrollbar.Value = col;
1419 if (top_index > vscrollbar.Maximum)
1420 vscrollbar.Value = vscrollbar.Maximum;
1422 vscrollbar.Value = top_index;
1423 Scroll (vscrollbar, vscrollbar.Value - top_index);
1427 // Navigates to the indicated item and returns the new item
1428 private int NavigateItemVisually (ItemNavigation navigation)
1430 int page_size, columns, selected_index = -1;
1433 columns = items_area.Width / ColumnWidthInternal;
1434 page_size = columns * RowCount;
1435 if (page_size == 0) {
1436 page_size = RowCount;
1439 page_size = items_area.Height / ItemHeight;
1442 switch (navigation) {
1444 case ItemNavigation.PreviousColumn: {
1445 if (SelectedIndex - RowCount < 0) {
1449 if (SelectedIndex - RowCount < top_index) {
1450 top_index = SelectedIndex - RowCount;
1454 selected_index = SelectedIndex - RowCount;
1458 case ItemNavigation.NextColumn: {
1459 if (SelectedIndex + RowCount >= Items.Count) {
1463 if (SelectedIndex + RowCount > last_visible_index) {
1464 top_index = SelectedIndex;
1468 selected_index = SelectedIndex + RowCount;
1472 case ItemNavigation.First: {
1479 case ItemNavigation.Last: {
1481 int rows = items_area.Height / ItemHeight;
1484 selected_index = Items.Count - 1;
1487 if (Items.Count < rows) {
1489 selected_index = Items.Count - 1;
1492 top_index = Items.Count - rows;
1493 selected_index = Items.Count - 1;
1499 case ItemNavigation.Next: {
1500 if (FocusedItem == Items.Count - 1)
1504 selected_index = FocusedItem + 1;
1509 ArrayList heights = new ArrayList ();
1510 if (draw_mode == DrawMode.OwnerDrawVariable) {
1511 for (int i = top_index; i <= FocusedItem + 1; i++) {
1512 int h = GetItemHeight (i);
1517 bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight;
1520 if (bottom >= items_area.Height) {
1521 int overhang = bottom - items_area.Height;
1524 if (draw_mode == DrawMode.OwnerDrawVariable)
1525 while (overhang > 0)
1526 overhang -= (int) heights [offset];
1528 offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight);
1529 top_index += offset;
1532 selected_index = FocusedItem + 1;
1536 case ItemNavigation.Previous: {
1537 if (FocusedItem > 0) {
1538 if (FocusedItem - 1 < top_index) {
1542 selected_index = FocusedItem - 1;
1547 case ItemNavigation.NextPage: {
1548 if (Items.Count < page_size) {
1549 NavigateItemVisually (ItemNavigation.Last);
1553 if (FocusedItem + page_size - 1 >= Items.Count) {
1554 top_index = Items.Count - page_size;
1556 selected_index = Items.Count - 1;
1559 if (FocusedItem + page_size - 1 > last_visible_index) {
1560 top_index = FocusedItem;
1564 selected_index = FocusedItem + page_size - 1;
1570 case ItemNavigation.PreviousPage: {
1572 int rows = items_area.Height / ItemHeight;
1573 if (FocusedItem - (rows - 1) <= 0) {
1579 if (SelectedIndex - (rows - 1) < top_index) {
1580 top_index = FocusedItem - (rows - 1);
1584 selected_index = FocusedItem - (rows - 1);
1593 return selected_index;
1597 private void OnGotFocus (object sender, EventArgs e)
1599 if (Items.Count == 0)
1602 if (FocusedItem == -1)
1605 InvalidateItem (FocusedItem);
1608 private void OnLostFocus (object sender, EventArgs e)
1610 if (FocusedItem != -1)
1611 InvalidateItem (FocusedItem);
1614 private bool KeySearch (Keys key)
1616 char c = (char) key;
1617 if (!Char.IsLetterOrDigit (c))
1620 int idx = FindString (c.ToString (), SelectedIndex);
1621 if (idx != ListBox.NoMatches)
1622 SelectedIndex = idx;
1627 internal void HandleKeyDown (Keys key)
1631 if (Items.Count == 0)
1634 if (KeySearch (key))
1639 case Keys.ControlKey:
1640 ctrl_pressed = true;
1644 shift_pressed = true;
1648 new_item = NavigateItemVisually (ItemNavigation.First);
1652 new_item = NavigateItemVisually (ItemNavigation.Last);
1656 new_item = NavigateItemVisually (ItemNavigation.Previous);
1660 new_item = NavigateItemVisually (ItemNavigation.Next);
1664 new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
1668 new_item = NavigateItemVisually (ItemNavigation.NextPage);
1672 if (multicolumn == true) {
1673 new_item = NavigateItemVisually (ItemNavigation.NextColumn);
1678 if (multicolumn == true) {
1679 new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
1684 if (selection_mode == SelectionMode.MultiSimple) {
1685 SelectedItemFromNavigation (FocusedItem);
1694 if (new_item != -1) {
1695 FocusedItem = new_item;
1697 if (selection_mode != SelectionMode.MultiSimple)
1698 SelectedItemFromNavigation (new_item);
1702 private void OnKeyUpLB (object sender, KeyEventArgs e)
1704 switch (e.KeyCode) {
1705 case Keys.ControlKey:
1706 ctrl_pressed = false;
1709 shift_pressed = false;
1716 internal void InvalidateItem (int index)
1718 if (!IsHandleCreated)
1720 Rectangle bounds = GetItemDisplayRectangle (index, top_index);
1721 if (ClientRectangle.IntersectsWith (bounds))
1722 Invalidate (bounds);
1725 internal virtual void OnItemClick (int index)
1727 OnSelectedIndexChanged (EventArgs.Empty);
1728 OnSelectedValueChanged (EventArgs.Empty);
1732 int[] prev_selection;
1733 bool button_pressed = false;
1734 Point button_pressed_loc = new Point (-1, -1);
1736 private void SelectExtended (int index)
1740 ArrayList new_selection = new ArrayList ();
1741 int start = anchor < index ? anchor : index;
1742 int end = anchor > index ? anchor : index;
1743 for (int i = start; i <= end; i++)
1744 new_selection.Add (i);
1747 foreach (int i in prev_selection)
1748 if (!new_selection.Contains (i))
1749 new_selection.Add (i);
1751 // Need to make a copy since we can't enumerate and modify the collection
1753 ArrayList sel_indices = (ArrayList) selected_indices.List.Clone ();
1754 foreach (int i in sel_indices)
1755 if (!new_selection.Contains (i))
1756 selected_indices.Remove (i);
1758 foreach (int i in new_selection)
1759 if (!sel_indices.Contains (i))
1760 selected_indices.AddCore (i);
1764 private void OnMouseDownLB (object sender, MouseEventArgs e)
1766 // Only do stuff with the left mouse button
1767 if ((e.Button & MouseButtons.Left) == 0)
1770 int index = IndexAtClientPoint (e.X, e.Y);
1774 switch (SelectionMode) {
1775 case SelectionMode.One:
1776 SelectedIndices.AddCore (index); // Unselects previous one
1779 case SelectionMode.MultiSimple:
1780 if (SelectedIndices.Contains (index))
1781 SelectedIndices.RemoveCore (index);
1783 SelectedIndices.AddCore (index);
1786 case SelectionMode.MultiExtended:
1787 shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1788 ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1790 if (shift_pressed) {
1791 SelectedIndices.ClearCore ();
1792 SelectExtended (index);
1799 prev_selection = new int [SelectedIndices.Count];
1800 SelectedIndices.CopyTo (prev_selection, 0);
1802 if (SelectedIndices.Contains (index))
1803 SelectedIndices.RemoveCore (index);
1805 SelectedIndices.AddCore (index);
1810 SelectedIndices.ClearCore ();
1811 SelectedIndices.AddCore (index);
1814 case SelectionMode.None:
1820 button_pressed = true;
1821 button_pressed_loc = new Point (e.X, e.Y);
1822 FocusedItem = index;
1825 private void OnMouseMoveLB (object sender, MouseEventArgs e)
1827 // Don't take into account MouseMove events generated with MouseDown
1828 if (!button_pressed || button_pressed_loc == new Point (e.X, e.Y))
1831 int index = IndexAtClientPoint (e.X, e.Y);
1835 switch (SelectionMode) {
1836 case SelectionMode.One:
1837 SelectedIndices.AddCore (index); // Unselects previous one
1840 case SelectionMode.MultiSimple:
1843 case SelectionMode.MultiExtended:
1844 SelectExtended (index);
1847 case SelectionMode.None:
1853 FocusedItem = index;
1856 internal override void OnDragDropEnd (DragDropEffects effects)
1858 // In the case of a DnD operation (started on MouseDown)
1859 // there will be no MouseUp event, so we need to reset
1861 button_pressed = false;
1864 private void OnMouseUpLB (object sender, MouseEventArgs e)
1866 // Only do stuff with the left mouse button
1867 if ((e.Button & MouseButtons.Left) == 0)
1871 OnDoubleClick (EventArgs.Empty);
1872 OnMouseDoubleClick (e);
1874 else if (e.Clicks == 1) {
1875 OnClick (EventArgs.Empty);
1879 if (!button_pressed)
1882 int index = IndexAtClientPoint (e.X, e.Y);
1883 OnItemClick (index);
1884 button_pressed = ctrl_pressed = shift_pressed = false;
1887 private void Scroll (ScrollBar scrollbar, int delta)
1889 if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled)
1893 if (scrollbar == hscrollbar)
1894 max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1;
1896 max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1;
1898 int val = scrollbar.Value + delta;
1901 else if (val < scrollbar.Minimum)
1902 val = scrollbar.Minimum;
1903 scrollbar.Value = val;
1906 private void OnMouseWheelLB (object sender, MouseEventArgs me)
1908 if (Items.Count == 0)
1911 int lines = me.Delta / 120;
1914 Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines);
1916 Scroll (vscrollbar, -lines);
1919 internal override void OnPaintInternal (PaintEventArgs pevent)
1924 Draw (pevent.ClipRectangle, pevent.Graphics);
1927 internal void RepositionScrollBars ()
1929 if (vscrollbar.is_visible) {
1930 vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height);
1931 vscrollbar.Location = new Point (items_area.Width, 0);
1934 if (hscrollbar.is_visible) {
1935 hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height);
1936 hscrollbar.Location = new Point (0, items_area.Height);
1940 // An item navigation operation (mouse or keyboard) has caused to select a new item
1941 internal void SelectedItemFromNavigation (int index)
1943 switch (SelectionMode) {
1944 case SelectionMode.None:
1945 // .Net doesn't select the item, only ensures that it's visible
1946 // and fires the selection related events
1947 EnsureVisible (index);
1948 OnSelectedIndexChanged (EventArgs.Empty);
1949 OnSelectedValueChanged (EventArgs.Empty);
1951 case SelectionMode.One: {
1952 SelectedIndex = index;
1955 case SelectionMode.MultiSimple: {
1956 if (SelectedIndex == -1) {
1957 SelectedIndex = index;
1960 if (SelectedIndices.Contains (index))
1961 SelectedIndices.Remove (index);
1963 SelectedIndices.AddCore (index);
1965 OnSelectedIndexChanged (EventArgs.Empty);
1966 OnSelectedValueChanged (EventArgs.Empty);
1972 case SelectionMode.MultiExtended: {
1973 if (SelectedIndex == -1) {
1974 SelectedIndex = index;
1977 if (ctrl_pressed == false && shift_pressed == false) {
1978 SelectedIndices.Clear ();
1981 if (shift_pressed == true) {
1982 ShiftSelection (index);
1983 } else { // ctrl_pressed or single item
1984 SelectedIndices.AddCore (index);
1988 OnSelectedIndexChanged (EventArgs.Empty);
1989 OnSelectedValueChanged (EventArgs.Empty);
1999 private void ShiftSelection (int index)
2001 int shorter_item = -1, dist = Items.Count + 1, cur_dist;
2003 foreach (int idx in selected_indices) {
2005 cur_dist = idx - index;
2007 cur_dist = index - idx;
2010 if (cur_dist < dist) {
2016 if (shorter_item != -1) {
2019 if (shorter_item > index) {
2023 start = shorter_item;
2027 selected_indices.Clear ();
2028 for (int idx = start; idx <= end; idx++) {
2029 selected_indices.AddCore (idx);
2034 internal int FocusedItem {
2035 get { return focused_item; }
2037 if (focused_item == value)
2040 int prev = focused_item;
2042 focused_item = value;
2044 if (has_focus == false)
2048 InvalidateItem (prev);
2051 InvalidateItem (value);
2053 // UIA Framework: Generates FocusedItemChanged event.
2054 OnUIAFocusedItemChangedEvent ();
2058 StringFormat string_format;
2059 internal StringFormat StringFormat {
2061 if (string_format == null) {
2062 string_format = new StringFormat ();
2063 string_format.FormatFlags = StringFormatFlags.NoWrap;
2065 if (RightToLeft == RightToLeft.Yes)
2066 string_format.Alignment = StringAlignment.Far;
2068 string_format.Alignment = StringAlignment.Near;
2069 CalculateTabStops ();
2071 return string_format;
2075 internal virtual void CollectionChanged ()
2080 if (Items.Count == 0) {
2081 selected_indices.List.Clear ();
2085 if (Items.Count <= focused_item)
2086 focused_item = Items.Count - 1;
2088 if (!IsHandleCreated || suspend_layout)
2096 void EnsureVisible (int index)
2098 if (!IsHandleCreated || index == -1)
2101 if (index < top_index) {
2105 } else if (!multicolumn) {
2106 int rows = items_area.Height / ItemHeight;
2107 if (index >= (top_index + rows))
2108 top_index = index - rows + 1;
2112 int rows = Math.Max (1, items_area.Height / ItemHeight);
2113 int cols = Math.Max (1, items_area.Width / ColumnWidthInternal);
2115 if (index >= (top_index + (rows * cols))) {
2116 int incolumn = index / rows;
2117 top_index = (incolumn - (cols - 1)) * rows;
2125 private void UpdateListBoxBounds ()
2127 if (IsHandleCreated)
2128 SetBoundsInternal (bounds.X, bounds.Y, bounds.Width, IntegralHeight ? SnapHeightToIntegral (requested_height) : requested_height, BoundsSpecified.None);
2131 private void UpdateScrollBars ()
2133 items_area = ClientRectangle;
2134 if (UpdateHorizontalScrollBar ()) {
2135 items_area.Height -= hscrollbar.Height;
2136 if (UpdateVerticalScrollBar ()) {
2137 items_area.Width -= vscrollbar.Width;
2138 UpdateHorizontalScrollBar ();
2140 } else if (UpdateVerticalScrollBar ()) {
2141 items_area.Width -= vscrollbar.Width;
2142 if (UpdateHorizontalScrollBar ()) {
2143 items_area.Height -= hscrollbar.Height;
2144 UpdateVerticalScrollBar ();
2148 RepositionScrollBars ();
2151 /* Determines if the horizontal scrollbar has to be displyed */
2152 private bool UpdateHorizontalScrollBar ()
2155 bool enabled = true;
2158 if (canvas_size.Width > items_area.Width) {
2160 hscrollbar.Maximum = canvas_size.Width / ColumnWidthInternal - 1;
2161 } else if (ScrollAlwaysVisible == true) {
2164 hscrollbar.Maximum = 0;
2166 } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) {
2168 hscrollbar.Maximum = canvas_size.Width;
2169 hscrollbar.LargeChange = Math.Max (0, items_area.Width);
2170 } else if (scroll_always_visible && horizontal_scrollbar) {
2173 hscrollbar.Maximum = 0;
2176 hbar_offset = hscrollbar.Value;
2177 hscrollbar.Enabled = enabled;
2178 hscrollbar.Visible = show;
2183 /* Determines if the vertical scrollbar has to be displyed */
2184 private bool UpdateVerticalScrollBar ()
2186 if (MultiColumn || (Items.Count == 0 && !scroll_always_visible)) {
2187 vscrollbar.Visible = false;
2189 } else if (Items.Count == 0) {
2190 vscrollbar.Visible = true;
2191 vscrollbar.Enabled = false;
2192 vscrollbar.Maximum = 0;
2197 bool enabled = true;
2198 if (canvas_size.Height > items_area.Height) {
2200 vscrollbar.Maximum = Items.Count - 1;
2201 vscrollbar.LargeChange = Math.Max (items_area.Height / ItemHeight, 0);
2202 } else if (ScrollAlwaysVisible) {
2205 vscrollbar.Maximum = 0;
2208 vscrollbar.Enabled = enabled;
2209 vscrollbar.Visible = show;
2215 private void VerticalScrollEvent (object sender, EventArgs e)
2217 int top_item = top_index;
2219 top_index = /*row_count + */ vscrollbar.Value;
2220 last_visible_index = LastVisibleItem ();
2222 int delta = (top_item - top_index) * ItemHeight;
2223 if (DrawMode == DrawMode.OwnerDrawVariable) {
2226 if (top_index < top_item)
2227 for (int i = top_index; i < top_item; i++)
2228 delta += GetItemHeight (i);
2230 for (int i = top_item; i < top_index; i++)
2231 delta -= GetItemHeight (i);
2234 if (IsHandleCreated)
2235 XplatUI.ScrollWindow (Handle, items_area, 0, delta, false);
2238 #endregion Private Methods
2240 public class IntegerCollection : IList, ICollection, IEnumerable
2242 private ListBox owner;
2243 private List<int> list;
2245 #region Public Constructor
2246 public IntegerCollection (ListBox owner)
2249 list = new List<int> ();
2253 #region Public Properties
2256 get { return list.Count; }
2259 public int this [int index] {
2260 get { return list[index]; }
2261 set { list[index] = value; owner.CalculateTabStops (); }
2265 #region Public Methods
2266 public int Add (int item)
2268 // This collection does not allow duplicates
2269 if (!list.Contains (item)) {
2272 owner.CalculateTabStops ();
2275 return list.IndexOf (item);
2278 public void AddRange (int[] items)
2283 public void AddRange (IntegerCollection value)
2288 void AddItems (IList items)
2291 throw new ArgumentNullException ("items");
2293 foreach (int i in items)
2294 if (!list.Contains (i))
2300 public void Clear ()
2303 owner.CalculateTabStops ();
2306 public bool Contains (int item)
2308 return list.Contains (item);
2311 public void CopyTo (Array destination, int index)
2313 for (int i = 0; i < list.Count; i++)
2314 destination.SetValue (list[i], index++);
2317 public int IndexOf (int item)
2319 return list.IndexOf (item);
2322 public void Remove (int item)
2326 owner.CalculateTabStops ();
2329 public void RemoveAt (int index)
2332 throw new IndexOutOfRangeException ();
2334 list.RemoveAt (index);
2336 owner.CalculateTabStops ();
2340 #region IEnumerable Members
2341 IEnumerator IEnumerable.GetEnumerator ()
2343 return list.GetEnumerator ();
2347 #region IList Members
2348 int IList.Add (object item)
2350 int? intValue = item as int?;
2351 if (!intValue.HasValue)
2352 throw new ArgumentException ("item");
2353 return Add (intValue.Value);
2361 bool IList.Contains (object item)
2363 int? intValue = item as int?;
2364 if (!intValue.HasValue)
2366 return Contains (intValue.Value);
2369 int IList.IndexOf (object item)
2371 int? intValue = item as int?;
2372 if (!intValue.HasValue)
2374 return IndexOf (intValue.Value);
2377 void IList.Insert (int index, object value)
2379 throw new NotSupportedException (string.Format (
2380 CultureInfo.InvariantCulture, "No items "
2381 + "can be inserted into {0}, since it is"
2382 + " a sorted collection.", this.GetType ()));
2385 bool IList.IsFixedSize
2387 get { return false; }
2390 bool IList.IsReadOnly
2392 get { return false; }
2395 void IList.Remove (object value)
2397 int? intValue = value as int?;
2398 if (!intValue.HasValue)
2399 throw new ArgumentException ("value");
2401 Remove (intValue.Value);
2404 void IList.RemoveAt (int index)
2409 object IList.this[int index] {
2410 get { return this[index]; }
2411 set { this[index] = (int)value; }
2415 #region ICollection Members
2416 bool ICollection.IsSynchronized {
2417 get { return true; }
2420 object ICollection.SyncRoot {
2421 get { return this; }
2426 [ListBindable (false)]
2427 public class ObjectCollection : IList, ICollection, IEnumerable
2429 internal class ListObjectComparer : IComparer
2431 public int Compare (object a, object b)
2433 string str1 = a.ToString ();
2434 string str2 = b.ToString ();
2435 return str1.CompareTo (str2);
2439 private ListBox owner;
2440 internal ArrayList object_items = new ArrayList ();
2442 #region UIA Framework Events
2444 // We are using Reflection to add/remove internal events.
2445 // Class ListProvider uses the events.
2447 //Event used to generate UIA StructureChangedEvent
2448 static object UIACollectionChangedEvent = new object ();
2450 internal event CollectionChangeEventHandler UIACollectionChanged {
2451 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
2452 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
2455 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
2457 CollectionChangeEventHandler eh
2458 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
2462 #endregion UIA Framework Events
2464 public ObjectCollection (ListBox owner)
2469 public ObjectCollection (ListBox owner, object[] value)
2475 public ObjectCollection (ListBox owner, ObjectCollection value)
2481 #region Public Properties
2483 get { return object_items.Count; }
2486 public bool IsReadOnly {
2487 get { return false; }
2491 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2492 public virtual object this [int index] {
2494 if (index < 0 || index >= Count)
2495 throw new ArgumentOutOfRangeException ("Index of out range");
2497 return object_items[index];
2500 if (index < 0 || index >= Count)
2501 throw new ArgumentOutOfRangeException ("Index of out range");
2503 throw new ArgumentNullException ("value");
2505 //UIA Framework event: Item Removed
2506 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, object_items [index]));
2508 object_items[index] = value;
2510 //UIA Framework event: Item Added
2511 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
2513 owner.CollectionChanged ();
2517 bool ICollection.IsSynchronized {
2518 get { return false; }
2521 object ICollection.SyncRoot {
2522 get { return this; }
2525 bool IList.IsFixedSize {
2526 get { return false; }
2529 #endregion Public Properties
2531 #region Public Methods
2532 public int Add (object item)
2535 object[] selectedItems = null;
2537 // we need to remember the original selected items so that we can update the indices
2539 selectedItems = new object[owner.SelectedItems.Count];
2540 owner.SelectedItems.CopyTo (selectedItems, 0);
2543 idx = AddItem (item);
2544 owner.CollectionChanged ();
2546 // If we are sorted, the item probably moved indexes, get the real one
2548 // update indices of selected items
2549 owner.SelectedIndices.Clear ();
2550 for (int i = 0; i < selectedItems.Length; i++) {
2551 owner.SelectedIndex = this.IndexOf (selectedItems [i]);
2553 return this.IndexOf (item);
2559 public void AddRange (object[] items)
2564 public void AddRange (ObjectCollection value)
2569 internal void AddItems (IList items)
2572 throw new ArgumentNullException ("items");
2574 foreach (object mi in items)
2577 owner.CollectionChanged ();
2580 public virtual void Clear ()
2582 owner.selected_indices.ClearCore ();
2583 object_items.Clear ();
2584 owner.CollectionChanged ();
2586 //UIA Framework event: Items list cleared
2587 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
2590 public bool Contains (object value)
2593 throw new ArgumentNullException ("value");
2595 return object_items.Contains (value);
2598 public void CopyTo (object[] destination, int arrayIndex)
2600 object_items.CopyTo (destination, arrayIndex);
2603 void ICollection.CopyTo (Array destination, int index)
2605 object_items.CopyTo (destination, index);
2608 public IEnumerator GetEnumerator ()
2610 return object_items.GetEnumerator ();
2613 int IList.Add (object item)
2618 public int IndexOf (object value)
2621 throw new ArgumentNullException ("value");
2623 return object_items.IndexOf (value);
2626 public void Insert (int index, object item)
2628 if (index < 0 || index > Count)
2629 throw new ArgumentOutOfRangeException ("Index of out range");
2631 throw new ArgumentNullException ("item");
2633 owner.BeginUpdate ();
2634 object_items.Insert (index, item);
2635 owner.CollectionChanged ();
2638 //UIA Framework event: Item Added
2639 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
2642 public void Remove (object value)
2647 int index = IndexOf (value);
2652 public void RemoveAt (int index)
2654 if (index < 0 || index >= Count)
2655 throw new ArgumentOutOfRangeException ("Index of out range");
2657 //UIA Framework element removed
2658 object removed = object_items [index];
2659 UpdateSelection (index);
2660 object_items.RemoveAt (index);
2661 owner.CollectionChanged ();
2663 //UIA Framework event: Item Removed
2664 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed));
2666 #endregion Public Methods
2668 #region Private Methods
2669 internal int AddItem (object item)
2672 throw new ArgumentNullException ("item");
2674 int cnt = object_items.Count;
2675 object_items.Add (item);
2677 //UIA Framework event: Item Added
2678 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
2683 // we receive the index to be removed
2684 void UpdateSelection (int removed_index)
2686 owner.selected_indices.Remove (removed_index);
2688 if (owner.selection_mode != SelectionMode.None) {
2689 int last_idx = object_items.Count - 1;
2691 // if the last item was selected, remove it from selection,
2692 // since it will become invalid after the removal
2693 if (owner.selected_indices.Contains (last_idx)) {
2694 owner.selected_indices.Remove (last_idx);
2696 // in SelectionMode.One try to put the selection on the new last item
2697 int new_idx = last_idx - 1;
2698 if (owner.selection_mode == SelectionMode.One && new_idx > -1)
2699 owner.selected_indices.Add (new_idx);
2705 internal void Sort ()
2707 object_items.Sort (new ListObjectComparer ());
2710 #endregion Private Methods
2713 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2715 private ListBox owner;
2716 ArrayList selection;
2717 bool sorting_needed; // Selection state retrieval is done sorted - we do it lazyly
2719 #region UIA Framework Events
2722 // We are using Reflection to add/remove internal events.
2723 // Class ListProvider uses the events.
2725 //Event used to generate UIA StructureChangedEvent
2726 static object UIACollectionChangedEvent = new object ();
2728 internal event CollectionChangeEventHandler UIACollectionChanged {
2729 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
2730 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
2733 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
2735 CollectionChangeEventHandler eh
2736 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
2741 #endregion UIA Framework Events
2744 public SelectedIndexCollection (ListBox owner)
2747 selection = new ArrayList ();
2750 #region Public Properties
2753 get { return selection.Count; }
2756 public bool IsReadOnly {
2757 get { return true; }
2760 public int this [int index] {
2762 if (index < 0 || index >= Count)
2763 throw new ArgumentOutOfRangeException ("Index of out range");
2766 return (int)selection [index];
2770 bool ICollection.IsSynchronized {
2771 get { return true; }
2774 bool IList.IsFixedSize{
2775 get { return true; }
2778 object ICollection.SyncRoot {
2779 get { return selection; }
2782 #endregion Public Properties
2784 #region Public Methods
2785 public void Add (int index)
2787 if (AddCore (index)) {
2788 owner.OnSelectedIndexChanged (EventArgs.Empty);
2789 owner.OnSelectedValueChanged (EventArgs.Empty);
2793 // Need to separate selection logic from events,
2794 // since selection changes using keys/mouse handle them their own way
2795 internal bool AddCore (int index)
2797 if (selection.Contains (index))
2800 if (index == -1) // Weird MS behaviour
2802 if (index < -1 || index >= owner.Items.Count)
2803 throw new ArgumentOutOfRangeException ("index");
2804 if (owner.selection_mode == SelectionMode.None)
2805 throw new InvalidOperationException ("Cannot call this method when selection mode is SelectionMode.None");
2807 if (owner.selection_mode == SelectionMode.One && Count > 0) // Unselect previously selected item
2808 RemoveCore ((int)selection [0]);
2810 selection.Add (index);
2811 sorting_needed = true;
2812 owner.EnsureVisible (index);
2813 owner.FocusedItem = index;
2814 owner.InvalidateItem (index);
2816 // UIA Framework event: Selected item added
2817 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, index));
2822 public void Clear ()
2825 owner.OnSelectedIndexChanged (EventArgs.Empty);
2826 owner.OnSelectedValueChanged (EventArgs.Empty);
2830 internal bool ClearCore ()
2832 if (selection.Count == 0)
2835 foreach (int index in selection)
2836 owner.InvalidateItem (index);
2840 // UIA Framework event: Selected items list updated
2841 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, -1));
2846 public bool Contains (int selectedIndex)
2848 foreach (int index in selection)
2849 if (index == selectedIndex)
2854 public void CopyTo (Array destination, int index)
2857 selection.CopyTo (destination, index);
2860 public IEnumerator GetEnumerator ()
2863 return selection.GetEnumerator ();
2866 // FIXME: Probably we can avoid sorting when calling
2867 // IndexOf (imagine a scenario where multiple removal of items
2869 public void Remove (int index)
2871 // Separate logic from events here too
2872 if (RemoveCore (index)) {
2873 owner.OnSelectedIndexChanged (EventArgs.Empty);
2874 owner.OnSelectedValueChanged (EventArgs.Empty);
2878 internal bool RemoveCore (int index)
2880 int idx = IndexOf (index);
2884 selection.RemoveAt (idx);
2885 owner.InvalidateItem (index);
2887 // UIA Framework event: Selected item removed from selection
2888 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index));
2893 int IList.Add (object value)
2895 throw new NotSupportedException ();
2900 throw new NotSupportedException ();
2903 bool IList.Contains (object selectedIndex)
2905 return Contains ((int)selectedIndex);
2908 int IList.IndexOf (object selectedIndex)
2910 return IndexOf ((int) selectedIndex);
2913 void IList.Insert (int index, object value)
2915 throw new NotSupportedException ();
2918 void IList.Remove (object value)
2920 throw new NotSupportedException ();
2923 void IList.RemoveAt (int index)
2925 throw new NotSupportedException ();
2928 object IList.this[int index]{
2929 get { return this [index]; }
2930 set {throw new NotImplementedException (); }
2933 public int IndexOf (int selectedIndex)
2937 for (int i = 0; i < selection.Count; i++)
2938 if ((int)selection [i] == selectedIndex)
2943 #endregion Public Methods
2944 internal ArrayList List {
2953 if (sorting_needed) {
2954 sorting_needed = false;
2960 public class SelectedObjectCollection : IList, ICollection, IEnumerable
2962 private ListBox owner;
2964 public SelectedObjectCollection (ListBox owner)
2969 #region Public Properties
2971 get { return owner.selected_indices.Count; }
2974 public bool IsReadOnly {
2975 get { return true; }
2979 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2980 public object this [int index] {
2982 if (index < 0 || index >= Count)
2983 throw new ArgumentOutOfRangeException ("Index of out range");
2985 return owner.items [owner.selected_indices [index]];
2987 set {throw new NotSupportedException ();}
2990 bool ICollection.IsSynchronized {
2991 get { return true; }
2994 object ICollection.SyncRoot {
2995 get { return this; }
2998 bool IList.IsFixedSize {
2999 get { return true; }
3002 #endregion Public Properties
3004 #region Public Methods
3005 public void Add (object value)
3007 if (owner.selection_mode == SelectionMode.None)
3008 throw new ArgumentException ("Cannot call this method if SelectionMode is SelectionMode.None");
3010 int idx = owner.items.IndexOf (value);
3014 owner.selected_indices.Add (idx);
3017 public void Clear ()
3019 owner.selected_indices.Clear ();
3022 public bool Contains (object selectedObject)
3024 int idx = owner.items.IndexOf (selectedObject);
3025 return idx == -1 ? false : owner.selected_indices.Contains (idx);
3028 public void CopyTo (Array destination, int index)
3030 for (int i = 0; i < Count; i++)
3031 destination.SetValue (this [i], index++);
3034 public void Remove (object value)
3039 int idx = owner.items.IndexOf (value);
3043 owner.selected_indices.Remove (idx);
3046 int IList.Add (object value)
3048 throw new NotSupportedException ();
3053 throw new NotSupportedException ();
3056 void IList.Insert (int index, object value)
3058 throw new NotSupportedException ();
3061 void IList.Remove (object value)
3063 throw new NotSupportedException ();
3066 void IList.RemoveAt (int index)
3068 throw new NotSupportedException ();
3071 public int IndexOf (object selectedObject)
3073 int idx = owner.items.IndexOf (selectedObject);
3074 return idx == -1 ? -1 : owner.selected_indices.IndexOf (idx);
3077 public IEnumerator GetEnumerator ()
3079 //FIXME: write an enumerator that uses selection.GetEnumerator
3080 // so that invalidation is write on selection changes
3081 object [] items = new object [Count];
3082 for (int i = 0; i < Count; i++) {
3083 items [i] = owner.items [owner.selected_indices [i]];
3086 return items.GetEnumerator ();
3089 #endregion Public Methods