【问题标题】:PropertyChangeCallback - whether change was from within controlPropertyChangeCallback - 更改是否在控制范围内
【发布时间】:2017-10-05 08:59:02
【问题描述】:

我有一个带有 PropertyChangedCallback 依赖属性的自定义控件。属性的值可以从自定义控件的逻辑内部或外部更改(通过用户交互或通过从客户端应用程序设置的值)。

有没有办法知道是什么导致了属性的变化?

我尝试查看“发件人”,但在每种情况下,发件人都是自定义控件本身。

举例说明:

    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,在这种情况下,HoursMinutesSeconds 将由控件更新。此逻辑在HandleSelectedTimeChanged 中处理。

但是,用户也可以修改HoursMinutesSeconds之一,其中SelectedTime必须相应更新。

正如您可能猜到的那样,这会产生一些循环,因为更改 Hours 会导致触发 SelectedTime 回调,这当然会更改 Hours/Mins/Secs再次调用他们的回调被触发。

我只想在更改来自控件外部时调用回调,或者在回调中检测到这一点并立即退出。

到目前为止,我想出的唯一想法是在更改其中一个属性之前立即设置一个私有变量,如果已设置,则在其回调退出中,然后在更改后立即清除它,但这似乎很混乱我。有更好的方法吗?

【问题讨论】:

  • 依赖属性在控件内部。如果您也在控制范围内更改它们的值,那么只需使用一些标志:在更改之前设置它,在回调中检查它。另一件事是coerce
  • “你可能猜到了,这会造成一个循环” 这不应该发生。仅当属性的值实际更改 时才会调用属性更改回调。因此,如果您更改Hours 属性,它的回调可能会设置SelectedTime 属性,这反过来又会再次设置Hours 属性值。但是,Hours 属性值没有改变,所以它的属性改变回调不会被调用。我怀疑您的问题与您的HoursMinutesSeconds 依赖属性被声明为类型object 有更多关系。它们应该是 int 吗?
  • @StevenRands - 这不是一个无限循环,我明白你在说什么,但它创造了一个令人费解的意大利面条流,这使得阅读/调试/维护变得困难,并可能导致其他问题控制范围内。
  • 为什么你的HoursMinutesSeconds依赖属性声明为object类型?我本来希望它们是 ints 或其他一些原始值类型。
  • 就我所知,您必须忍受不断更新的更新。 DP 并不擅长动态计算。

标签: c# wpf mvvm dependency-properties


【解决方案1】:

至于仅从外部触发更改事件,恐怕是不可能的。 这是您面临的一种非常常见的情况,并且有一些解决方案。

  1. 第一个也是最好的解决方案是完全避免这种情况。

在您的情况下,这意味着不是为每个时间组件编写多个依赖属性,而是为每个组件编写一个自定义值转换器,然后使用所需的转换器将值绑定到单个 SelectedTime 属性。我个人强烈推荐这种方法。

  1. 第二种方法是根据需要进行更改。

在您的情况下,这意味着在触发 UpdateHour 之前检查小时是否应该更新。如果没有,请不要触发它。这是一种干净的方法,会减少更新循环,但会产生性能开销。

  1. 第三种方法是使用 Dirty 标志。

这有点像你说的。您为 SelectedDate 保留一个布尔标志,其值为 false。当它被更改时,您将其设置为 true,如果为 true,则在下一个循环中退出并将其设置回 false。

正如你所说,这里很脏,很不干净。但可以完成工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多