简体   繁体   English

在C#中继承事件处理程序

[英]Inheriting Event Handlers in C#

I've kind of backed myself into a corner here. 我有点在这里支持自己。

I have a series of UserControls that inherit from a parent, which contains a couple of methods and events to simplify things so I don't have to write lines and lines of near-identical code. 我有一系列从父级继承的UserControl,它包含一些方法和事件来简化事情,因此我不必编写几乎相同代码的行和行。 As you do. 像你一样做。 The parent contains no other controls. 父级不包含其他控件。

What I want to do is just have one event handler, in the parent UserControl, which goes and does stuff that only the parent control can do (that is, conditionally calling an event, as the event's defined in the parent). 我想要做的只是在父UserControl中有一个事件处理程序,它只执行父控件可以执行的操作(即,有条件地调用事件,因为父事件中定义了事件)。 I'd then hook up this event handler to all my input boxes in my child controls, and the child controls would sort out the task of parsing the input and telling the parent control whether to throw that event. 然后我将这个事件处理程序连接到我的子控件中的所有输入框,子控件将解析输出的任务并告诉父控件是否抛出该事件。 Nice and clean, no repetitive, copy-paste code (which for me always results in a bug). 很好,干净,没有重复,复制粘贴代码(这对我来说总是会导致错误)。

Here's my question. 这是我的问题。 Visual Studio thinks I'm being too clever by half, and warns me that "the method 'CheckReadiness' [the event handler in the parent] cannot be the method for an event because a class this class derives from already defines the method." Visual Studio认为我太聪明了一半,并警告我“方法'CheckReadiness'[父级中的事件处理程序]不能是事件的方法,因为这个类派生的类已经定义了方法。” Yes, Visual Studio, that's the point . 是的,Visual Studio, 这就是重点 I want to have an event handler that only handles events thrown by child classes, and its only job is to enable me to hook up the children without having to write a single line of code. 希望有一个事件处理程序,它只处理子类抛出的事件,它唯一的工作就是让我能够连接子代,而不必编写一行代码。 I don't need those extra handlers - all the functionality I need is naturally called as the children process the user input. 我不需要那些额外的处理程序 - 我需要的所有功能自然被称为子进程处理用户输入。

I'm not sure why Visual Studio has started complaining about this now (as it let me do it before), and I'm not sure how to make it go away. 我不确定为什么Visual Studio现在开始抱怨这个(因为它让我以前做过),而且我不确定如何让它消失。 Preferably, I'd like to do it without having to define a method that just calls CheckReadiness. 最好,我想这样做而不必定义一个只调用CheckReadiness的方法。 What's causing this warning, what's causing it to come up now when it didn't an hour ago, and how can I make it go away without resorting to making little handlers in all the child classes? 造成这种警告的原因是什么原因导致它在一小时前没有出现,如何在不使用所有儿童班的小手柄的情况下让它消失?

Declare the parent method virtual, override it in the child classes and call 声明父方法virtual,在子类中覆盖它并调用

base.checkReadyness(sender, e);

(or derevation thereof) from within the child class. (或从其中删除)来自儿童类别。 This allows for future design evolution say if you want to do some specific error checking code before calling the parent event handler. 这允许未来的设计演变,如果你想在调用父事件处理程序之前做一些特定的错误检查代码。 You might not need to write millions of event handlers like this for each control, you could just write one, hook all the controls to this event handler which in turn calls the parent's event handler. 您可能不需要为每个控件编写数百万个这样的事件处理程序,您只需编写一个,将所有控件挂钩到此事件处理程序,然后调用父事件处理程序。

One thing that I have noted is that if all this code is being placed within a dll, then you might experience a performance hit trying to call an event handler from within a dll. 我注意到的一件事是,如果所有这些代码都放在一个dll中,那么你可能会遇到尝试从dll中调用事件处理程序的性能问题。

I've just come across this one as well, I agree that it feels like you're doing everything correctly. 我刚刚遇到过这个,我同意你觉得你正在做的一切都是正确的。 Declaring the method virtual is a work-around at best, not a solution. 将虚拟方法声明为最佳解决方案,而不是解决方案。

What is being done is valid - a control which only exists in the derived class, and the derived class is attaching an event handler to one of that control's events. 正在做的是有效的 - 一个只存在于派生类中的控件,派生类将一个事件处理程序附加到该控件的一个事件中。 The fact that the method which is handling the event is defined in the base class is neither here nor there, it is available at the point of binding to the event. 处理事件的方法在基类中定义的事实既不在这里也不在那里,它在绑定到事件时可用。 The event isn't being attached to twice or anything silly like that, it's simply a matter of where the method which handles the event is defined. 事件没有附加到两次或任何愚蠢的事情,它只是在定义处理事件的方法的问题。

Most definitely it is not a virtual method - I don't want the method to be overridable by a derived class. 绝对不是虚拟方法 - 我不希望方法被派生类覆盖。 Very frustrating, and in my opinion, a bug in dev-studio. 非常令人沮丧,在我看来,dev-studio中的一个错误。

I too have experienced this issue because in earlier versions of VS, you could "inherit" the event handlers. 我也经历过这个问题,因为在早期版本的VS中,你可以“继承”事件处理程序。 So the solution I found without having to override methods is simply to assign the event handler somewhere in the initialization phase of the form. 因此,我发现的解决方案,而不必覆盖方法只是在窗体的初始化阶段的某处分配事件处理程序。 In my case, done in the constructor (I'm sure OnLoad() would work as well): 在我的例子中,在构造函数中完成(我确信OnLoad()也可以工作):

    public MyForm()
    {
        InitializeComponent();
        btnOK.Click += Ok_Click;
    }

...where the Ok_Click handler resides in the base form. ... Ok_Click处理程序驻留在基本表单中的位置。 Food for thought. 值得深思。

I've just run into the exact problem Merus first raised and, like others who posted responses, I'm not at all clear why VS (I'm now using Visual C# 2010 Express) objects to having the event handler defined in the base class. 我刚刚遇到了Merus首次提出的确切问题,并且像其他发布回复的人一样,我不清楚为什么VS(我现在使用的是Visual C#2010 Express)对象在基地中定义了事件处理程序类。 The reason I'm posting a response is that in the process of getting around the problem by making the base class code a protected method that the derived classes simply invoke in their (essentially empty) event handlers, I did a refactor rename of the base class method and noticed that the VS designer stopped complaining. 我发布响应的原因是,在通过使基类代码成为派生类只在其(基本上是空的)事件处理程序中调用的受保护方法来解决问题的过程中,我对基础进行了重构重命名。类方法并注意到VS设计师停止了抱怨。 That is, it renamed the event handler registration (so it no longer followed the VS designer's convention of naming event handlers with ControlName_EventName), and that seemed to satisfy it. 也就是说,它重命名了事件处理程序注册(因此它不再遵循VS设计者使用ControlName_EventName命名事件处理程序的约定),这似乎满足了它。 When I then tried to register the (now renamed) base event handler against derived class controls by entering the name in the appropriate VS event, the designer created a new event handler in the derived class which I then deleted, leaving the derived class control registered to the base class (event handler) method. 当我尝试通过在相应的VS事件中输入名称来针对派生类控件注册(现在重命名的)基本事件处理程序时,设计器在派生类中创建了一个新的事件处理程序,然后我将其删除,从而使派生的类控件保持注册状态到基类(事件处理程序)方法。 Net, as you would expect, C# finds what we want to do legit. Net,正如您所期望的那样,C#找到了我们想要做的事情。 It's only the VS designer that doesn't like it when you following the designer's event handler naming convention. 当你遵循设计师的事件处理程序命名约定时,只有VS设计师不喜欢它。 I don't see the need for the designer to work that way. 我认为设计师不需要那样工作。 Anywho, time to carry on. Anywho,时间继续。

Here's what I did to get base methods called in several similar looking forms, each one of them having a few extra features to the common ones: 以下是我用几种类似外观形式调用基本方法的方法,每种方法都有一些额外的功能:

        protected override void OnLoad(EventArgs e)
    {
        try
        {
            this.SuspendLayout();
            base.OnLoad(e);

            foreach (Control ctrl in Controls)
            {
                Button btn = ctrl as Button;
                if (btn == null) continue;

                if (string.Equals(btn.Name, "btnAdd", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnAdd_Click);
                else if (string.Equals(btn.Name, "btnEdit", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnEdit_Click);
                else if (string.Equals(btn.Name, "btnDelete", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnDelete_Click);
                else if (string.Equals(btn.Name, "btnPrint", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnPrint_Click);
                else if (string.Equals(btn.Name, "btnExport", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnExport_Click);
            }

The chance of an omission of using the right fixed button name looks the same to me as the chance of not wiring the inherited handler manually. 遗漏使用正确的固定按钮名称的可能性对我来说与手动连接继承的处理程序的机会相同。

Note that you may need to test for this.DesignMode so that you skip the code in VS Designer at all, but it works fine for me even without the check. 请注意,您可能需要测试this.DesignMode,以便您完全跳过VS Designer中的代码,但即使没有检查,它也能正常工作。

If your event is already defined in your parent class, you do not need to rewire it again in your child class. 如果您的事件已在父类中定义,则无需在子类中重新连接它。 That will cause the event to fire twice. 这将导致事件发生两次。

Do verify if this is what is happening. 确认这是否正在发生。 HTH :) HTH :)

This article on MSDN should be a good starting points: Overriding Event Handlers with Visual Basic .NET . MSDN上的这篇文章应该是一个很好的起点: 用Visual Basic .NET覆盖事件处理程序 Take a look at the How the Handles Clause Can Cause Problems in the Derived Class section. 请查看“派生类中的句柄如何导致问题”部分。

为什么不在父类中将该方法声明为虚拟,然后您可以在派生类中重写它以添加额外的功能?

忘记它是一个事件处理程序,只是在子类中进行适当的常规方法覆盖。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM