Home > Blockchain >  How to send information from a class using a backgroundworker, back to the mainform
How to send information from a class using a backgroundworker, back to the mainform

Time:02-18

Hi,

I'm trying to write a UDP-client that listens to a port, and then display the incoming data in a textbox.

I have written a class; UDP_Receive() that starts a backgroundworker that listens to a specified port and receives the data. The code is based on this question; C# .Net receiving UDp packets in separater thread and application exit

I think I have solved the issues with the blocking .receive() by following the accepted answer in this question; How can I safely terminate UdpClient.receive() in case of timeout?

My question is how do I get the data I receive in the backgroundworkerthread (that I created in my class) back to the mainthread, so that I can display it in a textbox?

I thought of using Invoke, but I don't have any references to the textbox in my class.

textBox_UdpPositionInData.Invoke(new EventHandler(delegate
{
   textBox_UdpPositionInData.Text = receivedData;
}));

I found a very similar question about a tcp-server, but I can't see how to apply that solution here Send data from a background thread to the main thread

Any thoughts or suggestions are of course much appreciated!

Many Thanks!

    internal class UDP_Receive
    {
        private int _portToListen = 2003;
        private volatile bool listening;
        BackgroundWorker _backgroundWorker;

        //Constructor
        public UDP_Receive()
        {
            Debug.WriteLine("Constructor: UDP_Receive");
            this.listening = false;
        }

        public void StartListener() 
        {
            if ( (_backgroundWorker==null) || (!_backgroundWorker.IsBusy))
            {
                _backgroundWorker = new BackgroundWorker();
                _backgroundWorker.DoWork  = listenForUDPPackages_DoWork;
                _backgroundWorker.RunWorkerCompleted  =listenForUDPPackages_RunWorkerCompleted;
                _backgroundWorker.WorkerSupportsCancellation = true;
                _backgroundWorker.RunWorkerAsync();
                
                Debug.WriteLine("Creates a new thread: "   _backgroundWorker.ToString() );
                
                // We are listening
                this.listening = true;                
            }
        }

        public void StopListener()
        {
            // The user cancelled the UDP Port listening
            this.listening = false;

            // Cancel the backgroundworker
            _backgroundWorker.CancelAsync();

            // Debug
            Debug.WriteLine("Stops current thread: "   _backgroundWorker.ToString());
        
        }

        public bool IsListening
        {
            get { return this.listening; }            
        }

        public int PortToListen
        {
            get { return this._portToListen; }
            set { this._portToListen = value; }
        }


        private void listenForUDPPackages_DoWork(object sender, DoWorkEventArgs ev)        
        {
            
            UdpClient? listener = null;

            try
            {
                listener = new UdpClient(_portToListen);
            }
            catch (SocketException)
            {
                //do nothing
            }

            if (listener != null)
            {
                IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, _portToListen);

                try
                {
                    while (this.listening)
                    {

                        Debug.WriteLine("Waiting for UDP broadcast to port "   _portToListen);
                        byte[] receivedBytes = new byte[1024];
                        string receivedData;
                        
                        bool timeTracker = TrackFunction(TimeSpan.FromSeconds(2), () =>
                        {
                            receivedBytes = listener.Receive(ref groupEP);
                        });


                        Debug.WriteLine("Timetracker result: "   timeTracker.ToString());

                        if (receivedBytes == null || receivedBytes.Length == 0)
                        {
                            // We did not recieve any data
                            Debug.WriteLine("No data received befor Time out ");
                        }
                        else
                        {
                            // We managed to receive some data!
                            // No we want to process the data and then send the result to the Thread that initiated the class.
                            receivedData = Encoding.Default.GetString(receivedBytes);
                            Debug.WriteLine("Data received: "   receivedData);
                        }
                    }
                catch (Exception e)
                {
                    Debug.WriteLine("Exception: "   e.ToString());
                }
                finally
                {
                    listener.Close();
                    Debug.WriteLine("Finally: Done listening for UDP broadcast");

                }
            }
            else
            {
                Debug.WriteLine("Error: UdpClient(_portToListen) returned null");
            }
        }

        private void listenForUDPPackages_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e == null || e.Result == null)
            {
                Debug.WriteLine("listenForUDPPackages_RunWorkerCompleted e = null");
            }
            else
            {

                if (e.Cancelled)
                {
                    Debug.WriteLine("Operation was canceled");
                }
                else if (e.Error != null)
                {
                    Debug.WriteLine("Error: "   e.Error.Message);
                }
                else
                {
                    Debug.WriteLine("Result: "   e.Result.ToString());
                }
            }
        }

        private static bool TrackFunction(TimeSpan timeSpan, Action codeBlock)
        {
            try
            {
                Task task = Task.Factory.StartNew(() => codeBlock());
                task.Wait(timeSpan);
                return task.IsCompleted;
            }
            catch (AggregateException ae)
            {
                throw ae.InnerExceptions[0];
            }
        }

    }

CodePudding user response:

You can write this kind of code to keep the UI separate from the UDP_Receive class:

internal class UDP_Receive
{
    private Action<string> _invoke;
    public UDP_Receive(Action<string> invoke)
    {
        _invoke = invoke;
    }
    
    public void Foo()
    {
        _invoke("Hello");
    }
}

When you declare the class you then do it like this:

var ur = new UDP_Receive(t => textBox.Invoke(() => textBox.Text = t));

Now it's just a matter of calling ur.Foo() (in my example) to update the UI.

  • Related