[英]WPF Binding.ValidationRules based on condition
I currently have TextBox
with a Binding.ValidationRules
that work like; 我目前有一个
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>
And the custom ValidationRule
: 和自定义的
ValidationRule
:
public class IDValidator : ValidationRule
{
public string table { get; set; }
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
//Logic
}
}
Problem is under certain conditions I would want IDValidator
to be the ValidationRule
. 问题是在某些情况下,我希望
IDValidator
是ValidationRule
。 Other times I may want say IDValidator2
to be the ValidationRule
. 其他时候,我可能想说
IDValidator2
是ValidationRule
。
Now I couldn't find a way to accomplish this. 现在,我找不到实现此目的的方法。 So I figured hey why not send another value down to
IDValidator
and then handle it in the logic of Validate
like this: 所以我想了为什么不将另一个值向下发送到
IDValidator
,然后按照Validate
的逻辑来处理它,如下所示:
XMAL update: XMAL更新:
<local:IDValidator ValidatesOnTargetUpdated="True" table="Items" testing="{Binding Path=test}" />
IDValidator update: IDValidator更新:
public string testing { get; set; }
Problem is that doesn't seem to like sending a bind value down. 问题是似乎不喜欢向下发送绑定值。 How can I accomplish this?
我该怎么做?
This is doable, but it is not very simple and has some gotchas that you may not expect. 这是可行的,但是它不是很简单,并且有一些您可能不会想到的陷阱。 The underlying issue is that dynamic bindings can only be applied on objects that derive from
DependencyObject
. 潜在的问题是动态绑定只能应用于从
DependencyObject
派生的对象。 ValidationRule
is not such an object. ValidationRule
不是这样的对象。 However, we can add a property to a custom ValidationRule
that exposes a class that does derive from DependencyObject
. 但是,我们可以向自定义
ValidationRule
添加一个属性,该属性公开一个确实从DependencyObject
派生的类。 An example will help explain: 一个例子将有助于解释:
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
}
}
Note the IDValidatorRange
object returned from the Range
property. 请注意从
Range
属性返回的IDValidatorRange
对象。 You will need to create this class using DependencyProperties
with a mechanism for updating the IDValidator
rule properties. 您将需要使用
DependencyProperties
以及用于更新IDValidator
规则属性的机制来创建此类。 Here is an example of such a class: 这是此类的示例:
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();
}
}
You can see that I derived from Freezable
instead of its ancestor DependencyObject
because we will want to inherit a DataContext
for our bindings. 您会看到我派生自
Freezable
而不是其祖先DependencyObject
因为我们将要为绑定继承一个DataContext
。 DependencyObject
does not provide this but Freezable
does. DependencyObject
不提供此功能,但Freezable
提供。
Finally, we can put this all together in XAML like such: 最后,我们可以像这样将所有内容整合到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>
One last gotcha here, because validation rules do not hold or inherit a DataContext
this will prevent binding from working as expected if you try to declare everything inline with your rule. 最后一个陷阱,因为验证规则不保存或继承
DataContext
因此如果您尝试声明与规则内联的所有内容,则绑定将无法按预期工作。 Instead, declare your bindable rule options as a resource and set the property on your custom rule using a StaticBinding
. 而是将可绑定规则选项声明为资源,并使用
StaticBinding
在自定义规则上设置属性。
This approach is a lot of work and a bit confusing. 这种方法需要大量工作,并且有些混乱。 If your hands are not tied with the data context, I would recommend exploring other options.
如果您的双手与数据上下文无关,我建议您探索其他选择。 Using the
INotifyDataErrorInfo
interface on a view-model may be a more elegant approach to this problem. 在视图模型上使用
INotifyDataErrorInfo
接口可能是解决此问题的一种更优雅的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.