WPF 数据验证
效果:
文件结构:
添加如下引用:
NotifyBase类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp1.Model
{
public class NotifyBase : INotifyPropertyChanged, IDataErrorInfo
{
public string this[string columnName]
{
get
{
var errors = new List<ValidationResult>();
Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null), new ValidationContext(this)
{
MemberName = columnName
}, errors);
if (errors.Count > 0)
{
return string.Join(Environment.NewLine, errors.Select(e => e.ErrorMessage).ToArray());
}
return "";
}
}
public string Error => null;
public event PropertyChangedEventHandler PropertyChanged;
public void Notify([CallerMemberName] string propName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
}
DataErrorInfoModel类:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp1.Model
{
public class DataErrorInfoModel : NotifyBase
{
private string _userName;
[Required(ErrorMessage = "用户名不能为空")]
[StringLength(100, MinimumLength = 2, ErrorMessage = "最小长度为2")]
public string UserName
{
get { return _userName; }
set
{
_userName = value;
this.Notify();
}
}
private string _email;
[Required(ErrorMessage = "邮箱名不能为空")]
[StringLength(100, MinimumLength = 2, ErrorMessage = "最小长度为2")]
[RegularExpression("^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", ErrorMessage = "请填写正确的邮箱地址!")]
public string Email
{
get { return _email; }
set
{
_email = value;
this.Notify();
}
}
}
}
DataErrorInfoViewModel类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Model;
namespace WpfApp1.ViewModel
{
public class DataErrorInfoViewModel
{
public DataErrorInfoModel DModel { get; set; } = new DataErrorInfoModel();
}
}
窗体xaml代码:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<ControlTemplate x:Key="ExceptionTextBoxTemplate">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True" CornerRadius="5">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<Border Width="16" Height="16" CornerRadius="8" Margin="5" Background="Red" VerticalAlignment="Center" HorizontalAlignment="Right" Visibility="Collapsed" Name="validation" ToolTip="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox, Mode=FindAncestor}}">
<TextBlock Text="!" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="BorderBrush" Value="Red" TargetName="border"/>
<Setter Property="Visibility" Value="Visible" TargetName="validation"/>
<Setter Property="ToolTip" Value="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource Self}}"/>
<!--<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<TextBox Width="200" Height="40" VerticalContentAlignment="Center" Margin="10" Template="{StaticResource ExceptionTextBoxTemplate}" Validation.ErrorTemplate="{StaticResource ExceptionTextBoxTemplate}">
<TextBox.Text>
<Binding Path="DModel.UserName" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
</Binding>
</TextBox.Text>
</TextBox>
<TextBox Width="200" Height="40" VerticalContentAlignment="Center" Margin="10" Template="{StaticResource ExceptionTextBoxTemplate}" Validation.ErrorTemplate="{StaticResource ExceptionTextBoxTemplate}">
<TextBox.Text>
<Binding Path="DModel.Email" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
</Window>
后台代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new DataErrorInfoViewModel();
}
}