Results 1 to 22 of 22

Thread: [RESOLVED] Backgroundworker - Can not get datagrid to update

  1. #1

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Resolved [RESOLVED] Backgroundworker - Can not get datagrid to update

    I have looked and looked but something is just not clicking. I'm running a simple tcp server in the background and want to update a datagrid with the incoming information. The server is working, but I cannot get the UI grid updated.

    Code:
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Me.Show()
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            BackgroundWorker1.WorkerReportsProgress = True
            Main()
        End Sub
    
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    
            Dim D(20) As String
            Dim ReceivedLine As String
    
            ReceivedLine = CType(e.UserState, String)
            MsgBox(ReceivedLine)  ' This comes up and gives me the correct text
    
            D = ReceivedLine.Split("~")
    
            Try
    
                Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3))   ' nothing is added to the grid.  I did an add in form_load and it works.
    
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
    
        End Sub
    I set up the background worker and in the server sub I have reportprogress. The msgbox you see pops up and has the correct text in it, but the grid is not updating. I thought that could be assessed in this progress changed function. What am I missing?

    Thanks

  2. #2
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,715

    Re: Backgroundworker - Can not get datagrid to update

    What does Main() do? You should also have all of your work in the DoWork sub as opposed to the ProgressChanged sub. Also, you may want to consider replacing CType with DirectCast and MsgBox with MessageBox.Show.

    Edit - The reason for the suggestion to change to DirectCast is because of this article. Also for using the backgroundworker refer to this thread.
    Last edited by dday9; Apr 24th, 2013 at 03:47 PM.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  3. #3

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by dday9 View Post
    What does Main() do? You should also have all of your work in the DoWork sub as opposed to the ProgressChanged sub. Also, you may want to consider replacing CType with DirectCast and MsgBox with MessageBox.Show.

    Edit - The reason for the suggestion to change to DirectCast is because of this article. Also for using the backgroundworker refer to this thread.
    Ok - the way I read it was the DoWork could not talk directly to the UI which is why I was doing it this way. Never claim to be a programmer. Just trying to get a project done.

    Main is a simple TCP server including the following. The code will need to be cleaned up. I'm just trying to get this to work. The tcp should receive a string with fields separated by ~ as in 1~2~3~4~.... Break that up and post to the dataviewgrid:

    Code:
     Sub Main()
    
            BackgroundWorker1.WorkerReportsProgress = True
            serverSocket.Start()
            MsgBox("Server Started")
            counter = 0
            While (True)
                counter += 1
                clientSocket = serverSocket.AcceptTcpClient()
                Dim client As New handleClinet
                client.startClient(clientSocket, Convert.ToString(counter))
            End While
    
            clientSocket.Close()
            serverSocket.Stop()
            MsgBox("exit")
        End Sub
    
    
        Public Sub startClient(ByVal inClientSocket As TcpClient, _
        ByVal clineNo As String)
            Me.clientSocket = inClientSocket
            Me.clNo = clineNo
            Dim ctThread As Threading.Thread = New Threading.Thread(AddressOf doChat)
            ctThread.Start()
        End Sub
    
        Public Sub doChat()
    
            requestCount = 0
    
            While (True)
                Try
                    requestCount = requestCount + 1
                    Dim networkStream As NetworkStream = _
                            clientSocket.GetStream()
                    networkStream.Read(bytesFrom, 0, CInt(clientSocket.ReceiveBufferSize))
                    dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom)
                    If dataFromClient.Contains(vbCr) Or dataFromClient.Contains(vbCrLf) Then
                        BackgroundWorker1.ReportProgress(1, ReceivedLine)
                        RtnString = ReceivedLine
                        SendTCP(networkStream, ReceivedLine)
                        ReceivedLine = ""
                    Else
                        ReceivedLine += dataFromClient.Substring(0, 1)
                    End If
    
    
                Catch ex As Exception
                    MsgBox(ex.ToString)
                End Try
    
            End While
    
        End Sub
    tnx

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,989

    Re: Backgroundworker - Can not get datagrid to update

    Yeah, you are updating the grid in the ProgressChanged event, which should be right. You also say that the messagebox is showing correctly, which is interesting. I assume that you are getting no error message, either.

    What I would do would be to put a breakpoint on the key line:

    Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3))

    When execution stops at the breakpoint, the line has not yet executed, which is what you want. At that point, highlight Me.MainGrid.Rows and press Shift+F9. That will show you the result of that statement, which is the Rows collection. Take a look at the .Count property to see how many rows are currently there. Then close that window and press F11, which will step forward one line. At that point, go back and repeat those steps to see what Me.MainGrid.Rows.Count is now showing. If you see that it is one higher than it was before then you know that the line was added. At that point, the question becomes: Why can't you see it?

    There are a couple possible answers. One thing you could try would be Me.MainGrid.Refresh. I'm not quite sure what happens when the ReportProgress event is raised, and it seems really improbable that the paint message is not getting through, but .Refresh would solve that. Unfortunately, the other possibility doesn't seem quite right to me either, which is that you are updating the wrong grid. Still, those are a few early steps to take.
    My usual boring signature: Nothing

  5. #5

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by Shaggy Hiker View Post
    Yeah, you are updating the grid in the ProgressChanged event, which should be right. You also say that the messagebox is showing correctly, which is interesting. I assume that you are getting no error message, either.

    What I would do would be to put a breakpoint on the key line:

    Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3))

    When execution stops at the breakpoint, the line has not yet executed, which is what you want. At that point, highlight Me.MainGrid.Rows and press Shift+F9. That will show you the result of that statement, which is the Rows collection. Take a look at the .Count property to see how many rows are currently there. Then close that window and press F11, which will step forward one line. At that point, go back and repeat those steps to see what Me.MainGrid.Rows.Count is now showing. If you see that it is one higher than it was before then you know that the line was added. At that point, the question becomes: Why can't you see it?

    There are a couple possible answers. One thing you could try would be Me.MainGrid.Refresh. I'm not quite sure what happens when the ReportProgress event is raised, and it seems really improbable that the paint message is not getting through, but .Refresh would solve that. Unfortunately, the other possibility doesn't seem quite right to me either, which is that you are updating the wrong grid. Still, those are a few early steps to take.
    Ok - tried a few things based on your suggestion. There is only one grid in the forms so has to be that one. I have a statement in the Load functions that adds data and that appears normally. I did the following code:
    Code:
                MsgBox("Rows " + MainGrid.RowCount.ToString)
                MsgBox("data is " + D(0) + " " + D(1) + " " + D(2) + " " + D(3))
                Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3))
                MainGrid.Refresh()
                MsgBox("Rows " + MainGrid.RowCount.ToString)
    Still does not show up. The data is there in D(x) and the row count increase for each time it gets a line but nothing shows in the datagrid. I have gone through and looked at the grid's properties and see nothing obvious. They are all the default setting allowing user update, etc. I even went to the form, deleted the DataGridView that was names MainGrid and then placed another grid called default DataGridView1. Same results. Count show the rows are added, the data D(x) is populated but nothing actually appears in the grid.

    The grid settings are all default now. Went in and added the columns with names only. Did not change anything in the settings. There are no errors and it loops fine with each incoming message. Probably something simple right in front of me. I did get hit by a big limb while cutting some trees. Maybe I can use that as an excuse.

  6. #6
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Backgroundworker - Can not get datagrid to update

    the way I read it was the DoWork could not talk directly to the UI
    MsgBox("Server Started")
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

  7. #7
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: Backgroundworker - Can not get datagrid to update

    Isn't "D" a string array? If so, then just add the array without trying to specify the elements:


    vb.net Code:
    1. Me.MainGrid.Rows.Add(D)


    Edit: Just now noticed you initialized with 20 elements. Are they all needed?

    Edit...Again: Where are you initializing the ReceivedLine variable that is used here:

    vb.net Code:
    1. BackgroundWorker1.ReportProgress(1, ReceivedLine)

    I only see it declared in your ProgressChanged event, which is outside the scope of the DoWork event.
    Last edited by circuits2; Apr 24th, 2013 at 07:57 PM.
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  8. #8

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by circuits2 View Post
    Isn't "D" a string array? If so, then just add the array without trying to specify the elements:


    vb.net Code:
    1. Me.MainGrid.Rows.Add(D)


    Edit: Just now noticed you initialized with 20 elements. Are they all needed?

    Edit...Again: Where are you initializing the ReceivedLine variable that is used here:

    vb.net Code:
    1. BackgroundWorker1.ReportProgress(1, ReceivedLine)

    I only see it declared in your ProgressChanged event, which is outside the scope of the DoWork event.

    First, doing Me.MainGrid.Rows.Add(D) did nothing. Shows the same in the msgbox that rows are increased, but nothing appears in the grid in form1. 20 elements are not used in this example, but will be as the program develops. There are a few items like that but got stopped with the basic routines not working.

    ReceivedLine was originally a global. I since changed it to be declared in ProgressChanged. No change.

    I even tried putting a dummy add like Me.MainGrid.Add("a", "b", "c", "d") first thing in ProgressChanged and a row shows added, but still does not display in the form1.MainGrid datagridview.

  9. #9
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: Backgroundworker - Can not get datagrid to update

    Variables that are declared in the ProgressChanged event are declared in the UI thread. You need to declare it in the DoWork event as well, otherwise the data is never fully passed.

    Edit: Sorry, in your case it needs to be declared in DoChat()
    Last edited by circuits2; Apr 24th, 2013 at 08:41 PM.
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  10. #10

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by circuits2 View Post
    Variables that are declared in the ProgressChanged event are declared in the UI thread. You need to declare it in the DoWork event as well, otherwise the data is never fully passed.

    Edit: Sorry, in your case it needs to be declared in DoChat()
    Here is the code as it stands now after some changes discussed here to bring that up to date. Some issue. Will not update the datagridview UI. ReceivedLine is declared in DoChat() also.

    Code:
     
        Dim clNo As String
        Dim serverSocket As New TcpListener(8888)
        Dim clientSocket As TcpClient
        Dim counter As Integer
    
        Dim requestCount As Integer
        Dim bytesFrom(10024) As Byte
        Dim dataFromClient As String
        Dim sendBytes As [Byte]()
        Dim serverResponse As String
        Dim rCount As String
    
        Dim RtnString As String = ""
    
        Dim D(20) As String
    
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Me.Show()
            Me.MainGrid.Rows.Add("11", "2", "3", "4") ' This is added to the grid upon starting up so this works.
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            
            BackgroundWorker1.WorkerReportsProgress = True
            serverSocket.Start()
            MsgBox("Server Started")
            counter = 0
            While (True)
                counter += 1
                clientSocket = serverSocket.AcceptTcpClient()
                Dim client As New handleClinet
                client.startClient(clientSocket, Convert.ToString(counter))
            End While
    
            clientSocket.Close()
            serverSocket.Stop()
            MsgBox("exit")
    
        End Sub
    
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    
            Dim D(20) As String
            Dim ReceivedLine As String = ""
    
            ReceivedLine = CType(e.UserState, String)
            MsgBox(ReceivedLine) ' -----This shows the correct full string with ~ delimiters
            D = ReceivedLine.Split("~")
    
            Try
    
                ' This monitors the progress.  Row count is incremented each time
                ' this is done.  MsgBox above and here shows the data both as
                ' ReceivedLine and D.  Row is increased by count but does not display
                ' in the form1 grid
                MsgBox("Rows " + MainGrid.RowCount.ToString)
                MsgBox("data is " + D(0) + " " + D(1) + " " + D(2) + " " + D(3)) ' currently only using the first 4 variables until it works
                Me.MainGrid.Rows.Add(D)
                'Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3))  ' Not used per above line
                MainGrid.Refresh()
                MsgBox("Rows " + MainGrid.RowCount.ToString)
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
    
        End Sub
    
    
    
        Public Sub startClient(ByVal inClientSocket As TcpClient, _
        ByVal clineNo As String)
            Me.clientSocket = inClientSocket
            Me.clNo = clineNo
            Dim ctThread As Threading.Thread = New Threading.Thread(AddressOf doChat)
            ctThread.Start()
        End Sub
        Public Sub doChat()
    
            requestCount = 0
            Dim ReceivedLine As String = ""
    
            While (True)
                Try
                    requestCount = requestCount + 1
                    Dim networkStream As NetworkStream = _
                            clientSocket.GetStream()
                    networkStream.Read(bytesFrom, 0, CInt(clientSocket.ReceiveBufferSize))
                    dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom)
                    'dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"))
                    If dataFromClient.Contains(vbCr) Or dataFromClient.Contains(vbCrLf) Then
                        'MsgBox(ReceivedLine)
    
                        BackgroundWorker1.ReportProgress(1, ReceivedLine)
                        RtnString = ReceivedLine
                        SendTCP(networkStream, ReceivedLine)
                        ReceivedLine = ""
                    Else
                        ReceivedLine += dataFromClient.Substring(0, 1)
                    End If
    
                Catch ex As Exception
                    MsgBox(ex.ToString)
                End Try
    
            End While
    
        End Sub
    
        Sub SendTCP(N As NetworkStream, R As String)
            rCount = Convert.ToString(requestCount)
            serverResponse = "Server to clinet(" + R + ") "
            sendBytes = Encoding.ASCII.GetBytes(serverResponse)
            N.Write(sendBytes, 0, sendBytes.Length)
            N.Flush()
        End Sub

  11. #11
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: Backgroundworker - Can not get datagrid to update

    Ok, still, all of those variables are declared in the UI thread. That means that any routine that is called by DoWork cannot use them. Also, you need to remove the MsgBox calls from DoWork. MessageBox should be called from ProgressChanged.

    These cannot be accessed by any routine that is called by your backgroundworker:

    vb.net Code:
    1. Dim clNo As String
    2. Dim serverSocket As New TcpListener(8888)
    3. Dim clientSocket As TcpClient
    4. Dim counter As Integer
    5.  
    6. Dim requestCount As Integer
    7. Dim bytesFrom(10024) As Byte
    8. Dim dataFromClient As String
    9. Dim sendBytes As [Byte]()
    10. Dim serverResponse As String
    11. Dim rCount As String
    12.  
    13. Dim RtnString As String = ""
    14.  
    15. Dim D(20) As String
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  12. #12
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: Backgroundworker - Can not get datagrid to update

    You could move everything except the event code to a module and it would work fine.
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  13. #13

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by circuits2 View Post
    Ok, still, all of those variables are declared in the UI thread. That means that any routine that is called by DoWork cannot use them. Also, you need to remove the MsgBox calls from DoWork. MessageBox should be called from ProgressChanged.

    These cannot be accessed by any routine that is called by your backgroundworker:

    vb.net Code:
    1. Dim clNo As String
    2. Dim serverSocket As New TcpListener(8888)
    3. Dim clientSocket As TcpClient
    4. Dim counter As Integer
    5.  
    6. Dim requestCount As Integer
    7. Dim bytesFrom(10024) As Byte
    8. Dim dataFromClient As String
    9. Dim sendBytes As [Byte]()
    10. Dim serverResponse As String
    11. Dim rCount As String
    12.  
    13. Dim RtnString As String = ""
    14.  
    15. Dim D(20) As String
    Ok. This is a newbie question (which is the main problem here) but if I declare those variables in DoWork, they are not seen by StartClient or DoChat as they are only available to DoWork. Does that mean I need to declare them in DoWork and pass the variable(s) to the other Subs? If they can not be accessed, then how does the program work at all? It does everything but show the values in the datagridview.

    The main issue I am having is why is this information available to MsgBox both as the full line (ReceivedLine in ProgressChanged) and I can split the line into variables. I just cannot get them to show in the grid although count increases as lines are added. And, neither can I get just a fixed line as in

    Me.MainGrid.Rows.Add("a", "b", "c", "d")

    when placed in ProgressChanged? Those variables are only in that sub and also do not show up in the grid although the row count increases.



    Thanks for your help -- AND patience.

  14. #14

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by circuits2 View Post
    You could move everything except the event code to a module and it would work fine.
    I will try and move to a module and see what happens......

  15. #15
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: Backgroundworker - Can not get datagrid to update

    Everything that is called by DoWork needs to be self contained without relying on resources that are provided by the UI thread. Variables that are declared at the top of your Form class are in the UI thread, thus unavailable to your backgroundworker. You can declare them in DoWork and then pass the needed variables to your subs using arguments:

    vb.net Code:
    1. Public Sub DoChat(ByVal ThisString As String, ByVal ThisNum As Integer)
    2.  
    3.     ' Something Special Here
    4.  
    5. End Sub
    6.  
    7. Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    8.  
    9. Dim myString As String = "Blah Blah"
    10. Dim myNum As Integer = 2013
    11.  
    12. DoChat(myString, myNum)
    13.  
    14. End Sub

    Passing an argument ByVal will simply make a copy for the routine you are calling. Passing ByRef will allow the routine to change the actual variable that you are passing.
    Last edited by circuits2; Apr 24th, 2013 at 09:35 PM.
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  16. #16

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    Ok - regroup....

    I took the code and separated the tcpserver from the main UI form1 and into a module. I have the same issue that the grid will not show any update even though if I count rows they do increase.

    Code:
    Public Class Form1
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            BackgroundWorker1.WorkerReportsProgress = True
            AddHandler BackgroundWorker1.DoWork, AddressOf BackgroundWorker1_DoWork
            AddHandler BackgroundWorker1.ProgressChanged, AddressOf BackgroundWorker1_ProgressChanged
            Module1.Main()
        End Sub
    
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    
            Dim D(10) As String
            Dim ReceivedLine As String = ""
    
            ReceivedLine = CType(e.UserState, String)
            MsgBox(ReceivedLine)
            D = ReceivedLine.Split("~")
    
            Try
    
                ' This monitors the progress.  Row count is incremented each time
                ' this is done.  MsgBox above and here shows the data both as
                ' ReceivedLine and D correctly.  Row is increased by count but does not display
                ' in the form1 grid
                MsgBox("Rows " + MainGrid.RowCount.ToString)
                MsgBox("data is " + D(0) + " " + D(1) + " " + D(2) + " " + D(3))
                Me.MainGrid.Rows.Add(D)
                MsgBox("Rows " + MainGrid.RowCount.ToString)
    
                '
                ' Here I loop through the grid and the result shows each row with the correct first column
                ' but nothing is shown in the datagridview of form1
                '
                
                ' this tries to add to MainGrid. Same results, it is added and when 
                ' the for each row above comes around again it shows this line.  But the
                ' grid in form1 is still blank
                Me.MainGrid.Rows.Add("a1", "b1", "b2", "b3")
    
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
    
        End Sub
    
    End Class

    And the module code is

    Code:
    Imports System.Net.Sockets
    Imports System.Text
    Module Module1
    
        Sub Main()
    
            Dim serverSocket As New TcpListener(8888)
            Dim clientSocket As TcpClient
            Dim counter As Integer
    
            serverSocket.Start()
            counter = 0
            While (True)
                counter += 1
                clientSocket = serverSocket.AcceptTcpClient()
                Dim client As New handleClinet
                client.startClient(clientSocket, Convert.ToString(counter))
            End While
    
            clientSocket.Close()
            serverSocket.Stop()
    
        End Sub
        Public Class handleClinet
            Dim clientSocket As TcpClient
            Dim clNo As String
            Public Sub startClient(ByVal inClientSocket As TcpClient, _
            ByVal clineNo As String)
                Me.clientSocket = inClientSocket
                Me.clNo = clineNo
                Dim ctThread As Threading.Thread = New Threading.Thread(AddressOf doChat)
                ctThread.Start()
            End Sub
            Public Sub doChat()
    
                Dim requestCount As Integer = 0
                Dim bytesFrom(10024) As Byte
                Dim dataFromClient As String
                Dim ReceivedLine As String = ""
    
                While (True)
                    Try
                        requestCount = requestCount + 1
                        Dim networkStream As NetworkStream = clientSocket.GetStream()
                        networkStream.Read(bytesFrom, 0, CInt(clientSocket.ReceiveBufferSize))
                        dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom)
                        If dataFromClient.Contains(vbCr) Or dataFromClient.Contains(vbCrLf) Then                       
                            Form1.BackgroundWorker1.ReportProgress(1, ReceivedLine + "~xxx")
                            SendTCP(networkStream, ReceivedLine, requestCount)
                            ReceivedLine = ""
                        Else
                            ReceivedLine += dataFromClient.Substring(0, 1)
                        End If
    
                    Catch ex As Exception
                        MsgBox(ex.ToString)
                    End Try
    
                End While
    
            End Sub
    
            Sub SendTCP(N As NetworkStream, R As String, requestCount As Integer)
    
                Dim sendBytes As [Byte]()
                Dim serverResponse As String
                Dim rCount As String
    
                rCount = Convert.ToString(requestCount)
                serverResponse = "Server to clinet(" + R + ") "
                sendBytes = Encoding.ASCII.GetBytes(serverResponse)
                N.Write(sendBytes, 0, sendBytes.Length)
                N.Flush()
            End Sub
        End Class
    End Module
    This setup gives me the same result as when I had everything in one. The server starts and accepts a connect. I then send a string with ~ delimiters. The string is received, ProgressChanged is called and the information can be displayed in that sub using MsgBox. The received line and the split line is there. But, when I add it to the datagridview (MainGrid) nothing appears. Looking at the count of rows in MainGrid, it does increase with each time I send the string. Everything appears to be added, but nothing appears in the datagridview of form1.

    There is form1 and module1 in the project. The form1 design has only a datagridview control. The only change after adding the control was to change its name to MainGrid. Everything else is default. I tried putting it back to DataGridView1 but no difference. I put an add statement in form1_load with Me.MainGrid.Rows.Add("a", "b", "c", "d") and that appears in the grid....

  17. #17
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: Backgroundworker - Can not get datagrid to update

    See if this helps you at all. I made some changes. I created a new project with one form (Form1), one datagridview (DataGridView1), and dropped a backgroundworker (BackgroundWorker1) onto the form from the toolbox:


    vb.net Code:
    1. Imports System.Net
    2. Imports System.Net.Sockets
    3. Imports System.Text
    4.  
    5.  
    6. Public Class Form1
    7.  
    8.     Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    9.         Me.DataGridView1.Rows.Add("11", "2", "3", "4") ' This is added to the grid upon starting up so this works.
    10.         BackgroundWorker1.WorkerReportsProgress = True
    11.         BackgroundWorker1.RunWorkerAsync()
    12.     End Sub
    13.  
    14.     Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    15.  
    16.         ' DECLARE VARIABLES FOR BACKGROUND WORKER THREAD
    17.         Dim ipAddress As IPAddress = Dns.GetHostEntry("localhost").AddressList(0)
    18.         Dim ipLocalEndPoint As New IPEndPoint(ipAddress, 8888)
    19.         Dim serverSocket As New TcpListener(ipLocalEndPoint)
    20.         Dim clientSocket As TcpClient
    21.         Dim counter As Integer
    22.  
    23.         ' START TCP LISTENER
    24.         serverSocket.Start()
    25.  
    26.         ' WHAT DO WE NEED THIS COUNTER FOR?
    27.         counter = 0
    28.  
    29.         While (True)
    30.  
    31.             ' DO WE REALLY NEED A COUNT THAT IS NEVER USED?
    32.             counter += 1
    33.  
    34.             ' ACCEPT PENDING CONNECTION REQUEST
    35.             clientSocket = serverSocket.AcceptTcpClient()
    36.  
    37.             ' I GOT RID OF YOUR STARTCLIENT() ROUTINE BECAUSE IT WAS NOT NEEDED
    38.             ' DO YOUR "CHATTING"
    39.             doChat(clientSocket, BackgroundWorker1)
    40.  
    41.         End While
    42.  
    43.         ' STOP THE TCP LISTENER
    44.         serverSocket.Stop()
    45.  
    46.     End Sub
    47.  
    48.  
    49.     Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    50.  
    51.         Dim D(20) As String
    52.         Dim ReceivedLine As String = ""
    53.  
    54.         ReceivedLine = CType(e.UserState, String)
    55.         MsgBox(ReceivedLine) ' -----This shows the correct full string with ~ delimiters
    56.         D = ReceivedLine.Split(CChar("~"))
    57.  
    58.         Try
    59.  
    60.             ' This monitors the progress.  Row count is incremented each time
    61.             ' this is done.  MsgBox above and here shows the data both as
    62.             ' ReceivedLine and D.  Row is increased by count but does not display
    63.             ' in the form1 grid
    64.             MsgBox("Rows " + DataGridView1.RowCount.ToString)
    65.             MsgBox("data is " + D(0) + " " + D(1) + " " + D(2) + " " + D(3)) ' currently only using the first 4 variables until it works
    66.             Me.DataGridView1.Rows.Add(D)
    67.             'Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3))  ' Not used per above line
    68.             DataGridView1.Refresh()
    69.             MsgBox("Rows " + DataGridView1.RowCount.ToString)
    70.         Catch ex As Exception
    71.             MsgBox(ex.Message)
    72.         End Try
    73.  
    74.     End Sub
    75.  
    76.  
    77.     ' NOTICE I USED BYREF AND NOT BYVAL. THIS LETS ME USE THE TCPCLIENT THAT HAS ALREADY BEEN DECLARED
    78.     Public Sub doChat(ByRef clientSocket As TcpClient, ByRef bw As System.ComponentModel.BackgroundWorker)
    79.  
    80.         ' DECLARE VARIABLES FOR THIS SUB ONLY
    81.         Dim requestCount As Integer = 0
    82.         Dim dataFromClient As String
    83.         Dim ReceivedLine As String = ""
    84.         Dim bytesFrom(10024) As Byte
    85.         Dim RtnString As String = ""
    86.  
    87.  
    88.         While (True)
    89.             Try
    90.  
    91.                 ' REALLY? WHY DO WE NEED TO COUNT WHEN THE COUNT IS NOT USED?
    92.                 requestCount = requestCount + 1
    93.  
    94.                 ' OPEN NETWORK STREAM
    95.                 Dim networkStream As NetworkStream = clientSocket.GetStream()
    96.  
    97.                 ' READ YOUR BYTES
    98.                 networkStream.Read(bytesFrom, 0, CInt(clientSocket.ReceiveBufferSize))
    99.  
    100.                 ' PARSE YOUR DATA
    101.                 dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom)
    102.  
    103.                 ' PASS THE DATA BACK UP TO THE BACKGROUNDWORKER
    104.                 If dataFromClient.Contains(vbCr) Or dataFromClient.Contains(vbCrLf) Then
    105.                     bw.ReportProgress(1, ReceivedLine)
    106.                     RtnString = ReceivedLine
    107.                     SendTCP(networkStream, ReceivedLine)
    108.                     ReceivedLine = ""
    109.                 Else
    110.                     ReceivedLine += dataFromClient.Substring(0, 1)
    111.                 End If
    112.  
    113.             Catch ex As Exception
    114.                 Debug.WriteLine(ex.Message)
    115.             End Try
    116.  
    117.         End While
    118.  
    119.     End Sub
    120.  
    121.     Sub SendTCP(ByRef N As NetworkStream, ByVal R As String)
    122.         Dim sendBytes As [Byte]()
    123.         Dim serverResponse As String
    124.         serverResponse = "Server to clinet(" + R + ") "
    125.         sendBytes = Encoding.ASCII.GetBytes(serverResponse)
    126.         N.Write(sendBytes, 0, sendBytes.Length)
    127.         N.Flush()
    128.     End Sub
    129.  
    130. End Class
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  18. #18

    Thread Starter
    New Member
    Join Date
    Apr 2013
    Posts
    9

    Re: Backgroundworker - Can not get datagrid to update

    That worked for me so I'll consider this resolved (as far as the forum). I will look at your code (thanks!) and then modify my original one until I get it to work. Want to understand why the other was not work.

    Thanks for all your assistance.

  19. #19
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,989

    Re: [RESOLVED] Backgroundworker - Can not get datagrid to update

    I went fishing and wasn't around for any of this. However, I'd like to clear up some confusion.

    Variables that are not declared local are not thread specific. That's the whole reason for synchronization objects such as the Monitor, Mutex, and so forth. There is (mostly) no such thing as variables specific to any one thread, whether UI or BGW. That talk about moving things to a module made me think of one exception to that which can make it look like variables are thread local (variables that are declared within a method, and are therefore local variables, ARE thread local, but variables outside of the thread are not): Default instances of forms are thread specific. Therefore, if you are working with the default instance of forms, you could easily be creating a new instance of the form from any thread, in which case any form-level variables in that form would also be effectively thread-specific because the form itself was and the variables are part of the form. By moving to a module, you certainly aren't thread specific, because you are also certainly not using default instances.

    Ultimately, if the grid is increasing it's count, then the rows ARE being added. Why aren't you seeing them? Because you are looking at the wrong grid. You can prove this, too, but it won't be so easy. What you would need to do would be something like this: Add a button to the form with the click event holding something like Messagebox.Show(Me.MainGrid.Count). The button and the click event are clearly on the same form instance that you are seeing, so you would then run, get the ProgressChanged event, confirm that the row count increased, then press the button. I expect that you would see that the count when you do that is exactly the same as the number of rows you are seeing, rather than being the increased count you saw in the ProgressChanged event. If that is the case, you would have pretty good proof that the grid that had the new record added to it was not the one you were seeing. I haven't dealt with the issue of default instances being thread local, so I don't know all the details of it, but this is what makes most sense. After all, the alternative is to say that the grid has rows, but just decides not to show them occasionally and rather arbitrarily. Or else, perhaps the count of rows is arbitrarily not the actual number of rows that are in the grid. Either of these would be pretty hard to achieve deliberately, let alone by accident. Furthermore, if non-local variables were thread local there would be no such thing as Deadlocks or Race conditions, nor would there be need for Syncloc, Monitors, Mutexes, and the like. Finally, there is a case where a second form instance will be created for a thread, and that is the default instance, which you appear to be using (the startup form is almost always a default instance). So, though I don't know the details of how it is happening (JMC could probably explain it better), you are almost certainly adding the row to the wrong grid, and by adding that button you'd be able to prove it.
    My usual boring signature: Nothing

  20. #20
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: [RESOLVED] Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by Shaggy Hiker View Post
    I haven't dealt with the issue of default instances being thread local, so I don't know all the details of it, but this is what makes most sense.
    I ran into the issue with default instances a few days ago, which is how I spotted the problem. I was using a backgroundworker to update properties in the default instance of a form. The backgroundworker would run, report progress as usual, and complete without errors, but the properties would remain unchanged even though I watched each step of the process and saw the changes being made. In my case, I moved the properties outside of the form into a module and the entire application works flawlessly with three backgroundworkers.

    RVideo was originally declaring variables inside the form class and then accessing them from procedures that were run by the backgroundworker. This is a no-no. As proof, the only change I made to the original code was to move the variable declarations inside the subs and the thread is now resolved.
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

  21. #21
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,989

    Re: [RESOLVED] Backgroundworker - Can not get datagrid to update

    It isn't itself a problem. As he showed, and as you showed, you were updating something, you just weren't updating the same instance of the form as the one that you were displaying.
    My usual boring signature: Nothing

  22. #22
    Frenzied Member circuits2's Avatar
    Join Date
    Sep 2006
    Location
    Kansas City, MO
    Posts
    1,027

    Re: [RESOLVED] Backgroundworker - Can not get datagrid to update

    Quote Originally Posted by Shaggy Hiker View Post
    you just weren't updating the same instance of the form as the one that you were displaying.
    I agree. I'm curious how it could do this without throwing an exception. If there is only one instance of the form, the default instance, then the backgroundworker would either have to create a new instance or throw a null reference, wouldn't it?
    Show the love! Click (rate this post) under my name if I was helpful.

    My CodeBank Submissions: How to create a User Control | Move a form between Multiple Monitors (Screens) | Remove the MDI Client Border | Using Report Viewer with Visual Studio 2012 Express

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width