PropertyChangeCallback - 更改是否来自控制范围内
PropertyChangeCallback - whether change was from within control
我有一个自定义控件,它具有依赖性 属性 和 PropertyChangedCallback。 属性 的值可以从自定义控件的逻辑内部更改,也可以从外部更改(通过用户交互或从客户端应用程序设置的值)。
有没有办法判断是什么导致 属性 发生变化?
我试着查看 "sender" 但在每种情况下,发件人都是自定义控件本身。
举例说明:
public static readonly DependencyProperty SelectedTimeProperty =
DependencyProperty.Register("SelectedTime", typeof(DateTime?), typeof(TimePickerControl), new PropertyMetadata(null, new PropertyChangedCallback(HandleSelectedTimeChanged)));
public static readonly DependencyProperty HoursProperty =
DependencyProperty.Register("Hours", typeof(object), typeof(TimePickerControl), new PropertyMetadata(@"", (o, e) => ((TimePickerControl)o).OnHoursChanged(o, e.OldValue)));
public static readonly DependencyProperty MinutesProperty =
DependencyProperty.Register("Minutes", typeof(object), typeof(TimePickerControl), new PropertyMetadata(@"", (o, e) => ((TimePickerControl)o).OnMinutesChanged(o, e.OldValue)));
public static readonly DependencyProperty SecondsProperty =
DependencyProperty.Register("Seconds", typeof(object), typeof(TimePickerControl), new PropertyMetadata(@"", (o, e) => ((TimePickerControl)o).OnSecondsChanged(o, e.OldValue)));
因此客户端应用程序可以更新 SelectedTime
,在这种情况下,Hours
、Minutes
和 Seconds
将由控件更新。此逻辑在 HandleSelectedTimeChanged
.
中处理
但是,用户也可以修改 Hours
、Minutes
和 Seconds
之一,其中 SelectedTime
必须相应更新。
正如您可能猜到的那样,这会产生一个循环,因为 Hours
的变化会导致 SelectedTime
回调被触发,这当然会改变Hours/Mins/Secs 再次调用它们的回调。
我想要么仅在更改来自控件外部时调用回调,要么在回调中检测到这一点并立即退出。
到目前为止我想到的唯一想法是在更改其中一个属性之前立即设置一个私有变量,如果设置了它,则在其回调退出中设置,然后在更改后立即清除它,但这看起来很对我来说很乱。有更好的方法吗?
至于只从外部触发更改事件,恐怕是不可能的。
这是您面临的一种非常常见的情况,并且有一些解决方案。
- 第一个也是最好的解决方案是完全避免这种情况。
在你的情况下,这意味着不是为每个时间组件拥有多个依赖属性,而是为每个时间组件编写一个自定义值转换器,然后将值绑定到具有所需的单个 SelectedTime
属性转换器。我个人强烈推荐这种方法。
- 第二种方法是根据需要进行更改。
在您的情况下,这意味着在触发 UpdateHour
之前检查小时是否应该更新。如果不是,请不要触发它。这是一种干净的方法,可以减少更新循环,但会产生性能开销。
- 第三种方法是使用脏标志。
这有点像你说的。您为 SelectedDate
保留一个值为 false 的布尔标志。当它发生变化时,将其设置为 true,在下一个循环中,如果它是 true,则退出并将其设置回 false。
正如你所说,它又脏又脏。但是完成了工作。
我有一个自定义控件,它具有依赖性 属性 和 PropertyChangedCallback。 属性 的值可以从自定义控件的逻辑内部更改,也可以从外部更改(通过用户交互或从客户端应用程序设置的值)。
有没有办法判断是什么导致 属性 发生变化?
我试着查看 "sender" 但在每种情况下,发件人都是自定义控件本身。
举例说明:
public static readonly DependencyProperty SelectedTimeProperty =
DependencyProperty.Register("SelectedTime", typeof(DateTime?), typeof(TimePickerControl), new PropertyMetadata(null, new PropertyChangedCallback(HandleSelectedTimeChanged)));
public static readonly DependencyProperty HoursProperty =
DependencyProperty.Register("Hours", typeof(object), typeof(TimePickerControl), new PropertyMetadata(@"", (o, e) => ((TimePickerControl)o).OnHoursChanged(o, e.OldValue)));
public static readonly DependencyProperty MinutesProperty =
DependencyProperty.Register("Minutes", typeof(object), typeof(TimePickerControl), new PropertyMetadata(@"", (o, e) => ((TimePickerControl)o).OnMinutesChanged(o, e.OldValue)));
public static readonly DependencyProperty SecondsProperty =
DependencyProperty.Register("Seconds", typeof(object), typeof(TimePickerControl), new PropertyMetadata(@"", (o, e) => ((TimePickerControl)o).OnSecondsChanged(o, e.OldValue)));
因此客户端应用程序可以更新 SelectedTime
,在这种情况下,Hours
、Minutes
和 Seconds
将由控件更新。此逻辑在 HandleSelectedTimeChanged
.
但是,用户也可以修改 Hours
、Minutes
和 Seconds
之一,其中 SelectedTime
必须相应更新。
正如您可能猜到的那样,这会产生一个循环,因为 Hours
的变化会导致 SelectedTime
回调被触发,这当然会改变Hours/Mins/Secs 再次调用它们的回调。
我想要么仅在更改来自控件外部时调用回调,要么在回调中检测到这一点并立即退出。
到目前为止我想到的唯一想法是在更改其中一个属性之前立即设置一个私有变量,如果设置了它,则在其回调退出中设置,然后在更改后立即清除它,但这看起来很对我来说很乱。有更好的方法吗?
至于只从外部触发更改事件,恐怕是不可能的。 这是您面临的一种非常常见的情况,并且有一些解决方案。
- 第一个也是最好的解决方案是完全避免这种情况。
在你的情况下,这意味着不是为每个时间组件拥有多个依赖属性,而是为每个时间组件编写一个自定义值转换器,然后将值绑定到具有所需的单个 SelectedTime
属性转换器。我个人强烈推荐这种方法。
- 第二种方法是根据需要进行更改。
在您的情况下,这意味着在触发 UpdateHour
之前检查小时是否应该更新。如果不是,请不要触发它。这是一种干净的方法,可以减少更新循环,但会产生性能开销。
- 第三种方法是使用脏标志。
这有点像你说的。您为 SelectedDate
保留一个值为 false 的布尔标志。当它发生变化时,将其设置为 true,在下一个循环中,如果它是 true,则退出并将其设置回 false。
正如你所说,它又脏又脏。但是完成了工作。