深入浅出WPF-06.Binding(绑定)02
Binding对数据的校验和转换
1)数据校验,通过Binding的ValidationRules属性(Collection
<Slider Margin="5" Maximum="100" Minimum="0" SmallChange="1" x:Name="silder1">
<Slider.Value>
<Binding Path="CurrentValue">
<Binding.ValidationRules>
<local:MyValidationRule/>
</Binding.ValidationRules>
</Binding>
</Slider.Value>
</Slider>
public class MyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value != null && value is double input)
{
if (input > 0 && input < 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "can not null");
}
}
ValidationRule是个抽象类,使用的时候需要创建他的派生类并实现Validate方法。如果通过校验,就把ValidationResult对象的IsValid属性设为true,否则设为false,并设置ErrorContent的消息内容。
校验的默认行为是认为来自于Source的数据总是正确的,只有来自目标Target的数据才可能出问题(Target多为UI控件,多数是用户输入的数据),为了就是不让输入的数据污染Source数据,所以才进行校验。Binding只有在Target被外部方法更新时才会校验(手动输入)。如果想在Source数据更新时Target也进行校验,需要将校验条件的ValidatesOnTargetUpdated设置为true。
当校验错误的时候Validate方法返回的ValidationResult对象,携带的错误信息如何显示?需要用到后面的知识---路由事件(EventRouted)。
如果Binding对象的NotifyOnValidationError="True",这时,当数据校验错误的时候Binding会像报警器一样发出一个信号,这个信号以Target为起点,沿着树进行传播,直到某个节点监听并处理了这个信号。信号处理完之后,可以决定这个信号是继续传播,还是终止(e.Handled = true;)。这就是路由事件,传递这个信号的过程叫做路由。
private MainWindowViewModel model = new MainWindowViewModel();
public Window1()
{
InitializeComponent();
this.DataContext = model;
this.silder1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));
}
void ValidationError(object sender, RoutedEventArgs e)
{
if (Validation.GetErrors(this.silder1).Count > 0)
{
//处理错误信息
e.Handled = true;
}
}
2)数据转换,当源Source端的Path所关联的数据与Target端目标属性数据展示不一致时,我们就可以通过添加数据转换器来实现。比如最常用的性别,在数据源Source端一般使用枚举值,Target端一般使用字符串或者图片来区分,这是我们就可以使用转换器来实现。
xaml代码:
<TextBlock Margin="5" Height="23" Text="{Binding SexType, Converter={StaticResource DtoShowStringConverter}}"/>
性别枚举值:
/// <summary>
/// 性别
/// </summary>
public enum SexType : byte
{
/// <summary>
/// 女
/// </summary>
Female = 0,
/// <summary>
/// 男
/// </summary>
Male = 1,
/// <summary>
/// 未知
/// </summary>
Null = 2
}
转换器:
public class DtoShowStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return null;
string output = null;
if (value is SexType input)
{
switch (input)
{
case SexType.Female:
output = "女";
break;
case SexType.Male:
output = "男";
break;
case SexType.Null:
output = "未知";
break;
default:
break;
}
}
return output;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
当数据从Source流向Target时,Convert方法被调用,反之,ConvertBack被调用。第一个参数是传入的值,第二个参数是返回的值的类型,第三个参数是用来传递额外信息的(对应的Binding中的ConverterParameter)。我们最常用的是Source流向Target(Convert方法),极少使用ConvertBack。