Solved

Waiting for value in DataGridView Cell before advancing?

Posted on 2014-04-25
24
217 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
[X]
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
  • 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
MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

 

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
 

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

Creating Instructional Tutorials  

For Any Use & On Any Platform

Contextual Guidance at the moment of need helps your employees/users adopt software o& achieve even the most complex tasks instantly. Boost knowledge retention, software adoption & employee engagement with easy solution.

Question has a verified solution.

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

Suggested Solutions

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

710 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