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
相关产品推荐
相关产品推荐

