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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/90553/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 11:30:35  来源:igfitidea点击:

Inheriting Event Handlers in C#

提问by Merus

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. As you do. The parent contains no other controls.

我有一系列从父级继承的 UserControl,其中包含一些方法和事件来简化事情,因此我不必编写几行几行几乎相同的代码。像你一样做。父级不包含其他控件。

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). 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 alwaysresults in a bug).

我想要做的只是在父 UserControl 中有一个事件处理程序,它执行只有父控件才能执行的操作(即,有条件地调用事件,因为事件在父控件中定义)。然后我将这个事件处理程序连接到我的子控件中的所有输入框,子控件将整理解析输入并告诉父控件是否抛出该事件的任务。干净整洁,没有重复的复制粘贴代码(这对我来说总是导致错误)。

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." Yes, Visual Studio, that's the point. I wantto 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.

这是我的问题。Visual Studio 认为我太聪明了一半,并警告我“方法 'CheckReadiness' [父级中的事件处理程序] 不能作为事件的方法,因为此类派生自的类已经定义了该方法。” 是的,Visual Studio,这就是重点。我想要一个只处理子类抛出的事件的事件处理程序,它唯一的工作是让我无需编写一行代码就可以连接子类。我不需要那些额外的处理程序——我需要的所有功能都会在子进程处理用户输入时自然调用。

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. Preferably, I'd like to do it without having to define a method that just calls 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?

我不知道为什么 Visual Studio 现在开始抱怨这个(因为它让我以前这样做),我不知道如何让它消失。最好,我想这样做而不必定义一个只调用 CheckReadiness 的方法。是什么导致了这个警告,是什么导致它在一个小时前没有出现的情况下出现,以及如何在不诉诸于所有子类中的小处理程序的情况下让它消失?

采纳答案by TK.

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.

(或其 derevation)从子类中。如果您想在调用父事件处理程序之前执行一些特定的错误检查代码,这允许将来的设计演变。您可能不需要为每个控件编写数百万个这样的事件处理程序,您只需编写一个,将所有控件挂钩到此事件处理程序,该事件处理程序又调用父级的事件处理程序。

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 中调用事件处理程序时可能会遇到性能问题。

回答by Jon Limjap

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 :)

请验证这是否正在发生。哈 :)

回答by Dario Solera

This article on MSDN should be a good starting points: Overriding Event Handlers with Visual Basic .NET. Take a look at the How the Handles Clause Can Cause Problems in the Derived Classsection.

MSDN 上的这篇文章应该是一个很好的起点:Overriding Event Handlers with Visual Basic .NET。查看派生类部分中的句柄子句如何导致问题

回答by Phil Wright

Why not declare the method as virtual in the parent class and then you can override it in the derived classes to add extra functionality?

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

回答by ima

Forget that it's an event handler and just do proper regular method override in child class.

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

回答by MrCranky

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.

我也刚遇到过这个,我同意感觉就像你做的一切都是正确的。将方法声明为 virtual 充其量是一种解决方法,而不是解决方案。

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 中的一个错误。

回答by Steve Rehling

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. 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. 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. 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. Net, as you would expect, C# finds what we want to do legit. It's only the VS designer that doesn't like it when you following the designer's event handler naming convention. I don't see the need for the designer to work that way. Anywho, time to carry on.

我刚刚遇到了 Merus 首先提出的确切问题,并且像其他发布回复的人一样,我完全不清楚为什么 VS(我现在使用的是 Visual C# 2010 Express)对象在基础中定义事件处理程序班级。我发布回复的原因是,在通过使基类代码成为派生类在其(基本上为空)事件处理程序中简单调用的受保护方法来解决问题的过程中,我对基类进行了重构重命名class 方法并注意到 VS 设计器停止抱怨。也就是说,它重命名了事件处理程序注册(因此它不再遵循 VS 设计器使用 ControlName_EventName 命名事件处理程序的约定),这似乎满足了它。然后,当我尝试通过在适当的 VS 事件中输入名称来针对派生类控件注册(现已重命名的)基本事件处理程序时,设计人员在派生类中创建了一个新的事件处理程序,然后我将其删除,从而使派生类控件注册到基类(事件处理程序)方法。Net,正如您所期望的,C# 找到了我们想要做的合法的事情。当您遵循设计器的事件处理程序命名约定时,只有 VS 设计器不喜欢它。我不认为设计师需要那样工作。任何人,是时候继续了。C# 找到我们想要做的合法的事情。当您遵循设计器的事件处理程序命名约定时,只有 VS 设计器不喜欢它。我不认为设计师需要那样工作。任何人,是时候继续了。C# 找到我们想要做的合法的事情。当您遵循设计器的事件处理程序命名约定时,只有 VS 设计器不喜欢它。我不认为设计师需要那样工作。任何人,是时候继续了。

回答by Bolek

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 中的代码,但即使没有检查,它对我来说也能正常工作。

回答by user6436572

I too have experienced this issue because in earlier versions of VS, you could "inherit" the event handlers. 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):

我也遇到过这个问题,因为在 VS 的早期版本中,您可以“继承”事件处理程序。因此,我找到的无需覆盖方法的解决方案就是在表单的初始化阶段的某处分配事件处理程序。就我而言,在构造函数中完成(我确定 OnLoad() 也能工作):

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

...where the Ok_Click handler resides in the base form. Food for thought.

... Ok_Click 处理程序驻留在基本表单中的位置。深思熟虑。