我一直在尝试制作一个自定义 TextBox 组件,该组件允许我在 TextBox 的输入字段中包含一段静态文本,因此不允许用户更改它。
我发现我必须操纵/挂钩键输入事件(包括 WndProc)。
具体来说,我的目标是防止用户粘贴替换、剪切、删除可以“停靠”(或不停靠)到 TextBox 开头或结尾的静态文本。
我尝试了很多事情,但我一直面临的问题是我无法推断出选择的结束位置。
我目前拥有的(启发/基于TNumEditBox):
public class LibraryComboBox : HybridComboBox //Ignore the parent class' name; it is basically a ComboBox that supports the ReadOnly attribute
{
public LibraryComboBox()
: base()
{ }
public String SelectedLibrary { get; set; } //Static text
public TextPosition TextPosition = TextPosition.None; //"Docking" position
private const int WM_CHAR = 0x0102;
private const int WM_CUT = 0x0300;
private const int WM_COPY = 0x0301;
private const int WM_PASTE = 0x0302;
private const int WM_CLEAR = 0x0303;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE)
{
//TODO: Prevent overwriting the static part
}
else if (m.Msg == WM_CUT)
{
//TODO: Prevent cutting over the static part
}
else if (m.Msg == WM_CLEAR)
{
base.OnTextChanged(EventArgs.Empty);
}
else
{
base.WndProc(ref m);
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys)Shortcut.CtrlV)
{
string text = Clipboard.GetText();
for (int k = 0; k < text.Length; k++)
{
SendCharKey(text[k]);
}
return true;
}
else if (keyData == (Keys)Shortcut.CtrlC)
{
Clipboard.SetText(this.SelectedText);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!this.ReadOnly)
{
if (e.KeyData == Keys.Delete || e.KeyData == Keys.Back)
{
//TODO: Remove corresponding characters
e.SuppressKeyPress = true; // does not transform event to KeyPress, but to KeyUp
}
}
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (this.ReadOnly)
{
return;
}
//TODO: Prevent any unauthorized changes to the library path
if (this.SelectionStart < this.Text.IndexOf(this.SelectedLibrary))
e.Handled = true;
}
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);
}
}
public enum TextPosition
{
None = 0,
Left = 1,
Right = 2
}