One of the many small utilities that are probably reinvented every day is a user notification in a small popup window.
Typical usages are email notifications or status messages for long running processes. After joining the club of re-inventers, I hope to simplify the tasks for some readers by writing this article and submitting my solution called
PI (very imaginative short for
Using the code
I tried to make using
PI easy. Just add the
PopupMessageHandler Component to your application and call:
to start a new popup info.
The Component comes with designer support, so customization should be fairly easy.
The popup windows appears at the lower right corner of the screen just above the taskbar and will disappear after a configurable time span.
Some care had to be taken to handle multiple popup windows. Of course, they should not overlap and the number of windows displayed simultaneously must be limited. The very simple solution to this is using a queue to store messages that must wait for free space. Clicking a popup info usually signals that the user has seen it, so it can be closed. This can open a gap in our nice pile of windows that must be closed. Windows above a gap have to drop into the free space, waiting messages will be displayed on top of the stack.
Now, to a more complex aspect - getting messages back from the popup windows. For this, more information is required and a second version of the
AddMessage method has the additional parameters to specify what should happen if the user clicks on a message.
public void AddMessage(String yourMessage,
Control receiver, PIDelegate pd, object arg)
the message you want to show
the control that will be used to invoke the delegate
the delegate that will be invoked
an object that will be passed with the delegate
The test program shows an example for this call. The required delegate has the form:
public delegate void PIDelegate(object data)
Two more variants of
AddMessage exist, with an additional
int parameter that defines the time to live of the popups. If not specified, the component default
ttl will be used.
Points of Interest
One tricky thing in the implementation was thread synchronization. The popup messages do run in their own threads (taken from a
ThreadPool) and need to invoke a method in the main thread of a control. Fortunately, the control class contains several methods to perform this task and in this case,
BeginInvoke was used.
The main loop of the
PopupMessageHandler runs in a background thread that waits for a signal, if no messages are present. The
AddMessage methods lock the queue that is used to store popup infos, so they are thread safe.
- 28 May 2004 - minor code update