You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF MVVM模式服务端文本框验证:仅允许合法十进制数值

WPF MVVM 实现服务端文本框十进制数值验证

要实现符合要求的十进制数值验证,核心是在ViewModel层通过INotifyDataErrorInfo接口实现业务逻辑验证,确保输入内容为合法十进制格式,同时排除字母、特殊字符及格式错误的内容。以下是完整实现方案:

1. 核心验证逻辑

采用正则表达式格式校验 + decimal.TryParse范围校验的组合方式:

  • 正则表达式^-?\d+(\.\d+)?$:匹配可选负号开头、至少一位整数、可选小数点加至少一位小数的格式,直接排除字母、特殊字符、多个小数点等非法情况。
  • decimal.TryParse:确保输入数值在decimal类型有效范围内,避免超出范围的非法数值。

2. ViewModel实现(MVVM核心)

实现INotifyPropertyChanged和INotifyDataErrorInfo接口,将验证逻辑封装在ViewModel中,符合MVVM关注点分离原则:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;

public class MainViewModel : INotifyPropertyChanged, INotifyDataErrorInfo
{
    private decimal? _decimalValue;
    private readonly Dictionary<string, List<string>> _errorCollection = new Dictionary<string, List<string>>();

    public decimal? DecimalValue
    {
        get => _decimalValue;
        set
        {
            _decimalValue = value;
            ValidateInput(value?.ToString());
            OnPropertyChanged();
        }
    }

    private void ValidateInput(string input)
    {
        // 清除该属性原有错误
        ClearPropertyErrors(nameof(DecimalValue));

        // 空值场景可根据业务需求调整是否允许
        if (string.IsNullOrWhiteSpace(input))
            return;

        // 格式校验:排除字母、特殊字符、多小数点等
        var validDecimalPattern = new Regex(@"^-?\d+(\.\d+)?$");
        if (!validDecimalPattern.IsMatch(input))
        {
            AddPropertyError(nameof(DecimalValue), "请输入合法十进制数值,禁止字母、特殊字符或格式错误(如多个小数点)");
            return;
        }

        // 范围校验:确保数值在decimal类型范围内
        if (!decimal.TryParse(input, out _))
        {
            AddPropertyError(nameof(DecimalValue), "输入数值超出十进制类型的有效范围");
        }
    }

    #region INotifyPropertyChanged 实现
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion

    #region INotifyDataErrorInfo 实现
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    public bool HasErrors => _errorCollection.Count > 0;

    public IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName) || !_errorCollection.ContainsKey(propertyName))
            return null;
        return _errorCollection[propertyName];
    }

    private void AddPropertyError(string propertyName, string errorMsg)
    {
        if (!_errorCollection.ContainsKey(propertyName))
            _errorCollection[propertyName] = new List<string>();

        if (!_errorCollection[propertyName].Contains(errorMsg))
        {
            _errorCollection[propertyName].Add(errorMsg);
            RaiseErrorsChanged(propertyName);
        }
    }

    private void ClearPropertyErrors(string propertyName)
    {
        if (_errorCollection.ContainsKey(propertyName))
        {
            _errorCollection.Remove(propertyName);
            RaiseErrorsChanged(propertyName);
        }
    }

    private void RaiseErrorsChanged(string propertyName)
    {
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }
    #endregion
}

3. XAML视图绑定

在View中绑定ViewModel属性,并开启错误验证显示:

<Window x:Class="DecimalValidationDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DecimalValidationDemo"
        Title="十进制数值验证" Height="150" Width="320">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <Grid Margin="20">
        <StackPanel>
            <TextBox x:Name="DecimalTextBox"
                     Text="{Binding DecimalValue, 
                                    Mode=TwoWay, 
                                    UpdateSourceTrigger=PropertyChanged, 
                                    ValidatesOnNotifyDataErrors=True}"
                     Margin="0 0 0 10"
                     VerticalAlignment="Center"/>
            <!-- 显示错误提示 -->
            <TextBlock Foreground="Crimson"
                       Text="{Binding (Validation.Errors)[0].ErrorContent, ElementName=DecimalTextBox}"/>
        </StackPanel>
    </Grid>
</Window>

关键说明

  • UpdateSourceTrigger=PropertyChanged:设置为实时验证,用户每输入一个字符就触发ViewModel的验证逻辑;若需要失去焦点时验证,可改为LostFocus。
  • 空值处理:代码中允许空输入,若业务要求必须输入数值,可移除空值判断并添加空值错误提示。
  • 前端辅助限制(可选):如果需要在输入时直接阻止非法字符输入,可给TextBox添加PreviewTextInput事件处理,但这属于前端辅助,核心验证仍需保留在ViewModel层,确保业务逻辑一致性。

内容的提问来源于stack exchange,提问作者SHUBHENDU KUMAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 21:46:06