Click here to Skip to main content
12,395,548 members (56,069 online)
Click here to Skip to main content
Add your own
alternative version

Stats

242.8K views
7.7K downloads
147 bookmarked
Posted

A TreeView Control with ComboBox Dropdown Nodes

, 21 Sep 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
This article demonstrates how to use a ComboBox dropdown to select the text for nodes in a TreeView.

DropDownTreeView Control Screenshot

Introduction

Recently, I was designing a graphical interface that used a TreeView to represent the structure of some data. I needed to let the user change the text on a few items, though the text needed to remain in a certain format. If only I could place a ComboBox drop-down control in place of each TreeView item! That would allow the user to choose between a pre-defined set of items for the value of the TreeNode.

This article describes the result of a few evenings' work towards making this DropDownTreeView control a reality. Hope you like it and find it useful!

Background

I searched the web (starting with CodeProject, of course) to see if this had been done before. While I couldn't find exactly what I needed (which is why I wrote this example), I did find a few interesting ideas that I pieced together.

  • TreeView with Combo. This article, though completely unusable in its current form, provided the inspiration for this control.
  • Using the treeview in your applications. I used this idea of inheriting from TreeNode in my control.
  • DropDown TreeView Control. This is exactly the opposite problem that I wished to solve. This article places a TreeView in the dropdown of a ComboBox. On the other hand, I wish to place a ComboBox dropdown on a TreeView control.

My approach to the whole problem was to create my own control that inherits from TreeView that knows how to interpret extra data that I store in a class that inherits from TreeNode. I call the control a DropDownTreeView, and it knows how to display DropDownTreeNodes. Let's take a look at each in turn.

Extending the TreeNode

Since each DropDownTreeNode must be able to show a ComboBox, I simply added a ComboBox as a property to the DropDownTreeNode. To make everything work right, I needed to ensure that the DropDownStyle of the DropDownTreeNode's ComboBox was set to be a DropDownList, so this is set explicitly in the get/set methods.

public class DropDownTreeNode : TreeNode
{
    // *snip* Constructors go here
    
    private ComboBox m_ComboBox = new ComboBox();
    public ComboBox ComboBox
    {
        get
        {
            this.m_ComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
            return this.m_ComboBox;
        }
        set
        {
            this.m_ComboBox = value;
            this.m_ComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
        }
    }
}

This allows you to access the properties of the internal ComboBox using code like this:

DropDownTreeNode tn1 = new DropDownTreeNode("Vacation 2006 (Denver)");
tn1.ComboBox.Items.Add("Vacation 2006 (Denver)");
tn1.ComboBox.Items.Add("Vacation 2005 (Miami)");
tn1.ComboBox.Items.Add("Vacation 2004 (Washington DC)");
tn1.ComboBox.Items.Add("Vacation 2003 (Houston)");
tn1.ComboBox.SelectedIndex = 0;

Here is where the real power of inheritance comes into play. Because DropDownTreeNode inherits from TreeNode, it can be added to the internal Nodes collection within the Treeview. Essentially, this means that both regular TreeNodes and the new DropDownTreeNodes may be used in the TreeView's internal TreeNodeCollection.

TreeView tv = new TreeView();
TreeNode tn1 = new TreeNode("Test Node 1");
DropDownTreeNode tn2 = new DropDownTreeNode("Test Node 2");
// Legal!  This is how you would normally do it.
tv.Nodes.Add(tn1);
// Also legal!  Through inheritance, a DropDownTreeNode is a TreeNode.
tv.Nodes.Add(tn2);

Extending the TreeView

Now comes the interesting part -- displaying the ComboBox within a TreeView control. I am (relatively) new to Windows Forms, so this code may be completely on the wrong track. But it's a start, and has worked in my current project. Also, thanks to those CodeProject users who have made comments -- I've incorporated your suggestions into this version of the article.

Essentially, what I want to do is to create a control that inherits from TreeView so that it can listen for the NodeMouseClick event and show the selected node's ComboBox (but only if that node is a DropDownTreeNode). The code goes something like this:

public class DropDownTreeView : TreeView
{
    public DropDownTreeView() : base()
    {
    }

    private DropDownTreeNode m_CurrentNode = null;

    protected override void 
              OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
    {            
        // Are we dealing with a dropdown node?
        if (e.Node is DropDownTreeNode)
        {
            this.m_CurrentNode = (DropDownTreeNode)e.Node;

            // Need to add the node's ComboBox to the
            // TreeView's list of controls for it to work
            this.Controls.Add(this.m_CurrentNode.ComboBox);

            // Set the bounds of the ComboBox, with
            // a little adjustment to make it look right
            this.m_CurrentNode.ComboBox.SetBounds(
                this.m_CurrentNode.Bounds.X - 1,
                this.m_CurrentNode.Bounds.Y - 2,
                this.m_CurrentNode.Bounds.Width + 25,
                this.m_CurrentNode.Bounds.Height);

            // Listen to the SelectedValueChanged
            // event of the node's ComboBox
            this.m_CurrentNode.ComboBox.SelectedValueChanged += 
               new EventHandler(ComboBox_SelectedValueChanged);
            this.m_CurrentNode.ComboBox.DropDownClosed += 
               new EventHandler(ComboBox_DropDownClosed);
            
            // Now show the ComboBox
            this.m_CurrentNode.ComboBox.Show();
            this.m_CurrentNode.ComboBox.DroppedDown = true;
        }
        base.OnNodeMouseClick(e);
    }

    void ComboBox_SelectedValueChanged(object sender, EventArgs e)
    {
        HideComboBox();
    }
    
    void ComboBox_DropDownClosed(object sender, EventArgs e)
    {
        HideComboBox();
    }
}

We override the OnNodeMouseClick function, and inspect the current TreeNode that has been clicked (specified in e.Node). If the node isn't a DropDownTreeNode, then we don't need to do anything. On the other hand, if it is a DropDownTreeNode, then we proceed to add the node's ComboBox to the DropDownTreeView's control collection, set its bounds, and show it. Also, we need to know when the user has made a selection within the ComboBox that is being shown, so we add an event listener to the ComboBox's SelectedValueChanged event. We also want to know when something has occurred (such as the user clicking somewhere outside of the displayed ComboBox) that will make the DropDown close itself, so we subscribe to the DropDownClosed event.

When each of these event handlers are called, they execute code that hides the ComboBox:

private void HideComboBox()
{
    if (this.m_CurrentNode != null)
    {
        // Unregister the event listener
        this.m_CurrentNode.ComboBox.SelectedValueChanged -= 
                             ComboBox_SelectedValueChanged;
        this.m_CurrentNode.ComboBox.DropDownClosed -= 
                             ComboBox_DropDownClosed;

        // Copy the selected text from the ComboBox to the TreeNode
        this.m_CurrentNode.Text = this.m_CurrentNode.ComboBox.Text;

        // Hide the ComboBox
        this.m_CurrentNode.ComboBox.Hide();
        this.m_CurrentNode.ComboBox.DroppedDown = false;

        // Remove the control from the TreeView's
        // list of currently-displayed controls
        this.Controls.Remove(this.m_CurrentNode.ComboBox);

        // And return to the default state (no ComboBox displayed)
        this.m_CurrentNode = null;
    }

}

This code essentially reverses all of the operations that were performed to show the ComboBox. The code copies the selected text from the node's ComboBox into the text of the tree node. Then, it hides the ComboBox and sets it to not be dropped down.. The ComboBox is then removed from the TreeView's control list, and the current node is nulled out.

I ran into an interesting problem here, because the order of all of these operations is important. It is necessary to unsubscribe from the DropDownClosed event before the DroppedDown property is changed. Otherwise, setting the DroppedDown property to false will invoke a DropDownClosed event, and if there is still a handler for that, ComboBox_DropDownClosed will be called, in turn calling HideComboBox, creating a circular loop that crashes the application. Thankfully, Visual Studio 2005 has a great debugger, and this strange operation was not very difficult to detect.

As you can see, the operation of the DropDownTreeView is pretty straightforward. Basically, there are hidden ComboBoxes that are forced to appear directly on top of the node that is being edited, and then are hidden when the selection is complete.

I spent a little more time to make the control usable, because sometimes the user may want to cancel making a selection from the ComboBox when it is being shown. Subscribing to the DropDownClosed event and hiding the ComboBox did the trick if the user clicked outside the ComboBox. In addition, if the user scrolls the mouse wheel, the TreeView will scroll, but the ComboBox will not follow it. While I could have handled the event for a mouse wheel and moved the ComboBox accordingly, it was easier (and I think provides a cleaner visual appearance) to just hide it when this happens.

protected override void OnMouseWheel(MouseEventArgs e)
{
    HideComboBox();
    base.OnMouseWheel(e);
}

Using the code

Using the code is pretty straightforward. You'll need to add a DropDownTreeView control (not a normal TreeView) to your form.

Then, you'll need to populate the TreeView with any combination of TreeNodes and DropDownTreeNodes. You access the ComboBox property of the DropDownTreeNode and treat it just as you would any other ComboBox. Then, you can use a DropDownTreeNode anywhere you would normally use a regular TreeNode. Here is a short code snippet from the example project that was used to make the screenshot at the beginning:

DropDownTreeNode weightNode = new DropDownTreeNode("1/4 lb.");
weightNode.ComboBox.Items.Add("1/4 lb.");
weightNode.ComboBox.Items.Add("1/2 lb.");
weightNode.ComboBox.Items.Add("3/4 lb.");
weightNode.ComboBox.SelectedIndex = 0;

DropDownTreeNode pattyNode = new DropDownTreeNode("All beef patty");
pattyNode.ComboBox.Items.Add("All beef patty");
pattyNode.ComboBox.Items.Add("All chicken patty");
pattyNode.ComboBox.SelectedIndex = 0;

TreeNode meatNode = new TreeNode("Meat Selection");
meatNode.Nodes.Add(weightNode);
meatNode.Nodes.Add(pattyNode);

TreeNode burgerNode = new TreeNode("Hamburger Selection");
burgerNode.Nodes.Add(condimentsNode);
burgerNode.Nodes.Add(meatNode);
this.dropDownTreeView1.Nodes.Add(burgerNode);

Lastly, you'll need to add your TreeNodes and DropdownTreeNodes to the Nodes property of your DropDownTreeView, as shown in the last line of the above code sample.

I've divided the sample project into two Visual Studio projects -- one for the control, and one for the test application that uses the control. The control project will compile into a DLL that contains the two classes, DropDownTreeView and DropDownTreeNode. Form there, you can import this control into your Visual Studio Toolbox:

  1. Start a new instance of Visual Studio 2005. Create a new application using the Windows Application template.
  2. Copy the DropDownTreeView.dll into your project directory.
  3. From the new Windows Forms project, open up the main form in Design Mode. Go to the Toolbox, right click, and select Choose Items... Then, click on the Browse... button and select the DropDownTreeView.dll that you copied to your project in step 2.
  4. This should add the component and highlight it in the dialog box. Make sure that it is checked, and click OK.
  5. The DropDownTreeView control should show up in the "General" tab of the Toolbox -- now you can drag it onto your form to use it. It should behave exactly like a regular TreeView!
  6. Enjoy!

Conclusion

Hope you liked it! Please feel free to send me comments, and suggestions for improvement, whether you liked it or not, etc. This is my first CodeProject article and I had fun writing it.

History

  • 6/21/06 - Created first version of the article. Included sample code and example project.
  • 9/21/06 - Finally got around to updating the article. This version includes a number of bug fixes, courtesy of everyone that contacted me with improvements and suggestions. This version is a lot more solid than the first. Thanks go out to mpasqual, OrlandoCurioso, and Ashalatha Adavalli.

Contact Info

You may contact me regarding this article at matt dot valerio at gmail dot com.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mattman206
Engineer
United States United States
Just a lowly grad student...
http://thevalerios.net/matt/

You may also be interested in...

Comments and Discussions

 
Questionhow to get newly changed selection in combo Pin
Katrad6-Nov-15 5:29
memberKatrad6-Nov-15 5:29 
QuestionHow are you capturing the User Selected Combo Item? Pin
Jonas Zuikis30-Dec-13 9:44
memberJonas Zuikis30-Dec-13 9:44 
QuestionRe: How are you capturing the User Selected Combo Item? Pin
Katrad6-Nov-15 5:31
memberKatrad6-Nov-15 5:31 
QuestionHow to add textbox as treenode in treeview using c# Pin
Ravi Lagad24-Jul-13 3:28
memberRavi Lagad24-Jul-13 3:28 
GeneralMy vote of 5 Pin
q56341319-Nov-12 23:48
memberq56341319-Nov-12 23:48 
Questionis it possible to adjust ComboBox width? Pin
leonpros12-May-11 2:00
memberleonpros12-May-11 2:00 
GeneralMy vote of 5 Pin
Monjurul Habib27-Apr-11 9:27
memberMonjurul Habib27-Apr-11 9:27 
GeneralCan we add a Link Label to tree view???? Pin
gurupru15-Apr-11 10:32
membergurupru15-Apr-11 10:32 
QuestionComboBox.Width always tiny Pin
Brian_J17-Feb-11 4:30
memberBrian_J17-Feb-11 4:30 
AnswerRe: ComboBox.Width always tiny Pin
meaningoflights18-Sep-11 15:47
membermeaningoflights18-Sep-11 15:47 
GeneralMy vote of 5 Pin
Sandeep Mewara3-Oct-10 9:23
mentorSandeep Mewara3-Oct-10 9:23 
GeneralBig Major Problem with this TreeNode Pin
Cypher_CS11-Jun-10 6:02
memberCypher_CS11-Jun-10 6:02 
GeneralThis is really nice, Pin
Typone11-Jun-09 19:54
memberTypone11-Jun-09 19:54 
GeneralSystemInformation.VerticalScrollBarWidth Pin
Cyborgx3710-Dec-08 10:14
memberCyborgx3710-Dec-08 10:14 
GeneralVB version Pin
Andy_ORS30-Oct-08 4:42
memberAndy_ORS30-Oct-08 4:42 
GeneralASP.Net Version Pin
bwash61710-Oct-07 12:05
memberbwash61710-Oct-07 12:05 
GeneralRe: ASP.Net Version [modified] Pin
Mattman20610-Oct-07 12:16
memberMattman20610-Oct-07 12:16 
GeneralNice! [modified] Pin
Pegasus200324-Sep-07 21:12
memberPegasus200324-Sep-07 21:12 
GeneralRe: Nice! Pin
Mattman2061-Oct-07 12:55
memberMattman2061-Oct-07 12:55 
GeneralIssue with CheckBoxes Pin
xdomain20-Apr-07 8:04
memberxdomain20-Apr-07 8:04 
GeneralRe: Issue with CheckBoxes Pin
Mattman20620-Apr-07 8:13
memberMattman20620-Apr-07 8:13 
GeneralRe: Issue with CheckBoxes Pin
Mattman20620-Apr-07 8:22
memberMattman20620-Apr-07 8:22 
GeneralScrollable... Pin
foosah28-Nov-06 5:20
memberfoosah28-Nov-06 5:20 
GeneralRe: Scrollable... Pin
Mattman20628-Nov-06 6:28
memberMattman20628-Nov-06 6:28 
AnswerRe: Scrollable... Pin
KD34XBR96012-Apr-07 10:56
memberKD34XBR96012-Apr-07 10:56 
GeneralTreeView Control with multiple Checkboxes in each Node Pin
foosah7-Nov-06 8:36
memberfoosah7-Nov-06 8:36 
GeneralRe: TreeView Control with multiple Checkboxes in each Node Pin
Mattman2068-Nov-06 3:05
memberMattman2068-Nov-06 3:05 
GeneralHai Pin
NagarjunaChakravarthy28-Oct-06 2:31
memberNagarjunaChakravarthy28-Oct-06 2:31 
GeneralProblem With Horizontal Scrolling Pin
Spavi9-Oct-06 5:31
memberSpavi9-Oct-06 5:31 
GeneralRe: Problem With Horizontal Scrolling Pin
Mattman2069-Oct-06 5:40
memberMattman2069-Oct-06 5:40 
GeneralReplace the Combobox by Textbox not easy for me Pin
exeriale30-Sep-06 13:04
memberexeriale30-Sep-06 13:04 
GeneralRe: Replace the Combobox by Textbox not easy for me Pin
Mattman20610-Oct-06 15:40
memberMattman20610-Oct-06 15:40 
AnswerRe: Replace the Combobox by Textbox not easy for me Pin
Haakon Bruusgaard9-Jun-10 3:26
memberHaakon Bruusgaard9-Jun-10 3:26 
GeneralRe: Replace the Combobox by Textbox not easy for me Pin
Ravi Lagad24-Jul-13 4:12
memberRavi Lagad24-Jul-13 4:12 
GeneralCool but... Pin
bentarne28-Sep-06 20:09
memberbentarne28-Sep-06 20:09 
GeneralRe: Cool but... Pin
Mattman20630-Sep-06 5:04
memberMattman20630-Sep-06 5:04 
AnswerRe: Cool but... Pin
Moooog11-Feb-08 5:19
memberMoooog11-Feb-08 5:19 
GeneralRe: Cool but... Pin
Mattman20613-Feb-08 2:15
memberMattman20613-Feb-08 2:15 
GeneralTreeView with scrollbars Pin
Spavi28-Sep-06 1:32
memberSpavi28-Sep-06 1:32 
GeneralTreeNode as Text + ComboBox Pin
Aniket Salunkhe20-Sep-06 22:05
memberAniket Salunkhe20-Sep-06 22:05 
GeneralTreeview "Loading" Pin
hootsman30-Aug-06 21:53
memberhootsman30-Aug-06 21:53 
GeneralDoesn't seem to work Pin
Alex Leykin19-Jul-06 13:55
memberAlex Leykin19-Jul-06 13:55 
GeneralRe: Doesn't seem to work Pin
Mattman20619-Jul-06 14:02
memberMattman20619-Jul-06 14:02 
GeneralBug when scrolling Pin
Alex Palto27-Jun-06 2:21
memberAlex Palto27-Jun-06 2:21 
GeneralRe: Bug when scrolling Pin
Mattman20621-Jul-06 8:52
memberMattman20621-Jul-06 8:52 
Generalminor suggestion Pin
OrlandoCurioso23-Jun-06 4:02
memberOrlandoCurioso23-Jun-06 4:02 
GeneralRe: minor suggestion Pin
Mattman20621-Jul-06 8:37
memberMattman20621-Jul-06 8:37 
JokeGreat idea - a suggestion Pin
mpasqual22-Jun-06 10:19
membermpasqual22-Jun-06 10:19 
GeneralRe: Great idea - a suggestion Pin
Mattman20622-Jun-06 10:54
memberMattman20622-Jun-06 10:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160721.1 | Last Updated 21 Sep 2006
Article Copyright 2006 by Mattman206
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid