//Except where stated all code and programs in this project are the copyright of Jim Blackler, 2008. //jimblackler@gmail.com // //This is free software. Libraries and programs are distributed under the terms of the GNU Lesser //General Public License. Please see the files COPYING and COPYING.LESSER. using System; using System.Drawing; using System.Windows.Forms; namespace MiscControls { /// /// A text box which is shown in compact form, but is able to expand when it has multiple /// lines of text to show, and is in focus. /// public class ExpandableTextBox : TextBox { int originalHeight; /// /// Constructor for the control /// public ExpandableTextBox() { InitializeComponent(); originalHeight = Height; } private void InitializeComponent() { this.SuspendLayout(); // // ExpandableTextBox // this.Multiline = true; this.Enter += new System.EventHandler(this.ExpandableTextBox_Enter); this.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.ExpandableTextBox_PreviewKeyDown); this.Leave += new System.EventHandler(this.ExpandableTextBox_Leave); this.TextChanged += new System.EventHandler(this.ExpandableTextBox_TextChanged); this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ExpandableTextBox_KeyDown); this.ResumeLayout(false); } private void ExpandableTextBox_TextChanged(object sender, EventArgs e) { SetSize(false); } private void ExpandableTextBox_Leave(object sender, EventArgs e) { if (internalCall == 0) { Minimise(); } } private void ExpandableTextBox_Enter(object sender, EventArgs e) { if (internalCall == 0) { SetSize(true); } } Control addTo; Control originalParent; int internalCall; int originalChildIndex; Control placeHolder; private void SetSize(bool justEntered) { if (Text.Contains(Environment.NewLine)) { ScrollBars = ScrollBars.Vertical; if ((justEntered || Focused) && Height == originalHeight) { originalParent = Parent; // the placeholder preserves the layout of any layout managed parent panels placeHolder = new TextBox(); placeHolder.Bounds = Bounds; originalChildIndex = originalParent.Controls.GetChildIndex(this); originalParent.SuspendLayout(); internalCall++; originalParent.Controls.Remove(this); internalCall--; originalParent.Controls.Add(placeHolder); originalParent.Controls.SetChildIndex(placeHolder, originalChildIndex); // Get the control to add the expanded text box too ... probably the ultimate // underlying form. The reason we don't just add to the Parent is that this might // be a control with special layout control that will override our specified layout. addTo = originalParent; Size offset = new Size(0, 0); while (addTo.Parent != null && addTo.LayoutEngine != LayoutEngine) // ours has default layout { offset += new Size(addTo.Location); addTo = addTo.Parent; } Point newLocation = Location + offset; Location = newLocation; if (!Location.Equals(newLocation)) { throw new Exception("Could not set location"); } Size = new Size(Width, ExpandedHeight); addTo.SuspendLayout(); addTo.Controls.Add(this); BringToFront(); Focus(); originalParent.ResumeLayout(); addTo.ResumeLayout(); } } else { ScrollBars = ScrollBars.None; if (Minimise()) { Focus(); } } } private bool Minimise() { if (Height != originalHeight) { if (addTo != null) { addTo.SuspendLayout(); originalParent.SuspendLayout(); internalCall++; addTo.Controls.Remove(this); internalCall--; originalParent.Controls.Remove(placeHolder); originalParent.Controls.Add(this); originalParent.Controls.SetChildIndex(this, originalChildIndex); Size = new Size(Width, originalHeight); originalParent.ResumeLayout(); addTo.ResumeLayout(); addTo = null; } return true; } else { return false; } } /// /// The height of the text box in pixels, when it is expanded for multi-line editing. /// public int ExpandedHeight { get { return expandedHeight; } set { expandedHeight = value; } } private int expandedHeight = 100; private void ExpandableTextBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) { // using tab to change focus? Collapse control first or focus will get switched to a control on the parent page if (e.KeyCode == Keys.Tab) { if (Minimise()) { internalCall++; Focus(); internalCall--; } } else if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None) { e.IsInputKey = true; } } private void ExpandableTextBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { // e.SuppressKeyPress = true; } } } }