绑定下的数据验证
WPF中Binding数据校验、并捕获异常信息的三种方式讲到了三种方式,其中使用ValidatinRule的方式比较推荐,但是如果一个类中有多个属性,要为每个属性都要声明一个ValidatinRule,这样做非常麻烦。可以让类继承自IDataErrorInfo
来解决这个问题。
IDataErrorInfo基本使用
Data类中具有多个属性
public class Data : IDataErrorInfo
{
private string _value;
public string Value
{
get { return _value; }
set { _value = value; }
}
private string _myVar;
public string MyVar
{
get { return _myVar; }
set { _myVar = value; }
}
//索引器
//获得给定属性名称的错误信息
public string this[string columnName]
{
get
{
if (columnName == "Value" && this.Value =="123")
{
return "出错了~Value~[IDataErrorInfo]";
}
if (columnName == "MyVar" && this.MyVar == "123")
{
return "出错了~MyVar~[IDataErrorInfo]";
}
return string.Empty;
}
}
//获取该对象错误原因
//该案例没有用到
public string Error => "对象设置了123";
}
XAML代码
TextBox利用DataContext绑定属性
绑定数据源的方式有4种:Source、ElementName、DataContext、RelativeSource
<Window.DataContext>
<local:Data/>
</Window.DataContext>
<StackPanel>
<!--必须设置ValidatesOnDataErrors=True-->
<TextBox Text="{Binding Value,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" x:Name="tb"/>
<TextBlock Text="{Binding Path=(Validation.Errors)[0].ErrorContent,ElementName=tb}"/>
<Border BorderThickness="3" BorderBrush="Red"/>
<TextBox Text="{Binding MyVar,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" x:Name="ts"/>
<TextBlock Text="{Binding Path=(Validation.Errors)[0].ErrorContent,ElementName=ts}"/>
</StackPanel>
使用反射与特性
从上面看出,利用索引器和属性名称可以判断是否为某些特性的值,但是这样写仍然太过麻烦,如果一个类中有大量的属性,要为每个属性进行判断,这样会有大量的if
语句,可读性和可维护性都不太好。
既然在索引器中我们已经有了属性名称,我们可以利用反射来简化上面的步骤。
- 自定义一个Attribute特性类
public class NotValueAttribute : Attribute
{
public string ValidateValue { get; set; }
public NotValueAttribute(string value) { ValidateValue = value; }
}
- 在重写索引器中的get方法
public string this[string columnName]
{
get
{
PropertyInfo? pInfo = this.GetType().GetProperty(columnName, BindingFlags.Public | BindingFlags.Instance);
if (pInfo.IsDefined(typeof(NotValueAttribute), false))
{
NotValueAttribute attr = (NotValueAttribute)pInfo.GetCustomAttribute(typeof(NotValueAttribute), false);
//如果属性没有应用该特性
if (attr == null) { return string.Empty; }
//如果属性值为空
else if(pInfo.GetValue(this) == null) { return string.Empty; }
//如果属性值为定义的ValidateValue
else if (pInfo.GetValue(this).ToString() == attr.ValidateValue)
{
return "字段不能为" + attr.ValidateValue;
}
}
return string.Empty;
}
}
- 分别为属性增加特性
[NotValue("123")]
public string Value
{
get { return _value; }
set { _value = value; }
}
[NotValue("234")]
public string MyVar
{
get { return _myVar; }
set { _myVar = value; }
}
上面的这种写法可以简化验证所需要的代码,而且有很强的可读性和可维护性,如果直接把自定义的特性直接加到类上,使得该类中所有的属性都应用验证规则可以修改苏索引器,在上面所写的代码中加上
NotValueAttribute? classAttr =(NotValueAttribute?)this.GetType().GetCustomAttribute(typeof(NotValueAttribute), false);
if (classAttr !=null)
{
PropertyInfo? classPInfo = this.GetType().GetProperty(columnName, BindingFlags.Public | BindingFlags.Instance);
if (classPInfo.GetValue(this)==null) { return string.Empty; }
else if (classPInfo.GetValue(this).ToString() == classAttr.ValidateValue)
{
return "字段不能为" + classAttr.ValidateValue;
}
}
将自定义特性应用在类上
[NotValue("123")]
public class Data : IDataErrorInfo
案例:实现VS新建项目界面
文章来源:https://www.toymoban.com/news/detail-414140.html
- 创建一个继承自IDataErrorInfo的类
public class Data : IDataErrorInfo
{
public string this[string columnName]
{
get
{
var pi = this.GetType().GetProperty(columnName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (pi.IsDefined(typeof(RequiredAttribute), false)
&&
(pi.GetValue(this) == null || string.IsNullOrEmpty(pi.GetValue(this).ToString()))
)
return "字段为空了~~~[IDataErrorInfo]";
return "";
}
}
public string Error => null;
private string _projectName = "新建项目";
[Required]
public string ProjectName
{
get { return _projectName; }
set
{
_projectName = value;
}
}
private string _solutionName = "新建项目";
[Required]
public string SolutionName
{
get { return _solutionName; }
set { _solutionName = value; }
}
}
- XAML代码
<Window.DataContext>
<local:Data/>
</Window.DataContext>
<Window.Resources>
<Style TargetType="TextBlock" >
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<!--Validation.ErrorTemplate固定写法-->
<ControlTemplate x:Key="TextBoxErrorTemplate">
<AdornedElementPlaceholder/>
</ControlTemplate>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="0,5"/>
<Setter Property="Width" Value="500"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition MinHeight="30"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
VerticalContentAlignment="Center" BorderThickness="0"/>
</Border>
<TextBlock Text="{Binding Path=(Validation.Errors)[0].ErrorContent,
RelativeSource={RelativeSource Mode=TemplatedParent},StringFormat=* {0}}"
Grid.Row="1" Foreground="Red" Margin="0,3" FontSize="12" Visibility="Collapsed"
Name="errorTxt"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" TargetName="border"/>
<Setter Property="Visibility" Value="Visible" TargetName="errorTxt"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--必须设置,不然整个Template会有一个整体的边框-->
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource TextBoxErrorTemplate}"/>
</Style>
<Style TargetType="ComboBox">
<Setter Property="Height" Value="30"/>
<Setter Property="Margin" Value="0,5"/>
<Setter Property="Width" Value="500"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
<Style TargetType="Button">
<Setter Property="Height" Value="28"/>
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="5,0"/>
</Style>
</Window.Resources>
<Grid Margin="30">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
<RowDefinition Height="28"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="28"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="28"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="28"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="28"/>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock Text="配置新项目" FontSize="22"/>
<TextBlock Text="WPF应用程序" Grid.Row="1" FontSize="16" Margin="0,15"/>
<TextBlock Text="项目名称" Grid.Row="2"/>
<TextBox Grid.Row="3" Text="{Binding ProjectName,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}"/>
<TextBlock Text="位置" Grid.Row="4"/>
<ComboBox Grid.Row="5"/>
<TextBlock Text="解决方案" Grid.Row="6"/>
<ComboBox Grid.Row="7"/>
<TextBlock Text="解决方案名称" Grid.Row="8"/>
<TextBox Grid.Row="9" Text="{Binding SolutionName,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}"/>
<CheckBox Content="将解决方案和项目放在同一个目录中" Grid.Row="10"
VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Grid.Row="12" HorizontalAlignment="Right">
<Button Content="上一步"/>
<Button Content="下一步"/>
</StackPanel>
</Grid>
关注点要设置Validation.ErrorTemplate
,不然整个Template会有一个整体的边框
文章来源地址https://www.toymoban.com/news/detail-414140.html
到了这里,关于WPF绑定(Binding)下的数据验证IDataErrorInfo的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!