|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionRecently, I was designing a graphical interface that used a This article describes the result of a few evenings' work towards making this BackgroundI 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.
My approach to the whole problem was to create my own control that inherits from Extending the TreeNodeSince each 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 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 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 TreeViewNow comes the interesting part -- displaying the Essentially, what I want to do is to create a control that inherits from 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 When each of these event handlers are called, they execute code that hides the 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 I ran into an interesting problem here, because the order of all of these operations is important. It is necessary to unsubscribe from the As you can see, the operation of the I spent a little more time to make the control usable, because sometimes the user may want to cancel making a selection from the protected override void OnMouseWheel(MouseEventArgs e)
{
HideComboBox();
base.OnMouseWheel(e);
}
Using the codeUsing the code is pretty straightforward. You'll need to add a Then, you'll need to populate the 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 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,
ConclusionHope 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
Contact InfoYou may contact me regarding this article at matt dot valerio at gmail dot com. | ||||||||||||||||||||