Jason
Jason

Reputation: 2197

UDP listener on a thread and posting to GUI

I'm running a dialog based program that sends TCP out on a periodic, but also listens for UDP messages and displays the contents to the GUI. With the simple example I used initially, once I began listening in the while(true), all other GUI functionality was shut down. I then tried to spawn a thread to do the listening, but those examples required me to create a new class which hid the GUI elements from my view.

So my question is, what is the best practice to listen for UDP messages and write contents to the GUI without blocking the GUI thread?

Upvotes: 0

Views: 2112

Answers (1)

Servy
Servy

Reputation: 203821

You need to have the code doing the listening in a background thread of some sort. That's simple enough, there are lots of ways of string a background thread, from the Thread class, BackgroundWorker, Task, ThreadPool.QueueUserWorkItem (although in your case a thread pool thread is not appropriate, you need a full thread as your operation is long running), etc.

After that all you need is some way of updating the UI. There are again, several methods of doing so (some that are specific to the UI functionality you're using (WPF, winform, etc.) and some that aren't.

Using IProgress<T> is particularly useful, especially because it's not dependent on a particular UI technology. Create the Progress object in the UI, and specify how to update the UI when you have a particular result, pass the object to the background worker, and have it Report progress when it receives information.

An example might look something like this:

private void Form1_Load(object sender, EventArgs e)
{
    Progress<string> progress = new Progress<string>();
    progress.ProgressChanged += data =>
    {
        textBox1.AppendText(data);
    };

    Thread tcpListener = new Thread(() => ListenForData(progress));
    tcpListener.Start();
}

private void ListenForData(IProgress<string> progress)
{
    while (true)
    {
        Thread.Sleep(1000);//placeholder for real IO to get data
        progress.Report("data");
    }
}

If you don't have C# 4.5 creating your own Progress class is quite simple:

public interface IProgress<T>
{
    void Report(T data);
}

public class Progress<T> : IProgress<T>
{
    SynchronizationContext context;
    public Progress()
    {
        context = SynchronizationContext.Current
            ?? new SynchronizationContext();
    }

    public Progress(Action<T> action)
        : this()
    {
        ProgressReported += action;
    }

    public event Action<T> ProgressReported;

    void IProgress<T>.Report(T data)
    {
        var action = ProgressReported;
        if (action != null)
        {
            context.Post(arg => action((T)arg), data);
        }
    }
}

Upvotes: 1

Related Questions