首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C# WinForms TextBox 輸入驗證完整指南:範圍限制、實時校驗與最佳實踐

     編輯:程式設計疑難解答

核心需求

在 TextBox 中輸入數據,實時判斷是否超出範圍(如 0-1000),超出則提示並恢復/阻止輸入。

方案對比

事件觸發時機優點缺點推薦場景
TextChanged文本改變後簡單直觀、可獲取完整文本易觸發遞歸、光標位置重置、用戶體驗差簡單驗證、非數字輸入
KeyPress按鍵按下(字符輸入前)可攔截非法字符、光標不動無法處理粘貼、拖拽、IME 輸入僅允許數字/特定字符
Validating失去焦點前標準驗證流程、配合 ErrorProvider不即時、需手動觸發焦點轉移表單提交前整體驗證
PreviewKeyDown + TextChanged組合使用兼顧即時攔截與粘貼處理代碼較複雜生產級嚴格輸入控制

推薦方案一:KeyPress 攔截非數字 + TextChanged 範圍檢查


public partial class Form1 : Form {
    private string lastValidText = "0";
    
    public Form1() {
        InitializeComponent();
        txtNumber.KeyPress += TxtNumber_KeyPress;
        txtNumber.TextChanged += TxtNumber_TextChanged;
        txtNumber.Validating += TxtNumber_Validating;
    }

    // 1. 僅允許數字、退格、刪除、小數點(可選)
    private void TxtNumber_KeyPress(object sender, KeyPressEventArgs e) {
        if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.') {
            e.Handled = true; // 忽略該按鍵
        }
        // 限制小數點只能出現一次
        if (e.KeyChar == '.' && ((TextBox)sender).Text.Contains(".")) {
            e.Handled = true;
        }
    }

    // 2. 實時範圍檢查(文本改變後)
    private void TxtNumber_TextChanged(object sender, EventArgs e) {
        var tb = (TextBox)sender;
        if (decimal.TryParse(tb.Text, out decimal value)) {
            if (value > 1000) {
                MessageBox.Show("輸入值不能超過 1000", "範圍錯誤", 
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                // 恢復上次合法值
                tb.Text = lastValidText;
                tb.SelectionStart = tb.Text.Length; // 光標移至末尾
            } else {
                lastValidText = tb.Text;
            }
        } else if (tb.Text != "" && tb.Text != ".") {
            // 處理粘貼導致的非法文本
            tb.Text = lastValidText;
            tb.SelectionStart = tb.Text.Length;
        }
    }

    // 3. 失去焦點時最終驗證(防漏網)
    private void TxtNumber_Validating(object sender, CancelEventArgs e) {
        var tb = (TextBox)sender;
        if (decimal.TryParse(tb.Text, out decimal value)) {
            if (value < 0 || value > 1000) {
                e.Cancel = true; // 取消焦點轉移
                errorProvider1.SetError(tb, "範圍必須在 0-1000 之間");
            } else {
                errorProvider1.SetError(tb, "");
            }
        } else {
            e.Cancel = true;
            errorProvider1.SetError(tb, "請輸入有效數字");
        }
    }
}

推薦方案二:自定義 NumericTextBox 控件(企業級封裝)


public class NumericTextBox : TextBox {
    public decimal MinValue { get; set; } = decimal.MinValue;
    public decimal MaxValue { get; set; } = decimal.MaxValue;
    public int DecimalPlaces { get; set; } = 2;
    private string _lastValidText = "0";

    protected override void OnKeyPress(KeyPressEventArgs e) {
        base.OnKeyPress(e);
        // 允許:控制字符、數字、負號(首位)、小數點(唯一)
        if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar)) {
            if (e.KeyChar == '-' && SelectionStart == 0 && !Text.Contains("-")) return;
            if (e.KeyChar == '.' && !Text.Contains(".") && DecimalPlaces > 0) return;
            e.Handled = true;
        }
    }

    protected override void OnTextChanged(EventArgs e) {
        base.OnTextChanged(e);
        if (decimal.TryParse(Text, out decimal value)) {
            if (value < MinValue || value > MaxValue) {
                Text = _lastValidText;
                SelectionStart = Text.Length;
            } else {
                _lastValidText = Text;
            }
        } else if (Text != "" && Text != "-" && Text != ".") {
            Text = _lastValidText;
            SelectionStart = Text.Length;
        }
    }

    protected override void OnValidating(CancelEventArgs e) {
        base.OnValidating(e);
        if (!decimal.TryParse(Text, out _) || 
            decimal.Parse(Text) < MinValue || decimal.Parse(Text) > MaxValue) {
            e.Cancel = true;
        }
    }

    public decimal GetValue() => decimal.TryParse(Text, out var v) ? v : 0;
}

使用示例


// 設計器中拖入 NumericTextBox,屬性設置:
numericTextBox1.MinValue = 0;
numericTextBox1.MaxValue = 1000;
numericTextBox1.DecimalPlaces = 0; // 整數

// 代碼中獲取值
decimal val = numericTextBox1.GetValue();

進階:配合 ErrorProvider 顯示圖標提示


// 表單載入時綁定
errorProvider1.BlinkStyle = ErrorBlinkStyle.NeverBlink;
errorProvider1.ContainerControl = this;

// Validating 事件中
private void txtInput_Validating(object sender, CancelEventArgs e) {
    if (!ValidateInput((TextBox)sender)) {
        e.Cancel = true;
        errorProvider1.SetError((TextBox)sender, "輸入超出允許範圍 (0-1000)");
    } else {
        errorProvider1.SetError((TextBox)sender, "");
    }
}

避坑指南

  1. ❌ 在 TextChanged 中直接修改 Text 會再次觸發事件 → 使用標誌位或比較 lastValidText 避免遞歸
  2. ❌ 僅用 KeyPress 無法攔截右鍵粘貼、拖拽文本 → 必須配合 TextChanged
  3. ❌ int.Parse 拋異常性能差 → 用 decimal.TryParse 或 int.TryParse
  4. ❌ 忽略 Validating 事件 → 表單提交前最後一道防線
  5. ✅ 設置 CausesValidation = true(默認)確保驗證鏈生效
  6. ✅ 考慮國際化:小數點在某些地區為逗號 System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved