我目前有一个TextBox
和一个Binding.ValidationRules
,就像
<TextBox>
<Binding Path="MyID" NotifyOnValidationError="True" ValidatesOnDataErrors="True"
Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True"
NotifyOnTargetUpdated="True" Delay="100">
<Binding.ValidationRules>
<local:IDValidator ValidatesOnTargetUpdated="True" table="Items" />
</Binding.ValidationRules>
</Binding>
</TextBox>
和自定义
ValidationRule
:public class IDValidator : ValidationRule
{
public string table { get; set; }
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
//Logic
}
}
问题是在某些情况下,我希望
IDValidator
是ValidationRule
。其他时候我可能想说IDValidator2
是ValidationRule
。现在,我找不到实现此目的的方法。所以我想起了为什么不将另一个值向下发送到
IDValidator
并按照Validate
的逻辑处理它,如下所示:XMAL更新:
<local:IDValidator ValidatesOnTargetUpdated="True" table="Items" testing="{Binding Path=test}" />
IDValidator更新:
public string testing { get; set; }
问题是似乎不喜欢向下发送绑定值。我该怎么做?
最佳答案
这是可行的,但是它不是很简单,并且有一些您可能不会想到的陷阱。潜在的问题是动态绑定只能应用于从DependencyObject
派生的对象。 ValidationRule
不是这样的对象。但是,我们可以向自定义ValidationRule
添加一个属性,该属性公开确实从DependencyObject
派生的类。一个例子将有助于解释:
public class IDValidator : ValidationRule
{
private IDValidatorRange _range;
public int MinLength { get; set; }
public int MaxLength { get; set; }
public IDValidatorRange Range
{
get { return _range; }
set
{
_range = value;
value?.SetValidator(this);
}
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
// Logic
}
}
请注意从
IDValidatorRange
属性返回的Range
对象。您将需要使用DependencyProperties
创建具有用于更新IDValidator
规则属性的机制的此类。这是此类的示例:public class IDValidatorRange : Freezable
{
public static readonly DependencyProperty MinLengthProperty = DependencyProperty.Register(
"MinLength", typeof (int), typeof (IDValidatorRange), new FrameworkPropertyMetadata(5, OnMinLengthChanged));
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register(
"MaxLength", typeof (int), typeof (IDValidatorRange), new FrameworkPropertyMetadata(10, OnMaxLengthChanged));
public void SetValidator(IDValidator validator)
{
Validator = validator;
if (validator != null)
{
validator.MinLength = MinLength;
validator.MaxLength = MaxLength;
}
}
public int MaxLength
{
get { return (int) GetValue(MaxLengthProperty); }
set { SetValue(MaxLengthProperty, value); }
}
public int MinLength
{
get { return (int) GetValue(MinLengthProperty); }
set { SetValue(MinLengthProperty, value); }
}
private IDValidator Validator { get; set; }
private static void OnMaxLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var range = (IDValidatorRange) d;
if (range.Validator != null)
{
range.Validator.MaxLength = (int) e.NewValue;
}
}
private static void OnMinLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var range = (IDValidatorRange) d;
if (range.Validator != null)
{
range.Validator.MinLength = (int) e.NewValue;
}
}
protected override Freezable CreateInstanceCore()
{
return new IDValidatorRange();
}
}
您会看到我是从
Freezable
而不是其祖先DependencyObject
派生的,因为我们将要为绑定继承一个DataContext
。 DependencyObject
不提供此功能,但Freezable
提供。最后,我们可以像这样将所有内容整合到XAML中:
<TextBox>
<TextBox.Resources>
<local:IDValidatorRange x:Key="ValidatorRange"
MaxLength="{Binding MaxLength}"
MinLength="{Binding MinLength}" />
</TextBox.Resources>
<TextBox.Text>
<Binding Delay="100"
Mode="TwoWay"
NotifyOnSourceUpdated="True"
NotifyOnTargetUpdated="True"
NotifyOnValidationError="True"
Path="ID"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<local:IDValidator Range="{StaticResource ValidatorRange}" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
最后一个陷阱,因为验证规则不保存或继承
DataContext
,这将阻止绑定按预期工作,如果您尝试声明与规则内联的所有内容。而是,将可绑定规则选项声明为资源,并使用StaticBinding
在自定义规则上设置属性。这种方法需要大量工作,并且有些混乱。如果您的双手与数据上下文无关,我建议您探索其他选择。在视图模型上使用
INotifyDataErrorInfo
接口可能是解决此问题的一种更优雅的方法。关于c# - 基于条件的WPF Binding.ValidationRules,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35325659/