|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: If you like this article, please vote for it!
Introduction
BackgroundThere are already many open source controls for numeric edit, but most of which handle keyboard input only, few support mouse Cut, Copy, Paste and Clear in context menu, few process conventional shortcut keys such as Ctrl+X, Ctrl+C or Ctrl+V too.
Key PointsText edit box usually considers two input cases: one is keyboard input, the other is mouse operations, which correspond to
Another important task in 1) Override OnKeyDown EventThe first key point is that protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!this.ReadOnly)
{
if(e.KeyData == Keys.Delete || e.KeyData == Keys.Back)
{
if(this.SelectionLength > 0)
{
this.ClearSelection(); // clear first this.SelectedText
}
else
{
// delete char and recalculate this.SelectionStart
this.DeleteText(e.KeyData);
}
// does not transform event to KeyPress, but to KeyUp
e.SuppressKeyPress = true;
}
}
}
2) Handle Shortcut KeysThe commonly used shortcut keys include Ctrl+X, Ctrl+C and Ctrl+V. In .NET 2.0, the shortcut Ctrl+X can be captured by message protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys)Shortcut.CtrlV )
{
this.ClearSelection();
string text = Clipboard.GetText();
for (int k = 0; k < text.Length; k++) // cannot use SendKeys.Send
{
SendCharKey(text[k]);
}
return true;
}
else if (keyData == (Keys)Shortcut.CtrlC)
{
Clipboard.SetText(this.SelectedText);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void SendCharKey(char c)
{
Message msg = new Message();
msg.HWnd = this.Handle;
msg.Msg = WM_CHAR;
msg.WParam = (IntPtr)c;
msg.LParam = IntPtr.Zero;
base.WndProc(ref msg);
}
Method 3) Handle Context Menu MessagesIn .NET 2.0, the four operations in context menu: Cut, Copy, Paste, Clear correspond to four Windows messages and their values: public TNumEditBox()
{
this.ContextMenu = new ContextMenu();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE) // mouse paste
{
this.ClearSelection();
SendKeys.Send(Clipboard.GetText());
base.OnTextChanged(EventArgs.Empty);
}
else if (m.Msg == WM_COPY) // mouse copy
{
Clipboard.SetText(this.SelectedText);
}
else if (m.Msg == WM_CUT) // mouse cut or ctrl+x shortcut
{
Clipboard.SetText(this.SelectedText);
this.ClearSelection();
base.OnTextChanged(EventArgs.Empty);
}
else if (m.Msg == WM_CLEAR)
{
this.ClearSelection();
base.OnTextChanged(EventArgs.Empty);
}
else
{
base.WndProc(ref m);
}
}
Here 4) Override OnKeyPress EventIn
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (this.ReadOnly)
{
return;
}
if (e.KeyChar == (char)13 || e.KeyChar == (char)3 ||
e.KeyChar == (char)22 || e.KeyChar == (char)24)
{
return;
}
if (m_decimalLength == 0 && e.KeyChar == m_decimalSeparator)
{
e.Handled = true;
return;
}
if (!m_allowNegative && e.KeyChar == m_negativeSign &&
base.Text.IndexOf(m_negativeSign) < 0)
{
e.Handled = true;
return;
}
if (!char.IsDigit(e.KeyChar) && e.KeyChar != m_negativeSign &&
e.KeyChar != m_decimalSeparator)
{
e.Handled = true;
return;
}
if (base.Text.Length >= m_MaxValueLength && e.KeyChar != m_negativeSign)
{
e.Handled = true;
return;
}
if (e.KeyChar == m_decimalSeparator) // will position after dot(.)
{
this.SelectionLength = 0;
}
else
{
this.ClearSelection();
}
bool isNegative = (base.Text[0] == m_negativeSign) ? true : false;
if (isNegative && this.SelectionStart == 0)
{
this.SelectionStart = 1;
}
if (e.KeyChar == m_negativeSign)
{
int selStart = this.SelectionStart;
if (!isNegative)
{
base.Text = m_negativeSign + base.Text;
this.SelectionStart = selStart + 1;
}
else
{
base.Text = base.Text.Substring(1, base.Text.Length - 1);
if (selStart >= 1)
{
this.SelectionStart = selStart - 1;
}
else
{
this.SelectionStart = 0;
}
}
e.Handled = true; // minus(-) has been handled
return;
}
int dotPos = base.Text.IndexOf(m_decimalSeparator) + 1;
if (e.KeyChar == m_decimalSeparator)
{
if (dotPos > 0)
{
this.SelectionStart = dotPos;
}
e.Handled = true; // dot has been handled
return;
}
if (base.Text == "0")
{
this.SelectionStart = 0;
this.SelectionLength = 1; // replace the first char, i.e. 0
}
else if (base.Text == m_negativeSign + "0")
{
this.SelectionStart = 1;
this.SelectionLength = 1; // replace the first char, i.e. 0
}
else if (m_decimalLength > 0)
{
if (base.Text[0] == '0' && dotPos == 2 && this.SelectionStart <= 1)
{
this.SelectionStart = 0;
this.SelectionLength = 1; // replace the first char, i.e. 0
}
else if (base.Text.Substring(0, 2) == m_negativeSign + "0" &&
dotPos == 3 && this.SelectionStart <= 2)
{
this.SelectionStart = 1;
this.SelectionLength = 1; // replace the first char, i.e. 0
}
else if (this.SelectionStart == dotPos + m_decimalLength)
{
e.Handled = true; // last position after text
}
else if (this.SelectionStart >= dotPos)
{
this.SelectionLength = 1;
}
else if (this.SelectionStart < dotPos - 1)
{
this.SelectionLength = 0;
}
}
}
It must point out when you see
5) Method ClearSelectionThis method is used to clear selected text, i.e., private void ClearSelection()
{
if (this.SelectionLength == 0)
{
return;
}
if (this.SelectedText.Length == base.Text.Length)
{
base.Text = 0.ToString(m_valueFormatStr);
return;
}
int selLength = this.SelectedText.Length;
if (this.SelectedText.IndexOf(m_decimalSeparator) >= 0)
{
selLength--; // selected text contains dot(.), selected length minus 1
}
this.SelectionStart += this.SelectedText.Length; // after selected text
this.SelectionLength = 0;
for (int k = 1; k <= selLength; k++)
{
this.DeleteText(Keys.Back); // delete char one by one
}
}
6) Method DeleteTextThis method is used to delete one char by Delete key or BackSpace key. The core skill is to change Delete key to BackSpace key through adding
private void DeleteText(Keys key)
{
int selStart = this.SelectionStart; // base.Text will be delete at selStart - 1
if (key == Keys.Delete) // Delete key change to BackSpace key,
// adjust selStart value
{
selStart += 1; // adjust position for BackSpace
if (selStart > base.Text.Length) // text end
{
return;
}
if (this.IsSeparator(selStart - 1)) // next if delete dot(.) or thousands(;)
{
selStart++;
}
}
else // BackSpace key
{
if (selStart == 0) // first position
{
return;
}
if (this.IsSeparator(selStart - 1)) // char which will be delete is separator
{
selStart--;
}
}
if (selStart == 0 || selStart > base.Text.Length) // selStart - 1 no digit
{
return;
}
int dotPos = base.Text.IndexOf(m_decimalSeparator);
bool isNegative = (base.Text.IndexOf(m_negativeSign) >= 0) ? true : false;
if (selStart > dotPos && dotPos >= 0) // delete digit after dot(.)
{
base.Text = base.Text.Substring(0, selStart - 1) +
base.Text.Substring(selStart, base.Text.Length - selStart) + "0";
base.SelectionStart = selStart - 1; // SelectionStart is unchanged
}
else // delete digit before dot(.)
{
// delete 1st digit and Text is negative, i.e.. delete minus(-)
if (selStart == 1 && isNegative)
{
if (base.Text.Length == 1) // i.e. base.Text is '-'
{
base.Text = "0";
}
else if (dotPos == 1) // -.* format
{
base.Text = "0" + base.Text.Substring(1, base.Text.Length - 1);
}
else
{
base.Text = base.Text.Substring(1, base.Text.Length - 1);
}
base.SelectionStart = 0;
}
// delete 1st digit before dot(.) or Text.Length = 1
else if (selStart == 1 && (dotPos == 1 || base.Text.Length == 1))
{
base.Text = "0" + base.Text.Substring(1, base.Text.Length - 1);
base.SelectionStart = 1;
}
else if (isNegative && selStart == 2 && base.Text.Length == 2) // -* format
{
base.Text = m_negativeSign + "0";
base.SelectionStart = 1;
}
else if (isNegative && selStart == 2 && dotPos == 2) // -*.* format
{
base.Text = m_negativeSign + "0" +
base.Text.Substring(2, base.Text.Length - 2);
base.SelectionStart = 1;
}
else // selStart > 0
{
base.Text = base.Text.Substring(0, selStart - 1) +
base.Text.Substring(selStart, base.Text.Length - selStart);
base.SelectionStart = selStart - 1;
}
}
}
Using the CodeAfter unzipping file TNumEditBox.zip, we can double click the solution file TNumEditBox_Demo.sln to view the demo if we have Visual Studio 2005/2008, or we can run TNumEditBox_Demo.exe in subfolder \bin\ to test the control. There are two classes in TNumEditBox.cs: one is
Three usages must be noticed:
Conclusion
Although There are a lot of freeware Delphi controls well used for many years which have no C# versions. Now, we must consider these problems:
History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||