Display message on form from a thread

jccorner

Centurion
Joined
Jan 31, 2004
I'm fairly amazed that I'm having trouble finding some code to do this. So I'm asking my fellow programmers. Here's my situation: my windows program currently has one form and several classes which each run a thread that performs specific tasks including downloading a csv file from an ftp site and consumes it into a sql server db or checks the time and performs a stored procedure which will kick off some other tasks, etc. Now certain events/errors may occur in these threads. My issue is that I create a new class and then start the thread, but am having problems when I want to send a message from the thread class to the form when an event or error occurs. I can't invoke a method from the class and the form has no idea when an event occurs in the class. So, I'm stuck on where I should be going to accomplish this since multiple threads can be running on the form at once. I know I can create a form for each thread class, but want to try to utilize one form and not have to look at three different forms to see what the thread is doing. Thanks for any assistance.
 

MrPaul

Contributor
Joined
Jun 28, 2006
Location
Hampshire, UK
Events and delegates

I can't invoke a method from the class and the form has no idea when an event occurs in the class.

One solution - have the class raise events which the form can handle:

C#:
//In the class
public event EventHandler<EventArgs> ErrorOccurred;

private void ThreadProc()
{
    try {
        //Do some processing
    } catch (Exception e) {
        //An error occurred - raise the event
        if (ErrorOccurred != null) ErrorOccurred(this, EventArgs.Empty);
    }
}

C#:
//In the form
private void MyMethod()
{
    MyClass c1 = new MyClass();

    //Attach to event
    c1.ErrorOccurred += c1_ErrorOccurred;
    c1.Start();
}

//Handler for the ErrorOccurred event
private void c1_ErrorOccurred(object sender, EventArgs e)
{
    if (InvokeRequired) {
        //Marshal the event to the form's UI thread
        Invoke(new EventHandler<EventArgs>(c1_ErrorOccurred), sender, e);
        return;
    }

    //Act on the error - in this case, just show a message box
    MessageBox.Show("An error occurred while processing c1");
}

Here, the class MyClass exposes an event ErrorOccurred which the form can attach itself to in order to receive notification of an error. In the event handler, the call is marshalled to the UI thread using Invoke, so that there are no problems interacting with the form controls and UI elements.

I've used the EventHandler<EventArgs> delegate but you can define your own delegate which better matches the information you wish to pass to the form. I like to define my own EventArgs subclass with properties for all relevant event information.

Good luck :cool:
 

MrPaul

Contributor
Joined
Jun 28, 2006
Location
Hampshire, UK
Custom delegate

Okay, so lets first define a delegate which takes a string parameter:

C#:
public delegate void MyEventHandler(string exMessage);

Then, in the class, define an event of type MyEventHandler:

C#:
public event MyEventHandler ErrorOccurred;

private void ThreadProc()
{
    try {
        //Do some processing
    } catch (Exception e) {
        //An error occurred - raise the event
        if (ErrorOccurred != null) ErrorOccurred(e.Message);
    }
}

And in the form, implement a method with the same signature as the delegate, and attach it to the event:

C#:
//In the form
private void MyMethod()
{
    MyClass c1 = new MyClass();

    //Attach to event
    c1.ErrorOccurred += c1_ErrorOccurred;
    c1.Start();
}

//Handler for the ErrorOccurred event
private void c1_ErrorOccurred(string exMessage)
{
    if (InvokeRequired) {
        //Marshal the event to the form's UI thread
        Invoke(new MyEventHandler(c1_ErrorOccurred), exMessage);
        return;
    }

    //Act on the error - in this case, just show a message box
    MessageBox.Show("An error occurred while processing c1:\n\n" + exMessage);
}

Hope this gives you some idea. :)
 
Top Bottom