C# WinForm移除非法字符的输入框
文章目录
namespace System.Windows.Forms
{
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
/// <summary>
/// 移除非法字符的服务。
/// </summary>
public class TextBoxBaseRemoveCharService
{
public TextBoxBaseRemoveCharService(TextBoxBase textBox)
{
this.TextBox = textBox;
}
#region 初始化函数。
/// <summary>
/// 更新 有效字符 为 整数 的字符。
/// </summary>
public void UpdateValidCharAsInteger()
{
ValidChars = GetIntegerChars();
}
/// <summary>
/// 整数 的 字符。
/// </summary>
/// <returns></returns>
public static IList<char> GetIntegerChars()
{
return new char[]
{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
};
}
/// <summary>
/// 更新 无效字符 为 换行 的字符。
/// </summary>
public void UpdateInvalidCharAsNewLine()
{
InvalidChars = GetNewLineChars();
}
/// <summary>
/// 换行 的字符。
/// </summary>
/// <returns></returns>
public static IList<char> GetNewLineChars()
{
return new char[]
{
'\v',
'\r',
'\n',
};
}
#endregion 初始化函数。
#region 移除非法字符。
/// <summary>
/// 在 调用 <see cref="TextBoxBase.OnTextChanged(EventArgs)"/> 前执行。 <br />
/// 注意:在重载函数中,调用本函数,本函数所属的对象可能为 null 。
/// 所以,调用示例为 RemoveCharService?.OnTextChangedBefore()
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("", "S134")]
public void OnTextChangedBefore()
{
var safeValidChars = ValidChars;
var hasValidChars = safeValidChars != null && safeValidChars.Count > 0;
var safeInvalidChars = InvalidChars;
var hasInvalidChars = safeInvalidChars != null && safeInvalidChars.Count > 0;
if (DisabledRemoveInvalidChars || (!hasValidChars && !hasInvalidChars))
{
return;
}
string oldText = TextBox.Text;
if (string.IsNullOrEmpty(oldText))
{
return;
}
StringBuilder newBuilder = new StringBuilder(oldText.Length);
List<int> removeIndexes = new List<int>(16);
int index = -1;
foreach (var ch in oldText)
{
++index;
if (hasValidChars)
{
if (!safeValidChars.Contains(ch))
{
removeIndexes.Add(index);
}
else
{
newBuilder.Append(ch);
}
}
// 等价 else if (hasInvalidChars)
else
{
if (safeInvalidChars.Contains(ch))
{
removeIndexes.Add(index);
}
else
{
newBuilder.Append(ch);
}
}
}
OnTextChangedBeforeCore(oldText, newBuilder, removeIndexes);
}
private void OnTextChangedBeforeCore(string oldText, StringBuilder newBuilder, List<int> removeIndexes)
{
string newText = newBuilder.ToString();
if (newText != oldText)
{
TextBox.SuspendLayout();
try
{
// 处理重命名时,当输入非法字符时,会全选名称的问题。
int selectionStartOld = 0;
int selectionLengthOld = 0;
var isReadySelection = !string.IsNullOrEmpty(newText) &&
ReadySelect(out selectionStartOld, out selectionLengthOld);
TextBox.Text = newText;
// 处理重命名时,当输入非法字符时,会全选名称的问题。
if (isReadySelection)
{
selectionLengthOld -= MatchIndexCount(removeIndexes, selectionStartOld - 1, selectionStartOld + selectionLengthOld);
selectionStartOld -= MatchIndexCount(removeIndexes, -1, selectionStartOld);
GetSafeSelect(newText.Length, ref selectionStartOld, ref selectionLengthOld);
UpdateSelect(selectionStartOld, selectionLengthOld);
}
}
finally
{
TextBox.ResumeLayout();
}
}
}
private int MatchIndexCount(IList<int> indexList, int minIndex, int maxIndex)
{
int count = 0;
foreach (var index in indexList)
{
if (index > minIndex && index < maxIndex)
{
++count;
}
}
return count;
}
private bool ReadySelect(out int selectionStart, out int selectionLength)
{
bool isSuccessCompleted;
try
{
selectionStart = TextBox.SelectionStart;
selectionLength = TextBox.SelectionLength;
isSuccessCompleted = true;
}
catch (Exception ex)
{
TraceException("Ready selection exception: ", ex);
selectionStart = 0;
selectionLength = 0;
isSuccessCompleted = false;
}
return isSuccessCompleted;
}
private void UpdateSelect(int selectionStart, int selectionLength)
{
try
{
TextBox.Select(selectionStart, selectionLength);
}
catch (Exception ex)
{
TraceException("Update selection exception: ", ex);
}
}
private void GetSafeSelect(int length, ref int selectionStart, ref int selectionLength)
{
if (selectionStart > length)
{
selectionStart = length;
}
if (selectionLength > length)
{
selectionLength = length;
}
}
#endregion 移除非法字符。
private static void TraceException(string message, Exception ex)
{
System.Diagnostics.Trace.WriteLineIf(true, message + ex);
}
/// <summary>
/// 禁止移除非法字符。
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(false)]
public bool DisabledRemoveInvalidChars { get; set; }
/// <summary>
/// 有效字符。 <br />
/// 注意:<see cref="ValidChars"/> 和 <see cref="InvalidChars"/> 最多一个不为 null 。
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(null)]
private IList<char> ValidChars
{
get { return validChars; }
set
{
if (validChars != value)
{
if (value != null)
{
InvalidChars = null;
}
validChars = value;
}
}
}
private IList<char> validChars;
/// <summary>
/// 无效字符。 <br />
/// 注意:<see cref="ValidChars"/> 和 <see cref="InvalidChars"/> 最多一个不为 null 。
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(null)]
private IList<char> InvalidChars
{
get { return invalidChars; }
set
{
if (invalidChars != value)
{
if (value != null)
{
ValidChars = null;
}
invalidChars = value;
}
}
}
private IList<char> invalidChars;
private TextBoxBase TextBox { get; set; }
}
}
namespace System.Windows.Forms
{
using System.ComponentModel;
/// <summary>
/// 支持移除 非法字符 的输入框。
/// </summary>
public class RemoveInvalidCharTextBox : TextBox
{
/// <summary>
/// 测试代码:设置 有效字符 为 整数 的字符。
/// </summary>
[System.Diagnostics.Conditional("DEBUG")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("", "IDE0017")]
public static void TestValidCharAsInteger()
{
var form = new System.Windows.Forms.Form();
var textBox = new RemoveInvalidCharTextBox();
textBox.Dock =System.Windows.Forms.DockStyle.Top;
textBox.UpdateValidCharAsInteger();
form.Controls.Add(textBox);
System.Windows.Forms.Application.Run(form);
}
public RemoveInvalidCharTextBox()
{
RemoveCharService = new TextBoxBaseRemoveCharService(this);
}
protected override void OnTextChanged(EventArgs e)
{
RemoveCharService?.OnTextChangedBefore();
base.OnTextChanged(e);
}
/// <summary>
/// 更新 有效字符 为 整数 的字符。
/// </summary>
public void UpdateValidCharAsInteger()
{
RemoveCharService.UpdateValidCharAsInteger();
}
private TextBoxBaseRemoveCharService RemoveCharService { get; set; }
/// <summary>
/// 禁止移除非法字符。
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(false)]
public bool DisabledRemoveInvalidChars
{
get { return RemoveCharService.DisabledRemoveInvalidChars; }
set { RemoveCharService.DisabledRemoveInvalidChars = value; }
}
}
}