问题描述
这个问题更多是出于好奇,因为我已经找到了解决方法,但是我仍然想了解区别。我有一个简单的ContentDialog派生类,该类允许分别使用CalendarDatePicker和TimePicker选择两个日期和时间。我将它们的日期和时间属性绑定如下:
<StackPanel Orientation="Vertical" Grid.Column="0" Grid.Row="0">
<TextBlock>From</TextBlock>
<CalendarDatePicker Date="{x:Bind DateFromDate,Mode=TwoWay}" />
<TimePicker Time="{x:Bind DateFromTime,Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Column="1" Grid.Row="0">
<TextBlock>To</TextBlock>
<CalendarDatePicker Date="{x:Bind DatetoDate,Mode=TwoWay}" />
<TimePicker Time="{x:Bind DatetoTime,Mode=TwoWay}" />
</StackPanel>
,后面带有以下代码:
private DateTimeOffset _dateFromDate;
private TimeSpan _dateFromTime;
private DateTimeOffset _datetoDate;
private TimeSpan _datetoTime;
private DateTimeOffset DateFromDate
{
get => _dateFromDate;
set
{
_dateFromDate = value;
NotifyPropertyChanged();
}
}
private TimeSpan DateFromTime
{
get => _dateFromTime;
set
{
if (value != _dateFromTime)
{
_dateFromTime = value;
NotifyPropertyChanged();
}
}
}
private DateTimeOffset DatetoDate
{
get => _datetoDate;
set
{
_datetoDate = value;
NotifyPropertyChanged();
}
}
private TimeSpan DatetoTime {
get => _datetoTime;
set
{
if(value != _datetoTime)
{
_datetoTime = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
您可能会注意到,在绑定到TimePickers的TimeSpan属性中,检查该属性是否已更改。如果删除此属性,并将其保留在DateTimeOffset属性中,则每次我设置这些属性时都会引发StackOverflowException。如果您用谷歌搜索,您将遇到诸如this之类的问题,其中发生了非常明显的无限递归。如果我调试它,则确实会一次又一次调用setter,因此我的理论是,TimePicker背后的代码中的某个地方,当它收到Notification时,它不仅会获取属性,而且还会对其进行设置。有什么想法吗?
解决方法
这里发生了非常明显的无限递归。如果我对其进行调试,则确实会一次又一次地调用设置程序
我可以重现此问题,它看起来x:Bind TwoWay模型使绑定成为圆形,我可以确定这不是设计使然。当前,有许多解决方法可以解决此问题。
使用绑定替换x:Bind。
public TimeSpan DateToTime
{
get => _dateToTime;
set
{
_dateToTime = value;
OnPropertyChanged();
}
}
<TimePicker Time="{Binding DateToTime,Mode=TwoWay}" />
将TwoWay修改为OneWay。
<TimePicker Time="{x:Bind DateFromTime,Mode=OneWay}" />
最近提到的一个是使用条件语句停止此循环的。
请随时通过Windows反馈中心应用报告此情况。我将继续跟踪这个问题。
更新
请注意,NotifyPropertyChanged的文档明确指出仅在值实际更改时才触发NotifyPropertyChanged事件。 请注意,不遵循文档时,行为是不确定的。因此,在不遵循文档的情况下,由于两种行为均未定义,因此您无法假定不良情况下的行为将保持一致。
这里是INotifyPropertyChanged
上的doc。
仅当属性的设置程序无法防止在值等于先前值时触发PropertyChanged时,才会重现此问题。因此,无论行为如何不同,它们都是不确定的行为。如果您不遵循本文档,那么您会期望事情以奇怪的方式破坏,这再次是因为行为未定义。
为什么DatePicker可以在没有值等于先前值的情况下工作?
在某些情况下,不确定的行为可能会符合预期,但是由于它没有遵循文档,因此存在风险,因为它随时可能更改而不会发出警告。