Page 4 of 5
Now we can convert the simple minded implementation into a two thread version - but without actually having to get involved in threads.
First we create a global BackgroundWorker object:
BackgroundWorker bw = new BackgroundWorker();
we use the global velocity variables again:
int vx = 1;
int vy = 1;
Now the button that gets everything going has to setup the BackgroundWorker. First we set the worker to not support cancellation and to support the ProgressChanged event:
private void button1_Click(object sender,
Next we define the DoWork event handler using a lambda expression - although you could do it using a full delegate or an annyoumous delegate:
bw.WorkerSupportsCancellation = false;
bw.DoWork += (o1, e1) =>
The DoWork event handler simply calls the ReportProgress method in an infinite loop. Once again you have to imagine that this event handler is doing some intensive computation and occationally calling update to display its intermediate results.
The each time the ReportProgress method is called the ProgressChanged event is raised and its event handler is the Update method in the first example: To convert Update into an event handler we have to modify its definition:
void update(object o,
Now we can use it as the event handler:
Of course you could define this event handler using a lambda expression or anonymous delegate. This method just happens to be easier in this case as we have already defined the update method.
Finally we start the DoWork event handler running:
That's all there is to it but if you try the program out as it is you will mostly likely find that it doesn't work.
The reason is that non-UI thread hogs the processor and once again the UI thread doesn't get a look in. To give the UI thread a chance to process the updates you have to include a
In the infinite loop - then things all work. Notice that you can think of the Thread.Sleep(10) as a sort of DoEvents - so we come full circle. The problem is that a worker thread can put too many requests to run the event handler into the Dispatcher's queue before the UI thread can process them. This is a deeper problem with using a two thread architecture. The DoEvents command gave the UI thread time to process all pending events. In this case we put the worker thread to sleep for 10 milliseconds and hope that it can clear the pending events in that time. In many ways this isn't a good at DoEvents.
A complete solution would implement a producer consumer type architecture and ensure that the producer never overwhelmed the consumer.