The Missing .NET #1: Cue Banners in Windows Forms (EM_SETCUEBANNER, Text Prompt)

The .NET framework is huge, but not so huge that it does everything for everyone; there are things that they in Redmond miss or don’t do for whatever reason but is still generally applicable to many developers. So, dear reader, I present to you a new, hopefully weekly, series of posts on stuff I find missing in .NET, typically where even the Google fails to find the answer.


One of the subtle UI improvements we’ve seen over the past few windows versions, and on the web, is the cue banner, or text prompt. They are hardly groundbreaking — putting them in your app probably won’t win you awards, but they do serve to make your applications that much more polished and usable.

They are used increasingly more often now that Vista has come out, which solved a few problems that I’ll address later. You can see them used in the popular browsers IE 7 and Firefox in the search boxes, denoting the search engine of choice for the user in a subtle grey tone. Click inside those textboxes, however, and the text disappears. That’s all a cue banner is, that grey text, informing the user what exactly she is supposed to use the text control for.

Cue banners work great in places where a formatted string is required, say an email address or a URL or a phone number. Instead of cluttering up the window with tons of labels, explaining examples or ranges of valid values, you can put those in a cue banner. It makes the UI a tad more elegant and self-explanatory.

Firefox and IE 7 Search boxes displaying a cue banner of the default search engine.These aren’t exactly missing on the web though. Search for ‘cue banner’ in your favourite search engine and you’ll find all kinds of examples, but none of them cover everything, or in a way that seems satisfactory to me. An example of an inherited textbox for Winforms can be found at this Channel 9 post. Daniel Moth has a version that works for the .NET Compact Framework as well as the main framework and decided to eschew the OS support and do it completely in managed code. He’s braver than I; I’d prefer to have MS do all that work and then use it.

[ad]

The Code

Download the code I’ve covered in this article.

OK, so now we know what a cue banner is, how do we include them in our apps?

The first thing to remember is that this is all done in Win32 which requires P/Invoke. All we’re doing is sending a Win32 message on the window handle of the control. That’s pretty straightforward boilerplate code that you can find on pinvoke.net. The one thing you may have to search for is the value of the msg parameter, EM_SETCUEBANNER, but I got you covered.

private const int EM_SETCUEBANNER = 0x1501;
private const int EM_GETCUEBANNER = 0x1502;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(IntPtr hWnd, int msg,
int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);

You can certainly do what buddy did on Channel 9: inherit from TextBox, add the required property, call the P/Invoke method and call it a day but then you’d be missing something important. Cue banners can be placed on edit controls, not just textboxes. The unfortunate thing about WinForms is that it’s essentially a facade over Win32. It does a very good job, make no mistake, but if you push it in the wrong place you end up exposing what’s underneath. And what’s underneath is Win32 which identifies all controls with its corresponding HWND. As a consequence, Windows Forms has a pretty flat hierarchy (cf. with WPF which was designed when OO was the prevailing wisdom; a very deep hierarch). Therefore, if you want to display a cue banner in a ComboBox or a RichTextBox, which the OS allows, then you’d have to subclass ComboBox and RichTextBox. Well, that’s just not scalable or portable. You’d always have to import your own controls and use those in your projects. I’ve found that most custom controls suck when used in the designer, so who wants to use them?

Besides, all the info that’s required to make cue banners work is already there in the control! So let’s use it instead. It’s not ideal, but I prefer to keep it all in a static class. We only need to use the Handle property which Control owns and we should also parameterize the actual cue banner text so we write the following method to set cue banners:

public static void SetCueText(Control control, string text)
{
   SendMessage(control.Handle, EM_SETCUEBANNER, 0, text);
}

Easy or what? So now drop a text box on a form. Call SetCueText in the form constructor for the text box and you’re set. Now drop a ComboBox and do the same for it. Hit F5 and prepare to bask in the glo… Hey! Why isn’t the cue banner set in the ComboBox? This is where other articles completely fall down on this stuff. You see, the ComboBox is actually made up of three controls: a text box and a list box and a button; think of it as a really old and ubiquitous UserControl. ComboBox.Handle is the handle for the combined control, not the text control, so we’ll need a way to get its handle. For that, we need more P/Invoke:

[DllImport("user32.dll")]
private static extern bool GetComboBoxInfo(IntPtr hwnd, ref COMBOBOXINFO pcbi);

[StructLayout(LayoutKind.Sequential)]
private struct COMBOBOXINFO
{
   public int cbSize;
   public RECT rcItem;
   public RECT rcButton;
   public IntPtr stateButton;
   public IntPtr hwndCombo;
   public IntPtr hwndItem;
   public IntPtr hwndList;
}

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
   public int left;
   public int top;
   public int right;
   public int bottom;
}

OK, now we’re ready to add some more logic to the SetCueText method above:

public static void SetCueText(Control control, string text)
{
   if (control is ComboBox)
   {
      COMBOBOXINFO info = GetComboBoxInfo(control);
      SendMessage(info.hwndItem, EM_SETCUEBANNER, 0, text);
   }
   else
    {
        SendMessage(control.Handle, EM_SETCUEBANNER, 0, text);
    }
}

private static COMBOBOXINFO GetComboBoxInfo(Control control)
{
   COMBOBOXINFO info = new COMBOBOXINFO();
   //a combobox is made up of three controls, a button, a list and textbox;
    //we want the textbox
    info.cbSize = Marshal.SizeOf(info);
    GetComboBoxInfo(control.Handle, ref info);
   return info;
}

Hit F5 on your test app again, and voila: cue banner on ComboBox!

Notes

This only works on Windows XP and Vista.

On Windows XP, this conflicts with the East Asian Language packs, so if you have them installed, cue banners won’t work. Vista fixes this.

On Windows Vista, they’ve added a use for wParam parameter in the SendMessage() call. If you set it to TRUE, then the cue banner text will remain when the control gets focus.

I’ve found no use for the corresponding GetCueText, but if you want it, make sure you use a StringBuilder as the last parameter in SendMessage(), which requires another declaration of SendMessage.

Important: If you’ve done everything above and you still don’t see the wonderful cue banner text, check to see that before you call Application.Run(), you call Application.EnableVisualStyles(). That has to be called else cue banner won’t show up no matter what OS your are using.

Exercises

A few exercises for the reader:

  • SetCueText() is an ideal candidate for an extension method, if you’re allowed to use .NET 3.5. It’ll make the code just a little more readable. I’ll let you figure out how to do that.
  • There is a way you can have this on the designer. Just provide a component that implements IExtenderProvider to be dropped on the design surface.

Using the Command Pattern in Windows Forms clients

I’ve been doing a lot of research with the Command pattern lately at work. Here’s what I found: You’re doing yourself a disservice – and your team – if you don’t play the hell outta this thing!

It’s a very powerful design for non-trivial Windows Forms clients. What’s non-trivial? Anything that uses a menu, toolbar or context menu to show perform the same action. In fact it’s so useful and so powerful that I’m a little disappointed that Microsoft didn’t provide something like it in the framework itself. They’ve provided something in Avalon WPF, but I haven’t had the chance to play with it. I know they use it: Visual Studio and Office take advantage of it. (For example, think of how many ways you can copy and paste text.)

What are some of the advantages?

  • Automation – how easy is it to automate tasks in Visual Studio with a macro? Or reassign a keyboard shortcut? Enough said.
  • Completely decouples the UI from the business objects. It’s easy to say this but really hard to do it, especially if deadlines are tight. With commands, you can keep the UI and throw away the business objects or vice versa.
  • Easily allows plugins or addins. Suppose you have a client with a unique look that you want to control, but you want to offer the ability to extend or introduce functionality to third parties. Commands allow that. It’s how Visual Studio Add-ins do it.

There are disadvantages, of course – every design has drawbacks:

  • It complicates the application design. Every pattern complicates application design; they’re used because the benefits outweigh the cost. In fact, they should only be used when the benefits outweigh the costs.
  • Using commands complicate your controls and forms. Suppose you have a button that will be used to execute a command. Do you subclass Button so that it contains a Command and override OnClick? Do you use a normal Button and handle the Click event in the form? Change Button with MenuItem. Repeat questions.
  • Debugging is a little harder. There are features in .NET 2.0 to mitigate this one.

So what does a Command look like? Well, that’s largely up to you. The bare minimum would be one method that would allow you to perform the action associated with a Command:

public interface ICommand

{

void Execute();

}

All of your concrete commands would implement this interface and when the button or menu is clicked, call command.Execute(). Easy, eh? There is a whole lot more you can do with the shared interface, however. In fact, there is a lot of common code that you can take advantage of, which is why I prefer an abstract class, like so:

public abstract class Command

{

public string Key { get; protected set; }

public string DisplayName { get; protected set; }

 

public bool Enabled { get; }

 

public abstract void Execute();

}

All the properties would have an implementation, I leave it out because I’m only concerned with API right now. We still have that abstract Execute() method, but now we have a few properties that deserve some explanation. To further separate the UI from the business logic, if the text that the user sees is associated with the command rather than the UI, then you can easily replace the commands without modifying the UI at all. This is extremely powerful when you start dealing with collections of commands that can all be handled in the same way. So that explains DisplayName.

The Enabled property is fairly obvious: there are times when it would either be impossible or just plain wrong to perform an action; in those cases, you want to disable the UI so that the action cannot be performed. I’ll come back to the Enabled property in a second.

The Key property is for when Commands are grouped together in a collection. It makes sense to store most of your commands globally with the main form in a list or map. We’ll need a way to uniquely identify them so that we can retrieve them later. That’s what the Key property is for. Go to Tools -> Options in Visual Studio, select Keyboard. There you’ll see the keys for the commands in Visual Studio, no pun intended.

Now, by itself, the above Command is very powerful. However, we’re not done. Combine the above with Data Binding in Window Forms and you have to write almost no code at all. Data Binding is a very powerful technology, which you’ll know about if you’re one of the millions of ASP.NET developers out there. In .NET 2.0, Windows Forms apps got the same treatment. I can’t cover data binding in detail in this post, so I’ll just assume you know about it. To really take advantage of Data Binding I have to modify my Command class slightly:

public abstract class Command : INotifyPropertyChanged

{

bool enabled;

string key, displayName;

 

public event PropertyChangedEventHandler PropertyChanged;

 

public string Key

{

get { return key; }

protected set { key = value; }

}

 

public string DisplayName

{

get { return displayName; }

protected set

{

if (displayName != value)

{

displayName = value;

OnPropertyChanged(new PropertyChangedEventArgs(“DisplayName”));

}

}

}

 

public bool Enabled

{

get { return enabled; }

set

{

if (enabled != value)

{

enabled = value;

OnPropertyChanged(new PropertyChangedEventArgs(“Enabled”));

}

}

}

 

public abstract void Execute();

 

protected void OnPropertyChanged(PropertyChangedEventArgs e)

{

PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)

handler(this, e);

}

}

OK, I gave you the whole implementation. You’ll see that my Command class now implements the INotifyPropertyChanged interface. This allows the data binding code to update the control that has bound to the data when the data changes. You’ll note that DisplayName and Enabled will raise the PropertyChanged event. Therefore you can create a Button, hook it up to a Command with a minimum of code and let the power of data binding deal with turning the command on and off:

Button button = new Button();

Command command = new ArbitraryCommand(“My Data”);

button.DataBindings.Add(“Text”, command, “DisplayName”);

button.DataBindings.Add(“Enabled”, command, “Enabled”);

button.Click += delegate { command.Execute(); };

This technique is very powerful when your business objects change on their own without user interaction.

There are few things you have to note. The DisplayName property will have to be internationalized if your app is interested in the rest of the world, which will make the class more complex. Also, the Command pattern kind of falls down when you need to pass data to the command. You lose the polymorphism of the Command class when you have to either know the specific concrete type or what data must be passed to a particular command.

Still, if you are doing serious Windows Forms apps, you should consider the Command pattern.

Technorati tags: , patterns

Now playing: Santana – Just Feel Better (Feat. Steven Tyler Of Aerosmith)