Enter DataGrid at correct cell

Posted on 2007-03-30
Last Modified: 2012-08-14
In VB .NET 2003, I have a DataGrid with five columns. I have noticed that if I tab into the grid from the other controls on the form, the cell highlighted is the one that was last the CurrentCell when I was previously in the DataGrid. That's true even if I've moved to a different set of records, which isn't desirable behavior. (If there are no longer as many rows, focus goes to the first row, same column.) I thought of simply setting the .CurrentCell to the first row, first column in the Enter event handler for the DataGrid, but if a user clicks on a cell to make a change to it, I want that click to be recognized and focus to go immediately to that cell.

A couple of possibilities came to my mind to do this:

1) Change the CurrentCell in the Leave event handler. But I'm finding that if I do this, if I leave by means of clicking on a CheckBox, the CheckBox is changed but then focus returns to the DataGrid. (A second click on the CheckBox will get focus to stay there, but this kind of behavior will drive users nuts.)

2) Distinguish between entering the DataGrid via a tab entry (for which I'd set dg.CurrentCell = New DataGridCell(0, 0)) and via a mouse click. But I don't know how to do this.

If there's another way to do it, I'm open to that as well.
Question by:ElrondCT
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
LVL 34

Expert Comment

ID: 18830243
It's a bit late for me (I'm in the UK) but I see this has been hanging around now for 24 hours so here's a suggestion.  Not actually an answer ;-(


2) Distinguish between entering the DataGrid via a tab entry (for which I'd set dg.CurrentCell = New DataGridCell(0, 0)) and via a mouse click. But I don't know how to do this.

Nor do I.  Hence no response before now.  But the way I would go about trying to find out how to do it is by sticking debug code in the Enter and MouseEnter events and working back from what that revealed.  I've just had a play with this

    Private Sub DataGrid1_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGrid1.Enter
        Static i As Integer = 0
        Debug.WriteLine("Enter" & i.ToString & " Col:" & DataGrid1.CurrentCell.ColumnNumber.ToString & " row:" & DataGrid1.CurrentCell.RowNumber.ToString)
        i += 1
    End Sub

    Private Sub DataGrid1_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGrid1.MouseEnter
        Static i As Integer = 0
        Debug.WriteLine("MouseEnter" & i.ToString & " Col:" & DataGrid1.CurrentCell.ColumnNumber.ToString & " row:" & DataGrid1.CurrentCell.RowNumber.ToString)
        i += 1
    End Sub

and (although it's too late for me to work it out at the moment) I reckon there should be enough revealed by that as to the order in which the events fire to be able to distinguish between tabbing into the grid and clicking into it with the mouse.

Let me know if it seems that way to you, too, sufficiently for you to crack it.  If not, I'll see what I can work up on it.

LVL 34

Accepted Solution

Sancler earned 500 total points
ID: 18832010
I'd forgotten, when I posted last night, just how complex the enter / leave / gotfocus / lostfocus events were in a datagrid.  I still reckon it might be possible by reference to these events to set flags to distinguish between, and act differently depending on, whether entry to the grid was via mouse or tabbing.  But this might be an easier alternative.

One form, one button, and a couple of textboxes (just to provide other controls for focus to move to).  This code (excluding the Designer Generated stuff).

Public Class Form1
    Inherits System.Windows.Forms.Form

    Private dt As New DataTable("DummyData")
    Private setcell As Boolean = False

    Private Sub filltable()
        For i As Integer = 0 To 3
            Dim dc As New DataColumn("Col" & i.ToString, GetType(Integer))
        Dim dcb As New DataColumn("Col4", GetType(Boolean))
        For j As Integer = 0 To 4
            Dim dr As DataRow = dt.NewRow
            For i As Integer = 0 To 3
                dr(i) = j.ToString & i.ToString
            dr(4) = True
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        DataGrid1.DataSource = dt
    End Sub

    Private Sub DataGrid1_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGrid1.Enter
        If setcell Then
            DataGrid1.CurrentCell = New DataGridCell(0, 0)
            setcell = False
        End If
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim dr As DataRow = dt.Rows(0)
        Dim drn As DataRow = dt.NewRow
        drn.ItemArray = dr.ItemArray
        setcell = True
    End Sub
End Class

The thinking is that the specific problem (of cell-focus being on a different cell from that in which the user left it) occurs when two conditions are satisfied.  The first is that some change has been made to the data on which the grid is based: the other is that the user re-enters the grid by tabbing rather than with the mouse.  So, as illustrated here by the button1_click code, the idea is to set a flag WHEN THE CHANGE IS MADE TO THE DATA, and then the flag is checked (and cancelled if necessary) when the datagrid is entered by whatever means.  If data has been altered and entry is by tab, focus is set to cell(0,0).  If data has not been altered then, however entry occurs, the old cell regains focus.  Whether data has been changed or not, if entry is by mouse no cell receives focus until there is a click.

Would that meet your needs?

LVL 20

Author Comment

ID: 18836409
Roger, when this whole project is done, I think I'm going to need to pay you royalties!

I played around Saturday with the mouse events (which I hadn't thought about until you mentioned them in your first message). MouseEnter doesn't really do what I want, since that fires if one simply puts the mouse over the control, whether or not you click. Unfortunately, it turns out that MouseDown fires _after_ the Enter event. That makes it a lot less useful, IMHO, but that's the way it goes. I didn't have a lot of time to work with them, though, which is why I didn't post back.

However, I think your idea in your second posting will work well. Putting flags on the other 40 controls on the form would be tedious, but it occurs to me that really what I want is that, if the user is displaying a different record from the one edited when last in the grid, tabbing will go to the first cell. If they've edited the grid and stayed within the record for the other controls, then I think it's fine, if they tab back to the grid, to have it go back to the last cell they edited. It won't look odd in that situation (and frankly people are unlikely to use tab to go back to the grid after moving on to other controls, as opposed to when entering a new record). So all I need to do is set a flag when a new record is displayed on the form, and check that flag on entry to the grid. If it's the first time entering the grid, turn off the glad and set DataGrid1.CurrentCell = New DataGridCell(0, 0); otherwise, don't do anything.

Thanks once again. The time you spend on these questions amazes me.
LVL 20

Author Comment

ID: 18836514
As I was putting the new code in, I thought, "Wait a second. I'm back where I started, since I still don't know whether I'm coming in with a tab or a mouse click." If the user uses the mouse to get to the grid on a new record, I want the mouse-selected cell to get focus, not the first. But it turns out that that's exactly why MouseDown fires after Enter. If I set the .CurrentCell in Enter, it'll get updated during MouseDown to the cell clicked on. That's exactly what I want, so I'm in good shape.
LVL 20

Author Comment

ID: 18843598
Another follow-up: What I described worked fine for ordinary cells. But my grid has two custom cell types: a ComboBox and a DateTimePicker. The ComboBox works fine with this, but the DTP grabs focus and won't let go if the Enter event handler changes the CurrentCell. However, it eventually occurred to me that I could set the CurrentCell whenever the record displayed changes. So I took the setting out of the Enter event handler, and now I have

    dg.CurrentCell = New DataGridCell(0, 0)

in the PositionChanged event handler for the CurrencyManager, followed by a .Focus for the first control on the form (because setting .CurrentCell seems to set the Focus to the grid), and everything is working as I want.

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

740 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question