我有其他控件中包含一个文本框,允许输入的单行的WinForms对话框。 我想,让用户能够按Ctrl-Backspace键删除整个单词。 这是不是与外的现成文本框的默认行为; 我得到一个矩形的性格,而不是删除的字。
我已经证实了ShortcutsEnabled
属性设置为True
。
我发现我可以用一个RichTextBox,而不是一个TextBox得到我想要的行为。 这里的问题是,RichTextBox的(境特别)的外观是从文本框的不同,我并不需要或想要的文字标记的能力。
所以我的问题是如何最好地处理这种情况? 有没有对我缺少的文本框的一些财产? 或者是它最好使用RichTextBox的,更新的外观,因此是一致的,而文字的禁用标记?
我比较高兴编写代码来处理KeyDown和按键事件明确地,如果没有更好的办法,但认为这是值得一试第一。
Answer 1:
/ *更新:也请看看下面达米尔的回答,它可能是一个更好的解决办法:) * /
我会通过发送按Ctrl + Shift +左键和Backspace到TextBox模拟按Ctrl + Backspace键。 效果几乎是一样的,并没有必要手动处理控件的文本。 您可以使用此代码实现它:
class TextBoxEx : TextBox
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.Back))
{
SendKeys.SendWait("^+{LEFT}{BACKSPACE}");
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
您还可以修改app.config文件,迫使SendKey类使用发送键的新方法:
<configuration>
<appSettings>
<add key="SendKeys" value="SendInput" />
</appSettings>
</configuration>
Answer 2:
老问题,但我只是偶然发现不需要任何额外的代码的答案。
对于文本框启用自动完成和CTRL-Backspace键应该工作,只要你想它。
CTRL-Backspace键删除整个单词插入符号左边似乎是自动完成处理的“ 流氓特色 ”。 这就是为什么能够自动完成修复此问题。
源1 | 源2
-
你能使用的设定自动完成功能AutoCompleteMode
和AutoCompleteSource
你类似的东西(例如, Suggest
和RecentlyUsedList
)
Answer 3:
虽然给ProcessCmdKey重写工作不错,首先,它本身限制为Ctrl + Backspace键只有一个迭代,主要是因为使用SendWait模仿按键的,如果你按住Ctrl键的同时再次按Backspace键,系统似乎只认按下退格键。 如果你登录倍率的按键,你会发现,你从来没有真正按额外的键的集合。
另一种方法是明确地管理在给ProcessCmdKey重写文本框的外观,并且不发送多个键映射到系统中。 这很容易被应用到按Ctrl + Delete键也是如此。
我已经包含了一些常见的“停车点”为按Ctrl + Backspace键的行为,并使用switch语句,而不是一个正则表达式。 他们从来没有觉得不够干净,我通常会漏掉一个字
如果你看到我的代码的任何问题,通过各种手段,请让我知道。 好运的人仍然被这个难题糊涂!
public class TextBoxEx : TextBox
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Back | Keys.Control))
{
for (int i = this.SelectionStart - 1; i > 0; i--)
{
switch (Text.Substring(i, 1))
{ //set up any stopping points you want
case " ":
case ";":
case ",":
case "/":
case "\\":
Text = Text.Remove(i, SelectionStart - i);
SelectionStart = i;
return true;
case "\n":
Text = Text.Remove(i - 1, SelectionStart - i);
SelectionStart = i;
return true;
}
}
Clear(); //in case you never hit a stopping point, the whole textbox goes blank
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
}
}
Answer 4:
我不知道这是可能的,而不定制的KeyDown或按键事件,下面的代码工作,但:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.Back) && e.Control)
{
e.SuppressKeyPress = true;
int selStart = textBox1.SelectionStart;
while (selStart > 0 && textBox1.Text.Substring(selStart - 1, 1) == " ")
{
selStart--;
}
int prevSpacePos = -1;
if (selStart != 0)
{
prevSpacePos = textBox1.Text.LastIndexOf(' ', selStart - 1);
}
textBox1.Select(prevSpacePos + 1, textBox1.SelectionStart - prevSpacePos - 1);
textBox1.SelectedText = "";
}
}
Answer 5:
这是我登陆上去使用,它同样可以处理多行文本框
private void HandleCtrlBackspace_KeyDown(object sender, KeyEventArgs e) {
switch (e.KeyData) {
case (Keys.Back | Keys.Control):
e.SuppressKeyPress = true;
TextBox textbox = (TextBox)sender;
int i;
if (textbox.SelectionStart.Equals(0)) {
return;
}
int space = textbox.Text.LastIndexOf(' ', textbox.SelectionStart - 1);
int line = textbox.Text.LastIndexOf("\r\n", textbox.SelectionStart - 1);
if (space > line) {
i = space;
} else {
i = line;
}
if (i > -1) {
while (textbox.Text.Substring(i - 1, 1).Equals(' ')) {
if (i.Equals(0)) {
break;
}
i--;
}
textbox.Text = textbox.Text.Substring(0, i) + textbox.Text.Substring(textbox.SelectionStart);
textbox.SelectionStart = i;
} else if (i.Equals(-1)) {
textbox.Text = textbox.Text.Substring(textbox.SelectionStart);
}
break;
}
}
Answer 6:
这是溜溜的路要走:)
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
//if ctrl+bcksp
if (e.KeyChar == 127)
{
//if not last word
if (textBox1.Text.Split (' ').Count() > 1)
{
//remoce last word form list and put it back together (gotta love lambda)
textBox1.Text = textBox1.Text.Split (' ').Take (textBox1.Text.Split (' ').Count() - 1).Aggregate ((a,b) => a + " " + b);
//set selection at the end
textBox1.SelectionStart = textBox1.Text.Length;
}
else if (textBox1.Text.Split (' ').Count() == 1)
{
textBox1.Text = "";
}
}
}
Answer 7:
这工作不错:
static Regex RegExWholeWord = new Regex(@"(\r\n|[^A-Za-z0-9_\r\n]+?|\w+?) *$", RegexOptions.Compiled);
在键下,使用
var m = RegExWholeWord.Match(textbox.Text, 0, textbox.SelectionStart);
if (m.Success)
{
textbox.Text = textbox.Text.Remove(m.Index, m.Length);
textbox.SelectionStart = m.Index;
}
Answer 8:
正则表达式为这个做。 用它。
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
TextBox box = (TextBox)sender;
if (e.KeyData == (Keys.Back | Keys.Control))
{
if (!box.ReadOnly && box.SelectionLength == 0)
{
RemoveWord(box);
}
e.SuppressKeyPress = true;
}
}
private void RemoveWord(TextBox box)
{
string text = Regex.Replace(box.Text.Substring(0, box.SelectionStart), @"(^\W)?\w*\W*$", "");
box.Text = text + box.Text.Substring(box.SelectionStart);
box.SelectionStart = text.Length;
}
Answer 9:
我回答在VB而不是C#因为我一直在寻找在VB此解决方案,但无法找到一个,但这些C#响应帮我做出来:-D
在模块中创建此子
Public Sub ctrl_bksp(ByRef t As TextBox)
Dim ss As Integer = t.SelectionStart
Dim sl As Integer = t.SelectionLength
Dim tl As Integer = t.TextLength
'//Split either side of selection start
Dim strPre As String = Strings.Left(t.Text, tl - (tl - ss))
Dim strPost As String = Strings.Right(t.Text, tl - ss - sl)
'//Get Last Space Location in StrPre
Dim s As Integer = Strings.InStrRev(RTrim(strPre), " ")
strPre = Strings.Left(strPre, s)
t.Text = strPre & strPost
t.SelectionStart = s
End Sub
然后你可以从任何文本框的KeyPress事件中调用该子:
Private Sub Textbox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles Textbox1.KeyPress
Select Case e.KeyChar
Case Chr(127) '//Ctrl+Backspace
e.Handled = True
Call ctrl_bksp(Textbox1)
End Select
End Sub
这将工作无论身在何处的选择是字符串中,文字和是否被选中,并响应辉煌!
Answer 10:
DWF和giangurgolo ,感谢你提供的信息。 下面它的改良版本。 请注意,它也考虑ComboBox
,作为具有非常相同的问题,因为TextBox
。 另外请注意,快捷键只有积极的,如果配置TextBox
或ComboBox
允许这样做。
TextBoxEx:
public class TextBoxEx : TextBox
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
// Attention:
// Similar code exists in ComboBoxEx.ProcessCmdKey().
// Changes here may have to be applied there too.
if (ShortcutsEnabled)
{
if (keyData == (Keys.Control | Keys.Back))
{
if (!ReadOnly)
{
if (SelectionStart > 0)
{
int i = (SelectionStart - 1);
// Potentially trim white space:
if (char.IsWhiteSpace(Text, i))
i = (StringEx.StartIndexOfSameCharacterClass(Text, i) - 1);
// Find previous marker:
if (i > 0)
i = StringEx.StartIndexOfSameCharacterClass(Text, i);
else
i = 0; // Limit i as it may become -1 on trimming above.
// Remove until previous marker or the beginning:
Text = Text.Remove(i, SelectionStart - i);
SelectionStart = i;
return (true);
}
else
{
return (true); // Ignore to prevent a white box being placed.
}
}
}
else if (keyData == (Keys.Control | Keys.A))
{
if (!ReadOnly && Multiline)
{
SelectAll();
return (true);
}
}
}
return (base.ProcessCmdKey(ref msg, keyData));
}
}
ComboxBoxEx:
public class ComboBoxEx : ComboBox
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
// Attention:
// Similar code exists in TextBoxEx.ProcessCmdKey().
// Changes here may have to be applied there too.
if (keyData == (Keys.Control | Keys.Back))
{
if (DropDownStyle != ComboBoxStyle.DropDownList)
{
if (SelectionStart > 0)
{
int i = (SelectionStart - 1);
// Potentially trim white space:
if (char.IsWhiteSpace(Text, i))
i = (StringEx.StartIndexOfSameCharacterClass(Text, i) - 1);
// Find previous marker:
if (i > 0)
i = StringEx.StartIndexOfSameCharacterClass(Text, i);
else
i = 0; // Limit i as it may become -1 on trimming above.
// Remove until previous marker or the beginning:
Text = Text.Remove(i, SelectionStart - i);
SelectionStart = i;
return (true);
}
else
{
return (true); // Ignore to prevent a white box being placed.
}
}
}
return (base.ProcessCmdKey(ref msg, keyData));
}
}
字符串辅助(如静态类StringEx):
/// <summary>
/// Returns the start index of the same character class.
/// </summary>
/// <param name="str">The <see cref="string"/> object to process.</param>
/// <param name="startIndex">The search starting position.</param>
/// <returns>
/// The zero-based index position of the start of the same character class in the string.
/// </returns>
public static int StartIndexOfSameCharacterClass(string str, int startIndex)
{
int i = startIndex;
if (char.IsWhiteSpace(str, i)) // Includes 'IsSeparator' (Unicode space/line/paragraph
{ // separators) as well as 'IsControl' (<CR>, <LF>,...).
for (/* i */; i >= 0; i--)
{
if (!char.IsWhiteSpace(str, i))
return (i + 1);
}
}
else if (char.IsPunctuation(str, i))
{
for (/* i */; i >= 0; i--)
{
if (!char.IsPunctuation(str, i))
return (i + 1);
}
}
else if (char.IsSymbol(str, i))
{
for (/* i */; i >= 0; i--)
{
if (!char.IsSymbol(str, i))
return (i + 1);
}
}
else
{
for (/* i */; i >= 0; i--)
{
if (char.IsWhiteSpace(str, i) || char.IsPunctuation(str, i) || char.IsSymbol(str, i))
return (i + 1);
}
}
return (0);
}
Answer 11:
我曾与这些方法的问题:
- 更换。文本已滚动大文本的问题。
- 这样做SendKeys.SendWait(“^ + {左} {}退格”)在textBox.KeyDown事件处理程序并不稳定,在为我所有。
- 使用.Cut()改变剪贴板(但完全正常工作)。
纵观.NET参考源是什么.Cut()不会导致我到下面的解决方案:选择在文本框中的文字,然后用WM_CLEAR将其清除。 似乎做工精细,它不是人工发送按键事件。
class CtrlBackspaceSupport
{
TextBox textBox;
public CtrlBackspaceSupport(TextBox textBox)
{
this.textBox = textBox;
textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
}
[DllImport("user32.dll", SetLastError = true)]
static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
const int WM_CLEAR = 0x0303;
void textBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.Back)
{ // Ctrl+Backspace -> remove till word border before cursor
e.SuppressKeyPress = true;
if (0 == textBox.SelectionLength && textBox.SelectionStart > 1)
{ // nothing selected
var text = textBox.Text;
int indexOfSpace = text.LastIndexOf(' ', textBox.SelectionStart - 2);
if (-1 != indexOfSpace)
{ // found something
indexOfSpace++;
textBox.Select(indexOfSpace, textBox.SelectionStart - indexOfSpace);
SendMessage(new HandleRef(textBox, textBox.Handle).Handle, WM_CLEAR, 0, 0);
}
}
}
}
}
文章来源: Winforms Textbox - Using Ctrl-Backspace to Delete Whole Word