Winforms文本框 - 使用Ctrl-Backspace删除整个单词
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Winforms文本框 - 使用Ctrl-Backspace删除整个单词相关的知识,希望对你有一定的参考价值。
我有一个Winforms对话框,其中包含一个允许单行输入的TextBox。我想允许用户能够按Ctrl-Backspace删除整个单词。这不是开箱即用的TextBox的默认行为;我得到一个矩形字符,而不是删除单词。
我已经确认ShortcutsEnabled
属性设置为True
。
我确实发现我可以使用RichTextBox而不是TextBox来获取我想要的行为。这个问题是RichTextBox的外观(特别是边框)与TextBox的外观不同,我不需要或不想要标记文本的能力。
所以我的问题是如何最好地处理这种情况?我错过了TextBox上的一些属性吗?或者最好使用RichTextBox,更新外观以使其一致,并禁用文本的标记?
如果没有更好的方法,我很乐意编写处理KeyDown和KeyPress事件明确的代码,但认为值得先检查一下。
/ *更新:请看下面Damir的答案,它可能是一个更好的解决方案:) * /
我将Ctrl + Shift + Left和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>
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);
}
我有这些方法的问题:
- 替换.Text具有大文本的滚动问题。
- 在textBox.KeyDown事件处理程序中执行SendKeys.SendWait(“^ + {LEFT} {BACKSPACE}”)对我来说根本不稳定。
- 使用.Cut()更改剪贴板(否则可以正常工作)。
查看.NET参考源,.Cut()确实引出了以下解决方案:在TextBox中选择文本,然后使用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);
}
}
}
}
}
老问题,但我偶然发现了一个不需要任何额外代码的答案。
启用文本框的自动完成功能,CTRL-Backspace应该按照您的意愿工作。
CTRL-Backspace删除插入符号左侧的整个单词似乎是自动完成处理程序的“流氓功能”。这就是启用自动完成功能修复此问题的原因。
--
您可以通过将AutoCompleteMode
和AutoCompleteSource
设置为您喜欢的任何内容来启用自动完成功能(例如,以上是关于Winforms文本框 - 使用Ctrl-Backspace删除整个单词的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 C# winforms 中一次将文本写入多个文本框?
如何在 C# Winforms 程序的文本框中突出显示文本?