Background Worker ThreadsIronPython & Windows Forms, Part IX
![]() Note This is part of a series of tutorials on using IronPython with Windows Forms.
The BackgroundWorker ClassRecently we tried to add an 'activity indicator' (throbber) to a long running process in our Windows Forms application. Unfortunately we ran into difficulties. The main problem was that we were using the wrong event to detect when a control lost the focus. You might think that LostFocus was the obvious choice [1]. In fact this is a low level event only used when updating UICues. The correct event to use is Leave. LostFocus is raised when the user clicks on the exit button, but Leave
isn't. We spent part of today fixing all the places we used GotFocus
and LostFocus and replacing them with Enter
and Leave. Luckily it wasn't too many. Using the BackgroundWorker, suggested by Andriy in a comment, the code is quite nice [2]. You provide the BackgroundWorker with your long running process as an event handler. It has a method to detect if one is already running, and raises an event when it has finished. A common idiom in our code is to have our own event hooks. Rather than tightly coupling our objects together, they can raise events. An approximation of the code structure we used is shown below. This is also a good [3] example of how to use the BackgroundWorker. This code shows an event hook class [4], which provide the LongRunningStart and LongRunningStop events which enable and disable the activity indicator: the throbber. This is automatically triggered when the textbox Leave event is raised. (But I've omitted all the boiler-plate in setting up the form and textbox of course.) import clr clr.AddReference('System') clr.AddReference('System.Windows.Forms') from System.ComponentModel import BackgroundWorker from System.Windows.Forms import Form, TextBox class EventHook(object): def __init__(self): self.__handlers = [] def __iadd__(self, handler): self.handlers.append(handler) return self def __isub__(self, handler): self.handlers.remove(handler) return self def fire(self, *args, **keywargs): for handler in self.__handlers: handler(*args, **keywargs) class LongRunning(object): def __init__(self): self._worker = BackgroundWorker() # self.LongRunningStart = EventHook() self.LongRunningEnd = EventHook() self._worker.DoWork += lambda _, __: self.LongRunningProcessAsync() self._worker.RunWorkerCompleted += lambda _, __: self.LongRunningEnd.fire() def LongRunningProcess(self): # This can be called directly if you need a # synchronous call as well. # The long running process will block the GUI from # updating though. self.LongRunningStart.fire() self.__longRunningProcess() self.LongRunningEnd.fire() def LongRunningProcessAsync(self): # Just drop out if one is already running if not self._worker.IsBusy: self.LongRunningStart.fire() self._worker.RunWorkerAsync() def __longRunningProcess(self): # Do *lots* of stuff :-) class MainForm(Form): def __init__(self): self.longRunning = LongRunning() self.longRunning.LongRunningStart += self.enableThrobber self.longRunning.LongRunningEnd += self.disableThrobber self.textBox = TextBox self.Controls.Add(self.textBox) self.textBox.Leave += lambda _, __: self.longRunning.LongRunningProcessAsync() def enableThrobber(self): # do something def disableThrobber(self): # do something To check if the BackgroundWorker is in the middle of running, we use the IsBusy Property. To tell it what to do when started, we add our long running process to the DoWork Event, this is kicked off on a separate thread: so be careful ! This is actually launched by the RunWorkerAsync Method. When our process (bad choice of word, hey) has finished, the RunWorkerCompleted Event is raised. Notice that if we wrap our .NET event handlers in a lambda we don't need the sender and event arguments. lambda _, __: self.LongRunningEnd.fire() You can use the event argument sent to DoWork handlers to pass arguments when RunWorkerAsync is called, but this isn't shown.
For buying techie books, science fiction, computer hardware or the latest gadgets: visit The Voidspace Amazon Store. If you're looking for a new techie job, try the Voidspace Tech Job Board. This is part of the Hidden Network of technology and programming jobs.
Last edited Fri Feb 15 13:42:11 2008. Counter... |
|||||||||
|
Blogads
Follow me on: Tech Jobs |