C#代码:
RelativeSource rs = new RelativeSource();
rs.AncestorLevel = 2;
rs.AncestorType = typeof(DockPanel);
Binding binding = new Binding("Name") { RelativeSource = rs };
this.textBox1.SetBinding(TextBox.TextProperty, binding);
或在XAML中设置:
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel}, AncestorLevel=2}, Path=Name}"
如果TextBox需要关联自身的Name属性,代码是:
RelativeSource rs = new RelativeSource();
rs.Mode = RelativeSourceMode.Self;
Binding binding = new Binding("Name") { RelativeSource = rs };
this.textBox1.SetBinding(TextBox.TextProperty, binding);
RelativeSource类的Mode属性的类型是RelativeSourceMode枚举,它的取值有:PreviousData、Self、TemplatedParent和FindAncestor。RelativeSource类还有3个静态属性:PreviousData、Self、TemplatedParent,它们的类型是RelativeSource类。实际上这3个静态属性就是创建一个RelativeSource实例、把实例的Mode属性设置为相应的值,然后返回这个实例。之所以准备这3个静态属性是为了在XAML代码里直接获取RelativeSource属性。
Binding用于数据有效性校验的是它的ValidationRules属性,用于数据类型转换的是Converter属性。
Binding的ValidationRules属性类型是Collection<ValidationRule>,从而可以为每个Binding设置多个数据校验条件,每个条件是一个ValidationRule类型对象。ValidationRule是个抽象类,在使用时需要创建它的派生类并实现它的Validate方法。Validate方法的返回值是ValidationResult类型对象,如果校验通过,就把ValidationResult对象的IsValid属性设为True,反之则把IsValid属性设为false并为其ErrorContent属性设置一合适的消息内容(一般是一个字符串)。
XAML代码:
<StackPanel>
<TextBox x:Name="textBox1" Margin="5"/>
<Slider x:Name="slider1" Minimum="0" Maximum="100" Margin="5"/>
</StackPanel>
C#代码:
public class RangeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
double d = 0d;
if (double.TryParse(value.ToString(), out d))
if (d >= 0 && d <= 100)
return new ValidationResult(true, null);
return new ValidationResult(false, "Validation Failed!");
}
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
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的数据才有可能有问题。Binding只在Target被外部方法更新时校验数据,而来自Binding的Source数据更新Target时不会进行校验。如果想改变这种行为,或者说当来自Source的数据也有可能出问题时,就需要将校验条件的ValidatesOnTargetUpdated属性设为True。
将上面的XAML中slider改为:
<Slider x:Name="slider1" Minimum="-10" Maximum="100" Margin="5"/>
同时C#代码:
RangeValidationRule rvr = new RangeValidationRule();
rvr.ValidatesOnTargetUpdated = true;
binding.ValidationRules.Add(rvr);
要现实错误信息,在创建Binding时要把Binding对象的NotifyOnValidationError属性设为True.这样,当数据校验失败时Binding会发出一个信号,该信号会以Binding对象的Target为起点在UI元素树上传播。信号每到达一个结点,若该结点上设置有对这种信号的侦听器(事件处理器),那么这个侦听器就会被触发用以处理这个信号。信号处理完毕后,还可以选择是让信号继续向下传播还是就此终止――这就是路由事件。信号在UI元素树上的传递过程就称为路由(Route)。
C#代码:
public class RangeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
double d = 0d;
if (double.TryParse(value.ToString(), out d))
if (d >= 0 && d <= 100)
return new ValidationResult(true, null);
return new ValidationResult(false, "Validation Failed!");
}
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Binding binding = new Binding("Value") { Source = this.slider1 };
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rvr = new RangeValidationRule();
rvr.ValidatesOnTargetUpdated = true;
binding.ValidationRules.Add(rvr);
binding.NotifyOnValidationError = true;
this.textBox1.SetBinding(TextBox.TextProperty, binding);
this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
}
private void ValidationError(object sender, RoutedEventArgs e)
{
if (Validation.GetErrors(this.textBox1).Count > 0)
this.textBox1.ToolTip = Validation.GetErrors(this.textBox1)[0].ErrorContent.ToString();
}
}