[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 432
  • Last Modified:

How do I access a form's control from a function(within a class) in a thread?

Hello Experts,

The following block within clsUDPServer is where my problem lies which is in the Receive Functon.  The receive function is in a thread.

'******PROBLEM***********************************************************************
            objCollection.Add(ASCIIEncoding.ASCII.GetString(bytMessage)
            frmServer.lbMessages.DataSource = objCollection
'******PROBLEM***********************************************************************

I take it that I am not accessing the objCollection & the frmServer safely.  I heard that I need to use a delegate and synclock but I have no idea how to do that.

Please help!

-------------------------------- SUB MAIN ------------------------------------
Module mod_SubMain
    Sub Main()
        Application.Run(New frmServer)
    End Sub
End Module
-------------------------------- SUB MAIN ------------------------------------

-------------------------------- clsUDPSERVER ------------------------------------
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets

Public Class clsUDPServer

    Private objUDPServer As UdpClient
    Private objThreadListener As Thread
    Private intPort As Integer = 6580
    Private objCollection As Collection

    Public Sub Create()

        objUDPServer = New UdpClient(intPort)
        objThreadListener = New Thread(AddressOf Receive)
        objThreadListener.Start()

    End Sub

    Public Sub Close()

        objUDPServer.Close()
        objThreadListener.Abort()

    End Sub

    Private Sub Receive()

        Dim objIPEndPoint As New IPEndPoint(IPAddress.Any, intPort)
        Dim bytMessage As Byte()

        While True
            bytMessage = objUDPServer.Receive(objIPEndPoint)

'******PROBLEM***********************************************************************
            objCollection.Add(ASCIIEncoding.ASCII.GetString(bytMessage)
            frmServer.lbMessages.DataSource = objCollection
'******PROBLEM***********************************************************************

        End While

    End Sub

End Class
-------------------------------- clsUDPSERVER ------------------------------------

-------------------------------- frmSERVER ----------------------------------------
Public Class frmServer

    Private Sub frmServer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub frmServer_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

    End Sub

    Private Sub frmServer_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize

        If Me.WindowState = FormWindowState.Minimized Then
            Me.Hide()
        End If

    End Sub

    Private Sub niServer_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles niServer.DoubleClick

        Me.Show()
        Me.WindowState = FormWindowState.Normal

    End Sub

End Class
----------------------------------------- frmSERVER ------------------------------------------
0
Hepen
Asked:
Hepen
  • 5
  • 4
1 Solution
 
dumpsterdivingdaveCommented:
you can do it one of two ways, safely, and unsafely.

Unsafe:
place this somewhere in your main code, like before you call the thread.start() function.
Control.CheckForIllegalCrossThreadCalls = False

This will tell the program to ignore cross thread calls...  In a simple program where the control will only be accessed by one thread at a time, it's not a huge issue.  If multiple threads are accessing the same control, you can get some really strange and bad results.

Safe:
place this in your thread that has to access the control created from another thread
If frmServer.lbMessages.InvokeRequired() Then
     Dim d as MethodInvoker
     frmServer.lbMessages.Invoke(d)
     frmServer.lbMessages.DataSource = objCollection
Else
     frmServer.lbMessages.DataSource = objCollection
End If

The safe method creates a sort of copy of the control so that two processes don't both try to modify it.
0
 
HepenAuthor Commented:
I tried what you suggested and it looked like this. The problem is I can't even see frmServer's controls from within that receive function thread.

-----------------------------------

Private Sub Receive()

        Dim objIPEndPoint As New IPEndPoint(IPAddress.Any, intPort)
        Dim bytMessage As Byte()

        While True
            bytMessage = objUDPServer.Receive(objIPEndPoint)

If frmServer.lbMessages.InvokeRequired() Then
     Dim d as MethodInvoker
     frmServer.lbMessages.Invoke(d)
     frmServer.lbMessages.DataSource = objCollection
Else
     frmServer.lbMessages.DataSource = objCollection
End If

        End While

    End Sub

0
 
PockyMasterCommented:
frmServer is a type, not an instance as far as I can see. Receive is a thread function.

I believe I told you in another question you should wrap your Receive function into a class, create an instance of that class and start the thread from the class instance Receive address.

You could do this here as well, pass the instance of frmServer e.g. myFrmServer in the thread class constructor.. and then you are able to call it from your thread function.

e..g

Class MyThread
private _myServer as frmServer
public sub new (myServer as FrmServer)
_myServer = myServer
end sub

Private Sub Receive()

...
e.g. call
    _myServer.lblMessages.Invoke()
...
end Sub


End Class
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

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

 
HepenAuthor Commented:
What is happening exactly when I do _myServer.lblMessages.Invoke?

lblmessages is a label i want to set its text.

how would i do _myServer.lblMessages.invoke.text = "hello"

------------------------------------------------------
Private Sub Receive()
...
e.g. call
    _myServer.lblMessages.Invoke()
...
end Sub

0
 
PockyMasterCommented:

You can just do:
_myServer.lblMessages.text = "hello"
0
 
PockyMasterCommented:
I just copied the Invoke part from your example.. :D
0
 
HepenAuthor Commented:
You can just do:
_myServer.lblMessages.text = "hello"

I get the following error which I've been trying to fix for like 3 days LOL.

Cross-thread operation not valid: Control 'lblMessages' accessed from a thread other than the thread it was created on.

Here is my code do you see the problem? I did what you told me to do I believe.
----------------------------------------------------------------------------------------------

modSubMain:

Module modSubMain
    Private objUDPServer As clsUDPServer
    Private _frmServer As frmServer
    Sub Main()

        _frmServer = New frmServer

        objUDPServer = New clsUDPServer
        objUDPServer.Create()

        objUDPServer.SetIt(_frmServer)

        _frmServer.ShowDialog()
    End Sub
End Module


clsUDPServer:
Imports System.Text
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets

Public Class clsUDPServer

    Private _frmServer As frmServer

    Private objUDPServer As UdpClient
    Private objThread As Thread
    Private intPort As Integer = 6580

    Public Sub SetIt(ByVal frmForm As Form)
        _frmServer = frmForm
    End Sub

    Public Sub Create()
        objUDPServer = New UdpClient(intPort)
        objThread = New Thread(AddressOf Receive)
        objThread.Start()
    End Sub

    Public Sub Close()
        objUDPServer.Close()
    End Sub

    Public Sub Receive()

        Dim objIPEndPoint As New IPEndPoint(IPAddress.Any, intPort)
        Dim bytMessage As Byte()

        While True
            bytMessage = objUDPServer.Receive(objIPEndPoint)
            _frmServer.lblMessages.Text = "d"
        End While
    End Sub
End Class


0
 
PockyMasterCommented:
Hmm, you were right about that... it always worked in VS2003 though :D


Imports System.Text
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets


Public Class frmServer

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

        Dim tc As New clsUDPServer(Me, AddressOf UpdateLabel)
        Dim myThread As New Thread(AddressOf tc.Receive)

        myThread.Start()

    End Sub

    Private Sub UpdateLabel(ByVal newText As String)
        lblMessages.Text = newText
    End Sub
   
End Class

Public Class clsUDPServer

    Private _frm As frmServer
    Private objUDPServer As UdpClient
    Private objThread As Thread
    Private intPort As Integer = 6580

    Private _del As UpdateLabel
    Public Delegate Sub UpdateLabel(ByVal newText As String)


    Public Sub New(ByVal frm As frmServer, ByVal del As UpdateLabel)
        _frm = frm
        _del = del
    End Sub

    Private Sub Create()
        objUDPServer = New UdpClient(intPort)
    End Sub

    Private Sub Close()
        objUDPServer.Close()
    End Sub

    Public Sub Receive()

        Dim objIPEndPoint As New IPEndPoint(IPAddress.Any, intPort)
        Dim bytMessage As Byte()

        Create()

        _frm.Invoke(_del, "test")
        Close()
    End Sub
End Class

This works in VS2005 as well
0
 
PockyMasterCommented:
P.S. I removed some of your connection code to make testing easier for me .. so you probably will put the code back in your receive method
0
 
HepenAuthor Commented:
This was great. Now wouldn't it be awesome if you could just pass the complete form somehow so instead of having to build delegates to access each part of the form you can just invoke the entire form and just set its controls.  Do you see what I mean? I'm going to ask this in another question maybe you can answer it.
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now