Monday, June 23, 2008

Custom Drop Downs

For at least the last year I have had an unhealthy obsession with drop downs. Custom drop downs really.

That is, combo boxes. But when you click on the down arrow, you get a list with check boxes. Or a tree control. Or a tree control with check boxes. Or a custom edit surface with a text box and an "Apply" button. Or anything you can possibly imagine, really.

All of these things are immensely useful. And if the story ended there I would never have become so obsessed. Sadly, the story continues. It turns out, such things are not exactly easy to build.

My first attempt involved Subclassing the .NET combo box. I got a working drop down in the end, but it had some odd behavior, and was overall just a huge hack.

Next I learned that Infragistics had a component that you could use to create custom drop downs. Put any control in it you want and you're off to the races. For a time, my obsession was sated. Until we learned that this component could not be resized after it was opened. To resize it, you had to close it and reopen it. This results in noticeable, seizure inducing, flickering. And that = bad.

Later, I learned about how easy this was to do with WPF. In fact, it was the very first thing I ever tried in WPF. But that doesn't help me much at work where our software is all WinForms.

Fortunately, this story has a happy ending! It turns out that .NET 2.0 introduced a component much like the Infragistics one but without the added suck!

It is called the ToolStripDropDown. Basically it's just a Form with special properties that make it behave like a popup. It doesn't steal focus when it opens. It closes as soon a user clicks off it. It can have a shadow border (if you'd like) like a context menu. You can override its default close behavior by using the Closing event and checking the e.CloseReason enumeration value and setting e.Cancel = true. And best of all, it can host any .NET control you want to put in it, as long as you host that control in a TreeStripControlHost.

I stumbled on it at jfo's blog here and immediately put it into use. In the process of trying to do some wacky custom stuff I found the same material from jfo's blog, but on msdn here which you might prefer. Both of those show example code for putting a treeview in a custom drop down.

I must have spent months working on this problem. I probably executed thousands of Google searches looking for solutions. All I ever came across was people using borderless forms and the deactivate event, which doesn't quite cut it for all cases. So when I finally discovered this, my obsession compelled me to post about it.

The only thing that I haven't tried yet is making a "suggest" combo box using this technique. This is a control in which when the user types, you execute a stored procedure and fill the drop down with matching items. The potential problem spot here is that you need focus on the text box so you can type, but you need the drop down to be open. I'm guessing you could pull this off with the ToolStripDropDown though. If anyone knows for sure, please leave a comment!

5 comments:

  1. Hi, found your blog on a google search for ".net toolstripdropdown with text box focus" :)

    Ref. your last paragraph - that's exactly what I'm trying to do at the moment, and it doesn't work as the toolstripdropdown control grabs focus when you show it, and even setting the focus back to the text box with a call to Focus() doesn't work. Very annoying and a real shame as it would be perfect. If anyone does figure out how to do it, then please post code - I'm going to spend all day on it now and try and get it working myself :)

    ReplyDelete
  2. So, it was actually straightforward in the end, once I figured out what was happening. The answer is to make sure you set AutoClose to false before you call Show. Straight after the call to Show, set AutoClose to True again. It works like a charm then.

    I'm not entirely sure why having AutoClose set to open before Show is called causes it to freak out like that though, whether that is supposed to be expected behaviour or is a bug. MSDN doesn't give any insight.

    Hope this helps someone!

    ReplyDelete
  3. Thanks for posting back! I'm definitely going to have to play around with that following your tips here.

    ReplyDelete
  4. I'm trying the exact same thing here. The AutoClose tip works very well, but I don't fully understand the reason why it does.

    I do have another issue: when I open the dropdown with a click on the combo box arrow and I want to select an item in the tree, it requires 2 mouse cliks. It looks like the dropdown needs to gain focus first and the second click gets trough to the TreeView control.
    And there are more issues, but that one is the most obvious.

    Did anyone solve any of these this issues ? If so, can I see your code, please ?

    ReplyDelete
  5. So, it was actually straightforward in the end, once I figured out what was happening. The answer is to make sure you set AutoClose to false before you call Show. Straight after the call to Show, set AutoClose to True again. It works like a charm then.

    Well, not quite like a charm. When the popup menu comes up, and then you drag the parent form using the title bar, the popup menu does not go away as it should. If anyone happens to find a solution to that particular problem, let us know, because that is the only shortcoming I see with the current approach.

    ReplyDelete