WPF - 为什么没有“OnDataContextChanged” 可重写的方法?

发布于 2024-08-02 00:24:24 字数 146 浏览 4 评论 0原文

FrameworkElement 对象具有 DataContextChanged 事件。 但是,没有可以重写的 OnDataContextChanged 方法。

有什么想法吗?

The FrameworkElement object has DataContextChanged event. However, there is no OnDataContextChanged method that can be overridden.

Any ideas why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

明天过后 2024-08-09 00:24:24

如果方法是虚拟的,则用户可以选择通过调用基类方法来增强基功能,或者通过不调用基类方法来替换基类功能。 对于 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 更改时,会自动引发该事件,并且在任何其他时间引发该事件是没有意义的。

If a method is virtual, then the user has the option to either augment the base functionalty by calling the base class method or replace the base class functionality by failing to call the base class method. For OnEvent() methods, if you don't call the base class method then the event will not be raised (that's the responsibility of the base class method.) If the base class performs some kind of state management inside of the OnEvent method, this means that the derived class can accidentally invalidate the state of the object if the user chooses to omit a call to the base class method. Documentation can specify "please always call the base class method", but there's no way to enforce it.

When I see an event that doesn't have a virtual OnEvent() method, I usually assume the method performs some kind of internal state management and the designers of the class want to guarantee their state management runs. This isn't the case in FrameworkElement, and it's not the only event that doesn't follow the pattern, so I'm curious what the reasoning is.

I dug around in Reflector to see if I could discover a reason. There is an OnDataContextChanged() method, but it's a dependency property change handler and doesn't follow the standard event pattern. This is probably the reason for not making it protected virtual. It's non-standard, so it would be confusing. It's static, so you wouldn't be able to override it anyway. Since it's called automatically by the dependency property framework and you are unable to override it, I believe we have the reason why it's private instead of static virtual.

You could use a different pattern to expose the normal event pattern:

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(...);
    }
}

My guess why they didn't do this? Usually you call OnEvent() to raise the event. The event is automatically raised when DataContext changes, and it doesn't make sense for you to raise it at any other time.

雨的味道风的声音 2024-08-09 00:24:24

好问题。

我只是猜测,但是看看 Reflector,我会说这只是懒惰,也许还有一些(毫无根据的?)性能问题。 FrameworkElement 有一个通用的 EventHandlersStore ,它负责维护一大堆事件的事件信息(委托)。 CLR 事件中的添加和删除逻辑(例如 DataContextChanged)只需使用适当的键调用 EventHandlersStore 即可。

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

因此,简而言之,我认为没有任何技术原因不包含可重写的 OnDataContextChanged 方法。 对我来说,这看起来像是实施的捷径。

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

Good question.

I'm just guessing, but looking in Reflector I'd say it's just laziness, perhaps with a pinch of (unfounded?) performance concerns. FrameworkElement has a generic EventHandlersStore which is responsible for maintaining event information (delegates) for a whole bunch of events. The add and remove logic in the CLR events (such as DataContextChanged) simple call into the EventHandlersStore with the appropriate key.

There is a generic RaiseDependencyPropertyChanged method that is called to raise all different sorts of events. There is also a private OnDataContextChanged method that calls the RaiseDependencyPropertyChanged method. However, it is static and registered as part of the d-prop metadata.

So, in short, I see no technical reason not to include an overridable OnDataContextChanged method. Just looks like a short-cut in implementation to me.

Is this merely academic, or are you trying to achieve something here?

甜宝宝 2024-08-09 00:24:24

Silverlight 注意:

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

Microsoft Connect 错误报告已标记为“已修复”但没有表明这实际上意味着什么。

与此同时,您需要一种解决方法,例如 CodeProject 中的这个< /a> - 这非常简单,如果微软真的公开了该活动,应该很容易切换。

Silverlight Note:

At of Silverlight Beta 4 there IS no DataContextChanged event (well its not public at least).

The Microsoft Connect bug report has been marked as 'Fixed' but with no indication of what that actually means.

In the meantime you need a workaround such as this one from CodeProject - which is very simple and should be easy to switch out if Microsoft ever actually makes the event public.

兰花执着 2024-08-09 00:24:24

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

但是,您可以覆盖 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
        }
    }

}

Dependency properties usually don't have corresponding virtual methods for raising the event because it's expected that the change events will be managed by the dependecy property system itself.

What you can override however, to handle any dependency property changing is DependencyObject.OnPropertyChanged like so:

class MyClass : FrameworkElement {

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

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文