Solved

Waiting for value in DataGridView Cell before advancing?

Posted on 2014-04-25
24
212 Views
Last Modified: 2014-06-29
I have a DGV in which certain cells are populated automatically by pressing the enter key in the specific cell and then reading a value from a Digital Multimeter. Retrieving this value may take up to 2 seconds, however, the cursor advances to the next cell before the previous cell is populated with the value from the read. Is is possible to wait for the cursor to advance to the next cell until the current cell has a value?
0
Comment
Question by:BlakeMcKenna
  • 12
  • 11
24 Comments
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40023254
You can use the cell validating event.  

 private sub grid_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        
      if (string.IsNullOrWhiteSpace(grid(e.ColumnIndex,e.RowIndex).Value.ToString()) then           
                e.Cancel = true
                return
       end if
            
end sub

Open in new window

0
 

Author Comment

by:BlakeMcKenna
ID: 40023408
On an empty cell, I hit the enter key and I got the following error. See attachment!
Screenshot.jpg
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40023443
If cDGV(e.ColumnIndex, e.RowIndex).Value is nothing orelse  (string statement) then
0
 

Author Comment

by:BlakeMcKenna
ID: 40023471
I should have explained myself better. When a user hits the enter key, there is logic in the KeyPress event that retrieves a value to populate the cell. I am trying to minimize the number of events to use for this DGV. Your modified code works, however, that is the first event that is fired upon hitting the enter key. I need for the KeyPress event to fire to execute the retrieve value code.

So, it seems I need to have logic in the KeyPress event...
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40023493
How / where are you retrieving the value?  I mean in the key press but where are you calling it from?  Database, webservice?
0
 

Author Comment

by:BlakeMcKenna
ID: 40023508
There is a function call in the KeyPress Event that makes a call to a Digital Multimeter and retrieves a value from this device. So it's not a DB or Webservice
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40023601
Is that call done asynchronously or synchronously.  Can you pass a reference to the cell so you know which cell you need to update?  EG: don't prevent the user from changing cells, when it's done updating, go to this cell?
0
 

Author Comment

by:BlakeMcKenna
ID: 40023612
The call is asynchronous I'm not passing a reference because I'm assigning the retrieved value directly to the cell in the KeyPress Event. I do capture the row/column indexes and store them in variables. I'm wondering if I can capture the value in a variable and assign it to the cell in a different event?
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40027466
If the call is asynchronous you can pass a userstate as an object.

What I would do is pass a reference to the cell, and then when the value is returned, you can cast the reference back to the cell and update the value right in the process value event.

so for example:

Sub KeyPress

  AddHandler GetValueComplted, MyHandler  
  GetValueAsync(params, MydgCell)
end sub

Sub GetValueCompleted (sender, GetValueCompletedEventArgs e)
   DataGridCell cell = (DataGridCell) e.UserState
   cell.Value = e.Value
end sub


Something like that.  The above is just pseudo code to show the concept, not concrete or compilable.
0
 

Author Comment

by:BlakeMcKenna
ID: 40027518
I'm assuming I create this new event in the "KeyPress" event. What event should "MyHandler" be?

Can you show me this using VB.Net please?
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40027714
That is in VB.Net

Can you show me your code for processing the enter key, and retreiving the value from the digital Multireader?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:BlakeMcKenna
ID: 40027786
Look at your previous post. This code doesn't make sense to me!

Sub GetValueCompleted (sender, GetValueCompletedEventArgs e)
   DataGridCell cell = (DataGridCell) e.UserState
   cell.Value = e.Value
end sub

Open in new window


Here is the KeyPress Event:

    Private Sub cDGV_KeyUp(sender As Object, e As KeyEventArgs) Handles cDGV.KeyUp
        Try
            Dim blnLastCol As Boolean = False
            Dim oCurrentCell As DataGridViewCell = cDGV.CurrentCell

            If e.Handled = True Then
                Exit Sub
            End If

            EH.ErrorMessage = ""
            strCellData = ""

            colIDX = cDGV.CurrentCell.ColumnIndex
            rowIDX = cDGV.CurrentCell.RowIndex
            prevColIdx = colIDX - 1

            If prevColIdx > 0 Then
                strCellData = cDGV.Rows(rowIDX).Cells(prevColIdx - 1).Value
            End If

            If blnRunAdded Then
                startingCol = 5
            Else
                startingCol = 2
            End If

            If e.KeyCode = Keys.Return Or e.KeyCode = Keys.Tab Then
                If gblnOEM Then
                    If IsNumeric(cDGV.Rows(rowIDX).Cells(1).Value) Then
                        iRunValue = cDGV.Rows(rowIDX).Cells(1).Value
                    Else
                        iRunValue = 0
                    End If

                    If cboNLHyst.Checked Then
                        tmpCol += 1
                    End If

                    'The IF logic determines where to move the cursor after a reading is taken 
                    If rowIDX < cDGV.RowCount - 1 AndAlso (colIDX >= cDGV.ColumnCount - tmpCol And colIDX <= cDGV.ColumnCount) Then
                        If rowIDX = 0 Or rowIDX <> iTestRow Then
                            Dim i As Integer = 0
                        Else
                            If ValidateCellValues(cDGV.CurrentRow, colIDX) Then
                                If blnEnableFirstZero Then
                                    iRowFinished += 1
                                Else
                                    blnEnableFirstZero = True
                                End If

                                'If a new run has been added for a S/N, then the Rin, Rout and 1st Zero readings are skipped
                                If blnRunAdded Then
                                    cDGV.Columns(2).ReadOnly = False
                                    cDGV.Columns(3).ReadOnly = False
                                    cDGV.Columns(4).ReadOnly = False
                                End If

                                If cDGV.Columns(colIDX).HeaderText.IndexOf("Final Zero") Then
                                    cDGV.Rows(rowIDX).Cells(colIDX - 1).Value = GetDecimalPlaces(GetZeroOutput(RealReadMode, First0, oCurrentCell.Value, Me), gLoadDecimalPlaces)         'Gets Electronic Reading
                                    iTestRow += 1
                                End If
                            End If
                        End If

                        blnRunAdded = False
                        blnAddRunButtonClicked = False
                        startingCol = 2
                        cDGV.Rows(rowIDX + 1).ReadOnly = False
                        cDGV.CurrentCell = cDGV(startingCol, rowIDX + 1)
                    Else    'The ELSE logic will take a reading and place the value in the current cell
                        If Not cboManual.Checked And rowIDX <> 0 Then
                            If rowIDX = iTestRow Then
                                Select Case colIDX
                                    Case 0 To 2
                                        'Protected Columns
                                    Case 3
                                        If Not IsNothing(strCellData) AndAlso Not strCellData.Length = 0 Then
                                            cDGV.Rows(rowIDX).Cells(prevColIdx).Value = GetDecimalPlaces(ReadRin(1, 0), 0)
                                        End If
                                    Case 4
                                        If Not IsNothing(strCellData) AndAlso Not strCellData.Length = 0 Then
                                            cDGV.Rows(rowIDX).Cells(prevColIdx).Value = GetDecimalPlaces(ReadRout(1, 0), 0)
                                        End If
                                    Case 5  '1st Zero
                                        If Not IsNothing(strCellData) AndAlso Not strCellData.Length = 0 Then
                                            cDGV.Rows(rowIDX).Cells(prevColIdx).Value = GetDecimalPlaces(GetZeroOutput(RealReadMode, First0, oCurrentCell.Value, Me), gLoadDecimalPlaces)          'Gets Electronic Reading
                                        End If
                                    Case ((cDGV.ColumnCount + 1) - tmpCol) To cDGV.ColumnCount
                                        'Protected Columns
                                    Case colIDX
                                        If Not IsNothing(strCellData) AndAlso Not strCellData.Length = 0 Then
                                            sLoadAmt = GetLoadAmount(colIDX, 0)
                                            cDGV.Rows(rowIDX).Cells(prevColIdx).Value = GetDecimalPlaces(getOutput(RealReadMode, cmbOutputUnit.Text, sLoadAmt), gLoadDecimalPlaces)        'Gets Electronic Reading

                                            If colIDX = (cDGV.ColumnCount - tmpCol) And rowIDX = (cDGV.RowCount - 1) Then
                                                blnLastCol = True
                                            End If
                                        End If
                                End Select
                            End If
                        End If

                        If colIDX = cDGV.ColumnCount - tmpCol Then
                            If rowIDX = cDGV.RowCount - 1 Then
                                oCurrentCell = cDGV(startingCol, 1)
                            Else
                                oCurrentCell = cDGV(startingCol, rowIDX + 1)
                                If Not blnEnableFirstZero Then
                                    cDGV.Rows(rowIDX + 1).ReadOnly = False
                                    iRowFinished += 1
                                Else
                                    blnEnableFirstZero = True
                                End If
                            End If

                            blnAddRunButtonClicked = False
                            blnRunAdded = False
                        Else
                            oCurrentCell = cDGV(colIDX, rowIDX)
                        End If

                        cDGV.CurrentCell = oCurrentCell
                    End If
                Else
                    'AddHandler DelayCellAdvancement.KeyPress, AddressOf DelayCellAdvancement_KeyPress

                    If colIDX = 2 Then
                        idx += 1
                        sLoadAmt = GetLoadAmount(prevColIdx, rowIDX - 1)

                        If idx = cDGV.RowCount Then
                            cDGV.Rows(rowIDX).Cells(colIDX).Value = GetDecimalPlaces(getOutput(RealReadMode, cmbOutputUnit.Text, sLoadAmt), gLoadDecimalPlaces)         'Gets Electronic Reading
                            cDGV.ClearSelection()
                            txtFinalZero.Enabled = True
                            txtFinalZero.Focus()
                        Else
                            strCellValue = GetDecimalPlaces(getOutput(RealReadMode, cmbOutputUnit.Text, sLoadAmt), gLoadDecimalPlaces)        'Gets Electronic Reading
                            cDGV.Rows(rowIDX - 1).Cells(colIDX).Value = GetDecimalPlaces(getOutput(RealReadMode, cmbOutputUnit.Text, sLoadAmt), gLoadDecimalPlaces)         'Gets Electronic Reading
                            cDGV.CurrentCell = cDGV(startingCol, rowIDX)
                        End If
                    End If
                End If
            ElseIf e.KeyCode = Keys.Delete Then
                idx = rowIDX
                cDGV.CurrentCell.Value = ""
            End If

            If blnLastCol Then
                cDGV.ClearSelection()
                btnTestingComplete.BackColor = Color.LightGreen
                btnTestingComplete.Focus()
            End If

        Catch ex As Exception
            EH.ErrorMessage = "cDGV_KeyUp() - " & ex.Message & "...Contact Engineering!" & "~E"
        End Try

        EH.ProcessMessages(Me, sbr, EH.ErrorMessage)
    End Sub

Open in new window

0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40027949
I thought you said the readings were done asynchronously?

An asynchronous method you call the method specifying a call back method to invoke when the function is done.  These seem more synchronous?

Do you control the code for ReadRin, ReadRout, GetZeroOutput, and getOutput?
If so can you pass oCurrentCell as a param, and then update it in each call?
0
 

Author Comment

by:BlakeMcKenna
ID: 40028135
I'm a self-taught OOP. I looked up the definition of asynchronous/synchronous and apparently I thought it was something else. Can you show me an example of an asynchronous method plz?

I do control the code for the other Functions...
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40028271
What you're programming currently is synchronous.  Everything happens in lock step.

You call a function the processor jumps immediately to the function and then returns to the place when done.

Asynchronus programming happens in the background (may or may not be on a different thread).  

Esssentially you setup the function to call a "Callback method".  What you're saying to the program is hey, invoke this function, but I don't want to wait for it.  When it's done, go to this function over here so I can process the results.  The easiest way to tell is if you call a long running function in a synchronous mode your application will lock up while waiting for the results.  If it doesn't lock up you're most likely using asynchronous.

Google for asynchronous calls as it's really outside the scope of this question.

Since you control all of the other functions, I would pass oCurrentCell into each function as needed.  This way you don't care where the active cell is, you just run your code and when you're done update oCurrentCell.
0
 

Author Comment

by:BlakeMcKenna
ID: 40028300
Passing oCurrentCell into the function did not work...there was no change in the effect.
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40028302
post your code for one of the functions.
0
 

Author Comment

by:BlakeMcKenna
ID: 40028343
Here ya go:

    Public Function getOutput(ByVal ReadMode As Short, ByVal thisOutUnit As String, ByVal Value As Single, ByVal currentCell As DataGridViewCell) As Single
        Try
            Dim OutputValue As Single = UnrealOutput
            Dim thisExci As Double = CType(sglExci, Double)

            If ReadMode = PureTestMode Then
                Return Value
            End If

            If HPConnectedPort.IndexOf("Out") < 0 Then
                ConnectToOutputPort(thisOutUnit)
            End If

            If gstrFaultyDeviceName <> "" Then
                EH.ErrorMessage = "The " & gstrFaultyDeviceName & " is not functioning properly!" & "~I"
                EH.ProcessMessages(frmCalibration1, frmCalibration1.sbr, EH.ErrorMessage)
                Return UnrealOutput
            End If

            If thisOutUnit = "mV/V" Then
                OutputValue = CType((CType(readOutput(ReadMode, Value), Double) / thisExci) * 1000, Single)
            ElseIf thisOutUnit = "Vdc" Then
                OutputValue = readOutput(ReadMode, Value)
            ElseIf thisOutUnit = "mA" Then
                OutputValue = ReadOutputCurrent(ReadMode, Value) * 1000
            End If

            Return OutputValue

        Catch ex As Exception
            EH.ErrorMessage = "getOutput() - " & ex.Message & "...Contact Engineering!" & "~E"
        End Try

        EH.ProcessMessages(frmCalibration1, frmCalibration1.sbr, EH.ErrorMessage)
    End Function

Open in new window

0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40029648
You never used current cell -

Change it to a Sub as you will no longer need to return a value.

currentCell.Value = OutputValue

in place of the return.
0
 

Author Comment

by:BlakeMcKenna
ID: 40037875
I actually figured it out. The CellValidating event is what I want to use! I just need to figure out where to put the rest of the logic. But that is what you suggested in the first place.
0
 

Author Comment

by:BlakeMcKenna
ID: 40160558
I've requested that this question be closed as follows:

Accepted answer: 0 points for BlakeMcKenna's comment #a40037875

for the following reason:

I actually figured it out. The CellValidating event is what I want to use! I just need to figure out where to put the rest of the logic. But that is what you suggested in the first place.
0
 
LVL 40

Accepted Solution

by:
Kyle Abrahams earned 500 total points
ID: 40160560
The CellValidating event is what I want to use!  . . . But that is what you suggested in the first place.
0
 

Author Closing Comment

by:BlakeMcKenna
ID: 40166345
My apologies...I forgot about this question. That worked for me!
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

1.0 - Introduction Converting Visual Basic 6.0 (VB6) to Visual Basic 2008+ (VB.NET). If ever there was a subject full of murkiness and bad decisions, it is this one!   The first problem seems to be that people considering this task of converting…
It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

747 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now