(Print this page)

Comboboxes in Windows Form Datagrids
Published date: Wednesday, January 1, 2003
On: Moer and Éric Moreau's web site

I will author this new monthly column in which I will introduce you to topics mainly related to Windows Forms into the Visual Basic .Net environment (it is quite large to spend many months without rambling). The suggested format is a single topic in about 2 pages long (so that you can read it fast) and will almost always contains code snippet for you to start. Once you read this introduction, you should know whether the topic is applicable to your specific needs.

The topic for this month: How to integrate a ComboBox to a Windows Forms DataGrid?

For my first topic, I will explore something that is asked again and again in various .Net newsgroups (it was also a FAQ with prior VB version). I am sure that the lobbying done by third party vendors prevents Microsoft to add an easy way of doing it! As you will shortly discover, it is not that difficult. There are many ways of doing it and I have chosen one. The method I chose is only a matter of displaying a control (the ComboBox) over the another (the DataGrid). The DataGrid even gives you a control collection for you to add the controls to be hosted. If you dig that topic deeper, you will find that you can derive a "column style" (see the conclusion for a link on this).

Here is the recipe of success (regarding ComboBox in DataGrid!!!)

Before starting, I want to let you know that you can download complete and commented listing at the end of this article (instead of doing copy-and-paste of the code below).

Off course, the first thing you need to do is to create a new VB.Net Windows application. On the form, add a DataGrid control and sets its Dock property to "Fill" so that it fills the form completely. Do not change any other properties for now or your success is at risk.

Now, in the code window, just after the "Windows Form Designer generated code" section, copy this first snippet of code:

Private mcnSQL As New SqlClient.SqlConnection( _
  "SERVER=(local); INTEGRATED SECURITY=SSPI; DATABASE=northwind")

Private mdaEmploye As New SqlClient.SqlDataAdapter( _
  "SELECT TitleOfCourtesy, FirstName, LastName, Title FROM Employees", mcnSQL)

Private mds As New DataSet()
This code is used to declare and initialize objects required to connect to the database (I suppose that you have the NorthWind database from a local SQL Server available), set a DataAdapter (named mdaEmploye), and declare a DataSet (named mds) that will be filled later.

Have you noticed that we haven't add any ComboBox control to the form? Aren't we supposed to show one? Just after the three previous lines of the database connection, copy this single line of code that declares a ComboBox object that will be displayed at runtime.

Private mctlCombo As New ComboBox()

You are now ready to fill the dataset, initialize the combo, add the ComboBox to the DataGrid controls collection. This is all done during the Load event. Just copy this code.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

   AddHandler mctlCombo.TextChanged, AddressOf Ctrls_TextChanged

   With mctlCombo
      .Name = "MyCombo"
      .Visible = False
      .Items.Clear()
      .Items.Add("Sales Representative")
      .Items.Add("Inside Sales Coordinator")
      .Items.Add("Vice President, Sales")
      .Items.Add("Sales Manager")
      .Items.Add("Flunky")
   End With

   mdaEmploye.Fill(mds, "Employees")
   DataGrid1.PreferredRowHeight = mctlCombo.Height
   DataGrid1.DataSource = mds
   DataGrid1.DataMember = "Employees"
   DataGrid1.Controls.Add(mctlCombo)
End Sub

So far so good. Now we need some code to show or hide the ComboBox. The code below does that for you.

Private Sub DataGrid1_Paint( _
  ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles DataGrid1.Paint

   If DataGrid1.CurrentCell.ColumnNumber = 3 Then
      mctlCombo.Width = DataGrid1.GetCurrentCellBounds.Width
   End If
End Sub

Private Sub DataGrid1_CurrentCellChanged( _
  ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGrid1.CurrentCellChanged

   If DataGrid1.CurrentCell.ColumnNumber = 3 Then
      With mctlCombo
         .Visible = False
         .Width = 0
         .Left = DataGrid1.GetCurrentCellBounds.Left
         .Top = DataGrid1.GetCurrentCellBounds.Top
         .Text = DataGrid1.Item(DataGrid1.CurrentCell).ToString & ""
         .Visible = True
      End With
   Else
      HideComboBox(sender, e)
   End If
End Sub

Private Sub HideComboBox( _
  ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGrid1.Scroll, DataGrid1.Click

   mctlCombo.Visible = False
   mctlCombo.Width = 0
End Sub

The last thing we need to do is to replace the current value of the DataGrid with the newly selected item from the ComboBox. And guess what, I have some code for that too!

Private Sub Ctrls_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs)

  'When the an item is selected, the grid must show this new value
  If DataGrid1.CurrentCell.ColumnNumber = 3 Then
      mctlCombo.Visible = False
      If DataGrid1.Item(DataGrid1.CurrentCell).ToString & "" = "" Then SendKeys.Send("*")
      DataGrid1.Item(DataGrid1.CurrentCell) = mctlCombo.Text
   End If
End Sub

You are now ready to run the project. If you follow these easy steps, you should get what you see in the image below.


Conclusion

Wasn't it easy? For sure it could have been a lot easier if Microsoft already have added it to the DataGrid itself. By using this method, you can easily host almost any control into a datagrid. There are many web sites that explain how to continue on this idea. Surely a good starting point that also gives you links to other great sites is the George Sheperd's Windows Forms FAQ.

So that's it for this month. I hope you appreciated it and that you will spend some time reading my next columns too! If you have any suggestions of topics you want to see, just le me know and I will do my best to cover it in the following months.


(Print this page)