-
Apr 24th, 2013, 11:45 AM
#1
Thread Starter
New Member
[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
-
Apr 24th, 2013, 03:44 PM
#2
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.
-
Apr 24th, 2013, 03:56 PM
#3
Thread Starter
New Member
Re: Backgroundworker - Can not get datagrid to update
Originally Posted by dday9
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
-
Apr 24th, 2013, 04:30 PM
#4
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
-
Apr 24th, 2013, 05:04 PM
#5
Thread Starter
New Member
Re: Backgroundworker - Can not get datagrid to update
Originally Posted by Shaggy Hiker
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.
-
Apr 24th, 2013, 06:31 PM
#6
Re: Backgroundworker - Can not get datagrid to update
the way I read it was the DoWork could not talk directly to the UI
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!
-
Apr 24th, 2013, 07:47 PM
#7
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:
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:
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.
-
Apr 24th, 2013, 08:23 PM
#8
Thread Starter
New Member
Re: Backgroundworker - Can not get datagrid to update
Originally Posted by circuits2
Isn't "D" a string array? If so, then just add the array without trying to specify the elements:
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:
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.
-
Apr 24th, 2013, 08:33 PM
#9
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.
-
Apr 24th, 2013, 08:54 PM
#10
Thread Starter
New Member
Re: Backgroundworker - Can not get datagrid to update
Originally Posted by circuits2
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
-
Apr 24th, 2013, 08:59 PM
#11
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:
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
-
Apr 24th, 2013, 09:06 PM
#12
Re: Backgroundworker - Can not get datagrid to update
You could move everything except the event code to a module and it would work fine.
-
Apr 24th, 2013, 09:11 PM
#13
Thread Starter
New Member
Re: Backgroundworker - Can not get datagrid to update
Originally Posted by circuits2
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:
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
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.
-
Apr 24th, 2013, 09:12 PM
#14
Thread Starter
New Member
Re: Backgroundworker - Can not get datagrid to update
Originally Posted by circuits2
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......
-
Apr 24th, 2013, 09:20 PM
#15
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:
Public Sub DoChat(ByVal ThisString As String, ByVal ThisNum As Integer) ' Something Special Here End Sub Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork Dim myString As String = "Blah Blah" Dim myNum As Integer = 2013 DoChat(myString, myNum) 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.
-
Apr 24th, 2013, 11:21 PM
#16
Thread Starter
New Member
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....
-
Apr 25th, 2013, 01:09 AM
#17
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:
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.DataGridView1.Rows.Add("11", "2", "3", "4") ' This is added to the grid upon starting up so this works.
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
' DECLARE VARIABLES FOR BACKGROUND WORKER THREAD
Dim ipAddress As IPAddress = Dns.GetHostEntry("localhost").AddressList(0)
Dim ipLocalEndPoint As New IPEndPoint(ipAddress, 8888)
Dim serverSocket As New TcpListener(ipLocalEndPoint)
Dim clientSocket As TcpClient
Dim counter As Integer
' START TCP LISTENER
serverSocket.Start()
' WHAT DO WE NEED THIS COUNTER FOR?
counter = 0
While (True)
' DO WE REALLY NEED A COUNT THAT IS NEVER USED?
counter += 1
' ACCEPT PENDING CONNECTION REQUEST
clientSocket = serverSocket.AcceptTcpClient()
' I GOT RID OF YOUR STARTCLIENT() ROUTINE BECAUSE IT WAS NOT NEEDED
' DO YOUR "CHATTING"
doChat(clientSocket, BackgroundWorker1)
End While
' STOP THE TCP LISTENER
serverSocket.Stop()
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(CChar("~"))
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 " + DataGridView1.RowCount.ToString)
MsgBox("data is " + D(0) + " " + D(1) + " " + D(2) + " " + D(3)) ' currently only using the first 4 variables until it works
Me.DataGridView1.Rows.Add(D)
'Me.MainGrid.Rows.Add(D(0), D(1), D(2), D(3)) ' Not used per above line
DataGridView1.Refresh()
MsgBox("Rows " + DataGridView1.RowCount.ToString)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
' NOTICE I USED BYREF AND NOT BYVAL. THIS LETS ME USE THE TCPCLIENT THAT HAS ALREADY BEEN DECLARED
Public Sub doChat(ByRef clientSocket As TcpClient, ByRef bw As System.ComponentModel.BackgroundWorker)
' DECLARE VARIABLES FOR THIS SUB ONLY
Dim requestCount As Integer = 0
Dim dataFromClient As String
Dim ReceivedLine As String = ""
Dim bytesFrom(10024) As Byte
Dim RtnString As String = ""
While (True)
Try
' REALLY? WHY DO WE NEED TO COUNT WHEN THE COUNT IS NOT USED?
requestCount = requestCount + 1
' OPEN NETWORK STREAM
Dim networkStream As NetworkStream = clientSocket.GetStream()
' READ YOUR BYTES
networkStream.Read(bytesFrom, 0, CInt(clientSocket.ReceiveBufferSize))
' PARSE YOUR DATA
dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom)
' PASS THE DATA BACK UP TO THE BACKGROUNDWORKER
If dataFromClient.Contains(vbCr) Or dataFromClient.Contains(vbCrLf) Then
bw.ReportProgress(1, ReceivedLine)
RtnString = ReceivedLine
SendTCP(networkStream, ReceivedLine)
ReceivedLine = ""
Else
ReceivedLine += dataFromClient.Substring(0, 1)
End If
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End While
End Sub
Sub SendTCP(ByRef N As NetworkStream, ByVal R As String)
Dim sendBytes As [Byte]()
Dim serverResponse As String
serverResponse = "Server to clinet(" + R + ") "
sendBytes = Encoding.ASCII.GetBytes(serverResponse)
N.Write(sendBytes, 0, sendBytes.Length)
N.Flush()
End Sub
End Class
-
Apr 25th, 2013, 09:10 AM
#18
Thread Starter
New Member
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.
-
Apr 25th, 2013, 10:36 AM
#19
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
-
Apr 25th, 2013, 11:54 AM
#20
Re: [RESOLVED] Backgroundworker - Can not get datagrid to update
Originally Posted by Shaggy Hiker
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.
-
Apr 25th, 2013, 12:30 PM
#21
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
-
Apr 25th, 2013, 01:05 PM
#22
Re: [RESOLVED] Backgroundworker - Can not get datagrid to update
Originally Posted by Shaggy Hiker
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?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|