FrameworkElement
对象有DataContextChanged
个事件。但是,没有可以覆盖的OnDataContextChanged
方法。
任何想法为什么?
答案 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
}
}
}