Как запустить проверку для одного свойства, когда другое свойство было проверено, используя пользовательские ValidationAttribute и INotifyDataErrorInfo
До недавнего времени я использовал расширенную версию IDataErrorInfo
интерфейс. Мое расширение позволяет мне работать с несколькими ошибками одновременно, и пока оно мне очень хорошо помогло. Однако с введением INotifyDataErrorInfo
интерфейс, я думал, что поэкспериментирую с ним, чтобы увидеть, есть ли какие-либо улучшения.
Пройдя несколько онлайн-уроков, я начал работать с различными ValidationAttribute
с из System.ComponentModel.DataAnnotations namespace
, Используя эти Attribute
Позволяет вам предоставить основные правила проверки, как это:
[MinLength(3, ErrorMessage = "Name must be longer than 3 characters.")]
public string Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); Validate("Name", name); }
}
Первоначально это выглядело довольно хорошо, так как сообщения об ошибках вставляются прямо в Valaidation.Errors
Коллекция доступна в приложении ErrorTemplate
s. Тем не менее, большинство встроенных правил проверки действительно являются базовыми, и я привык применять сложные правила проверки, которые включают другие значения свойств.
Поэтому я решил найти способ создать простое правило проверки, включающее несколько свойств: правило, в котором должно быть установлено одно или два поля. Итак, я объявил класс, который расширил ValidationAttribute
и после поиска в Интернете, нашел способ получить доступ к другим значениям свойств.
Я выбил базовый интерфейс с кастомом ErrorTemplate
применяется к каждому TextBox
, который отображал Validation.Errors
коллекция для свойства привязки данных:
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="#4FFF0000" BorderThickness="1" Margin="0,10">
<AdornedElementPlaceholder />
</Border>
<Image Name="WarningImage" Source="pack://application:,,,/WpfApplication1;component/Images/Warning_16.png" Margin="5,0,0,0" Tag="{Binding}" />
<Popup PlacementTarget="{Binding ElementName=WarningImage}" Placement="Right" Margin="5,0,0,0" AllowsTransparency="True" IsOpen="True">
<Border BorderThickness="1" BorderBrush="#4FFF0000" CornerRadius="5" Background="White" Padding="5" Margin="10">
<Border.Effect>
<DropShadowEffect Color="Red" Opacity="0.5" BlurRadius="15" ShadowDepth="0" />
</Border.Effect>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</Popup>
</StackPanel>
</ControlTemplate>
С моим обычаем Attribute
установить на Name
собственности, мне удалось добавить ValidationResult
в Validation.Errors
сбор через интерфейс, когда ни одно из свойств не было установлено, но вот проблема: если я добавлю значение в один из других TextBox
Если данные связаны с другими обязательными свойствами, сообщение об ошибке в первом TextBox
останется там.
Если бы я вернулся к первому TextBox
и что-то напечатало, тогда проверка работала бы, поэтому даже если я удалил значение, он все равно знал, что было установлено одно из обязательных свойств. Таким образом, код проверки работает, но проблема в том, что изменения свойств в других обязательных свойствах не запускают проверку в Name
имущество.
Даже когда я применил тот же обычай Attribute
с другими обязательными свойствами произошло то же самое... каждая ошибка проверки будет очищаться только при вводе соответствующего TextBox
, Я также попробовал встроенный CustomValidationAttribute
что позволяет нам вызывать метод в классе для проверки, но конечный результат был таким же.
Код проверки работает, но не вызывается другими необходимыми изменениями свойств. Я даже пытался позвонить Validate
метод, передавая имена других свойств, но завершившихся непрерывным циклом. Итак, вопрос в том, как я могу запустить проверку одного свойства, когда другое свойство было проверено?
1 ответ
Вот что я сделал, в классе, содержащем From
а также To
свойства. Я хотел подтвердить это From
меньше или равно To
,
Логика проверки применяется с использованием CustomValidationAttribute
, что проще, чем создавать свои собственные классы атрибутов проверки. Вы просто сообщаете ему тип вашего класса и имя вызываемого метода, который содержит вашу логику проверки (хотя метод должен иметь конкретную сигнатуру). Вот мой соответствующий код:-
[CustomValidation(typeof(MyModel), "ValidateRange")]
public double From
{
get
{
return _from;
}
set
{
if (_from != value)
{
_from = value;
OnPropertyChanged("From");
// Validate the other side
ValidateProperty("To", _to);
}
}
}
[CustomValidation(typeof(MyModel), "ValidateRange")]
public double To
{
get
{
return _to;
}
set
{
if (_to != value)
{
_to = value;
OnPropertyChanged("To");
// Validate the other side
ValidateProperty("From", _from);
}
}
}
private static ValidationResult ValidateRange(ValidationContext validationContext)
{
var model = validationContext.ObjectInstance as MyModel;
if (model.From > model.To)
{
return new ValidationResult("Invalid range");
}
return null;
}
Как вы можете видеть, код в одном установщике свойств вызывает проверку свойства "прочее", точно так же, как вы упоминали в предыдущем абзаце. Нет причин, по которым он должен идти в бесконечный цикл, если только ваш код проверки не пытается установить одно из свойств, которое вызовет другой вызов Validate(), и так далее, и так далее.