Introduction
Solving a simple Windows Desktop Z-order problem with a modal dialog box took me more than just the half hour to code the solution. I soon found myself writing a completely custom MessageBox()
class. And if that weren't enough, I then started adding icons, color schemes and a passel of overrides. What the heck is wrong with me? As if there aren't already a number of these projects here. Well, none of them seem to solve the original problem -- dialog boxes disappearing behind other windows.
This one solves that problem. Read on...
Background
Numerous MessageBox()
projects and programming articles erroneously suggest or imply that by setting the 'TopMost
' property, that the form/dialogbox/graphic will always stay foremost in the Windows desktop 'Z-order' (or, simply, on top of the rest of the open windows) no matter what happens.
Nope.
This is not true and is evidenced after clicking on any other window on the desktop. Doing so will cause your dialog box to instantly vanish despite this simple yet deceiving property setting; your important modal dialog box is now buried somewhere under all the other open applications vying for your attention.
While this may not be the end of the world, at the very least it is really annoying. When you're running a collection of other applications, the last thing you want to do is go on an Easter-egg like hunt for your lost dialog box that's locking-up one of your apps. I've mistaken a hidden dialog box for an unresponsive app several times and have force-closed the app all because I didn't recognize or see the dialog box pop-up in the first place.
And, besides, I'm fast approaching the time I'll be able to hide my own Easter eggs, so I don't need any help hiding things.
All fun and inconvenience aside, it can be the end of the world if your code is running on a closed system, e.g., a kiosk, or other locked-down finite state system where the user may not have access to special key combinations that allow you to cycle through and re-discover the elusive and now hidden dialog box.
Hidden modal dialogs on these types of systems can be really bad news. Think of an ATM use-case scenario in Alaska. 'JR' rolls up and wants some cash from the machine late at night. It's 15 below outside and a 20 mile ride back home. Only, tonight, the ATM alerts JR that he qualifies for a low interest loan while it processes his request. Oh, oops, JR misses the tiny "No thanks" button and hits another part of the touch screen by mistake. Poof! There goes the main menu, and with it, JR's card and his chances of buying another six-pack.
And a few seconds later, poof! There goes the ATM, shot 30 times at close range...
Solution
Simply stated, the rather easy solution to all this is to have a background timer or thread that re-asserts the TopMost
property of the form. Continuously. It's really that simple, but you'd be amazed at how many developers have missed this important requirement.
They may have missed, but JR didn't.
Sadly, even in this day and age, several industrial and commercial packages lack this needed feature. Now you can do this with ease by instantiating an instance of SuperMessageBox
and setting the alwaysOnTop
argument to true
in the constructor. Once set, nothing; no window, no system dialog, no other app will cause any SuperMessageBox
dialog to be hidden behind any another window. Not even Windows Task manager with the 'Always On Top' option set will mask over SuperMessageBox
.
Using the Code
There's two separate projects here: the SuperMessageBox.dll code and a test app to help you get started using SuperMessageBox
. I recommend looking at the SuperMessageBoxTester
application to familiarize yourself, otherwise the constructor / public
methods are fully XML commented and should be reasonably straightforward... Unless, maybe if you're an angry Alaskan Python coder with an empty AR-15...
To use the Supermessagebox
class, you can use the default constructor or start by creating a ColorScheme
object to specify the upper and lower colors to be displayed. Next, instantiate a Supermessagebox
object, passing the ColorScheme
object in the constructor and set the Alwaysontop
variable in the constructor to true
if desired.
Once the SuperMessageBox
object is created, simply access one of the .Show()
overloads, passing it your message text, header text, button(s) selection, icon selection, a time-out timespan if desired, an animation style if wanted, and a windows sound type. In all, there are 21 overloads to the .Show()
method to mix and match options with.
Example:
// Dialog box colors Text color
ColorScheme CS = new ColorScheme(ColorScheme.PresetColor.Salmon, Color.White);
SuperMessageBox SMB = new SuperMessageBox(CS, true);
DialogResult DR = SMB.Show("Want a low-interest loan?",
"Don'tShoot!", SuperMessageBox.Buttons.YesNo);
I created the ColorScheme
class so that there was an available set of pre-defined colors. When I'm writing code, one of the last things I want to hassle with is tracking down the RGB values of colors (or spend time wandering around in the named colors in System.Drawing.Colors
) looking for a halfway decent contrast to the main application's color scheme.
As seen above in the first line, choosing a color scheme is as simple as perusing the ColorScheme.PresetColor
enumeration prior to calling the constructor and picking one you like. If none of the 25 or so canned color schemes work for you, you can always use one of the other five constructors for ColorScheme
and specify your own custom color scheme using RGB values or colors from the often tiresome System.Drawing.Colors
set.
Your choice. And I guess that's the point - you get to have a choice, and is why I wrote this solution.
Fold / Spindle / Mutilate and change whatever you need here - it's just a starting point. Add your own custom PreSet colors, or change the ones I've provided. The test application provides a kind of WYSIWYG interface that should help you get going.
Improvements
There are a number of clever and intelligent folks on here - I just don't have the time or need to further improve the class. If I did, I'd be guilty of what a manager of mine once said, "polishing apples." So, if you have the time and inclination, here's some apple-polishing ideas I've dismissed for the lack of need and for the sake of time:
- Adding video / animated icons
- Add a custom sound option - ability to feed it MP3's or .WAV's
- Add borders (Hint: Add an
OnPaint()
override)
- If you really insist, add a drop-shadow option.
- Add a vertical scroll bar for those of you who like to *abuse* dialog boxes [I'm looking at you, KEITH P.]
- Add a screen position option so you can tell it what part (or in the case of multiple screens) which display
Icon Licenses
All the icons used and included in the SuperMessageBox
project are from the Open Icon Library originally created on 10th of November, 2009 by Jeff Israel. Icons in this library fall under GPL / Creative Commons licenses. (License file is included with the source package.) Yup, and if you look, there's one in there that I made; that one falls under the CPOL license.
Disclaimer
There are likely a hundred better ways to do things - I'm a hardware and software engineer, so if you're a software guru and can point out a cleaner approach on some things, you'll find I'm all ears. Otherwise, I'm generally of the mindset that readable code is almost always far better than someone's idea of 'elegant' anyday. My hat's off to you if you're willing to share your knowledge - just always do so with patience and humility!
History
- Version 1.1 December 2015
- Initial release (Since Mike's rule of happy computing #1 is NEVER buy/use version dot-zero of anything