* ListBox.cs: If the items are cleared with Items.Clear set
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListBox.cs
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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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.
19 //
20 // Copyright (c) 2004-2006 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Mike Kestner  <mkestner@novell.com>
25 //
26
27 // COMPLETE
28
29 using System;
30 using System.Drawing;
31 using System.Collections;
32 using System.ComponentModel;
33 using System.ComponentModel.Design;
34 using System.ComponentModel.Design.Serialization;
35 using System.Reflection;
36 using System.Runtime.InteropServices;
37
38 namespace System.Windows.Forms
39 {
40         [DefaultProperty("Items")]
41         [DefaultEvent("SelectedIndexChanged")]
42         [Designer ("System.Windows.Forms.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43         public class ListBox : ListControl
44         {
45                 public const int DefaultItemHeight = 13;
46                 public const int NoMatches = -1;
47                 
48                 internal enum ItemNavigation
49                 {
50                         First,
51                         Last,
52                         Next,
53                         Previous,
54                         NextPage,
55                         PreviousPage,
56                         PreviousColumn,
57                         NextColumn
58                 }
59                 
60                 Hashtable item_heights;
61                 private int item_height = -1;
62                 private int column_width = 0;
63                 private int requested_height = -1;
64                 private DrawMode draw_mode = DrawMode.Normal;
65                 private int horizontal_extent = 0;
66                 private bool horizontal_scrollbar = false;
67                 private bool integral_height = true;
68                 private bool multicolumn = false;
69                 private bool scroll_always_visible = false;
70                 private int selected_index = -1;                
71                 private SelectedIndexCollection selected_indices;               
72                 private SelectedObjectCollection selected_items;
73                 private ArrayList selection = new ArrayList ();
74                 private ArrayList display_selection = new ArrayList ();
75                 private SelectionMode selection_mode = SelectionMode.One;
76                 private bool sorted = false;
77                 private bool use_tabstops = true;
78                 private int column_width_internal = 120;
79                 private ImplicitVScrollBar vscrollbar;
80                 private ImplicitHScrollBar hscrollbar;
81                 private int hbar_offset;
82                 private bool suspend_layout;
83                 private bool ctrl_pressed = false;
84                 private bool shift_pressed = false;
85                 private bool has_focus = false;
86                 private bool explicit_item_height = false;
87                 private int top_index = 0;
88                 private int last_visible_index = 0;
89                 private Rectangle items_area;
90                 private int focused_item = -1;          
91                 private ObjectCollection items;
92
93                 public ListBox ()
94                 {
95                         border_style = BorderStyle.Fixed3D;                     
96                         BackColor = ThemeEngine.Current.ColorWindow;
97
98                         items = CreateItemCollection ();
99                         selected_indices = new SelectedIndexCollection (this);
100                         selected_items = new SelectedObjectCollection (this);
101
102                         /* Vertical scrollbar */
103                         vscrollbar = new ImplicitVScrollBar ();
104                         vscrollbar.Minimum = 0;
105                         vscrollbar.SmallChange = 1;
106                         vscrollbar.LargeChange = 1;
107                         vscrollbar.Maximum = 0;
108                         vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent);
109                         vscrollbar.Visible = false;
110
111                         /* Horizontal scrollbar */
112                         hscrollbar = new ImplicitHScrollBar ();
113                         hscrollbar.Minimum = 0;
114                         hscrollbar.SmallChange = 1;
115                         hscrollbar.LargeChange = 1;
116                         hscrollbar.Maximum = 0;
117                         hscrollbar.Visible = false;
118                         hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent);
119
120                         /* Events */
121                         MouseDown += new MouseEventHandler (OnMouseDownLB);
122                         MouseMove += new MouseEventHandler (OnMouseMoveLB);
123                         MouseUp += new MouseEventHandler (OnMouseUpLB);
124                         MouseWheel += new MouseEventHandler (OnMouseWheelLB);
125                         KeyDown += new KeyEventHandler (OnKeyDownLB);
126                         KeyUp += new KeyEventHandler (OnKeyUpLB);
127                         GotFocus += new EventHandler (OnGotFocus);
128                         LostFocus += new EventHandler (OnLostFocus);
129                         
130                         SetStyle (ControlStyles.UserPaint, false);
131                 }
132
133                 #region Events
134                 [Browsable (false)]
135                 [EditorBrowsable (EditorBrowsableState.Never)]
136                 public new event EventHandler BackgroundImageChanged {
137                         add { base.BackgroundImageChanged += value; }
138                         remove { base.BackgroundImageChanged -= value; }
139                 }
140
141                 [Browsable (false)]
142                 [EditorBrowsable (EditorBrowsableState.Advanced)]
143                 public new event EventHandler Click {
144                         add { base.Click += value; }
145                         remove { base.Click -= value; }
146                 }
147
148                 public event DrawItemEventHandler DrawItem;
149                 public event MeasureItemEventHandler MeasureItem;
150
151                 [Browsable (false)]
152                 [EditorBrowsable (EditorBrowsableState.Never)]
153                 public new event PaintEventHandler Paint {
154                         add { base.Paint += value; }
155                         remove { base.Paint -= value; }
156                 }
157
158                 public event EventHandler SelectedIndexChanged;
159
160                 [Browsable (false)]
161                 [EditorBrowsable (EditorBrowsableState.Advanced)]
162                 public new event EventHandler TextChanged {
163                         add { base.TextChanged += value; }
164                         remove { base.TextChanged -= value; }
165                 }
166                 #endregion // Events
167
168                 #region Public Properties
169                 public override Color BackColor {
170                         get { return base.BackColor; }
171                         set {
172                                 if (base.BackColor == value)
173                                         return;
174
175                                 base.BackColor = value;
176                                 base.Refresh ();        // Careful. Calling the base method is not the same that calling 
177                         }                               // the overriden one that refresh also all the items
178                 }
179
180                 [Browsable (false)]
181                 [EditorBrowsable (EditorBrowsableState.Never)]
182                 public override Image BackgroundImage {
183                         get { return base.BackgroundImage; }
184                         set { 
185                                 base.BackgroundImage = value;
186                                 base.Refresh ();
187                         }
188                 }
189
190                 [DefaultValue (BorderStyle.Fixed3D)]
191                 [DispId(-504)]
192                 public BorderStyle BorderStyle {
193                         get { return InternalBorderStyle; }
194                         set { 
195                                 InternalBorderStyle = value; 
196                                 UpdateBounds ();
197                         }
198                 }
199
200                 [DefaultValue (0)]
201                 [Localizable (true)]
202                 public int ColumnWidth {
203                         get { return column_width; }
204                         set {
205                                 if (value < 0)
206                                         throw new ArgumentException ("A value less than zero is assigned to the property.");
207
208                                 column_width = value;
209
210                                 if (value == 0)
211                                         ColumnWidthInternal = 120;
212                                 else
213                                         ColumnWidthInternal = value;
214
215                                 base.Refresh ();
216                         }
217                 }
218
219                 protected override CreateParams CreateParams {
220                         get { return base.CreateParams;}
221                 }
222
223                 protected override Size DefaultSize {
224                         get { return new Size (120, 96); }
225                 }
226
227                 [RefreshProperties(RefreshProperties.Repaint)]
228                 [DefaultValue (DrawMode.Normal)]
229                 public virtual DrawMode DrawMode {
230                         get { return draw_mode; }
231
232                         set {
233                                 if (!Enum.IsDefined (typeof (DrawMode), value))
234                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
235                                         
236                                 if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
237                                         throw new ArgumentException ("Cannot have variable height and multicolumn");
238
239                                 if (draw_mode == value)
240                                         return;
241
242                                 draw_mode = value;
243
244                                 if (draw_mode == DrawMode.OwnerDrawVariable)
245                                         item_heights = new Hashtable ();
246                                 else
247                                         item_heights = null;
248
249                                 base.Refresh ();
250                         }
251                 }
252
253                 public override Color ForeColor {
254                         get { return base.ForeColor; }
255                         set {
256
257                                 if (base.ForeColor == value)
258                                         return;
259
260                                 base.ForeColor = value;
261                                 base.Refresh ();
262                         }
263                 }
264
265                 [DefaultValue (0)]
266                 [Localizable (true)]
267                 public int HorizontalExtent {
268                         get { return horizontal_extent; }
269                         set {
270                                 if (horizontal_extent == value)
271                                         return;
272
273                                 horizontal_extent = value;
274                                 base.Refresh ();
275                         }
276                 }
277
278                 [DefaultValue (false)]
279                 [Localizable (true)]
280                 public bool HorizontalScrollbar {
281                         get { return horizontal_scrollbar; }
282                         set {
283                                 if (horizontal_scrollbar == value)
284                                         return;
285
286                                 horizontal_scrollbar = value;
287                                 UpdateScrollBars ();
288                                 base.Refresh ();
289                         }
290                 }
291
292                 [DefaultValue (true)]
293                 [Localizable (true)]
294                 [RefreshProperties(RefreshProperties.Repaint)]
295                 public bool IntegralHeight {
296                         get { return integral_height; }
297                         set {
298                                 if (integral_height == value)
299                                         return;
300
301                                 integral_height = value;
302                                 UpdateBounds ();
303                         }
304                 }
305
306                 [DefaultValue (13)]
307                 [Localizable (true)]
308                 [RefreshProperties(RefreshProperties.Repaint)]
309                 public virtual int ItemHeight {
310                         get {
311                                 if (item_height == -1) {
312                                         SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
313                                         item_height = (int) sz.Height;
314                                 }
315                                 return item_height;
316                         }
317                         set {
318                                 if (value > 255)
319                                         throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
320
321                                 explicit_item_height = true;
322                                 if (item_height == value)
323                                         return;
324
325                                 item_height = value;
326                                 if (IntegralHeight)
327                                         UpdateBounds ();
328                                 Layout ();
329                         }
330                 }
331
332                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
333                 [Localizable (true)]
334                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
335                 public ObjectCollection Items {
336                         get { return items; }
337                 }
338
339                 [DefaultValue (false)]
340                 public bool MultiColumn {
341                         get { return multicolumn; }
342                         set {
343                                 if (multicolumn == value)
344                                         return;
345
346                                 if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
347                                         throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
348                                         
349                                 multicolumn = value;
350                                 Layout ();
351                         }
352                 }
353
354                 [Browsable (false)]
355                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
356                 [EditorBrowsable (EditorBrowsableState.Advanced)]
357                 public int PreferredHeight {
358                         get {
359                                 int itemsHeight = 0;
360                                 if (draw_mode == DrawMode.Normal)
361                                         itemsHeight = FontHeight * items.Count;
362                                 else if (draw_mode == DrawMode.OwnerDrawFixed)
363                                         itemsHeight = ItemHeight * items.Count;
364                                 else if (draw_mode == DrawMode.OwnerDrawVariable) {
365                                         for (int i = 0; i < items.Count; i++)
366                                                 itemsHeight += (int) item_heights [Items [i]];
367                                 }
368                                 
369                                 return itemsHeight;
370                         }
371                 }
372
373                 public override RightToLeft RightToLeft {
374                         get { return base.RightToLeft; }
375                         set {
376                                 base.RightToLeft = value;                               
377                                 if (base.RightToLeft == RightToLeft.Yes)
378                                         StringFormat.Alignment = StringAlignment.Far;                           
379                                 else
380                                         StringFormat.Alignment = StringAlignment.Near;                          
381                                 base.Refresh ();
382                         }
383                 }
384
385                 // Only affects the Vertical ScrollBar
386                 [DefaultValue (false)]
387                 [Localizable (true)]
388                 public bool ScrollAlwaysVisible {
389                         get { return scroll_always_visible; }
390                         set {
391                                 if (scroll_always_visible == value)
392                                         return;
393
394                                 scroll_always_visible = value;
395                                 UpdateScrollBars ();
396                         }
397                 }
398
399                 [Bindable(true)]
400                 [Browsable (false)]
401                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
402                 public override int SelectedIndex {
403                         get { return selected_index;}
404                         set {
405                                 if (value < -1 || value >= Items.Count)
406                                         throw new ArgumentOutOfRangeException ("Index of out range");
407
408                                 if (SelectionMode == SelectionMode.None)
409                                         throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
410
411                                 if (selected_index == value)
412                                         return;
413
414                                 if (value == -1)
415                                         ClearSelected ();
416                                 else if (SelectionMode == SelectionMode.One)
417                                         UnSelectItem (selected_index, true);
418
419                                 SelectItem (value);
420                                 selected_index = value;
421                                 FocusedItem = value;
422                                 OnSelectedIndexChanged  (new EventArgs ());
423                                 OnSelectedValueChanged (new EventArgs ());
424                         }
425                 }
426
427                 [Browsable (false)]
428                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
429                 public SelectedIndexCollection SelectedIndices {
430                         get { return selected_indices; }
431                 }
432
433                 [Bindable(true)]
434                 [Browsable (false)]
435                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
436                 public object SelectedItem {
437                         get {
438                                 if (SelectedItems.Count > 0)
439                                         return SelectedItems[0];
440                                 else
441                                         return null;
442                         }
443                         set {
444                                 if (value != null && !Items.Contains (value))
445                                         return; // FIXME: this is probably an exception
446                                         
447                                 SelectedIndex = value == null ? - 1 : Items.IndexOf (value);
448                         }
449                 }
450
451                 [Browsable (false)]
452                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
453                 public SelectedObjectCollection SelectedItems {
454                         get {return selected_items;}
455                 }
456
457                 [DefaultValue (SelectionMode.One)]
458                 public virtual SelectionMode SelectionMode {
459                         get { return selection_mode; }
460                         set {
461                                 if (!Enum.IsDefined (typeof (SelectionMode), value))
462                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
463
464                                 if (selection_mode == value)
465                                         return;
466                                         
467                                 selection_mode = value;
468                                         
469                                 switch (selection_mode) {
470                                 case SelectionMode.None: 
471                                         ClearSelected ();
472                                         break;                                          
473
474                                 case SelectionMode.One:
475                                         while (SelectedIndices.Count > 1)
476                                                 UnSelectItem (SelectedIndices [SelectedIndices.Count - 1], true);
477                                         break;
478
479                                 default:
480                                         break;                                          
481                                 }
482                         }
483                 }
484
485                 [DefaultValue (false)]
486                 public bool Sorted {
487                         get { return sorted; }
488
489                         set {
490                                 if (sorted == value)
491                                         return;
492
493                                 sorted = value;
494                                 if (sorted)
495                                         Sort ();
496                         }
497                 }
498
499                 [Bindable (false)]
500                 [Browsable (false)]
501                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
502                 [EditorBrowsable (EditorBrowsableState.Advanced)]
503                 public override string Text {
504                         get {
505                                 if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
506                                         return GetItemText (SelectedItem);
507
508                                 return base.Text;
509                         }
510                         set {
511
512                                 base.Text = value;
513
514                                 if (SelectionMode == SelectionMode.None)
515                                         return;
516
517                                 int index;
518
519                                 index = FindStringExact (value);
520
521                                 if (index == -1)
522                                         return;
523
524                                 SelectedIndex = index;
525                         }
526                 }
527
528                 [Browsable (false)]
529                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
530                 public int TopIndex {
531                         get { return top_index; }
532                         set {
533                                 if (value == top_index)
534                                         return;
535
536                                 if (value < 0 || value >= Items.Count)
537                                         return;
538
539                                 top_index = value;
540                                 UpdateTopItem ();
541                                 base.Refresh ();
542                         }
543                 }
544
545                 [DefaultValue (true)]
546                 public bool UseTabStops {
547                         get { return use_tabstops; }
548
549                         set {
550                                 if (use_tabstops == value)
551                                         return;
552
553                                 use_tabstops = value;                                   
554                                 if (use_tabstops)
555                                         StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
556                                 else
557                                         StringFormat.SetTabStops (0, new float [0]);
558                                 base.Refresh ();
559                         }
560                 }
561
562                 #endregion Public Properties
563
564                 #region Private Properties
565
566                 private int ColumnWidthInternal {
567                         get { return column_width_internal; }
568                         set { column_width_internal = value; }
569                 }
570
571                 private int row_count = 1;
572                 private int RowCount {
573                         get {
574                                 return MultiColumn ? row_count : Items.Count;
575                         }
576                 }
577
578                 #endregion Private Properties
579
580                 #region Public Methods
581                 protected virtual void AddItemsCore (object[] value)
582                 {
583                         Items.AddRange (value);
584                 }
585
586                 public void BeginUpdate ()
587                 {
588                         suspend_layout = true;
589                 }
590
591                 public void ClearSelected ()
592                 {
593                         foreach (int i in selected_indices) {
594                                 UnSelectItem (i, false);
595                         }
596
597                         selection.Clear ();
598                 }
599
600                 protected virtual ObjectCollection CreateItemCollection ()
601                 {
602                         return new ObjectCollection (this);
603                 }
604
605                 public void EndUpdate ()
606                 {
607                         suspend_layout = false;
608                         Layout ();
609                         base.Refresh ();
610                 }
611
612                 public int FindString (String s)
613                 {
614                         return FindString (s, -1);
615                 }
616
617                 public int FindString (string s,  int startIndex)
618                 {
619                         if (Items.Count == 0)
620                                 return -1; // No exception throwing if empty
621
622                         if (startIndex < -1 || startIndex >= Items.Count - 1)
623                                 throw new ArgumentOutOfRangeException ("Index of out range");
624
625                         startIndex++;
626                         for (int i = startIndex; i < Items.Count; i++) {
627                                 if ((GetItemText (Items[i])).StartsWith (s))
628                                         return i;
629                         }
630
631                         return NoMatches;
632                 }
633
634                 public int FindStringExact (string s)
635                 {
636                         return FindStringExact (s, -1);
637                 }
638
639                 public int FindStringExact (string s,  int startIndex)
640                 {
641                         if (Items.Count == 0)
642                                 return -1; // No exception throwing if empty
643
644                         if (startIndex < -1 || startIndex >= Items.Count - 1)
645                                 throw new ArgumentOutOfRangeException ("Index of out range");
646
647                         startIndex++;
648                         for (int i = startIndex; i < Items.Count; i++) {
649                                 if ((GetItemText (Items[i])).Equals (s))
650                                         return i;
651                         }
652
653                         return NoMatches;
654                 }
655
656                 public int GetItemHeight (int index)
657                 {
658                         if (index < 0 || index >= Items.Count)
659                                 throw new ArgumentOutOfRangeException ("Index of out range");
660                                 
661                         if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
662                                 
663                                 object o = Items [index];
664                                 if (item_heights.Contains (o))
665                                         return (int) item_heights [o];
666                                 
667                                 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
668                                 OnMeasureItem (args);
669                                 item_heights [o] = args.ItemHeight;
670                                 return args.ItemHeight;
671                         }
672
673                         return ItemHeight;
674                 }
675
676                 public Rectangle GetItemRectangle (int index)
677                 {
678                         if (index < 0 || index >= Items.Count)
679                                 throw new  ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
680
681                         Rectangle rect = new Rectangle ();
682
683                         if (MultiColumn) {
684                                 int col = index / RowCount;
685                                 rect.Y = ((index - top_index) % RowCount) * ItemHeight;
686                                 rect.X = col * ColumnWidthInternal;
687                                 rect.Height = ItemHeight;
688                                 rect.Width = ColumnWidthInternal;
689                         } else {
690                                 rect.X = 0;                             
691                                 rect.Height = GetItemHeight (index);
692                                 rect.Width = items_area.Width;
693                                 
694                                 if (DrawMode == DrawMode.OwnerDrawVariable) {
695                                         rect.Y = 0;
696                                         if (index >= top_index) {
697                                                 for (int i = top_index; i < index; i++) {
698                                                         rect.Y += GetItemHeight (i);
699                                                 }
700                                         } else {
701                                                 for (int i = index; i < top_index; i++) {
702                                                         rect.Y -= GetItemHeight (i);
703                                                 }
704                                         }
705                                 } else {
706                                         rect.Y = ItemHeight * (index - top_index);      
707                                 }                               
708                         }
709
710                         return rect;
711                 }
712
713                 public bool GetSelected (int index)
714                 {
715                         if (index < 0 || index >= Items.Count)
716                                 throw new ArgumentOutOfRangeException ("Index of out range");
717
718                         return SelectedIndices.Contains (index);
719                 }
720
721                 public int IndexFromPoint (Point p)
722                 {
723                         return IndexFromPoint (p.X, p.Y);
724                 }
725
726                 // Only returns visible points
727                 public int IndexFromPoint (int x, int y)
728                 {
729
730                         if (Items.Count == 0) {
731                                 return -1;
732                         }
733
734                         for (int i = top_index; i <= last_visible_index; i++) {
735                                 if (GetItemRectangle (i).Contains (x,y) == true)
736                                         return i;
737                         }
738
739                         return -1;
740                 }
741
742                 protected override void OnChangeUICues (UICuesEventArgs e)
743                 {
744                         base.OnChangeUICues (e);
745                 }
746
747                 protected override void OnDataSourceChanged (EventArgs e)
748                 {
749                         base.OnDataSourceChanged (e);
750                         BindDataItems ();
751                         
752                         if (DataSource == null || DataManager == null) {
753                                 SelectedIndex = -1;
754                         } 
755                         else {
756                                 SelectedIndex = DataManager.Position;
757                         }
758                 }
759
760                 protected override void OnDisplayMemberChanged (EventArgs e)
761                 {
762                         base.OnDisplayMemberChanged (e);
763
764                         if (DataManager == null || !IsHandleCreated)
765                                 return;
766
767                         BindDataItems ();
768                         base.Refresh ();
769                 }
770
771                 protected virtual void OnDrawItem (DrawItemEventArgs e)
772                 {                       
773                         switch (DrawMode) {
774                         case DrawMode.OwnerDrawFixed:
775                         case DrawMode.OwnerDrawVariable:
776                                 if (DrawItem != null)
777                                         DrawItem (this, e);
778                                 break;
779
780                         default:
781                                 ThemeEngine.Current.DrawListBoxItem (this, e);
782                                 break;
783                         }
784                 }
785
786                 protected override void OnFontChanged (EventArgs e)
787                 {
788                         base.OnFontChanged (e);
789
790                         if (use_tabstops)
791                                 StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
792
793                         if (explicit_item_height) {
794                                 base.Refresh ();
795                         } else {
796                                 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
797                                 item_height = (int) sz.Height;
798                                 if (IntegralHeight)
799                                         UpdateBounds ();
800                                 Layout ();
801                         }
802                 }
803
804                 protected override void OnHandleCreated (EventArgs e)
805                 {
806                         base.OnHandleCreated (e);
807
808                         SuspendLayout ();
809                         Controls.AddImplicit (vscrollbar);
810                         Controls.AddImplicit (hscrollbar);
811                         ResumeLayout ();
812                         Layout ();
813                 }
814
815                 protected override void OnHandleDestroyed (EventArgs e)
816                 {
817                         base.OnHandleDestroyed (e);
818                 }
819
820                 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
821                 {
822                         if (draw_mode != DrawMode.OwnerDrawVariable)
823                                 return;
824                                 
825                         if (MeasureItem != null)
826                                 MeasureItem (this, e);
827                 }
828
829                 protected override void OnParentChanged (EventArgs e)
830                 {
831                         base.OnParentChanged (e);
832                 }
833
834                 protected override void OnResize (EventArgs e)
835                 {
836                         base.OnResize (e);
837                         if (canvas_size.IsEmpty || MultiColumn)
838                                 Layout ();
839                 }
840
841                 protected override void OnSelectedIndexChanged (EventArgs e)
842                 {
843                         base.OnSelectedIndexChanged (e);
844
845                         if (SelectedIndexChanged != null)
846                                 SelectedIndexChanged (this, e);
847                 }
848
849                 protected override void OnSelectedValueChanged (EventArgs e)
850                 {
851                         base.OnSelectedValueChanged (e);
852                 }
853
854                 public override void Refresh ()
855                 {
856                         if (draw_mode == DrawMode.OwnerDrawVariable)
857                                 item_heights.Clear ();
858                         
859                         base.Refresh ();
860                 }
861
862                 protected override void RefreshItem (int index)
863                 {
864                         if (index < 0 || index >= Items.Count)
865                                 throw new ArgumentOutOfRangeException ("Index of out range");
866                                 
867                         if (draw_mode == DrawMode.OwnerDrawVariable)
868                                 item_heights.Remove (Items [index]);
869                 }
870
871                 protected override void SetBoundsCore (int x,  int y, int width, int height, BoundsSpecified specified)
872                 {
873                         if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
874                                 requested_height = height;
875
876                         if (IntegralHeight) {
877                                 int border;
878                                 switch (border_style) {
879                                 case BorderStyle.Fixed3D:
880                                         border = ThemeEngine.Current.Border3DSize.Height;
881                                         break;
882                                 case BorderStyle.FixedSingle:
883                                         border = ThemeEngine.Current.BorderSize.Height;
884                                         break;
885                                 case BorderStyle.None:
886                                 default:
887                                         border = 0;
888                                         break;
889                                 }
890                                 height -= (2 * border);
891                                 height -= height % ItemHeight;
892                                 height += (2 * border);
893                         }
894
895                         base.SetBoundsCore (x, y, width, height, specified);
896                         UpdateScrollBars ();
897                 }
898
899                 protected override void SetItemCore (int index,  object value)
900                 {
901                         if (index < 0 || index >= Items.Count)
902                                 return;
903
904                         Items[index] = value;
905                 }
906
907                 protected override void SetItemsCore (IList value)
908                 {
909                         BeginUpdate ();
910                         try {
911                                 Items.Clear ();
912                                 Items.AddRange (value);
913                         } finally {
914                                 EndUpdate ();
915                         }
916                 }
917
918                 public void SetSelected (int index, bool value)
919                 {
920                         if (index < 0 || index >= Items.Count)
921                                 throw new ArgumentOutOfRangeException ("Index of out range");
922
923                         if (SelectionMode == SelectionMode.None)
924                                 throw new InvalidOperationException ();
925
926                         if (value)
927                                 SelectItem (index);
928                         else
929                                 UnSelectItem (index, true);
930                 }
931
932                 protected virtual void Sort ()
933                 {
934                         if (Items.Count == 0)
935                                 return;
936
937                         Items.Sort ();
938                         base.Refresh ();
939                 }
940
941                 public override string ToString ()
942                 {
943                         return base.ToString ();
944                 }
945
946                 protected virtual void WmReflectCommand (ref Message m)
947                 {
948                 }
949
950                 protected override void WndProc (ref Message m)
951                 {
952                         base.WndProc (ref m);
953                 }
954
955                 #endregion Public Methods
956
957                 #region Private Methods
958
959                 private Size canvas_size;
960
961                 private void Layout ()
962                 {
963                         if (!IsHandleCreated || suspend_layout)
964                                 return;
965
966                         if (MultiColumn)
967                                 LayoutMultiColumn ();
968                         else
969                                 LayoutSingleColumn ();
970
971                         UpdateScrollBars ();
972                         last_visible_index = LastVisibleItem ();
973                 }
974
975                 private void LayoutSingleColumn ()
976                 {
977                         int height, width;
978
979                         switch (DrawMode) {
980                         case DrawMode.OwnerDrawVariable:
981                                 height = 0;
982                                 width = HorizontalExtent;
983                                 for (int i = 0; i < Items.Count; i++) {
984                                         height += GetItemHeight (i);
985                                 }
986                                 break;
987
988                         case DrawMode.OwnerDrawFixed:
989                                 height = Items.Count * ItemHeight;
990                                 width = HorizontalExtent;
991                                 break;
992
993                         case DrawMode.Normal:
994                         default:
995                                 height = Items.Count * ItemHeight;
996                                 width = 0;
997                                 for (int i = 0; i < Items.Count; i++) {
998                                         SizeF sz = DeviceContext.MeasureString (GetItemText (Items[i]), Font);
999                                         if ((int) sz.Width > width)
1000                                                 width = (int) sz.Width;
1001                                 }
1002                                 break;
1003                         }
1004
1005                         canvas_size = new Size (width, height);
1006                 }
1007
1008                 private void LayoutMultiColumn ()
1009                 {
1010                         int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0);
1011                         row_count = usable_height / ItemHeight;
1012                         if (row_count == 0)
1013                                 row_count = 1;
1014                         int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1015                         Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1016                         if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) {
1017                                 usable_height = ClientRectangle.Height - hscrollbar.Height;
1018                                 row_count = usable_height / ItemHeight;
1019                                 cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1020                                 sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1021                         }
1022                         canvas_size = sz;
1023                 }
1024
1025                 internal void Draw (Rectangle clip, Graphics dc)
1026                 {                               
1027                         Theme theme = ThemeEngine.Current;
1028
1029                         if (hscrollbar.Visible && vscrollbar.Visible) {
1030                                 // Paint the dead space in the bottom right corner
1031                                 Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height);
1032                                 if (rect.IntersectsWith (clip))
1033                                         dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect);
1034                         }
1035
1036                         dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area);
1037
1038                         if (Items.Count == 0)
1039                                 return;
1040
1041                         for (int i = top_index; i <= last_visible_index; i++) {
1042                                 Rectangle rect = GetItemDisplayRectangle (i, top_index);
1043
1044                                 if (!clip.IntersectsWith (rect))
1045                                         continue;
1046
1047                                 DrawItemState state = DrawItemState.None;
1048
1049                                 if (SelectedIndices.Contains (i))
1050                                         state |= DrawItemState.Selected;
1051                                         
1052                                 if (has_focus && FocusedItem == i)
1053                                         state |= DrawItemState.Focus;
1054                                         
1055                                 if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) {
1056                                         rect.X -= hscrollbar.Value;
1057                                         rect.Width += hscrollbar.Value;
1058                                 }
1059
1060                                 OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, ForeColor, BackColor));
1061                         }
1062                 }
1063
1064                 // Converts a GetItemRectangle to a one that we can display
1065                 internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
1066                 {
1067                         Rectangle item_rect;
1068                         Rectangle first_item_rect = GetItemRectangle (first_displayble);
1069                         item_rect = GetItemRectangle (index);
1070                         item_rect.X -= first_item_rect.X;
1071                         item_rect.Y -= first_item_rect.Y;
1072                         
1073                         return item_rect;
1074                 }
1075
1076                 // Value Changed
1077                 private void HorizontalScrollEvent (object sender, EventArgs e)
1078                 {
1079                         if (multicolumn) {
1080                                 int top_item = top_index;
1081                                 int last_item = last_visible_index;
1082
1083                                 top_index = RowCount * hscrollbar.Value;
1084                                 last_visible_index = LastVisibleItem ();
1085
1086                                 if (top_item != top_index || last_item != last_visible_index)
1087                                         Invalidate (items_area);
1088                         }
1089                         else {
1090                                 int old_offset = hbar_offset;
1091                                 hbar_offset = hscrollbar.Value;
1092
1093                                 if (hbar_offset < 0)
1094                                         hbar_offset = 0;
1095
1096                                 XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false);
1097                         }
1098                 }
1099
1100                 // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
1101                 // has screen coordinates
1102                 private int IndexAtClientPoint (int x, int y)
1103                 {       
1104                         if (Items.Count == 0)
1105                                 return -1;
1106                         
1107                         if (x < 0)
1108                                 x = 0;
1109                         else if (x > ClientRectangle.Right)
1110                                 x = ClientRectangle.Right;
1111
1112                         if (y < 0)
1113                                 y = 0;
1114                         else if (y > ClientRectangle.Bottom)
1115                                 y = ClientRectangle.Bottom;
1116
1117                         for (int i = top_index; i <= last_visible_index; i++)
1118                                 if (GetItemDisplayRectangle (i, top_index).Contains (x, y))
1119                                         return i;
1120
1121                         return -1;
1122                 }
1123
1124                 private int LastVisibleItem ()
1125                 {
1126                         Rectangle item_rect;
1127                         int top_y = items_area.Y + items_area.Height;
1128                         int i = 0;
1129
1130                         if (top_index >= Items.Count)
1131                                 return top_index;
1132
1133                         for (i = top_index; i < Items.Count; i++) {
1134
1135                                 item_rect = GetItemDisplayRectangle (i, top_index);
1136                                 if (MultiColumn) {
1137
1138                                         if (item_rect.X > items_area.Width)
1139                                                 return i - 1;
1140                                 }
1141                                 else {                                  
1142                                         if (item_rect.Y + item_rect.Height > top_y) {
1143                                                 return i;
1144                                         }
1145                                 }
1146                         }
1147                         return i - 1;
1148                 }
1149
1150                 private void UpdateTopItem ()
1151                 {
1152                         if (MultiColumn) {                              
1153                                 int col = top_index / RowCount;
1154                                 
1155                                 if (col > hscrollbar.Maximum)
1156                                         hscrollbar.Value = hscrollbar.Maximum;
1157                                 else
1158                                         hscrollbar.Value = col;
1159                         } else {
1160                                 int val = vscrollbar.Value;
1161                                 if (top_index > vscrollbar.Maximum)
1162                                         vscrollbar.Value = vscrollbar.Maximum;
1163                                 else
1164                                         vscrollbar.Value = top_index;
1165                                 Scroll (vscrollbar, vscrollbar.Value - top_index);
1166                                 XplatUI.ScrollWindow (Handle, items_area, 0, ItemHeight * (val - vscrollbar.Value), false);
1167                         }
1168                 }
1169                 
1170                 // Navigates to the indicated item and returns the new item
1171                 private int NavigateItemVisually (ItemNavigation navigation)
1172                 {                       
1173                         int page_size, columns, selected_index = -1;
1174
1175                         if (multicolumn) {
1176                                 columns = items_area.Width / ColumnWidthInternal; 
1177                                 page_size = columns * RowCount;
1178                                 if (page_size == 0) {
1179                                         page_size = RowCount;
1180                                 }
1181                         } else {
1182                                 page_size = items_area.Height / ItemHeight;     
1183                         }
1184
1185                         switch (navigation) {
1186
1187                         case ItemNavigation.PreviousColumn: {
1188                                 if (FocusedItem - RowCount < 0) {
1189                                         return -1;
1190                                 }
1191
1192                                 if (FocusedItem - RowCount < top_index) {
1193                                         top_index = FocusedItem - RowCount;
1194                                         UpdateTopItem ();
1195                                 }
1196                                         
1197                                 selected_index = FocusedItem - RowCount;
1198                                 break;
1199                         }
1200                         
1201                         case ItemNavigation.NextColumn: {
1202                                 if (FocusedItem + RowCount >= Items.Count) {
1203                                         break;
1204                                 }
1205
1206                                 if (FocusedItem + RowCount > last_visible_index) {
1207                                         top_index = FocusedItem;
1208                                         UpdateTopItem ();
1209                                 }
1210                                         
1211                                 selected_index = FocusedItem + RowCount;                                        
1212                                 break;
1213                         }
1214
1215                         case ItemNavigation.First: {
1216                                 top_index = 0;
1217                                 selected_index  = 0;
1218                                 UpdateTopItem ();
1219                                 break;
1220                         }
1221
1222                         case ItemNavigation.Last: {
1223
1224                                 int rows = items_area.Height / ItemHeight;
1225                                 if (Items.Count < rows) {
1226                                         top_index = 0;
1227                                         selected_index  = Items.Count - 1;
1228                                         UpdateTopItem ();
1229                                 } else {
1230                                         top_index = Items.Count - rows;
1231                                         selected_index  = Items.Count - 1;
1232                                         UpdateTopItem ();
1233                                 }
1234                                 break;
1235                         }
1236
1237                         case ItemNavigation.Next: {
1238                                 if (FocusedItem == Items.Count - 1)
1239                                         return -1;
1240
1241                                 int bottom = 0;
1242                                 ArrayList heights = new ArrayList ();
1243                                 if (draw_mode == DrawMode.OwnerDrawVariable) {
1244                                         for (int i = top_index; i <= FocusedItem + 1; i++) {
1245                                                 int h = GetItemHeight (i);
1246                                                 bottom += h;
1247                                                 heights.Add (h);
1248                                         }
1249                                 } else {
1250                                         bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight;
1251                                 }
1252
1253                                 if (bottom >= items_area.Height) {
1254                                         int overhang = bottom - items_area.Height;
1255
1256                                         int offset = 0;
1257                                         if (draw_mode == DrawMode.OwnerDrawVariable)
1258                                                 while (overhang > 0)
1259                                                         overhang -= (int) heights [offset];
1260                                         else
1261                                                 offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight);
1262                                         top_index += offset;
1263                                         UpdateTopItem ();                                               
1264                                 }
1265                                 selected_index = FocusedItem + 1;
1266                                 break;
1267                         }
1268
1269                         case ItemNavigation.Previous: {
1270                                 if (FocusedItem > 0) {
1271                                         if (FocusedItem - 1 < top_index) {
1272                                                 top_index--;
1273                                                 UpdateTopItem ();
1274                                         }
1275                                         selected_index = FocusedItem - 1;
1276                                 }                                       
1277                                 break;
1278                         }
1279
1280                         case ItemNavigation.NextPage: {
1281                                 if (Items.Count < page_size) {
1282                                         NavigateItemVisually (ItemNavigation.Last);
1283                                         break;
1284                                 }
1285
1286                                 if (FocusedItem + page_size - 1 >= Items.Count) {
1287                                         top_index = Items.Count - page_size;
1288                                         UpdateTopItem ();
1289                                         selected_index = Items.Count - 1;                                               
1290                                 }
1291                                 else {
1292                                         if (FocusedItem + page_size - 1  > last_visible_index) {
1293                                                 top_index = FocusedItem;
1294                                                 UpdateTopItem ();
1295                                         }
1296                                         
1297                                         selected_index = FocusedItem + page_size - 1;                                           
1298                                 }
1299                                         
1300                                 break;
1301                         }                       
1302
1303                         case ItemNavigation.PreviousPage: {
1304                                         
1305                                 int rows = items_area.Height / ItemHeight;
1306                                 if (FocusedItem - (rows - 1) <= 0) {
1307                                                                                                                                                 
1308                                         top_index = 0;                                  
1309                                         UpdateTopItem ();                                       
1310                                         SelectedIndex = 0;                                      
1311                                 }
1312                                 else { 
1313                                         if (FocusedItem - (rows - 1)  < top_index) {
1314                                                 top_index = FocusedItem - (rows - 1);
1315                                                 UpdateTopItem ();                                               
1316                                         }
1317                                         
1318                                         selected_index = FocusedItem - (rows - 1);
1319                                 }
1320                                         
1321                                 break;
1322                         }               
1323                         default:
1324                                 break;                          
1325                         }
1326                         
1327                         return selected_index;
1328                 }
1329                 
1330                 
1331                 private void OnGotFocus (object sender, EventArgs e)                    
1332                 {                       
1333                         has_focus = true;                       
1334                         
1335                         if (FocusedItem != -1)
1336                                 InvalidateItem (FocusedItem);
1337                 }               
1338                 
1339                 private void OnLostFocus (object sender, EventArgs e)                   
1340                 {                       
1341                         has_focus = false;
1342                         
1343                         if (FocusedItem != -1)
1344                                 InvalidateItem (FocusedItem);
1345                 }               
1346
1347                 private void OnKeyDownLB (object sender, KeyEventArgs e)
1348                 {                                       
1349                         int new_item = -1;
1350                         
1351                         if (Items.Count == 0)
1352                                 return;
1353
1354                         switch (e.KeyCode) {
1355                                 
1356                                 case Keys.ControlKey:
1357                                         ctrl_pressed = true;
1358                                         break;
1359                                         
1360                                 case Keys.ShiftKey:
1361                                         shift_pressed = true;
1362                                         break;
1363                                         
1364                                 case Keys.Home:
1365                                         new_item = NavigateItemVisually (ItemNavigation.First);
1366                                         break;  
1367
1368                                 case Keys.End:
1369                                         new_item = NavigateItemVisually (ItemNavigation.Last);
1370                                         break;  
1371
1372                                 case Keys.Up:
1373                                         new_item = NavigateItemVisually (ItemNavigation.Previous);
1374                                         break;                          
1375         
1376                                 case Keys.Down:                         
1377                                         new_item = NavigateItemVisually (ItemNavigation.Next);
1378                                         break;
1379                                 
1380                                 case Keys.PageUp:
1381                                         new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
1382                                         break;                          
1383         
1384                                 case Keys.PageDown:                             
1385                                         new_item = NavigateItemVisually (ItemNavigation.NextPage);
1386                                         break;
1387
1388                                 case Keys.Right:
1389                                         if (multicolumn == true) {
1390                                                 new_item = NavigateItemVisually (ItemNavigation.NextColumn);
1391                                         }
1392                                         break;                          
1393         
1394                                 case Keys.Left:                 
1395                                         if (multicolumn == true) {      
1396                                                 new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
1397                                         }
1398                                         break;
1399                                         
1400                                 case Keys.Space:
1401                                         if (selection_mode == SelectionMode.MultiSimple) {
1402                                                 SelectedItemFromNavigation (FocusedItem);
1403                                         }
1404                                         break;
1405                                 
1406
1407                                 default:
1408                                         break;
1409                                 }
1410                                 
1411                                 if (new_item != -1) {
1412                                         FocusedItem = new_item;
1413                                         if (selection_mode != SelectionMode.MultiSimple && selection_mode != SelectionMode.None) {
1414                                                 SelectedItemFromNavigation (new_item);
1415                                         }
1416                                 }
1417                 }
1418                 
1419                 private void OnKeyUpLB (object sender, KeyEventArgs e)                  
1420                 {
1421                         switch (e.KeyCode) {
1422                                 case Keys.ControlKey:
1423                                         ctrl_pressed = false;
1424                                         break;
1425                                 case Keys.ShiftKey:
1426                                         shift_pressed = false;
1427                                         break;
1428                                 default: 
1429                                         break;
1430                         }
1431                 }               
1432
1433                 internal void InvalidateItem (int index)
1434                 {
1435                         Rectangle bounds = GetItemDisplayRectangle (index, top_index);
1436                         if (ClientRectangle.IntersectsWith (bounds))
1437                                 Invalidate (bounds);
1438                 }
1439
1440                 internal virtual void OnItemClick (int index)
1441                 {
1442                         OnSelectedIndexChanged  (EventArgs.Empty);
1443                         OnSelectedValueChanged (EventArgs.Empty);
1444                 }
1445
1446                 int anchor = -1;
1447                 int[] prev_selection;
1448                 bool button_pressed = false;
1449
1450                 private void SelectExtended (int index)
1451                 {
1452                         SuspendLayout ();
1453
1454                         ArrayList new_selection = new ArrayList ();
1455                         int start = anchor < index ? anchor : index;
1456                         int end = anchor > index ? anchor : index;
1457                         for (int i = start; i <= end; i++)
1458                                 new_selection.Add (i);
1459
1460                         if (ctrl_pressed)
1461                                 foreach (int i in prev_selection)
1462                                         if (!selection.Contains (i))
1463                                                 new_selection.Add (i);
1464
1465                         foreach (int i in SelectedIndices)
1466                                 if (!new_selection.Contains (i))
1467                                         UnSelectItem (i, true);
1468
1469                         foreach (int i in new_selection)
1470                                 if (!SelectedIndices.Contains (i))
1471                                         SelectItem (i);
1472                         ResumeLayout ();
1473                 }
1474
1475                 private void OnMouseDownLB (object sender, MouseEventArgs e)
1476                 {
1477                         int index = IndexAtClientPoint (e.X, e.Y);
1478                         
1479                         if (index == -1)
1480                                 return;
1481
1482                         switch (SelectionMode) {
1483                         case SelectionMode.One:
1484                                 if (SelectedIndex != index) {
1485                                         UnSelectItem (SelectedIndex, true);
1486                                         SelectItem (index);
1487                                 }
1488                                 selected_index = index;
1489                                 break;
1490
1491                         case SelectionMode.MultiSimple:
1492                                 if (SelectedIndices.Contains (index))
1493                                         UnSelectItem (index, true);
1494                                 else
1495                                         SelectItem (index);
1496                                 break;
1497
1498                         case SelectionMode.MultiExtended:
1499                                 shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1500                                 ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1501
1502                                 if (ctrl_pressed) {
1503                                         prev_selection = new int [selection.Count];
1504                                         SelectedIndices.CopyTo (prev_selection, 0);
1505                                 } else
1506                                         ClearSelected ();
1507
1508                                 if (!shift_pressed)
1509                                         anchor = index;
1510
1511                                 SelectExtended (index);
1512                                 break;
1513
1514                         case SelectionMode.None:
1515                         default:
1516                                 return;
1517                         }
1518                                 
1519                         button_pressed = true;
1520                         FocusedItem = index;
1521                 }
1522
1523                 private void OnMouseMoveLB (object sender, MouseEventArgs e)
1524                 {
1525                         if (!button_pressed)
1526                                 return;
1527
1528                         int index = IndexAtClientPoint (e.X, e.Y);
1529
1530                         switch (SelectionMode) {
1531                         case SelectionMode.One:
1532                                 if (index == selected_index)
1533                                         return;
1534
1535                                 UnSelectItem (SelectedIndex, true);
1536                                 SelectItem (index);
1537                                 selected_index = index;
1538                                 break;
1539
1540                         case SelectionMode.MultiSimple:
1541                                 break;
1542
1543                         case SelectionMode.MultiExtended:
1544                                 SelectExtended (index);
1545                                 break;
1546
1547                         case SelectionMode.None:
1548                         default:
1549                                 return;
1550                         }
1551
1552                         FocusedItem = index;
1553                 }
1554
1555                 private void OnMouseUpLB (object sender, MouseEventArgs e)
1556                 {
1557                         if (!button_pressed)
1558                                 return;
1559
1560                         int index = IndexAtClientPoint (e.X, e.Y);
1561                         OnItemClick (index);
1562                         button_pressed = ctrl_pressed = shift_pressed = false;
1563                 }
1564
1565                 private void Scroll (ScrollBar scrollbar, int delta)
1566                 {
1567                         if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled)
1568                                 return;
1569
1570                         int max;
1571                         if (scrollbar == hscrollbar)
1572                                 max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1;
1573                         else
1574                                 max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1;
1575
1576                         int val = scrollbar.Value + delta;
1577                         if (val > max)
1578                                 val = max;
1579                         else if (val < scrollbar.Minimum)
1580                                 val = scrollbar.Minimum;
1581                         scrollbar.Value = val;
1582                 }
1583
1584                 private void OnMouseWheelLB (object sender, MouseEventArgs me)
1585                 {
1586                         if (Items.Count == 0)
1587                                 return;
1588
1589                         int lines = me.Delta / 120;
1590
1591                         if (MultiColumn)
1592                                 Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines);
1593                         else
1594                                 Scroll (vscrollbar, -lines);
1595                 }
1596
1597                 internal override void OnPaintInternal (PaintEventArgs pevent)
1598                 {
1599                         if (suspend_layout)
1600                                 return;
1601
1602                         Draw (pevent.ClipRectangle, pevent.Graphics);
1603                 }
1604
1605                 internal void RepositionScrollBars ()
1606                 {
1607                         if (vscrollbar.is_visible) {
1608                                 vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height);
1609                                 vscrollbar.Location = new Point (items_area.Width, 0);
1610                         }
1611
1612                         if (hscrollbar.is_visible) {
1613                                 hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height);
1614                                 hscrollbar.Location = new Point (0, items_area.Height);
1615                         }
1616                 }
1617
1618                 // Add an item in the Selection array and marks it visually as selected
1619                 private void SelectItem (int index)
1620                 {
1621                         if (index == -1 || SelectedIndices.Contains (index))
1622                                 return;
1623
1624                         selection.Add (Items[index]);
1625                         InvalidateItem (index);
1626                 }               
1627                 
1628                 // An item navigation operation (mouse or keyboard) has caused to select a new item
1629                 internal void SelectedItemFromNavigation (int index)
1630                 {
1631                         switch (SelectionMode) {
1632                                 case SelectionMode.None: // Do nothing
1633                                         break;
1634                                 case SelectionMode.One: {
1635                                         SelectedIndex = index;
1636                                         break;
1637                                 }
1638                                 case SelectionMode.MultiSimple: {
1639                                         if (SelectedIndex == -1) {
1640                                                 SelectedIndex = index;
1641                                         } else {
1642
1643                                                 if (SelectedIndices.Contains (index))
1644                                                         UnSelectItem (index, true);
1645                                                 else {
1646                                                         SelectItem (index);
1647                                                         OnSelectedIndexChanged  (new EventArgs ());
1648                                                         OnSelectedValueChanged (new EventArgs ());
1649                                                 }
1650                                         }
1651                                         break;
1652                                 }
1653                                 
1654                                 case SelectionMode.MultiExtended: {
1655                                         if (SelectedIndex == -1) {
1656                                                 SelectedIndex = index;
1657                                         } else {
1658
1659                                                 if (ctrl_pressed == false && shift_pressed == false) {
1660                                                         ClearSelected ();
1661                                                 }
1662                                                 
1663                                                 if (shift_pressed == true) {
1664                                                         ShiftSelection (index);
1665                                                 } else { // ctrl_pressed or single item
1666                                                         SelectItem (index);
1667                                                 }
1668                                                 
1669                                                 OnSelectedIndexChanged  (new EventArgs ());
1670                                                 OnSelectedValueChanged (new EventArgs ());
1671                                         }
1672                                         break;
1673                                 }                               
1674                                 
1675                                 default:
1676                                         break;
1677                         }                       
1678                 }
1679                 
1680                 private void ShiftSelection (int index)
1681                 {
1682                         int shorter_item = -1, dist = Items.Count + 1, cur_dist;
1683                         
1684                         foreach (int idx in selected_indices) {
1685                                 if (idx > index) {
1686                                         cur_dist = idx - index;
1687                                 }
1688                                 else {
1689                                         cur_dist = index - idx;                                 
1690                                 }
1691                                                 
1692                                 if (cur_dist < dist) {
1693                                         dist = cur_dist;
1694                                         shorter_item = idx;
1695                                 }
1696                         }
1697                         
1698                         if (shorter_item != -1) {
1699                                 int start, end;
1700                                 
1701                                 if (shorter_item > index) {
1702                                         start = index;
1703                                         end = shorter_item;
1704                                 } else {
1705                                         start = shorter_item;
1706                                         end = index;
1707                                 }
1708                                 
1709                                 ClearSelected ();
1710                                 for (int idx = start; idx <= end; idx++) {
1711                                         SelectItem (idx);       
1712                                 }
1713                         }
1714                 }
1715                 
1716                 internal int FocusedItem {
1717                         get { return focused_item; }
1718                         set {                   
1719                                 if (focused_item == value)
1720                                         return;
1721
1722                                 int prev = focused_item;                        
1723                         
1724                                 focused_item = value;
1725                         
1726                                 if (has_focus == false)
1727                                         return;
1728
1729                                 if (prev != -1)
1730                                         InvalidateItem (prev);
1731                         
1732                                 if (value != -1)
1733                                         InvalidateItem (value);
1734                         }
1735                 }
1736
1737                 // Removes an item in the Selection array and marks it visually as unselected
1738                 private void UnSelectItem (int index, bool remove)
1739                 {
1740                         if (index == -1)
1741                                 return;
1742
1743                         if (remove)
1744                                 selection.Remove (Items[index]);
1745
1746                         InvalidateItem (index);
1747                 }
1748
1749                 StringFormat string_format;
1750                 internal StringFormat StringFormat {
1751                         get {
1752                                 if (string_format == null) {
1753                                         string_format = new StringFormat ();
1754                                         if (RightToLeft == RightToLeft.Yes)
1755                                                 string_format.Alignment = StringAlignment.Far;
1756                                         else
1757                                                 string_format.Alignment = StringAlignment.Near;
1758                                         if (use_tabstops)
1759                                                 string_format.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
1760                                 }
1761                                 return string_format;
1762                         }
1763
1764                 }
1765
1766                 internal virtual void CollectionChanged ()
1767                 {
1768                         if (sorted) 
1769                                 Sort ();
1770                         
1771                         if (Items.Count == 0) {
1772                                 selected_index = -1;
1773                                 focused_item = -1;
1774                                 top_index = 0;
1775                         }
1776                         
1777                         if (!IsHandleCreated || suspend_layout)
1778                                 return;
1779
1780                         Layout ();
1781
1782                         base.Refresh ();
1783                 }
1784
1785                 private void UpdateBounds ()
1786                 {
1787                         if (requested_height == -1)
1788                                 return;
1789
1790                         SetBounds(0, 0, 0, requested_height, BoundsSpecified.Height);
1791                 }
1792
1793                 private void UpdateScrollBars ()
1794                 {
1795                         items_area = ClientRectangle;
1796                         if (UpdateHorizontalScrollBar ()) {
1797                                 items_area.Height -= hscrollbar.Height;
1798                                 if (UpdateVerticalScrollBar ()) {
1799                                         items_area.Width -= vscrollbar.Width;
1800                                         UpdateHorizontalScrollBar ();
1801                                 }
1802                         } else if (UpdateVerticalScrollBar ()) {
1803                                 items_area.Width -= vscrollbar.Width;
1804                                 if (UpdateHorizontalScrollBar ()) {
1805                                         items_area.Height -= hscrollbar.Height;
1806                                         UpdateVerticalScrollBar ();
1807                                 }
1808                         }
1809
1810                         RepositionScrollBars ();
1811                 }
1812
1813                 /* Determines if the horizontal scrollbar has to be displyed */
1814                 private bool UpdateHorizontalScrollBar ()
1815                 {
1816                         bool show = false;
1817                         bool enabled = true;
1818
1819                         if (MultiColumn) {
1820                                 if (canvas_size.Width > items_area.Width) {
1821                                         show = true;
1822                                         hscrollbar.Maximum  = canvas_size.Width / ColumnWidthInternal - 1;
1823                                 } else if (ScrollAlwaysVisible == true) {
1824                                         enabled = false;
1825                                         show = true;
1826                                         hscrollbar.Maximum  = 0;
1827                                 }
1828                         } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) {
1829                                 show = true;                                    
1830                                 hscrollbar.Maximum = canvas_size.Width;
1831                                 hscrollbar.LargeChange = items_area.Width;
1832                         }
1833
1834                         hbar_offset = hscrollbar.Value;
1835                         hscrollbar.Enabled = enabled;
1836                         hscrollbar.Visible = show;
1837
1838                         return show;
1839                 }
1840
1841                 /* Determines if the vertical scrollbar has to be displyed */
1842                 private bool UpdateVerticalScrollBar ()
1843                 {
1844                         if (MultiColumn) {
1845                                 vscrollbar.Visible = false;
1846                                 return false;
1847                         }
1848
1849                         bool show = false;
1850                         bool enabled = true;
1851                         if (canvas_size.Height > items_area.Height) {
1852                                 show = true;
1853                                 vscrollbar.Maximum = Items.Count - 1;
1854                                 vscrollbar.LargeChange = items_area.Height / ItemHeight;
1855                         } else if (ScrollAlwaysVisible) {
1856                                 show = true;
1857                                 enabled = false;
1858                                 vscrollbar.Maximum = 0;
1859                         }
1860
1861                         vscrollbar.Enabled = enabled;
1862                         vscrollbar.Visible = show;
1863
1864                         return show;
1865                 }
1866
1867                 // Value Changed
1868                 private void VerticalScrollEvent (object sender, EventArgs e)
1869                 {
1870                         int top_item = top_index;
1871
1872                         top_index = /*row_count + */ vscrollbar.Value;
1873                         last_visible_index = LastVisibleItem ();
1874
1875                         int diff = top_item - top_index;
1876
1877                         XplatUI.ScrollWindow (Handle, items_area, 0, ItemHeight * diff, false);
1878                 }
1879
1880                 #endregion Private Methods
1881
1882                 [ListBindable (false)]
1883                 public class ObjectCollection : IList, ICollection, IEnumerable
1884                 {
1885                         internal class ListObjectComparer : IComparer
1886                         {
1887                                 private ListBox owner;
1888                         
1889                                 public ListObjectComparer (ListBox owner)
1890                                 {
1891                                         this.owner = owner;
1892                                 }
1893                                 
1894                                 public int Compare (object a, object b)
1895                                 {
1896                                         string str1 = a.ToString ();
1897                                         string str2 = b.ToString ();                                    
1898                                         return str1.CompareTo (str2);
1899                                 }
1900                         }
1901
1902                         private ListBox owner;
1903                         internal ArrayList object_items = new ArrayList ();
1904
1905                         public ObjectCollection (ListBox owner)
1906                         {
1907                                 this.owner = owner;
1908                         }
1909
1910                         public ObjectCollection (ListBox owner, object[] obj)
1911                         {
1912                                 this.owner = owner;
1913                                 AddRange (obj);
1914                         }
1915
1916                         public ObjectCollection (ListBox owner,  ObjectCollection obj)
1917                         {
1918                                 this.owner = owner;
1919                                 AddRange (obj);
1920                         }
1921
1922                         #region Public Properties
1923                         public int Count {
1924                                 get { return object_items.Count; }
1925                         }
1926
1927                         public bool IsReadOnly {
1928                                 get { return false; }
1929                         }
1930
1931                         [Browsable(false)]
1932                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1933                         public virtual object this [int index] {
1934                                 get {
1935                                         if (index < 0 || index >= Count)
1936                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1937
1938                                         return object_items[index];
1939                                 }
1940                                 set {
1941                                         if (index < 0 || index >= Count)
1942                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1943                                         if (value == null)
1944                                                 throw new ArgumentNullException ("value");
1945
1946                                         object_items[index] = value;
1947                                         owner.CollectionChanged ();
1948                                 }
1949                         }
1950
1951                         bool ICollection.IsSynchronized {
1952                                 get { return false; }
1953                         }
1954
1955                         object ICollection.SyncRoot {
1956                                 get { return this; }
1957                         }
1958
1959                         bool IList.IsFixedSize {
1960                                 get { return false; }
1961                         }
1962
1963                         #endregion Public Properties
1964                         
1965                         #region Public Methods
1966                         public int Add (object item)
1967                         {
1968                                 int idx;
1969
1970                                 idx = AddItem (item);
1971                                 owner.CollectionChanged ();
1972                                 return idx;
1973                         }
1974
1975                         public void AddRange (object[] items)
1976                         {
1977                                 foreach (object mi in items)
1978                                         AddItem (mi);
1979
1980                                 owner.CollectionChanged ();
1981                         }
1982
1983                         public void AddRange (ObjectCollection col)
1984                         {
1985                                 foreach (object mi in col)
1986                                         AddItem (mi);
1987
1988                                 owner.CollectionChanged ();
1989                         }
1990
1991                         internal void AddRange (IList list)
1992                         {
1993                                 foreach (object mi in list)
1994                                         AddItem (mi);
1995
1996                                 owner.CollectionChanged ();
1997                         }
1998
1999                         public virtual void Clear ()
2000                         {
2001                                 owner.selection.Clear ();
2002                                 object_items.Clear ();
2003                                 owner.CollectionChanged ();
2004                         }
2005                         public bool Contains (object obj)
2006                         {
2007                                 return object_items.Contains (obj);
2008                         }
2009
2010                         public void CopyTo (object[] dest, int arrayIndex)
2011                         {
2012                                 object_items.CopyTo (dest, arrayIndex);
2013                         }
2014
2015                         void ICollection.CopyTo (Array dest, int index)
2016                         {
2017                                 object_items.CopyTo (dest, index);
2018                         }
2019
2020                         public IEnumerator GetEnumerator ()
2021                         {
2022                                 return object_items.GetEnumerator ();
2023                         }
2024
2025                         int IList.Add (object item)
2026                         {
2027                                 return Add (item);
2028                         }
2029
2030                         public int IndexOf (object value)
2031                         {
2032                                 return object_items.IndexOf (value);
2033                         }
2034
2035                         public void Insert (int index,  object item)
2036                         {
2037                                 if (index < 0 || index > Count)
2038                                         throw new ArgumentOutOfRangeException ("Index of out range");
2039                                         
2040                                 owner.BeginUpdate ();
2041                                 object_items.Insert (index, item);
2042                                 owner.CollectionChanged ();
2043                                 owner.EndUpdate ();
2044                         }
2045
2046                         public void Remove (object value)
2047                         {                               
2048                                 RemoveAt (IndexOf (value));                             
2049                         }
2050
2051                         public void RemoveAt (int index)
2052                         {
2053                                 if (index < 0 || index >= Count)
2054                                         throw new ArgumentOutOfRangeException ("Index of out range");
2055
2056                                 owner.selection.Remove (object_items [index]);
2057                                 object_items.RemoveAt (index);
2058                                 owner.CollectionChanged ();
2059                         }
2060                         #endregion Public Methods
2061
2062                         #region Private Methods
2063                         internal int AddItem (object item)
2064                         {
2065                                 if (item == null)
2066                                         throw new ArgumentNullException ("item");
2067
2068                                 int cnt = object_items.Count;
2069                                 object_items.Add (item);
2070                                 return cnt;
2071                         }
2072
2073                         internal void Sort ()
2074                         {
2075                                 object_items.Sort (new ListObjectComparer (owner));
2076                         }
2077
2078                         #endregion Private Methods
2079                 }
2080
2081                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2082                 {
2083                         private ListBox owner;
2084
2085                         public SelectedIndexCollection (ListBox owner)
2086                         {
2087                                 this.owner = owner;
2088                         }
2089
2090                         #region Public Properties
2091                         [Browsable (false)]
2092                         public int Count {
2093                                 get { return owner.selection.Count; }
2094                         }
2095
2096                         public bool IsReadOnly {
2097                                 get { return true; }
2098                         }
2099
2100                         public int this [int index] {
2101                                 get {
2102                                         if (index < 0 || index >= Count)
2103                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2104
2105                                         return owner.Items.IndexOf (owner.selection [index]);
2106                                 }
2107                         }
2108
2109                         bool ICollection.IsSynchronized {
2110                                 get { return true; }
2111                         }
2112
2113                         bool IList.IsFixedSize{
2114                                 get { return true; }
2115                         }
2116
2117                         object ICollection.SyncRoot {
2118                                 get { return this; }
2119                         }
2120
2121                         #endregion Public Properties
2122
2123                         #region Public Methods
2124                         public bool Contains (int selectedIndex)
2125                         {
2126                                 foreach (object o in owner.selection)
2127                                         if (owner.Items.IndexOf (o) == selectedIndex)
2128                                                 return true;
2129                                 return false;
2130                         }
2131
2132                         public void CopyTo (Array dest, int index)
2133                         {
2134                                 foreach (object o in owner.selection)
2135                                         dest.SetValue(owner.Items.IndexOf (o), index++);
2136                         }
2137
2138                         public IEnumerator GetEnumerator ()
2139                         {
2140                                 //FIXME: write an enumerator that uses owner.selection.GetEnumerator
2141                                 //  so that invalidation is write on selection changes
2142                                 ArrayList indices = new ArrayList ();
2143                                 foreach (object o in owner.selection)
2144                                         indices.Add (owner.Items.IndexOf (o));
2145                                 return indices.GetEnumerator ();
2146                         }
2147
2148                         int IList.Add (object obj)
2149                         {
2150                                 throw new NotSupportedException ();
2151                         }
2152
2153                         void IList.Clear ()
2154                         {
2155                                 throw new NotSupportedException ();
2156                         }
2157
2158                         bool IList.Contains (object selectedIndex)
2159                         {
2160                                 return Contains ((int)selectedIndex);
2161                         }
2162
2163                         int IList.IndexOf (object selectedIndex)
2164                         {
2165                                 return IndexOf ((int) selectedIndex);
2166                         }
2167
2168                         void IList.Insert (int index, object value)
2169                         {
2170                                 throw new NotSupportedException ();
2171                         }
2172
2173                         void IList.Remove (object value)
2174                         {
2175                                 throw new NotSupportedException ();
2176                         }
2177
2178                         void IList.RemoveAt (int index)
2179                         {
2180                                 throw new NotSupportedException ();
2181                         }
2182
2183                         object IList.this[int index]{
2184                                 get {return owner.Items.IndexOf (owner.selection [index]); }
2185                                 set {throw new NotImplementedException (); }
2186                         }
2187
2188                         public int IndexOf (int selectedIndex)
2189                         {
2190                                 for (int i = 0; i < owner.selection.Count; i++)
2191                                         if (owner.Items.IndexOf (owner.selection [i]) == selectedIndex)
2192                                                 return i;
2193                                 return -1;
2194                         }
2195                         #endregion Public Methods
2196                 }
2197
2198                 public class SelectedObjectCollection : IList, ICollection, IEnumerable
2199                 {
2200                         private ListBox owner;
2201
2202                         public SelectedObjectCollection (ListBox owner)
2203                         {
2204                                 this.owner = owner;
2205                         }
2206
2207                         #region Public Properties
2208                         public int Count {
2209                                 get { return owner.selection.Count; }
2210                         }
2211
2212                         public bool IsReadOnly {
2213                                 get { return true; }
2214                         }
2215
2216                         [Browsable(false)]
2217                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2218                         public object this [int index] {
2219                                 get {
2220                                         if (index < 0 || index >= Count)
2221                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2222
2223                                         return owner.selection [index];
2224                                 }
2225                                 set {throw new NotSupportedException ();}
2226                         }
2227
2228                         bool ICollection.IsSynchronized {
2229                                 get { return true; }
2230                         }
2231
2232                         object ICollection.SyncRoot {
2233                                 get { return this; }
2234                         }
2235
2236                         bool IList.IsFixedSize {
2237                                 get { return true; }
2238                         }
2239
2240                         #endregion Public Properties
2241
2242                         #region Public Methods
2243                         public bool Contains (object selectedObject)
2244                         {
2245                                 return owner.selection.Contains (selectedObject);
2246                         }
2247
2248                         public void CopyTo (Array dest, int index)
2249                         {
2250                                 owner.selection.CopyTo (dest, index);
2251                         }
2252
2253                         int IList.Add (object value)
2254                         {
2255                                 throw new NotSupportedException ();
2256                         }
2257
2258                         void IList.Clear ()
2259                         {
2260                                 throw new NotSupportedException ();
2261                         }
2262
2263                         void IList.Insert (int index, object value)
2264                         {
2265                                 throw new NotSupportedException ();
2266                         }
2267
2268                         void IList.Remove (object value)
2269                         {
2270                                 throw new NotSupportedException ();
2271                         }
2272
2273                         void IList.RemoveAt (int index)
2274                         {
2275                                 throw new NotSupportedException ();
2276                         }
2277         
2278                         public int IndexOf (object item)
2279                         {
2280                                 return owner.selection.IndexOf (item);
2281                         }
2282
2283                         public IEnumerator GetEnumerator ()
2284                         {
2285                                 return owner.selection.GetEnumerator ();
2286                         }
2287
2288                         #endregion Public Methods
2289                 }
2290
2291         }
2292 }
2293