来自《深入浅出WPF》(刘铁猛)读书笔记
Binding的数据校验
使用属性ValidationRules,类型为Collection<validationRule>。ValidationRule类是一个抽象类,在使用的时候我们需要创建它的派生类并实现它的Validate方法。Validate方法的返回值是ValidationResult类型对象,如果校验通过,就把ValidationResult对象的IsValid属性设为true,反之,需要把IsValid属性设为false并为其ErrorContent属性设置一个合适的消息内容(一般是个字符串)。
下面实例是在UI上绘制一个textBox和一个Slider,以Slider为源,TextBox为目标。Slider的取值范围【0,100】。
为了进行校验,需要准备一个ValidationRule的派生类:
public class RangeValidationRule:ValidationRule
{
//need commit Validate method
public override ValidationResult Validate (object value, System.Globalization.CultureInfo cultureInfo)
{
double d=0;
if(double.TryParse(value.ToString(),out d))
{
if(d>=0 && d<=100) return new ValidationResult(true,null);
}
return new ValidationResult(false,"Validation Failed");
}
}
然后在窗体的构造器里这样建立Binding:
public Window1()
{
InitializeComponent();
Binding binding=new Binding("Value"){Source=this.slider1};
binding.UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rvr=new RangeValidationRule();
binding.ValidationRules.Add(rvr);
this.textBox1.SetBinding(TextBox.TextProperty,binding);
}
Binding进行校验时的默认行为是认为来自Source的数据总是正确的,只有来自Target的数据(因为Target多为UI控件,所以等价于用户输入的数据)才有可能有问题。只有在Target被外部方法更新时校验数据,而来自Binding的Source数据更新Target时不用进行校验的。如果想改变这种行为,或者说当来自Source的数据也有可能出问题时,我们就需要将校验的ValiatesOnTargetUpdated属性设为true。
如何显示ValidationFailed的消息:
binding.NotifyOnValidationError=true;
...
this.textBox1.AddHandler(Validation.ErrorEvent,new RoutedEventHandler(this.ValidationError));
用于侦听校验错误事件的事件处理器如下:
void ValidationError(object sender,RoutedEventArgs e)
{
if(Validation.GetErrors(this.textBox1).Count>0)
this.textBox1.ToolTip=Validation.GetErrors(this.textBox1)[0].ErrorContent.ToString();
}
程序运行时如果校验失败,TextBox的ToolTip就会提示用户。
Binding的数据转换
上例中Slider的Value(double)与TextBox(string)建立关联,需要做数据转换。
简单的类型转换,WPF类库可以帮我们做完,其他的需要手动写Converter,方法是创建一个类并让这个类实现IValueConverter接口。
public interface IValueConveter
{
object Convert(object value,Type targetType,object parameter,CultureInfo culture);
object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture);
}
Binding对象的Mode属性会影响到这两个方法的调用。如果Mode为TwoWay或Default,那两个方法都有可能被调用;如果为OneWay或Default行为,则只有Convert被调用。
MultiBinding
有时候UI需要显示的信息由不止一个数据来源决定,这就组要MultiBinding,即多路Binding。
凡是能使用Binding对象的场合都能使用MultiBinding,它具有一个名为Bindings的属性,其类型是Collection<BindingBase>,通过这个属性MultiBinding把一组Binding对象集合起来,处在这个集合中的Binding对象可以拥有自己的数据校验与转换机制,他们汇聚起来的数据将共同决定传往MultiBinding目标的数据。
MultiBinding对于添加子级bindingde1顺序是敏感的,因为这个顺序决定了汇聚到Converter里数据的顺序;Converter实现的是IMultiValueConverter接口。