У меня было то, что кажется довольно простым ValidationRule
- я пытаюсь подтвердить, что конкретная дата не в будущем. Вот пример кода для иллюстрации проблемы:
public class DateNotInTheFutureValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var date = (DateTime)value;
// StackOverflowException here
var now = DateTime.Now;
ValidationResult validationResult = null;
if (date > now)
{
validationResult = new ValidationResult(false, "Cannot be in the future");
}
else
{
validationResult = ValidationResult.ValidResult;
}
return validationResult;
}
}
Для справки: да, я понимаю, что большая часть этого может быть сведена к одному выражению с использованием троичной формы, но это было более полезно для иллюстрации проблемы.
Я применяю это к DatePicker
так:
<DatePicker Name="startDatePicker" HorizontalAlignment="Left" Margin="89,94,0,0" VerticalAlignment="Top">
<DatePicker.SelectedDate>
<Binding RelativeSource="{RelativeSource Self}" Path="SelectedDate">
<Binding.ValidationRules>
<validationRules:DateNotInTheFutureValidationRule/>
</Binding.ValidationRules>
</Binding>
</DatePicker.SelectedDate>
</DatePicker>
У меня также есть следующий стиль для обработки случая, когда правило нарушается:
<Window.Resources>
<Style TargetType="{x:Type DatePicker}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Red" />
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Странная вещь: когда я выбираю дату в будущем в DatePicker
, она работает как ожидалось - она работает без исключения и возвращает правильный ValidationResult
, указывающий, что это неверно. Однако триггеры не работают - я просто получаю следующее сообщение об ошибке:
Невозможно получить значение «Item []» (тип «ValidationError») из «(Validation.Errors)» (тип «ReadOnlyObservableCollection`1 '). BindingExpression: Путь = (0) [0] .ErrorContent; DataItem = 'DatePicker' (Name = 'startDatePicker'); Целевым элементом является DatePicker (Name = 'startDatePicker'); Свойство target - «ToolTip» (тип «Object»). ArgumentOutOfRangeException: «System.ArgumentOutOfRangeException: указанный аргумент находится вне диапазона допустимых значений.
Имя параметра: индекс '
Новые элементы стиля не применяются, даже если я жестко закодирую установщик для всплывающей подсказки в какое-то текстовое значение вместо привязки данных. Однако этот код взят почти напрямую из документации; также сообщения, которые я прочитал об этой ошибке, указывают на то, что эта ошибка должна возникать только тогда, когда у вас нет ошибок проверки, а не когда вы делаете . Почему это происходит?
Если я удаляю строку, устанавливающую ToolTip
, я больше не получаю ошибку, но ни один из других сеттеров не имеет никакого эффекта - DatePicker
выглядит точно так же, как и раньше.
Однако, если я установил DatePicker
на дату в прошлом, я получаю исключение переполнения стека при попытке вызвать DateTime.Now
.
Обычно исключение переполнения стека указывает на какую-то бесконечную рекурсию - фактически, когда я устанавливаю точку останова на этой строке, она действительно , на самом деле, получает удар несколько раз, поэтому кажется, что это это именно то, что происходит.
Как говорится, почему это происходит? Как вызов DateTime.Now
может привести к рекурсивному вызову метода Validate? И почему это происходит только тогда, когда я пропускаю свидание в прошлом?