Dec 01

changing the display order of columns in a datagridview on windows forms

Recently I needed to specify the order that columns were supposed to show up in a datagridview. Normally, one could do this by just changing their SQL query to return the fields in the order that the user wanted to see them. But in my case, this wouldn’t work. You see, I was adding columns to the the gridview because I wanted calendar columns instead of plain text columns containing a date and I also wanted dropdown lists for some of the columns. So even though I could write my query with the columns in the right order I changed the order when I added the new columns (because I had to remove the old column that was formatted in the default way and add the new properly formatted column).

So what to do to get the columns to show up in the order I wanted? Well, just tell it what order you want them to show up in… duh.

Like so:

With dgvRBDDataStaged
 .AutoGenerateColumns =
False
 .Columns(“RBD_Key”).DisplayIndex = 0
 .Columns(“RBD_Carrier”).DisplayIndex = 1
 .Columns(
“Service”).DisplayIndex = 2
 .Columns(
“CountryCode”).DisplayIndex = 3
 etc…
 ‘Just for kicks make one invisible
 .Columns(“RBD_Record_Status”).Visible = False
End With

You will see that there is a secret to it. I never even knew that the AutoGenerateColumns property existed in the windows forms world. [Note: it has a default value of true]. I use it all the time in asp.net, but never have I used it on the windows forms side… until now. Without setting ‘AutoGenerateColumns = false’ first setting those displayIndex values just  doesn’t seem to work. Without setting that property first it seems to “sort of” works in that some of the columns are reordered to what you intended but some are not (which is worse than just not working at all) and will just confuse you to no end. It might work fine without setting that property, but if you did any manual column adding / removing forget about it… you have no hope without setting that property as specified. Just use it as I described and you should get the results you are looking for.

As for my sources, I did many google searches and found questions regarding this topic all over the place, but the most useful thread was this one.

Nov 11

HOWTO create a Pop-up menu (context menu) for single cell of a datagrid

Recently I needed fo find a way for a user to be presented with a list of possible values, but to also be able to ignore that list and enter their own value into a datagrid cell. I figured I could just use a combo box column (dropdownlist) and it would behave the same way as a combobox does when it is on a form (not within a datagrid). In that situation the user can just enter a value into the text portion of the combo box assuming they did not like any of the options in the box itself. Well, that’s not the way a comboboxcolumn works… you choose from the list it makes available… that’s all you get for free.

Unfortunately, that was not an option. I had to allow the user to enter their own value if they didn’t see the one they wanted in the list. So, what I did was I set the column up as a regular Text based column. Then I implemented a pop-up menu that showed when the user right clicked on a cell in a particular column. Before popping up it determines what the correct menu items for cells in the columns in which it resides  and then makes those options available to the user. It took me a little while to figure out – hopefully this will save someone some time.

My sample code below is in VB. Basically it makes use of the fact that when in a datagrid a right click causes “CellContextMenuStripNeeded” to be fired. So we build up our menu strip there. You could ofcourse also have a static menustrip and set striptoShow directly to it rather than building up stripToShow everytime.

”””””””””””””””’ SET UP SOME PRIVATE VARIABLES WE WILL NEED ””””””””””””””’

 Private theCellImHoveringOver As DataGridViewCellEventArgs
Private stripToShow As ContextMenuStrip

 ”””””””””””””””’ DETERMINE WHICH POPUP TO SHOW (IF ANY) ””””””””””””””’

‘NOTE: dgv is a DataGridView

Private Sub dgv_CellContextMenuStripNeeded(ByVal sender As Object,
ByVal e As DataGridViewCellContextMenuStripNeededEventArgs) _
Handles dgv.CellContextMenuStripNeeded

 Try

      If (theCellImHoveringOver .ColumnIndex = -1) Then
          Return ‘ nothing special to pop up here
     
End If

     If (dgv.Columns(theCellImHoveringOver.ColumnIndex).Name = “Column_Name_Here”) Then
          If (dgv.Rows(theCellImHoveringOver.RowIndex).Cells(“Column_Name_Here”).Selected) Then   �
               ‘ NOTE: I only want it to do this if the cell i right click on is SELECTED
              
If stripToShow Is Nothing Then
                      stripToShow = New ContextMenuStrip()
                      
stripToShow .Items.Add(“Item1”, Nothing, New System.EventHandler(AddressOf Me.stripToShow _Item_Click))
                      stripToShow .Items.Add(“Item2”, Nothing, New System.EventHandler(AddressOf Me.stripToShow _Item_Click))
                      ‘NOTE: I added a handler for the click. In my handler I will set the cell value to whatever the user selects from the menu
               End If
               e.ContextMenuStrip = stripToShow�
          E
nd If
     
End If

Catch ex As Exception
        MessageBox.Show(
“There was an error popping up the menu. Please try again.”)
End Try

 End Sub 

          ”””””””””””””””’ Keep up with which cell I am on ””””””””””””””’

Private Sub dgv_CellMouseEnter(ByVal sender As Object, _
ByVal e As DataGridViewCellEventArgs) _
Handles dgv.CellMouseEnter

     theCellImHoveringOver = e

End Sub

”””””””””””””””””” Handler of Menu Clicks  ””””””””””””””””””’

 

Private Sub stripToShow _Item_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
      Dim str As String = CType(sender, System.Windows.Forms.ToolStripItem).Text
      dgv.Rows(theCellImHoveringOver.RowIndex).Cells(“Column_Name_Here”).Value = str

End Sub

I think that is all there is to it! Let me know if you use it. It’s nice to hear others find this type of stuff useful as well.