Notifications
June 28th, 2009
A guy I work with has known my girlfriend since they were both kids, so he knew what I was up to. There was a bit of a discussion at work a few days ago, when he casually mentioned the project to another developer.
I ended up involved in the conversation, and I ended up getting some good feedback on some of the things I should be doing. We also tackled a major problem with this application: notifications.
Notifications are a fundamental part of my Review Manager. Otherwise, we would just fall back into the same problems that we currently have with the review spreadsheet (oddly, the non-shared spreadsheet that can only be used by one person at a time..), and that’s that no one ever checks the damn thing. If nobody knows you’re looking for a review, nobody will do your review. This is why so many people, myself included, tend to just spam the team with an “I need an XYZ review” emails.
I’m hoping my app will solve this problems in two ways:
- First, everyone will have the app open because it will minimize to the tray. This makes it quick to check if you’re in the mood to pick up a random review, and it’s easy to access when you need to broadcast that you need something done
- Everyone gets notified (once by default, and only if you’re allowed to do that type of review) that someone needs a review done, hopefully in a non-invasive way.
The main problem I had with this was determining how to display the notification without interrupting the users workflow.
After a few searches on Google and StackOverflow, I came across these two overrides:
protected override CreateParams CreateParams
{
get
{
CreateParams bp = base.CreateParams;
bp.ExStyle |= WS_EX_TOPMOST;
return bp;
}
}
protected override bool ShowWithoutActivation
{
get
{
return true;
}
}
The CreateParams override simply adds the option to push the form to the top of the Z-Order. This is so common that WinForms have a property already built to include this – Form.TopMost. The problem with using TopMost is that it will activate the form, stealing the focus away from the user. Since this is exactly opposite to what we want, we can’t use it. The CreateParams override will handle this functionality for us, and the ShowWithoutActivation override does exactly what it sounds like. The result is a form which is displayed above all else, but that doesn’t take the focus away from whatever the user is working on.
I decided to also allow the user to define for how long the notification is displayed. This is simply a second constructor for the form, and is in fact the only constuctor with any logic in it. The constructor without a timeout simply passes the buck onto the one that does, along with a default value of 5 seconds:
public FadeNotification (string title, string message, int timeout)
{
InitializeComponent();
DisplayDuration = timeout;
tips.SetToolTip(lblMessage, message);
this.Text = title;
if (message.Length > MAX_MSG_LENGTH)
{
message = message.Substring(0, (MAX_MSG_LENGTH - 3)) + "...";
}
lblMessage.Text = message;
State = DisplayState.Appearing;
}
// if no timeout is specified, use a default value
public FadeNotification(string title, string message) : this(title, message, DEFAULT_DURATION) { }
Another thing you might notice in this snippet is that I’m a bit lazy with the message. I played around with the label on the form a bit, and generally hated how it was coming out. What I decided to do instead, was to make the label the size of the form, and center it. I set the font to a nice(ish) looking size, and sent it on its way. If the message gets long enough to wrap, it looks like crap, so I just cut it off. For what I’m using it for, the maximum length I set is more than sufficient. If it’s not, the end gets chopped off and replaced with an ellipsis (sort of, since there actually is an ellipsis character which I’m not using for no particularly good reason).
This new form became revision 3 (and 4, since I left a literal in where I passed to the other constructor.. oops) in my SVN repository. There should have been more revisions relating to this, I know, but this is basically a sandbox which became too valuable. It wasn’t even originally in the same project as my main stuff. I’ll have to learn to play with my working copy more, but this source control stuff is still new to me.
The code is available in a RAR file if anyone wants to review it. I haven’t decided how I’m going to formally release this when I’m done the project, so for now lets just consider this my copyright from now. If you would like to use this in your own project (you won’t), drop me a line and force the licensing issue. It’s likely going to be LGPL’d at some point, but who knows.
Leave a Reply