Question

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.

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

Was it helpful?

Solution

Declare the parent method virtual, override it in the child classes and call

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.

OTHER TIPS

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.

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

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

...where the Ok_Click handler resides in the base form. 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. 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.

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

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 Class section.

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?

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top