2008-12-02 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ComboBox.cs
index ecadd3f5399f1e261d9e5ef5a08f8003d1bb9b49..4e4dd460b73b5878f68fa88040590259cb09b597 100644 (file)
@@ -70,6 +70,7 @@ namespace System.Windows.Forms
                private Rectangle button_area;
                private Rectangle listbox_area;
                private const int button_width = 16;
+               bool drop_down_button_entered;
 #if NET_2_0
                private AutoCompleteStringCollection auto_complete_custom_source = null;
                private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None;
@@ -111,6 +112,8 @@ namespace System.Windows.Forms
                        MouseUp += new MouseEventHandler (OnMouseUpCB);
                        MouseMove += new MouseEventHandler (OnMouseMoveCB);
                        MouseWheel += new MouseEventHandler (OnMouseWheelCB);
+                       MouseEnter += new EventHandler (OnMouseEnter);
+                       MouseLeave += new EventHandler (OnMouseLeave);
                        KeyDown +=new KeyEventHandler(OnKeyDownCB);
                }
 
@@ -243,6 +246,8 @@ namespace System.Windows.Forms
 
                                if(auto_complete_custom_source != null)
                                        auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
+
+                               SetTextBoxAutoCompleteData ();
                        }
                }
 
@@ -260,6 +265,7 @@ namespace System.Windows.Forms
                                        throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteMode", value));
 
                                auto_complete_mode = value;
+                               SetTextBoxAutoCompleteData ();
                        }
                }
 
@@ -277,6 +283,25 @@ namespace System.Windows.Forms
                                        throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteSource", value));
 
                                auto_complete_source = value;
+                               SetTextBoxAutoCompleteData ();
+                       }
+               }
+
+               void SetTextBoxAutoCompleteData ()
+               {
+                       if (textbox_ctrl == null)
+                               return;
+
+                       textbox_ctrl.AutoCompleteMode = auto_complete_mode;
+
+                       if (auto_complete_source == AutoCompleteSource.ListItems) {
+                               textbox_ctrl.AutoCompleteSource = AutoCompleteSource.CustomSource;
+                               textbox_ctrl.AutoCompleteCustomSource = null;
+                               textbox_ctrl.AutoCompleteInternalSource = this;
+                       } else {
+                               textbox_ctrl.AutoCompleteSource = auto_complete_source;
+                               textbox_ctrl.AutoCompleteCustomSource = auto_complete_custom_source;
+                               textbox_ctrl.AutoCompleteInternalSource = null;
                        }
                }
 #endif
@@ -319,6 +344,7 @@ namespace System.Windows.Forms
                [DefaultValue ((string)null)]
                [AttributeProvider (typeof (IListSource))]
                [RefreshProperties (RefreshProperties.Repaint)]
+               [MWFCategory("Data")]
                public new object DataSource {
                        get { return base.DataSource; }
                        set { base.DataSource = value; }
@@ -331,6 +357,7 @@ namespace System.Windows.Forms
 
                [RefreshProperties(RefreshProperties.Repaint)]
                [DefaultValue (DrawMode.Normal)]
+               [MWFCategory("Behavior")]
                public DrawMode DrawMode {
                        get { return draw_mode; }
                        set {
@@ -353,6 +380,7 @@ namespace System.Windows.Forms
                [Browsable (true)]
                [DefaultValue (106)]
                [EditorBrowsable (EditorBrowsableState.Always)]
+               [MWFCategory("Behavior")]
                public int DropDownHeight {
                        get {
                                return drop_down_height;
@@ -369,6 +397,7 @@ namespace System.Windows.Forms
 
                [DefaultValue (ComboBoxStyle.DropDown)]
                [RefreshProperties(RefreshProperties.Repaint)]
+               [MWFCategory("Appearance")]
                public ComboBoxStyle DropDownStyle {
                        get { return dropdown_style; }
                        set {
@@ -400,11 +429,14 @@ namespace System.Windows.Forms
                                        show_dropdown_button = false;
                                        
                                        CreateComboListBox ();
-
-                                       if (IsHandleCreated) {
-                                               Controls.AddImplicit (listbox_ctrl);
-                                               listbox_ctrl.Visible = true;
-                                       }
+                                       Controls.AddImplicit (listbox_ctrl);
+                                       listbox_ctrl.Visible = true;
+
+                                       // This should give us a 150 default height
+                                       // for Simple mode if size hasn't been set
+                                       // (DefaultSize doesn't work for us in this case)
+                                       if (requested_height == -1)
+                                               requested_height = 150;
                                } else {
                                        show_dropdown_button = true;
                                        button_state = ButtonState.Normal;
@@ -417,11 +449,15 @@ namespace System.Windows.Forms
                                                textbox_ctrl.Text = GetItemText (selected_item);
                                        textbox_ctrl.BorderStyle = BorderStyle.None;
                                        textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit);
+                                       textbox_ctrl.KeyPress += new KeyPressEventHandler (OnTextKeyPress);
                                        textbox_ctrl.Click += new EventHandler (OnTextBoxClick);
                                        textbox_ctrl.ContextMenu = ContextMenu;
 
                                        if (IsHandleCreated == true)
                                                Controls.AddImplicit (textbox_ctrl);
+#if NET_2_0
+                                       SetTextBoxAutoCompleteData ();
+#endif
                                }
                                
                                ResumeLayout ();
@@ -433,6 +469,7 @@ namespace System.Windows.Forms
                        }
                }
 
+               [MWFCategory("Behavior")]
                public int DropDownWidth {
                        get { 
                                if (dropdown_width == -1)
@@ -472,13 +509,14 @@ namespace System.Windows.Forms
                                if (value) 
                                        DropDownListBox ();
                                else
-                                       listbox_ctrl.Hide ();
+                                       listbox_ctrl.HideWindow ();
                        }
                }
 
 #if NET_2_0
                [DefaultValue (FlatStyle.Standard)]
                [Localizable (true)]
+               [MWFCategory("Appearance")]
                public FlatStyle FlatStyle {
                        get { return flat_style; }
                        set {
@@ -508,6 +546,7 @@ namespace System.Windows.Forms
 
                [DefaultValue (true)]
                [Localizable (true)]
+               [MWFCategory("Behavior")]
                public bool IntegralHeight {
                        get { return integral_height; }
                        set {
@@ -520,6 +559,7 @@ namespace System.Windows.Forms
                }
 
                [Localizable (true)]
+               [MWFCategory("Behavior")]
                public int ItemHeight {
                        get {
                                if (item_height == -1) {
@@ -552,12 +592,14 @@ namespace System.Windows.Forms
 #if NET_2_0
                [MergableProperty (false)]
 #endif
+               [MWFCategory("Data")]
                public ComboBox.ObjectCollection Items {
                        get { return items; }
                }
 
                [DefaultValue (8)]
                [Localizable (true)]
+               [MWFCategory("Behavior")]
                public int MaxDropDownItems {
                        get { return maxdrop_items; }
                        set {
@@ -578,6 +620,7 @@ namespace System.Windows.Forms
 
                [DefaultValue (0)]
                [Localizable (true)]
+               [MWFCategory("Behavior")]
                public int MaxLength {
                        get { return max_length; }
                        set {
@@ -615,9 +658,7 @@ namespace System.Windows.Forms
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [Browsable (false)]
                public int PreferredHeight {
-                       get {
-                               return ItemHeight + 6;
-                       }
+                       get { return Font.Height + 8; }
                }
 
                [Browsable (false)]
@@ -634,9 +675,9 @@ namespace System.Windows.Forms
 
                                if (dropdown_style != ComboBoxStyle.DropDownList) {
                                        if (value == -1)
-                                               SetControlText("");
+                                               SetControlText (string.Empty, false);
                                        else
-                                               SetControlText (GetItemText (Items [value]));
+                                               SetControlText (GetItemText (Items [value]), false);
                                }
 
                                if (DropDownStyle == ComboBoxStyle.DropDownList)
@@ -660,7 +701,11 @@ namespace System.Windows.Forms
                                object item = selected_index == -1 ? null : Items [selected_index];
                                if (item == value)
                                        return;
-                               SelectedIndex = Items.IndexOf (value);
+
+                               if (value == null)
+                                       SelectedIndex = -1;
+                               else
+                                       SelectedIndex = Items.IndexOf (value);
                        }
                }
                
@@ -724,6 +769,7 @@ namespace System.Windows.Forms
                }
 
                [DefaultValue (false)]
+               [MWFCategory("Behavior")]
                public bool Sorted {
                        get { return sorted; }
                        set {
@@ -757,7 +803,7 @@ namespace System.Windows.Forms
                                if (value == null) {
                                        if (SelectedIndex == -1) {
                                                if (dropdown_style != ComboBoxStyle.DropDownList)
-                                                       SetControlText ("");
+                                                       SetControlText (string.Empty, false);
                                        } else {
                                                SelectedIndex = -1;
                                        }
@@ -786,6 +832,24 @@ namespace System.Windows.Forms
 
                #endregion Public Properties
 
+               #region Internal Properties
+               internal Rectangle ButtonArea {
+                       get { return button_area; }
+               }
+
+               internal Rectangle TextArea {
+                       get { return text_area; }
+               }
+               #endregion
+
+               #region UIA Framework Properties
+
+               internal TextBox UIATextBox {
+                       get { return textbox_ctrl; }
+               }
+
+               #endregion UIA Framework Properties
+
                #region Public Methods
 #if NET_2_0
                [Obsolete ("This method has been deprecated")]
@@ -972,25 +1036,37 @@ namespace System.Windows.Forms
                {
                        base.OnDisplayMemberChanged (e);
 
-                       if (DataManager == null || !IsHandleCreated)
+                       if (DataManager == null)
+                               return;
+
+                       if (selected_index != -1 && DropDownStyle != ComboBoxStyle.DropDownList)
+                               SetControlText (GetItemText (Items [selected_index]), true);
+
+                       if (!IsHandleCreated)
                                return;
 
-                       BindDataItems ();
                        SelectedIndex = DataManager.Position;
+                       Invalidate ();
                }
 
                protected virtual void OnDrawItem (DrawItemEventArgs e)
                {
+                       DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
+
+               internal void HandleDrawItem (DrawItemEventArgs e)
+               {
+                       // Only raise OnDrawItem if we are in an OwnerDraw mode
                        switch (DrawMode) {
-                       case DrawMode.OwnerDrawFixed:
-                       case DrawMode.OwnerDrawVariable:
-                               DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
-                               if (eh != null)
-                                       eh (this, e);
-                               break;
-                       default:
-                               ThemeEngine.Current.DrawComboBoxItem (this, e);
-                               break;
+                               case DrawMode.OwnerDrawFixed:
+                               case DrawMode.OwnerDrawVariable:
+                                       OnDrawItem (e);
+                                       break;
+                               default:
+                                       ThemeEngine.Current.DrawComboBoxItem (this, e);
+                                       break;
                        }
                }
 
@@ -1024,10 +1100,8 @@ namespace System.Windows.Forms
                        if (textbox_ctrl != null)
                                textbox_ctrl.Font = Font;
                        
-                       if (!item_height_specified) {
-                               SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
-                               item_height = (int) sz.Height;
-                       }
+                       if (!item_height_specified)
+                               item_height = Font.Height + 2;
 
                        if (IntegralHeight)
                                UpdateComboBoxBounds ();
@@ -1088,10 +1162,13 @@ namespace System.Windows.Forms
                {
                        base.OnHandleCreated (e);
 
+                       SetBoundsInternal (Left, Top, Width, PreferredHeight, BoundsSpecified.None);
+
                        if (textbox_ctrl != null)
                                Controls.AddImplicit (textbox_ctrl);
 
                        LayoutComboBox ();
+                       UpdateComboBoxBounds ();
                }
 
                protected override void OnHandleDestroyed (EventArgs e)
@@ -1101,9 +1178,19 @@ namespace System.Windows.Forms
 
                protected override void OnKeyPress (KeyPressEventArgs e)
                {
-                       // int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex);
-                       //if (index != -1)
-                       //      SelectedIndex = index;
+                       if (dropdown_style == ComboBoxStyle.DropDownList) {
+                               int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex + 1);
+                               if (index != -1) {
+                                       SelectedIndex = index;
+                                       if (DroppedDown) { //Scroll into view
+                                               if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+                                                       listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
+                                               // Or, selecting an item earlier in the list.
+                                               if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+                                                       listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
+                                       }
+                               }
+                       }
 
                        base.OnKeyPress (e);
                }
@@ -1167,6 +1254,12 @@ namespace System.Windows.Forms
                        for (int i = 0; i < Items.Count; i++) {
                                RefreshItem (i);
                        }
+
+                       LayoutComboBox ();
+                       Refresh ();
+
+                       if (selected_index != -1 && DropDownStyle != ComboBoxStyle.DropDownList)
+                               SetControlText (GetItemText (Items [selected_index]), false);
                }
 
                public override void ResetText ()
@@ -1225,31 +1318,9 @@ namespace System.Windows.Forms
 #endif
 
 #if NET_2_0
-               private float current_factor_width = 1f;
-               
-               // WTF? WTF? WTF????
-               // I am sure this is tied to something I missed that makes this make sense.
-               // Every time you double the size of the control, subtract 4 pixels from it
                protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
                {
-                       // Never change the ComboBox's height
-                       specified &= ~BoundsSpecified.Height;
-
-                       int width = ClientSize.Width;
-                       
-                       // Go back to the original (un-4-subtracted) size
-                       if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width)
-                               width += (int)(((current_factor_width) - 1f) * 4.0f);
-                               
-                       Rectangle new_bounds = GetScaledBounds (new Rectangle (Location, new Size (width, ClientSize.Height)), factor, specified);
-                       
-                       // Subtract 4 for every time the control is 'doubled'
-                       if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width) {
-                               new_bounds.Width += (int)(((factor.Width * current_factor_width) - 1f) * -4.0f);
-                               current_factor_width *= factor.Width;
-                       }
-                               
-                       SetBounds (new_bounds.X, new_bounds.Y, new_bounds.Width, new_bounds.Height, specified);
+                       base.ScaleControl (factor, specified);
                }
 #endif
 
@@ -1280,21 +1351,14 @@ namespace System.Windows.Forms
 
                protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
                {
-                       if ((specified & BoundsSpecified.Height) != 0) {
-                               requested_height = height;
+                       bool vertically_anchored = (Anchor & AnchorStyles.Top) != 0 && (Anchor & AnchorStyles.Bottom) != 0;
+                       bool vertically_docked = Dock == DockStyle.Left || Dock == DockStyle.Right || Dock == DockStyle.Fill;
 
-                               if (DropDownStyle == ComboBoxStyle.Simple && height > PreferredHeight) {
-                                       if (IntegralHeight) {
-                                               int border = ThemeEngine.Current.Border3DSize.Height;
-                                               int lb_height = height - PreferredHeight - 2;
-                                               if (lb_height - 2 * border > ItemHeight) {
-                                                       int partial = (lb_height - 2 * border) % ItemHeight;
-                                                       height -= partial;
-                                               } else
-                                                       height = PreferredHeight;
-                                       }
-                               } else
-                                       height = PreferredHeight;
+                       if ((specified & BoundsSpecified.Height) != 0 ||
+                               (specified == BoundsSpecified.None && (vertically_anchored || vertically_docked))) {
+
+                               requested_height = height;
+                               height = SnapHeight (height);
                        }
 
                        base.SetBoundsCore (x, y, width, height, specified);
@@ -1330,6 +1394,13 @@ namespace System.Windows.Forms
                        case Msg.WM_KEYUP:
                        case Msg.WM_KEYDOWN:
                                Keys keys = (Keys) m.WParam.ToInt32 ();
+#if NET_2_0
+                               // Don't pass the message to base if auto complete is being used and available.
+                               if (textbox_ctrl != null && textbox_ctrl.CanNavigateAutoCompleteList) {
+                                       XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam);
+                                       return;
+                               }
+#endif
                                if (keys == Keys.Up || keys == Keys.Down)
                                        break;
                                goto case Msg.WM_CHAR;
@@ -1432,18 +1503,7 @@ namespace System.Windows.Forms
                        is_flat = style == FlatStyle.Flat || style == FlatStyle.Popup;
 #endif
 
-                       if (DropDownStyle == ComboBoxStyle.Simple)
-                               dc.FillRectangle (theme.ResPool.GetSolidBrush (Parent.BackColor), ClientRectangle);
-
-                       if (style == FlatStyle.Popup && (is_entered || Focused)) {
-                               Rectangle area = text_area;
-                               area.Height -= 1;
-                               area.Width -= 1;
-                               dc.DrawRectangle (theme.ResPool.GetPen (SystemColors.ControlDark), area);
-                               dc.DrawLine (theme.ResPool.GetPen (SystemColors.ControlDark), button_area.X - 1, button_area.Top, button_area.X - 1, button_area.Bottom);
-                       }
-                       if (!is_flat && clip.IntersectsWith (text_area))
-                               ControlPaint.DrawBorder3D (dc, text_area, Border3DStyle.Sunken);
+                       theme.ComboBoxDrawBackground (this, dc, clip, style);
 
                        int border = theme.Border3DSize.Width;
 
@@ -1462,28 +1522,42 @@ namespace System.Windows.Forms
                                }
                                
                                state |= DrawItemState.ComboBoxEdit;
-                               OnDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, ForeColor, BackColor));
+                               HandleDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, ForeColor, BackColor));
                        }
                        
                        if (show_dropdown_button) {
-                               dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
-
                                ButtonState current_state;
                                if (is_enabled)
                                        current_state = button_state;
                                else
                                        current_state = ButtonState.Inactive;
 
+                               if (is_flat || theme.ComboBoxNormalDropDownButtonHasTransparentBackground (this, current_state))
+                                       dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
+
                                if (is_flat) {
                                        theme.DrawFlatStyleComboButton (dc, button_area, current_state);
                                } else {
-                                       theme.CPDrawComboButton (dc, button_area, current_state);
+                                       theme.ComboBoxDrawNormalDropDownButton (this, dc, clip, button_area, current_state); 
                                }
                        }
                }
 
+               internal bool DropDownButtonEntered {
+                       get { return drop_down_button_entered; }
+                       private set {
+                               if (drop_down_button_entered == value)
+                                       return;
+                               drop_down_button_entered = value;
+                               if (ThemeEngine.Current.ComboBoxDropDownButtonHasHotElementStyle (this))
+                                       Invalidate (button_area);
+                       }
+               }
+
                internal void DropDownListBox ()
                {
+                       DropDownButtonEntered = false;
+
                        if (DropDownStyle == ComboBoxStyle.Simple)
                                return;
                        
@@ -1492,6 +1566,13 @@ namespace System.Windows.Forms
 
                        listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height));
 
+                       FindMatchOrSetIndex(SelectedIndex);
+
+#if NET_2_0
+                       if (textbox_ctrl != null)
+                               textbox_ctrl.HideAutoCompleteList ();
+#endif
+
                        if (listbox_ctrl.ShowWindow ())
                                dropped_down = true;
 
@@ -1505,6 +1586,7 @@ namespace System.Windows.Forms
                        if (DropDownStyle == ComboBoxStyle.Simple)
                                return;
                                
+                       FindMatchOrSetIndex (SelectedIndex);
                        button_state = ButtonState.Normal;
                        Invalidate (button_area);
                        dropped_down = false;
@@ -1539,11 +1621,16 @@ namespace System.Windows.Forms
                        return -1;
                }
 
+               // Search in the list for the substring, starting the search at the list 
+               // position specified, the search wraps thus covering all the list.
                internal int FindStringCaseInsensitive (string search, int start_index)
                {
                        if (search.Length == 0) {
                                return -1;
                        }
+                       // Accept from first item to after last item. i.e. all cases of (SelectedIndex+1).
+                       if (start_index < 0 || start_index > Items.Count)
+                               throw new ArgumentOutOfRangeException("start_index");
 
                        for (int i = 0; i < Items.Count; i++) {
                                int index = (i + start_index) % Items.Count;
@@ -1571,35 +1658,111 @@ namespace System.Windows.Forms
                        }
                }
 
+               internal void RestoreContextMenu ()
+               {
+                       textbox_ctrl.RestoreContextMenu ();
+               }
+
                private void OnKeyDownCB(object sender, KeyEventArgs e)
                {
                        if (Items.Count == 0)
                                return;
 
+                       int offset;
                        switch (e.KeyCode) 
                        {
                                case Keys.Up:
-                                       SelectedIndex = Math.Max(SelectedIndex-1, 0);
+                                       FindMatchOrSetIndex(Math.Max(SelectedIndex - 1, 0));
+
+                                       if (DroppedDown)
+                                               if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+                                                       listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
                                        break;
        
                                case Keys.Down:
-                                       SelectedIndex = Math.Min(SelectedIndex+1, Items.Count-1);
+                                       if ((e.Modifiers & Keys.Alt) == Keys.Alt)
+                                               DropDownListBox ();
+                                       else
+                                               FindMatchOrSetIndex(Math.Min(SelectedIndex + 1, Items.Count - 1));
+                                               
+                                       if (DroppedDown)
+                                               if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+                                                       listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
                                        break;
                                
                                case Keys.PageUp:
-                                       if (listbox_ctrl != null)
-                                               SelectedIndex = Math.Max(SelectedIndex- (listbox_ctrl.page_size-1), 0);
+                                       offset = listbox_ctrl == null ? MaxDropDownItems - 1 : listbox_ctrl.page_size - 1;
+                                       if (offset < 1)
+                                               offset = 1;
+
+                                       SelectedIndex = Math.Max (SelectedIndex - offset, 0);
+
+                                       if (DroppedDown)
+                                               if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+                                                       listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
                                        break;
        
                                case Keys.PageDown:
-                                       if (listbox_ctrl != null)
-                                               SelectedIndex = Math.Min(SelectedIndex+(listbox_ctrl.page_size-1), Items.Count-1);
+                                       if (SelectedIndex == -1) {
+                                               SelectedIndex = 0;
+                                               if (dropdown_style != ComboBoxStyle.Simple)
+                                                       return;
+                                       }
+
+                                       offset = listbox_ctrl == null ? MaxDropDownItems - 1 : listbox_ctrl.page_size - 1;
+                                       if (offset < 1)
+                                               offset = 1;
+
+                                       SelectedIndex = Math.Min (SelectedIndex + offset, Items.Count - 1);
+
+                                       if (DroppedDown)
+                                               if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+                                                       listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
                                        break;
                                
+                               case Keys.Enter:        
+                               case Keys.Escape:
+                                       DropDownListBoxFinished ();
+                                       break;
+                                       
+                               case Keys.Home:
+                                       if (dropdown_style == ComboBoxStyle.DropDownList) {
+                                               SelectedIndex = 0;
+
+                                               if (DroppedDown)
+                                                       if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+                                                               listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
+                                       }
+                                       
+                                       break;
+                               case Keys.End:
+                                       if (dropdown_style == ComboBoxStyle.DropDownList) {
+                                               SelectedIndex = Items.Count - 1;
+
+                                               if (DroppedDown)
+                                                       if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+                                                               listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
+                                       }
+                                       
+                                       break;
                                default:
                                        break;
                        }
                }
+
+               // If no item is currently selected, and an item is found matching the text 
+               // in the textbox, then selected that item.  Otherwise the item at the given 
+               // index is selected.
+               private void FindMatchOrSetIndex(int index)
+               {
+                       int match = -1;
+                       if (SelectedIndex == -1 && Text.Length != 0)
+                               match = FindStringCaseInsensitive(Text);
+                       if (match != -1)
+                               SelectedIndex = match;
+                       else
+                               SelectedIndex = index;
+               }
                
                void OnMouseDownCB (object sender, MouseEventArgs e)
                {
@@ -1623,8 +1786,28 @@ namespace System.Windows.Forms
                        Capture = true;
                }
 
+               void OnMouseEnter (object sender, EventArgs e)
+               {
+                       if (ThemeEngine.Current.CombBoxBackgroundHasHotElementStyle (this))
+                               Invalidate ();
+               }
+
+               void OnMouseLeave (object sender, EventArgs e)
+               {
+                       if (ThemeEngine.Current.CombBoxBackgroundHasHotElementStyle (this)) {
+                               drop_down_button_entered = false;
+                               Invalidate ();
+                       } else {
+                               if (show_dropdown_button)
+                                       DropDownButtonEntered = false;
+                       }
+               }
+
                void OnMouseMoveCB (object sender, MouseEventArgs e)
                {
+                       if (show_dropdown_button && !dropped_down)
+                               DropDownButtonEntered = button_area.Contains (e.Location);
+
                        if (DropDownStyle == ComboBoxStyle.Simple)
                                return;
 
@@ -1684,14 +1867,16 @@ namespace System.Windows.Forms
                {
                        if (process_textchanged_event == false)
                                return; 
-                               
-                       OnTextChanged (EventArgs.Empty);
 
                        int item = FindStringCaseInsensitive (textbox_ctrl.Text);
                        
-                       if (item == -1)
+                       if (item == -1) {
+                               // Setting base.Text below will raise this event
+                               // if we found something
+                               OnTextChanged (EventArgs.Empty);
                                return;
-
+                       }
+                       
                        // TODO:  THIS IS BROKEN-ISH
                        // I don't think we should hilight, and setting the top item does weirdness
                        // when there is no scrollbar
@@ -1703,10 +1888,17 @@ namespace System.Windows.Forms
 
                        base.Text = textbox_ctrl.Text;
                }
-               
-               internal void SetControlText (string s)
+
+               private void OnTextKeyPress (object sender, KeyPressEventArgs e)
+               {
+                       selected_index = -1;
+               }
+
+               internal void SetControlText (string s, bool suppressTextChanged)
                {
-                       process_textchanged_event = false;
+                       if (suppressTextChanged)
+                               process_textchanged_event = false;
+                               
                        textbox_ctrl.Text = s;
                        textbox_ctrl.SelectAll ();
                        process_textchanged_event = true;
@@ -1719,10 +1911,29 @@ namespace System.Windows.Forms
 
                        // Save the requested height since set bounds can destroy it
                        int save_height = requested_height;
-                       SetBounds (bounds.X, bounds.Y, bounds.Width, requested_height, BoundsSpecified.Height);
+                       SetBounds (bounds.X, bounds.Y, bounds.Width, SnapHeight (requested_height),
+                               BoundsSpecified.Height);
                        requested_height = save_height;
                }
 
+               int SnapHeight (int height)
+               {
+                       if (DropDownStyle == ComboBoxStyle.Simple && height > PreferredHeight) {
+                               if (IntegralHeight) {
+                                       int border = ThemeEngine.Current.Border3DSize.Height;
+                                       int lb_height = (height - PreferredHeight - 2) - border * 2;
+                                       if (lb_height > ItemHeight) {
+                                               int partial = (lb_height) % ItemHeight;
+                                               height -= partial;
+                                       } else if (lb_height < ItemHeight)
+                                               height = PreferredHeight;
+                               }
+                       } else
+                               height = PreferredHeight;
+
+                       return height;
+               }
+
                private void UpdatedItems ()
                {
                        if (listbox_ctrl != null) {
@@ -1740,6 +1951,32 @@ namespace System.Windows.Forms
 
                        private ComboBox owner;
                        internal ArrayList object_items = new ArrayList ();
+                       
+                       #region UIA Framework Events
+
+#if NET_2_0
+                       //NOTE:
+                       //      We are using Reflection to add/remove internal events.
+                       //      Class ListProvider uses the events.
+                       //
+                       //Event used to generate UIA StructureChangedEvent
+                       static object UIACollectionChangedEvent = new object ();
+
+                       internal event CollectionChangeEventHandler UIACollectionChanged {
+                               add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
+                               remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
+                       }
+                       
+                       internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
+                       {
+                               CollectionChangeEventHandler eh
+                                       = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
+                               if (eh != null)
+                                       eh (owner, args);
+                       }
+#endif
+
+                       #endregion UIA Framework Events
 
                        public ObjectCollection (ComboBox owner)
                        {
@@ -1770,7 +2007,18 @@ namespace System.Windows.Forms
                                        if (value == null)
                                                throw new ArgumentNullException ("value");
 
+#if NET_2_0
+                                       //UIA Framework event: Item Removed
+                                       OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, object_items [index]));
+#endif
+
                                        object_items[index] = value;
+                                       
+#if NET_2_0
+                                       //UIA Framework event: Item Added
+                                       OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
+#endif
+
                                        if (owner.listbox_ctrl != null)
                                                owner.listbox_ctrl.InvalidateItem (index);
                                        if (index == owner.SelectedIndex) {
@@ -1823,6 +2071,11 @@ namespace System.Windows.Forms
                                object_items.Clear ();
                                owner.UpdatedItems ();
                                owner.Refresh ();
+                               
+#if NET_2_0
+                               //UIA Framework event: Items list cleared
+                               OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
+#endif
                        }
                        
                        public bool Contains (object value)
@@ -1833,7 +2086,18 @@ namespace System.Windows.Forms
                                return object_items.Contains (value);
                        }
 
-                       public void CopyTo (object[] dest, int arrayIndex)
+#if NET_2_0
+                       public void CopyTo (object [] destination, int arrayIndex)
+                       {
+                               object_items.CopyTo (destination, arrayIndex);
+                       }
+
+                       void ICollection.CopyTo (Array destination, int index)
+                       {
+                               object_items.CopyTo (destination, index);
+                       }
+#else
+                       public void CopyTo (object [] dest, int arrayIndex)
                        {
                                object_items.CopyTo (dest, arrayIndex);
                        }
@@ -1842,6 +2106,7 @@ namespace System.Windows.Forms
                        {
                                object_items.CopyTo (dest, index);
                        }
+#endif
 
                        public IEnumerator GetEnumerator ()
                        {
@@ -1872,8 +2137,13 @@ namespace System.Windows.Forms
                                
                                if (owner.Sorted)
                                        AddItem (item);
-                               else
+                               else {
                                        object_items.Insert (index, item);
+#if NET_2_0
+                                       //UIA Framework event: Item added
+                                       OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
+#endif                                 
+                               }
                                
                                owner.EndUpdate ();     // Calls UpdatedItems
                        }
@@ -1897,8 +2167,18 @@ namespace System.Windows.Forms
                                if (index == owner.SelectedIndex)
                                        owner.SelectedIndex = -1;
 
+#if NET_2_0
+                               object removed = object_items [index];
+#endif
+
+
                                object_items.RemoveAt (index);
                                owner.UpdatedItems ();
+                               
+#if NET_2_0
+                               //UIA Framework event: Item removed
+                               OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed));
+#endif
                        }
                        #endregion Public Methods
 
@@ -1913,12 +2193,30 @@ namespace System.Windows.Forms
                                        foreach (object o in object_items) {
                                                if (String.Compare (item.ToString (), o.ToString ()) < 0) {
                                                        object_items.Insert (index, item);
+                                                       
+                                                       // If we added the new item before the selectedindex
+                                                       // bump the selectedindex by one, behavior differs if
+                                                       // Handle has not been created.
+                                                       if (index <= owner.selected_index && owner.IsHandleCreated)
+                                                               owner.selected_index++;
+                                                               
+#if NET_2_0
+                                                       //UIA Framework event: Item added
+                                                       OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
+#endif
+
                                                        return index;
                                                }
                                                index++;
                                        }
                                }
                                object_items.Add (item);
+                               
+#if NET_2_0
+                               //UIA Framework event: Item added
+                               OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
+#endif
+                               
                                return object_items.Count - 1;
                        }
                        
@@ -1932,9 +2230,30 @@ namespace System.Windows.Forms
 
                        internal void Sort ()
                        {
-                               object_items.Sort ();
+                               // If the objects the user put here don't have their own comparer,
+                               // use one that compares based on the object's ToString
+                               if (object_items.Count > 0 && object_items[0] is IComparer)
+                                       object_items.Sort ();
+                               else
+                                       object_items.Sort (new ObjectComparer (owner));
                        }
 
+                       private class ObjectComparer : IComparer
+                       {
+                               private ListControl owner;
+                               
+                               public ObjectComparer (ListControl owner)
+                               {
+                                       this.owner = owner;
+                               }
+                               
+                               #region IComparer Members
+                               public int Compare (object x, object y)
+                               {
+                                       return string.Compare (owner.GetItemText (x), owner.GetItemText (y));
+                               }
+                               #endregion
+                       }
                        #endregion Private Methods
                }
 
@@ -2088,11 +2407,6 @@ namespace System.Windows.Forms
                                }
                        }
 
-                       protected override void Select (bool directed, bool forward)
-                       {
-                               // Do nothing, we never want to be selected
-                       }
-
                        internal override bool InternalCapture {
                                get {
                                        return Capture;
@@ -2110,11 +2424,15 @@ namespace System.Windows.Forms
                        {
                                int width, height;
                                bool show_scrollbar = false;
-                               
+
                                if (owner.DropDownStyle == ComboBoxStyle.Simple) {
                                        Rectangle area = owner.listbox_area;
                                        width = area.Width;
                                        height = area.Height;
+
+                                       // No calculation needed
+                                       if (height <= 0 || width <= 0)
+                                               return;
                                }
                                else { // DropDown or DropDownList
                                        
@@ -2136,12 +2454,15 @@ namespace System.Windows.Forms
                                        }
                                }
                                
-                               page_size = height / owner.ItemHeight;
+                               page_size = Math.Max (height / owner.ItemHeight, 1);
+
+                               ComboBoxStyle dropdown_style = owner.DropDownStyle;
+                               if ((dropdown_style != ComboBoxStyle.Simple && owner.Items.Count <= owner.MaxDropDownItems)
+                                       || (dropdown_style == ComboBoxStyle.Simple && owner.Items.Count * owner.ItemHeight < height)) {
 
-                               if (owner.Items.Count <= owner.MaxDropDownItems) {
                                        if (vscrollbar_ctrl != null)
                                                vscrollbar_ctrl.Visible = false;
-                                       if (owner.DropDownStyle != ComboBoxStyle.Simple)
+                                       if (dropdown_style != ComboBoxStyle.Simple)
                                                height = owner.ItemHeight * owner.items.Count;
                                } else {
                                        /* Need vertical scrollbar */
@@ -2157,14 +2478,14 @@ namespace System.Windows.Forms
                                        
                                        vscrollbar_ctrl.Dock = DockStyle.Right;
 
-                                       vscrollbar_ctrl.Maximum = owner.Items.Count - 2;
+                                       vscrollbar_ctrl.Maximum = owner.Items.Count - 1;
 #if NET_2_0
-                                       int large = page_size - 1;
+                                       int large = page_size;
 #else
-                                       int large = (owner.DropDownStyle == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items) - 1;
+                                       int large = (dropdown_style == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items) - 1;
 #endif
-                                       if (large < 0)
-                                               large = 0;
+                                       if (large < 1)
+                                               large = 1;
                                        vscrollbar_ctrl.LargeChange = large;
                                        show_scrollbar = vscrollbar_ctrl.Visible = true;
 
@@ -2207,8 +2528,8 @@ namespace System.Windows.Forms
                                                                state |= DrawItemState.Focus;
                                                        }
                                                }
-                                               
-                                               owner.OnDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect,
+
+                                               owner.HandleDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect,
                                                        i, state, owner.ForeColor, owner.BackColor));
                                        }
                                }
@@ -2277,7 +2598,7 @@ namespace System.Windows.Forms
                                        Invalidate (GetItemDisplayRectangle (index, top_item));
                        }
 
-                       private int LastVisibleItem ()
+                       public int LastVisibleItem ()
                        {
                                Rectangle item_rect;
                                int top_y = textarea_drawable.Y + textarea_drawable.Height;
@@ -2301,6 +2622,11 @@ namespace System.Windows.Forms
                                Invalidate ();
                        }
 
+                       public int FirstVisibleItem ()
+                       {
+                               return top_item;
+                       }
+                       
                        bool scrollbar_grabbed = false;
 
                        bool InScrollBar {
@@ -2354,8 +2680,18 @@ namespace System.Windows.Forms
                                        return;
                                }
 
+                               bool is_change = owner.SelectedIndex != index;
+                               
                                owner.SelectedIndex = index;
                                owner.OnSelectionChangeCommitted (new EventArgs ());
+                               
+                               // If the user selected the already selected item, SelectedIndex
+                               // won't fire these events, but .Net does, so we do it here
+                               if (!is_change) {
+                                       owner.OnSelectedValueChanged (EventArgs.Empty);
+                                       owner.OnSelectedIndexChanged (EventArgs.Empty);
+                               }
+                               
                                HideWindow ();
                        }
 
@@ -2389,7 +2725,7 @@ namespace System.Windows.Forms
                                if (delta == 0 || vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible)
                                        return;
 
-                               int max = owner.Items.Count - page_size;
+                               int max = vscrollbar_ctrl.Maximum - page_size + 1;
 
                                int val = vscrollbar_ctrl.Value + delta;
                                if (val > max)
@@ -2421,9 +2757,7 @@ namespace System.Windows.Forms
                        
                        protected override void WndProc(ref Message m) {
                                if (m.Msg == (int)Msg.WM_SETFOCUS) {
-                                       if (m.WParam != IntPtr.Zero) {
-                                               XplatUI.SetFocus(m.WParam);
-                                       }
+                                       owner.Select (false, true);
                                }
                                base.WndProc (ref m);
                        }