Does anyone use the DataGridView with combo boxes in *editable* (type-in) mode?
Here is some code that makes it a lot easier. I combined the best examples I could find from the FAQ, the forum, and tech support, along with some changes of my own.
It is a customized DataGridView wrapper that handles the dirty work for you so that all combo boxes are editable by default.
To use it:
(1) Paste this code into a new VB class file called APSDataGridView.vb
(2) Then go to Project -> ...Properties -> Application tab -> Root Namespace, and clear the root namespace.
(3) Recompile your project, and it will appear at the top of the toolbox.
(4) Use the APSDataGridView control where you would use a DataGridView.
This code requires Visual Basic 2005 or later.
Let me know if you want a C# version, or if you have questions or problems.
Regards,
Aaron Stewart
' APSDataGridView.vb ' ' Wrapper for DataGridView ' Modifies default behavior so that Combo Boxes are editable (type-in) by default. ' ' This can be handy because type-in DataGridView combo boxes are a lot more ' involved than you might think. ' ' Aaron Stewart, 2007 ' Instructions: ' (1) Create a new Windows Forms project in VB.NET 2005 or higher. ' ' (2) Create a new class (not a user control) named APSDataGridView.vb ' and paste this code into it, replacing what is there. ' ' (3) Go to Project -> ...Properties -> Application tab -> Root Namespace, ' and clear the root namespace. (This is necessary for VB, not C#) ' ' (4) Compile the project. The APSDataGridView is now available in the Toolbox, at the top. ' ' (5) Now go to your form (such as Form1.vb) and add an APSDataGridView control using the designer. ' Don't make it too small. ' ' (6) Now in your form code you can paste the example or write your own code. ' ' (7) Compile and run ' ' (8) You can try it with the test cases below. ' Some differences when using APSDataGridView: ' ' (1) If you want to set Combo Box parameters with the EditingControlShowing event, ' use the EditingControlShowing2 event instead. If you are not dealing with Combo Boxes, ' you can use the regular EditingControlShowing event. ' ' (2) Do not use the CellValidating event. Use CellValidating2 instead. ' (This allows combo box validation handler to work without conflicts.) ' The DataGridView does not directly support type-in (editable) ComboBox mode, ' and all of the published examples I have seen are incomplete. ' ' To get the DataGridView to work properly with ComboBoxes, do ALL of the following: ' (1) In DataGridView.EditingControlShowing, set ComboBox.DropDownStyle = ComboBoxStyle.DropDown for the desired column(s) (Source: DataGridView FAQ) ' (2) Set DataGridView.NotifyCurrentCellDirty(True) in DataGridView.EditingControlShowing (Source: Microsoft Support) ' (3) In DataGridView1.CellValidating, force the ComboBox SelectedIndex : cbo.SelectedIndex = cbo.FindStringExact(cbo.Text.Trim) (Source: Forum member Aspnot, http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=254131&SiteID=1 ; See also http://msdn.microsoft.com/msdnmag/issues/06/01/DevQA/ ) ' (4) In ComboBox.PreviewKeyDown, if e.KeyCode = Keys.Enter then force ComboBox.DroppedDown = False (Source: My own experiments) ' (5) In ComboBox.PreviewKeyDown, if e.KeyCode = Keys.Escape then set ComboBox.Text = "" . (Source: My own experiments) ' Even with all of these, the behavior isn't as nice as with Access or Excel. ' Motivation for these: ' #1 - This puts the combo box into type-in mode ' #2 - Without this the DataGridView stays in an unfinished edit mode even after you leave the cell ' (Also, test case #2 below will fail if this is done in ComboBox.TextChanged instead of ' DataGridView.EditingControlShowing and the ComboBox is set to AutoCompleteMode.SuggestAppend) ' #3 - Similar to #2 - the DataGridView won't work right without it ' #4 - Resolves an issue with ComboBoxes where if you open the drop-down and type an entry and press ENTER, it loses the value. ' #5 - For test case #11. Allows ESC to work properly with the DataGridView. Normally ESC works fine, but if AutoComplete (Append) is enabled AND you enter text that matches something on the list, then something interferes with the ESC key. ' Test cases for validating an editable ComboBox : ' Try all of these cases on the new row at the bottom of the DataGridView (and if you like, also try them on an interior row). ' ' Here are the test cases: ' (1) Drop-down, click an item, submit ' (2) Type a known value, submit (try this with and without matching capitalization) ' (3) Drop-down, type a known value (do not use the arrow keys to select it), press ENTER ' (4) Drop-down, select a value using the arrow keys or mouse, press ENTER ' (5)* Drop-down, start typing a known value, then try to use the arrow keys to select a different value (this case does not work cleanly like in Access or Excel) ' (6) Enter a value other than the first value, submit, return to this cell, Clear it, press ENTER. ' (7)* Set AutoCompleteMode.SuggestAppend, AutoCompleteSource.ListItems. It works but it isn't as nice as Access or Excel. ' (8)* At the new row, drop-down but don't enter a value, submit. (This is probably acceptable behavior). ' (9) Start entering a known value. Then drop-down. Then TAB. (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=254131&SiteID=1) ' (10) Start typing a value not matching the list, then press ESC to cancel it. The new row should completely disappear. ' (11) Start typing a value that matches an item in the list (so that AutoComplete kicks in), then press ESC to cancel it. The new row should completely disappear. It might be tolerable if it leaves a blank but no pencil icon. ' ' Cases marked with an asterisk(*) do not work as nicely as Access or Excel. ' Notes: ' (i) All of these cases start with an empty combo box, unless otherwise specified. ' (ii) Drop-down : by clicking on the mouse or pressing Alt+Down ' (iii) Submit : Normally clicking off the control, pressing TAB, and ' pressing ENTER are all ways submit the value. However, in some ' cases a specific submit method is specified. ' (iv) Clear: Press Ctrl+0 or edit and delete the text or edit and press delete. ' Imports System.Windows.Forms Namespace APS.Windows.Forms ' Derived DataGridView that takes care of the details so combo boxes use type-in (editable) mode. Public Class APSDataGridView Inherits System.Windows.Forms.DataGridView ' It seems to generate the delegate [event]EventHandler automatically from the event declaration... 'Public Delegate Sub ComboBoxItemNotInListEventHandler(ByVal dgv As DataGridView, ByVal cbo As ComboBox, ByVal cboColumn As DataGridViewComboBoxColumn, ByVal e As DataGridViewCellValidatingEventArgs) Public Event ComboBoxItemNotInList(ByVal dgv As DataGridView, ByVal cbo As ComboBox, ByVal cboColumn As DataGridViewComboBoxColumn, ByVal e As DataGridViewCellValidatingEventArgs) ' Constructor Public Sub New() MyBase.New() End Sub ' This makes combo boxes "editable" so you can type in them. See the DataGridView FAQ. Protected Overrides Sub OnEditingControlShowing( _ ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Dim dgv As DataGridView = Me 'sender If (TypeOf e.Control Is ComboBox) Then Dim cbo As ComboBox = DirectCast(e.Control, ComboBox) ' Optional: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=254131&SiteID=1 'cbo.AutoCompleteMode = AutoCompleteMode.SuggestAppend 'cbo.AutoCompleteSource = AutoCompleteSource.ListItems ' This makes it a type-in combo box cbo.DropDownStyle = ComboBoxStyle.DropDown ' Adjust the ComboBox behavior: AddHandler cbo.PreviewKeyDown, New PreviewKeyDownEventHandler(AddressOf comboBox_PreviewKeyDown) ' (Thanks to Ying Liu, Microsoft Supportdgv.NotifyCurrentCellDirty(True) End If ' Call registered event handlers... MyBase.OnEditingControlShowing(e) End Sub ' Validate typed-in values... Protected Overrides Sub OnCellValidating(ByVal e As DataGridViewCellValidatingEventArgs) Dim dgv As DataGridView = Me 'sender If Not TypeOf (dgv.EditingControl) Is ComboBox Then ' Every control path should call MyBase.OnCellValidating MyBase.OnCellValidating(e) Else Dim cbo As ComboBox = dgv.EditingControl If (cbo Is Nothing) Then MyBase.OnCellValidating(e) Exit Sub ' cbo is Nothing if the user did not edit the cell End If ' This does two things: ' (1) This makes the combo box case-insensitive. ' (2) You have to force the SelectedIndex when using type-in mode or it will not properly recognize the change ' This little gem comes from ' http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=254131&SiteID=1 cbo.SelectedIndex = cbo.FindStringExact(cbo.Text.Trim) ' You could customize the handling below on a column-by-column basis... If cbo.SelectedIndex = -1 Then ' The item wasn't in the list... ' Is it because the value is empty? If (cbo.Text.Trim = String.Empty) Then ' We assume that it's okay to have an empty value here... ' Let the user delete the value... ' Don't Raise Event ComboBoxItemNotInList... Else ' A value was entered but it was not in the list... Dim cboColumn As DataGridViewComboBoxColumn = dgv.Columns(e.ColumnIndex) RaiseEvent ComboBoxItemNotInList(dgv, cbo, cboColumn, e) If (e.Cancel = True) Then ' How do we cancel a value if it creates a new row? Beep() ' Set a breakpoint here ' ? force dgv value to empty??? ' Don't return yet - we still need to call the base class event handler Else ' If the user added the item to the combo box, we need to accept the new value... ' Again, from http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=254131&SiteID=1 cbo.SelectedIndex = cbo.FindStringExact(cbo.Text.Trim) End If End If End If End If ' Call the base class handler and user handlers... MyBase.OnCellValidating(e) End Sub Protected Shared Sub comboBox_PreviewKeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) ' There is a glitch if you are using a ComboBox either in a DataGridView or standalone. ' If you open the ComboBox dropdown but then type a value and press ENTER, the value is lost. ' This error does not appear if you press TAB. ' This is the workaround. If (e.KeyCode = Keys.Enter) Then Dim cbo As ComboBox = sender If cbo.DroppedDown Then cbo.DroppedDown = False End If End If ' Allow the ESC key to cancel changes even if AutoComplete mode has been active. If (e.KeyCode = Keys.Escape) Then Dim cbo As ComboBox = sender ' I don't know why this works, but it does: cbo.Text = "" End If End Sub End Class End Namespace