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);
}