From time to time, it’s a good idea to go back and re-examine old code. With time comes greater knowledge and new tricks; and in the case of two of my earlier custom Windows Forms controls, this was certainly true. You may remember my ComboBox control with grouping support, as well as my ComboBox with a TreeView drop-down – I have revisited these controls, with particular mind to implementing what I learnt from my experience with the Buffered Paint API.

New versions of GroupedComboBox and ComboTreeBoxGroupedComboBox

To refresh your memory, this control extends ComboBox and adds a new property; GroupMember. Using PropertyDescriptor and owner-drawing, it groups together items whose grouping values are equal.

What’s new:

  • On Windows Vista and 7, the control did not appear in the ‘button style’ consistent with normal ComboBox controls in DropDownList mode; this is a limitation of owner-drawing, but one that can be overcome through the use of VisualStyleRenderer. This is a slightly dodgy hack in that it pre-supposes the appearance of the ComboBox in this mode, but the functionality is only applied when the OS is identified as Vista or 7.
  • The control is inconsistent with other ComboBox controls because it is not animated. With the BufferedPainter<T> class I developed, implementing buffered animation was simple.

ComboTreeBox

The ComboTreeBox is a control developed entirely from scratch (i.e. its base class is Control) that uses a hierarchical/tree structure as its data representation (instead of a flat list). As such, it has behaviours in common with both ComboBox and TreeView. The drop-down/pop-up portion of the control is implemented using ToolStripDropDown, bitmap caching and custom rendering.

What’s new:

  • As with GroupedComboBox, the control did not appear in the Windows Vista/7 style. As the control has no editable portion and is entirely owner-drawn, it was easy to simulate the appearance under the appropriate OS. Under XP, it falls back to the default visual style. When themes are disabled, it draws in the classic style.
  • The control was not animated. Once again, BufferedPainter<T> was used to implement animation.
  • Due to a strongly-typed reference to its designer class, the control previously did not work with the “Client Profile” version of the .NET Framework. Rather cheekily, I have substituted my custom designer for the built-in designer that the DomainUpDown control uses – this works well for constraining the height of the control and avoids the need to reference the System.Design assembly (included only with the full version of the framework).
  • Minor tweaks were made to the way focused items are drawn; this is only apparent if focus cues are enabled in Windows.

Download

Please visit the project page here: Drop-Down Controls

47 thoughts on “Drop-Down Controls Revisited

  1. -2
    vote

    public VisualStateTrigger(VisualStateTriggerTypes type, TState state, Rectangle bounds = default(Rectangle), AnchorStyles anchor = AnchorStyles.Top | AnchorStyles.Left)
    {
    Type = type;
    State = state;
    Bounds = bounds;
    Anchor = anchor;
    }

    give an error ……..Error 4 Default parameter specifiers are not permitted

    Reply
    • 0
      vote

      Akber: You need to build using the C# 4.0 compiler (Visual Studio 2010); default parameters have been allowed in C# for some time now.

      Alternatively, you can add some overloaded methods to simulate the effect of having default parameters:

      public VisualStateTrigger(VisualStateTriggerTypes type, TState state, Rectangle bounds) : this(type, state, bounds, AnchorStyles.Top | AnchorStyles.Left) { }

      public VisualStateTrigger(VisualStateTriggerTypes type, TState state) : this(type, state, default(Rectangle), AnchorStyles.Top | AnchorStyles.Left) { }

      Reply
      • vote

        I tried by adding the above 2 overloads…and still i was getting error so i changed this function as :

        public VisualStateTrigger(VisualStateTriggerTypes type, TState state, Rectangle bounds = default(Rectangle), AnchorStyles anchor = AnchorStyles.Top | AnchorStyles.Left) {
        Type = type;
        State = state;
        Bounds = bounds;
        Anchor = anchor;
        }

        public VisualStateTrigger(VisualStateTriggerTypes type, TState state, Rectangle bounds , AnchorStyles anchor ) {
        Type = type;
        State = state;
        Bounds = bounds;
        Anchor = anchor;
        }

        Reply
          • vote

            groupbox works but combotreebox doesnt work plz help…i have already used ur control n now this erroor coming ..i cnnot do anything else bcoz this project is at the last stage and i cannot change it…

  2. Pingback: A ComboBox Control With Grouping | Brad Smith's Coding Blog

  3. vote

    GroupedComboBox 2 issues
    1. Have dupicated group, seems not grouping very well; For exmaple:
    Fruit
    A
    B
    Fruit
    C
    2. The DropDownList Items showing overlapped on screen, seems the height is not adjusted very well. Only the last item of each group showing full height, even group item showing partially.

    Reply
    • 0
      vote

      If your drop-down contains content that requires a horizontal scroll bar, you should consider using a more appropriate type of control.

      Reply
  4. vote

    Hello, thanks a lot for your control. I am using this control and is excelent. Congratulations.

    I’d like to add to the control the property ReadOnly. (For What? I want to disabled the control but I am not want to use enabled=false because it changes the color). Can you give me a clue? I work with Visual Basic and I can not find where make the change in the C# code.

    Thanks

    Reply
    • vote

      Hi Manuel,

      I chose not to implement a ReadOnly property on my controls because the built-in ComboBox control (which they are based on) does not implement such a property either. The purpose of read-only mode on the TextBox control is to allow text to be selected and scrolled while still preventing user input – for the ComboTreeBox control, there is no editable portion, so this property cannot apply. For the GroupedComboBox control, read-only mode would only affect the control in Simple or DropDown modes.

      If you still wanted to implement this property, it would be complex; you would have to disable the dropdown behaviour in response to the mouse/keyboard events (with the ComboBox control, this is difficult because the control handles input using a native method instead of a managed one). Visually, however, it would be relatively simple; simply render the controls in the normal way if the ReadOnly property is set to true – although I think the background is usually filled with a different colour, so you would have to account for that.

      Personally, I do not think it is worth attempting this; it is not consistent with other Windows Forms controls of the same type.

      Reply
    • vote

      Thanks for pointing this out. There’s an easy fix – in DropDownControlBase.cs, add the following method:

      protected override void OnEnabledChanged(EventArgs e) {
      base.OnEnabledChanged(e);
      _bufferedPainter.State = GetComboBoxState();
      }

      Reply
  5. vote

    I would like to try the control, but when I add a reference to the dll in my project the items do get added to the toolbox. The only problem is that they are greyed out, so I cannot add the controls to my project.
    Is this a known issue, or is there something I am doing wrong?

    Reply
    • vote

      If they don’t immediately appear, right-click in the Toolbox and select “Choose Items…” – then click Browse and locate the DLL. The controls should then appear in the list with checkmarks beside them. When you click OK, they will appear in the Toolbox.

      Reply
      • vote

        They do appear in the toolbox, just like you said. The only problem is that they are greyed out and thus I am unable to drag them to my form. No clue what the deal with that is.

        Reply
        • vote

          That sounds very unusual. I’ve only ever seen that happen when trying to add controls while the code is running…

          Check that both assemblies target the same version of the .NET Framework (recompile the controls DLL as necessary). If that doesn’t work, try adding the code directly into your project instead of via an assembly reference? Might help to shed some light on the cause of the problem.

          Reply
          • vote

            i bleave the reasion for this is because the IDE was complaing about
            public partial class DropDownControlBase : Control {
            changeing it to
            public class DropDownControlBase : Control {
            works very well
            is there a way to stop the parent node from being selectable? so can only select child nodes ?

          • 0
            vote

            To achieve this, you would have to add an additional property to ComboTreeNode. Then, in ComboTreeBox and ComboTreeDropDown, you would have to test this property during mouse/keyboard events, as well as when the SelectedNode property is changed, to make sure that the node may not be selected. You may also wish to change the appearance of nodes which cannot be selected; e.g. graying them out or not drawing the highlight when the mouse hovers over it.

    • -1
      vote

      Is it posable to creat a method/event that is
      selectedname
      selectedtext
      selectedindex
      I looked at the source of this and now have a Disable Parent property that wont select the parent Node but the set selectedNode by name text and index is a bit beound my skils I think, I see where to do it in ComboTreeNode.cs but not sur how to write the _selectednode by name

      Reply
  6. vote

    Never mind LinkQ works just fine with some changing of the control I have the ComboTree working exactly how I need it to.
    Can you please confirm that the “protected override void OnSelectedItemChanged” of “groupcombobox.cs” is not firing?
    Because I have a list that I have added and it behaves very odd…
    I added groups male and female
    Then added lion tiger
    AnamleGbid.ValueMember = “Value”;
    AnamleGbid.DisplayMember = “Display”;
    AnamleGbid.GroupMember = “Group”;
    AnamleGbid.DataSource = new ArrayList(new object[] {
    new{Display = “Tiger”, Group= “Female”, Value = 1337532130},
    new{Display = “Tiger”, Group= “Male”, Value = 3},
    new{Display = “Lion”,Group= “Female”, Value = -930376119},
    new{Display = “Lion”,Group= “Male”, Value = 9},
    });
    If you click on a male lion it selects the female lion same with tiger it’s not selecting based on Value how can I change this nore is the event firing how can I change this?

    Reply
    • vote

      It would be possible to implement this. They would function in a similar way to the expand/collapse glyphs, in that they would capture mouse clicks without closing the dropdown or changing the selection.

      Loosely speaking, you would need to:

      • Add a ShowCheckBoxes property to the control.
      • Add Checked or CheckState properties to the nodes.
      • Leave space for the checkbox glyph and paint it along with each node.
      • Handle mouse events (hover, click, etc) for when the pointer is within the bounds of the checkbox glyph.
      Reply
    • vote

      If you’re not familiar with C#, I would suggest downloading the binary (DLL) package from this page. You will be able to add it as a reference in your VB.NET project by browsing to the location of the file. The control should then appear in the toolbox when you design your forms. One of the great things about the .NET Framework is that you can use any assembly in your project, regardless of whether it is written in C#, C++ or VB.NET (or any of the other .NET languages). Let me know how you get on.

      Note: Visual Studio may not automatically add controls from assemblies that were downloaded from the internet. If the controls don’t appear in the toolbox immediately, you may have to add them using the ‘choose items…’ command.

      Reply
  7. vote

    Wow, this library is seriously cool! Just completely what I feared I had to write myself. Did not show up immediately after I referenced the library but with Tools / Choose Toolbox Items I was able to get them working.

    Many thanks for such a great library!

    Reply
  8. vote

    Hey Bradley,

    is it possible with this library to have a dropdown chek list, witjout the tree? I tried adding only parents to the ctbCheckboxes.Nodes, but then you get those little grey lines from the hierarchy in front of the checkboxes?

    Reply
    • vote

      I actually made this modification in a personal project not too long ago, so I can publish an updated version containing the change. The control will simply hide the expand/collapse glyphs if there are no child nodes. Thank you for your donation too!

      Reply
  9. vote

    Hey Bradley, that is exactly what I mean, that would make the thing have even one more display style. If you could update it that would be great!
    Donation well deserved, saves me a lot of time so it’s absolutely worth it

    Reply
  10. vote

    Hee Bradley,

    what I notice is that the CascadeCheckState does not work for more than 2 levels. I have a 6 level deep hierarchy and then it fails cascade down up all the way.

    Bastiaan

    Reply
  11. vote

    Hi sir! good day, i had some question to ask , i try to use your code on my program, but seems like .GroupMember had an error saying missing a using directive or assembly reference. sorry i’m new at this things.
    thank you!

    Reply
    • vote

      Make sure that your project is targeting the correct version of the .NET Framework (either 3.5 or 4/4.5 depending on which version you downloaded). If you’re still having problems, paste the exact error message into a comment and let me know.

      Reply
      • vote

        Here is the error
        Error 1 ‘System.Windows.Forms.ComboBox’ does not contain a definition for ‘GroupMember’ and no extension method ‘GroupMember’ accepting a first argument of type ‘System.Windows.Forms.ComboBox’ could be found (are you missing a using directive or an assembly reference?

        Reply
    • vote

      ComboTreeBox will let you have multiple nested groups. For example:

      ComboTreeNode n1, n2, n3;
      n1 = comboTreeBox1.Nodes.Add("Orange");
      n2 = n1.Nodes.Add("Cat");
      n3 = n2.Nodes.Add("Techno");
      n3.Nodes.Add("Square");
      n3.Nodes.Add("Circle");
      n3.Nodes.Add("Octogon");
      n3 = n2.Nodes.Add("Rock");
      n3.Nodes.Add("Pentagon");
      n3.Nodes.Add("Triangle");
      n2 = n1.Nodes.Add("Dog");
      n3 = n2.Nodes.Add("Pop");
      n3.Nodes.Add("Rhombus");
      n3 = n2.Nodes.Add("Country");
      n3.Nodes.Add("Hexagon");
      n3.Nodes.Add("Dodecahedron");
      n3.Nodes.Add("Decagon");
      n1 = comboTreeBox1.Nodes.Add("Blue");
      // etc

      Reply

Leave a reply

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

required