WPF数据绑定验证和伴随的数据触发器要么导致堆栈溢出异常,要么没有任何效果



我有一个似乎相当简单的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,表明这是不正确的。然而,触发器不起作用——我只收到以下错误消息:

无法从"(Validation.Errors("(类型为"ReadOnlyObservableCollection`1'"(中获取"Item[]"值(类型为ValidationError'(。BindingExpression:路径=(0([0]。ErrorContent;DataItem='DatePicker'(名称='startDatePicker](;目标元素是"DatePicker"(名称="startDatePicker"(;目标属性为"ToolTip"(类型为"Object"(ArgumentOutOfRangeException:"System.ArgumentOut OfRangeException:指定的参数超出了有效值的范围。参数名称:index‘

即使我将ToolTip的setter硬编码为某个文本值而不是进行数据绑定,也不会应用新的样式元素。然而,该代码几乎直接取自文档;我读到的关于这个错误的帖子似乎也表明,这个错误应该只发生在没有验证错误的时候,而不是当的时候。为什么会发生这种情况?

如果我删除了设置ToolTip的行,我就不会再收到错误了,但其他setter都没有任何效果——DatePicker看起来和以前一模一样。

但是,如果我将DatePicker设置为过去的某个日期,那么当我尝试调用DateTime.Now时,会出现堆栈溢出异常。

通常,堆栈溢出异常会指示某种无限递归-事实上,当我在这一行设置断点时,它确实,事实上,它会反复被命中,所以看起来这正是发生的事情。

话虽如此,为什么会发生这种情况?调用DateTime.Now怎么可能导致对Validate方法的递归调用?为什么只有当我过去约会时它才会这么做?

下面的语句将触发无限循环,因为您将属性绑定到自身(SelectedDate(

<Binding RelativeSource="{RelativeSource Self}" Path="SelectedDate">

如果你有datacontext(VM(成员,你可以绑定到它

否则,您可以重新调整现有属性的用途,如下面的"标记",使其在中工作

<Binding RelativeSource="{RelativeSource Self}" Path="Tag">

希望这能有所帮助。

您正在将DatePicker的SelectedDate属性绑定到其自身。(这似乎是堆栈溢出的一个可能原因…(

WPF通常使用MVVM来完成,其中绑定值在ViewModel上,请尝试。

最新更新