Here is the final solution I used. It was made possible in part by you
people, the people at Experts Exchange, and also by Code Project:
/* File: DropTextBox.cs **** Class: DropTextBox */
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace DropTextBox_NS
{
public class DropTextBox : ComboBox
{
// DLLs for mouse capture, Idle_Mind, Experts-Exchange
[DllImport("user32.dll")]
public static extern int SetCapture(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetCapture();
[DllImport("user32.dll")]
public static extern int ReleaseCapture();
public TextBox myTextBox;
public Panel myPanel;
public Label myLabel;
private String cannotContain; // keeps track of what
characters cannot be accepted in the text box or drop-down
// * * * * * * * * * * * * CLASS Accessors * * * * * * * * * * * * *
* //
public int WidthOfTextBox
{
get
{
return myTextBox.Width;
}
set
{
myTextBox.Width = value;
myPanel.Width = value;
myLabel.Width = value;
}
} // end WidthOfTextBox
public int HeightOfTextBox
{
get
{
return myTextBox.Height;
}
set
{
myTextBox.Height = value;
}
} // end HeightOfTextBox
public String CannotContainChars
{
get
{
return cannotContain;
}
set
{
cannotContain = value;
}
} // end CannotContainChars
// * * * * * * * * * * * * Constructors * * * * * * * * * * * * * *
* //
public DropTextBox()
{
this.DropDownHeight = 1;
this.cannotContain = "";
myLabel = new Label();
myLabel.Text = "Press TAB to Close This Window";
// must create a text box and place it under the drop-down
myTextBox = new TextBox();
this.myTextBox.Multiline = true;
this.myTextBox.Name = "textBox1";
this.myTextBox.Size = new System.Drawing.Size(120, 43);
this.myTextBox.TabIndex = 2;
myTextBox.Visible = false;
//create instructional panel
this.myPanel = new Panel();
this.myPanel.Name = "APanel";
this.myPanel.Size = new System.Drawing.Size(120, 14);
this.myPanel.Visible = false;
this.myPanel.BorderStyle = BorderStyle.FixedSingle;
this.myPanel.BackColor = System.Drawing.Color.AliceBlue;
this.myPanel.Controls.Add(myLabel);
this.myTextBox.LostFocus += new
System.EventHandler(this.HideTextBox);
this.myTextBox.MouseMove += new
MouseEventHandler(this.TextBoxMouseMove); // experts-exchange
this.myTextBox.MouseDown += new
MouseEventHandler(this.TextBoxMouseDown);
// set up filtering for the text box
this.myTextBox.TextChanged += new
System.EventHandler(this.FilterTextBox);
// set up filtering for the drop-down box
this.TextChanged += new System.EventHandler(this.FilterComboBox);
} // end constructor
// * * * * * * * * * * * * OVERRIDEN event handlers * * * * * * * *
* * * * * * * //
// at this point, we can legaly add the control to the parent form
protected override void CreateHandle()
{
base.CreateHandle();
this.Parent.Controls.Add(this.myTextBox);
this.Parent.Controls.Add(this.myPanel);
} // end CreateHandle ()
// this was the last thing we needed to implement in order for the
box to close correctly
protected override void OnDropDownClosed(EventArgs e)
{
base.OnDropDownClosed(e);
myTextBox.Capture = true;
}
// override the drop down so that it brings up our text box instead
protected override void OnDropDown(EventArgs e)
{
base.OnDropDown(e);
// if the text box is already visible, just hide it
if (myTextBox.Visible)
{
myTextBox.Visible = false;
myPanel.Visible = false;
myTextBox.Capture = false;
}
else // if not, show it
{
this.myTextBox.Text = this.Text;
this.myTextBox.Location = new
System.Drawing.Point(this.Location.X, this.Location.Y + this.Size.Height);
this.myPanel.Location = new
System.Drawing.Point(this.Location.X, this.Location.Y + this.Size.Height +
myTextBox.Height + 1);
myTextBox.Visible = true;
myPanel.Visible = true;
myTextBox.Capture = true;
this.myTextBox.BringToFront(); // ensure that it is visible
to the user
this.myTextBox.Focus(); // bring the cursor down to
the text box
}
} // end OnDropDown ()
// * * * * * * * * * * * * * * This section by Idle_Mind, Experts
Exchange * * * * * * * * * * * * * * * //
private void TextBoxMouseMove(object sender, MouseEventArgs e)
{
myTextBox.Capture = true;
}
private void TextBoxMouseDown(object sender, MouseEventArgs e)
{
if (e.X < 0 || e.X > myTextBox.Width || e.Y < 0 || e.Y >
myTextBox.Height)
{
myTextBox.Capture = false;
myTextBox.Visible = false;
}
}
// * * * * * * * * * * * * Helper Procedures * * * * * * * * * * * *
* * * //
//private void HideTextBox_mouseClick(object sender,
System.EventArgs e)
public void HideTextBox_mouseClick()
{
myTextBox.Visible = false;
myPanel.Visible = false;
this.Text = myTextBox.Text;
myTextBox.Capture = false;
}
// hide the text box from view
private void HideTextBox(object sender, System.EventArgs e)
{
myTextBox.Visible = false;
myPanel.Visible = false;
this.Text = myTextBox.Text;
myTextBox.Capture = false;
} // end HideTextBox ()
// called when the text box is modified so we can filter out
unwanted characters
// Adapted from
http://www.codeproject.com/useritems/FilterTextBox.asp#xx1333295xx , Hamed JI
12 Jan 2006
private void FilterTextBox(object sender, System.EventArgs e)
{
// if we do have a filter applied, start filtering
if (this.cannotContain.Length > 0)
{
// for each character in the must not contain field
foreach (char character in this.cannotContain.ToCharArray())
{
// if we find a character contained in the forbidden
string, remove it
if (myTextBox.Text.Contains(character.ToString()))
{
myTextBox.Text =
myTextBox.Text.Replace(character.ToString(), ""); // get rid of the offending
character
myTextBox.SelectionStart = myTextBox.Text.Length;
// put the cursor back to where it was
}
} // end FOREACH character in the forbidden string
} // end IF forbidden string
} // end FilterTextBox ()
// called when the comboBox text is modified so we can filter
unwanted characters
private void FilterComboBox(object sender, System.EventArgs e)
{
// if we do have a filter applied, start filtering
if (this.cannotContain.Length > 0)
{
// for each character in the must not contain field
foreach (char character in this.cannotContain.ToCharArray())
{
// if we find a character contained in the forbidden
string, remove it
if (this.Text.Contains(character.ToString()))
{
this.Text = this.Text.Replace(character.ToString(),
""); // get rid of the offending character
this.SelectionStart = this.Text.Length; // put the
cursor back to where it was
}
} // end FOREACH character in the forbidden string
} // end IF forbidden string
} // end FilterComboBox ()
} // end class DropTextBox ()
} // end _NS
I know the indenting probably will not look right after I post this, but you
get the picture. (Experts-Exchange has such a nice way of displaying code
that was pasted into their forms... why not here?)