0

Web Developer here and need some advice on how to achieve what must be a common requirement in Windows Forms.

I have a windows client app that calls a business object in a separate project to perform some long running tasks. Difference to other examples is that the process live in another class library i.e. Business.LongRunningTask();

I have a list box in the client that I would like to have logged to by the task. I can run the process on the UI thread passsing in the instance of the textbox and calling Application.DoEvents() when I log to the textbox from within the task. All fine, but not elegant and would prefer not to call Application.DoEvents();

If I run the long running process on a separate thread using delegates I cannot access the textbox or delegates created in the windows client form which rules out BeginInvoke calls.

Surely this is bad design on my part and would appreciate some feedback.

Samuel Goldenbaum
  • 18,391
  • 17
  • 66
  • 104

4 Answers4

2

You're looking for the BackgroundWorker class.

To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished.

You can find a complete example here: http://msdn.microsoft.com/en-us/library/b2zk6580(v=VS.100).aspx#Y1351

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
0

I can run the process on the UI thread passsing in the instance of the textbox and calling Application.DoEvents() when I log to the textbox from within the task.

Yes, you could also pass in an instance of ILoggingINnterface that you have used to put in the code to write to the text box FROM WITHIN THE UI and thus have taken care of all the nice BginInvoke stuff ;)

If I run the long running process on a separate thread using delegates I cannot access the textbox or delegates created in the windows client form which rules out BeginInvoke calls.

Ah. No. You just most invoke back to the dispatcher thread then you can access all the UI elemente you like.

TomTom
  • 61,059
  • 10
  • 88
  • 148
0

Yeah, avoid Application.DoEvents().

To marshall the call back onto the UI thread, call this.Invoke(YourDelegate)

richard
  • 12,263
  • 23
  • 95
  • 151
0

To access UI elements from a different thread, you can use control.Invoke to call a delegate on the owning thread. I used this at one point to create a live log screen which was updated from a timer while a different worker thread was running. Heres a simplified version:

public class DifferentClassLibrary
{
    public delegate void StringDataDelegate(string data);
    public event StringDataDelegate UpdatedData;

    public void DoStuff()
    {
        if (UpdatedData != null)
        {
            Thread.Sleep(10000);
            UpdatedData("data");
        }
    }
}

And in the winform:

public void UpdateTextBoxCallback(string data)
{
    if (uiTextBoxLiveLogView.InvokeRequired)
    {
        uiTextBoxLiveLogView.Invoke(new DifferentClassLibrary.StringDataDelegate(UpdateTextBoxCallback), data);
    }
    else
    {
        uiTextBoxLiveLogView.Text += data;
    }
}

void Main()
{
    DifferentClassLibrary test = new DifferentClassLibrary();
    test.UpdatedData += UpdateTextBoxCallback;

    Thread thread = new Thread(new ThreadStart(test.DoStuff));
    thread.Start();
}
Simon Bondo
  • 456
  • 4
  • 4