WPF 数据绑定验证和随附的数据触发器要么导致堆栈溢出异常,要么没有任何效果
WPF Data Binding Validation and accompanying Data Triggers either results in a Stack Overflow Exception, or has no effect whatsoever
我的日期看起来相当简单 ValidationRule
- 我正在尝试验证某个特定日期是否在未来。下面是一个代码示例来说明问题:
public class DateNotInTheFutureValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var date = (DateTime)value;
// WhosebugException 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>
奇怪的事情:当我 select 在 DatePicker
中的未来日期时,这按预期工作 - 它无一例外地运行并且 returns 正确的 ValidationResult
表示这是不正确的。但是,触发器不起作用 - 我只收到以下错误消息:
Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0)[0].ErrorContent; DataItem='DatePicker' (Name='startDatePicker'); target element is 'DatePicker' (Name='startDatePicker'); target property is 'ToolTip' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index'
新样式元素未应用,即使我将工具提示的 setter 硬编码为某个文本值而不是进行数据绑定。但是,此代码几乎直接取自文档;我读过的关于这个错误的帖子似乎表明这个错误应该只发生在你不有验证错误的时候,而不是当你做[=46时=].为什么会这样?
如果我删除设置 ToolTip
的行,我不会再收到错误,但是其他 setter 的 none 有任何影响 - DatePicker
看起来和以前完全一样。
但是,如果我将 DatePicker
设置为过去的日期,当我尝试调用 DateTime.Now
.
时会出现堆栈溢出异常
通常,Stack Overflow Exception 表示某种无限递归 - 事实上,当我在此行设置断点时,它 会 ,事实上,它会重复命中, 所以看起来这正是正在发生的事情。
话虽如此,为什么会这样?调用 DateTime.Now
怎么可能导致对 Validate 方法的递归调用?为什么它只在我传递过去的日期时才这样做?
以下语句将触发无限循环,因为您将 属性 绑定到自身 (SelectedDate)
<Binding RelativeSource="{RelativeSource Self}" Path="SelectedDate">
如果您有数据上下文 (VM) 成员,则可以绑定到它。
否则,您可以重新利用现有的 属性,例如 'Tag',以使其正常工作
<Binding RelativeSource="{RelativeSource Self}" Path="Tag">
希望对您有所帮助。
您正在将 DatePicker 的 SelectedDate 属性 绑定到自身。 (这似乎是堆栈溢出的可能原因......)
WPF 通常使用 MVVM 完成,其中绑定值在 ViewModel 上,试试看。
我的日期看起来相当简单 ValidationRule
- 我正在尝试验证某个特定日期是否在未来。下面是一个代码示例来说明问题:
public class DateNotInTheFutureValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var date = (DateTime)value;
// WhosebugException 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>
奇怪的事情:当我 select 在 DatePicker
中的未来日期时,这按预期工作 - 它无一例外地运行并且 returns 正确的 ValidationResult
表示这是不正确的。但是,触发器不起作用 - 我只收到以下错误消息:
Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0)[0].ErrorContent; DataItem='DatePicker' (Name='startDatePicker'); target element is 'DatePicker' (Name='startDatePicker'); target property is 'ToolTip' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: index'
新样式元素未应用,即使我将工具提示的 setter 硬编码为某个文本值而不是进行数据绑定。但是,此代码几乎直接取自文档;我读过的关于这个错误的帖子似乎表明这个错误应该只发生在你不有验证错误的时候,而不是当你做[=46时=].为什么会这样?
如果我删除设置 ToolTip
的行,我不会再收到错误,但是其他 setter 的 none 有任何影响 - DatePicker
看起来和以前完全一样。
但是,如果我将 DatePicker
设置为过去的日期,当我尝试调用 DateTime.Now
.
通常,Stack Overflow Exception 表示某种无限递归 - 事实上,当我在此行设置断点时,它 会 ,事实上,它会重复命中, 所以看起来这正是正在发生的事情。
话虽如此,为什么会这样?调用 DateTime.Now
怎么可能导致对 Validate 方法的递归调用?为什么它只在我传递过去的日期时才这样做?
以下语句将触发无限循环,因为您将 属性 绑定到自身 (SelectedDate)
<Binding RelativeSource="{RelativeSource Self}" Path="SelectedDate">
如果您有数据上下文 (VM) 成员,则可以绑定到它。
否则,您可以重新利用现有的 属性,例如 'Tag',以使其正常工作
<Binding RelativeSource="{RelativeSource Self}" Path="Tag">
希望对您有所帮助。
您正在将 DatePicker 的 SelectedDate 属性 绑定到自身。 (这似乎是堆栈溢出的可能原因......)
WPF 通常使用 MVVM 完成,其中绑定值在 ViewModel 上,试试看。