Это выполнимо, но это не очень просто и имеет некоторые ошибки, которых вы не можете ожидать. Основная проблема заключается в том, что динамические привязки могут применяться только к объектам, которые производятся от 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
на модели представления может быть более изящным подходом к этой проблеме.
тест существует в качестве опоры на том же объекте, на котором существует идентификатор? – user3690202