WPF - 为什么没有“OnDataContextChanged”可覆盖的方法?

时间:2009-08-18 13:33:03

标签: c# wpf datacontext

FrameworkElement对象有DataContextChanged个事件。但是,没有可以覆盖的OnDataContextChanged方法。

任何想法为什么?

4 个答案:

答案 0 :(得分:3)

如果方法是虚拟的,那么用户可以选择通过调用基类方法来扩充基本功能,或者通过调用基类方法来替换基类功能。对于OnEvent()方法,如果不调用基类方法,则不会引发事件(这是基类方法的责任。)如果基类在OnEvent方法内部执行某种状态管理,这意味着如果用户选择省略对基类方法的调用,派生类可能会意外地使对象的状态无效。文档可以指定“请始终调用基类方法”,但是没有办法强制执行它。

当我看到一个没有虚拟OnEvent()方法的事件时,我通常认为该方法执行某种内部状态管理,并且该类的设计者希望保证其状态管理运行。这不是FrameworkElement中的情况,并且它不是唯一不遵循模式的事件,所以我很好奇是什么原因。

我在Reflector中挖了一下,看看能不能找到原因。 一个OnDataContextChanged()方法,但它是一个依赖项属性更改处理程序,并不遵循标准事件模式。这可能是不使其受到虚拟保护的原因。这是非标准的,所以会让人感到困惑。它是静态的,所以无论如何你都无法覆盖它。由于它是由依赖属性框架自动调用的,你无法覆盖它,我相信我们之所以有私有而不是静态虚拟的原因。

您可以使用不同的模式来公开正常的事件模式:

class FrameworkElement
{
    // difference: use DataContextPropertyChanged as the change callback
    public static readonly DependencyProperty DataContextProperty = ...

    protected virtual void OnDataContextChanged(...)
    {
        // raise the DataContextChanged event
    }

    private static void DataContextPropertyChanged(...)
    {
        ((FrameworkElement)d).OnDataContextChanged(...);
    }
}

我猜他们为什么不这样做?通常,您调用OnEvent()来引发事件。当DataContext发生更改时,会自动引发该事件,并且在任何其他时间都无法提升它。

答案 1 :(得分:1)

好问题。

我只是在猜测,但是看着Reflector,我会说这只是懒惰,或许有一些(没有根据的?)性能问题。 FrameworkElement具有通用EventHandlersStore,负责维护一大堆事件的事件信息(委托)。 CLR事件中的添加和删除逻辑(例如DataContextChanged)使用适当的密钥调用EventHandlersStore

有一个通用RaiseDependencyPropertyChanged方法被调用来引发所有不同类型的事件。还有一个调用OnDataContextChanged方法的私有RaiseDependencyPropertyChanged方法。但是,它是静态的,并作为d-prop元数据的一部分注册。

因此,简而言之,我认为没有技术理由不包含可覆盖的OnDataContextChanged方法。对我来说,看起来像是一个捷径。

这仅仅是学术性的,还是你想在这里取得成就?

答案 2 :(得分:0)

Silverlight注意:

在Silverlight Beta 4中,没有DataContextChanged事件(至少它不公开)。

Microsoft Connect bug report已标记为“已修复”但未明确说明实际含义。

与此同时,您需要一个解决方法,例如this one from CodeProject - 这非常简单,如果Microsoft实际上公开该事件,则应该很容易切换。

答案 3 :(得分:0)

依赖项属性通常没有相应的虚拟方法来引发事件,因为预期更改事件将由dependecy属性系统本身管理。

然而,您可以覆盖的是,处理任何依赖项属性更改是DependencyObject.OnPropertyChanged,如下所示:

class MyClass : FrameworkElement {

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) {
        base.OnPropertyChanged(e);
        if (e.Property == FrameworkElement.DataContextProperty) {
            // do something with e.NewValue/e.OldValue
        }
    }

}