1

I have the following forms in my winforms framework

  • FormBase (inherited from Form)
  • FormBaseList (inherited from FormBase)
  • FormBaseDetail (inherited from FormBase)

Now every form in the application inherits from on one of the 3 above.
For example FormCustomerList will be inherited from FormBaseList

Now in FormBaseList the event FormBaseList_Shown is present (by doubleclicking on it in the properties window in VS)

What I would like to know in the code from FormBaseList_Show is if there is an event FormCustomerList_Show present (again by doubleclick on it in the properties window).

Is that even possible ?

So why do I want this ?
Because some changes in the framework require the forms to not use the Shown event anymore but a custom event.
I would like to catch and show a warning to the developer if he adds a Show event to a form, and if it is really needed he can set a property that will hide this warning.
This warning does not needs to be shown at designtime, at runtime would be enough. But if its possible at designtime that would be a bonus.
So can this be done and is there maybe a better way to do this ?

I hope this explanation is clear

EDIT

The idea is that when a developer makes use of a Show event he must get a warning (either at designtime or runtime). If he feels that he really needs the Show method he should be able to set the warning off for this particular form

GuidoG
  • 11,359
  • 6
  • 44
  • 79
  • https://stackoverflow.com/a/3856171/17034 – Hans Passant May 02 '19 at 12:26
  • I've posted two solutions. One solution for run-time (including two different options) and one solution for design-time. Since the solutions are totally different and include multiple options, I decided to post the in two separate answers. – Reza Aghaei May 03 '19 at 15:14

3 Answers3

1

You should shadow the Shown event and deprecate it this way:

[Obsolete("Shown event is deprecated.")]
public new event EventHandler Shown
{
    add { base.Shown += value; }
    remove { base.Shown -= value; }
}

You have marked it as obsolete and it will show a warning in Error List window at compile time when you build your solution.

Also the event will keep working as expected by subscribing to the original Shown event of the base.

To disable the warning, add the following line of code at top of designer.cs file of the form which has subscribed to the event:

#pragma warning disable CS0618 // Type or member is obsolete

and add this line to bottom:

#pragma warning restore CS0618 // Type or member is obsolete

Note: In the other files, except designer.cs file, it's enough to surround just the event handler subscription by #pragma. But for designer.cs, you cannot surround event handler subscription, because by changing anything in designer, the content of InitializeComponent and the block of code which is defining member variables will be auto-generated and all your manual changes in designer.cs will be lost. But if you put #pragma at top and bottom of the file, it's safe and will not be removed from designer.cs.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • ok this might work, but it needs editing of the designer.cs which i like to avoid – GuidoG May 03 '19 at 06:08
  • This works, I've already tried that. This change in designer file is persistent. You don't need to be worry about it. – Reza Aghaei May 03 '19 at 06:32
  • I am not worried about the change in the designer file is being persistent, I change code there too every now and then. I was hoping for an easy way in my framework, like setting a custom property on the form that would hide the warning – GuidoG May 03 '19 at 13:56
  • Custom property is a run-time solution. – Reza Aghaei May 03 '19 at 14:25
  • Yes, I said that in my question that a runtime solution would also suffice. – GuidoG May 03 '19 at 14:27
  • Also, if the custom property is on a base form, the warning might still show up in designtime I think. I found that lots of code is executed in designtime just because its in a base form, not entire sure off course – GuidoG May 03 '19 at 14:29
  • I see Hans has shared a link which you will find it useful for run-time solution. Is there any reason that you are not using that? – Reza Aghaei May 03 '19 at 14:38
  • Well it involves using reflection and in the link its also explained that microsoft does not wants us to do it that way. So I rather not do it like that – GuidoG May 03 '19 at 14:40
  • Than I guess I have to make a choice between your method or the method of Hans. Thanks for your time and effort – GuidoG May 03 '19 at 14:47
1

To throw exception or show a message box at run-time you have the following options:

  • Shadow the Shown event and in the add part, throw an exception (unless the skip flag has been set).
  • Using reflection find the event handler list for Shown event and check if there is a handler attached to the event.

In both solutions, a boolean property can be used to override the behavior in derived forms.

Option 1 - Shadowing Shown event and add the code to add

You can shadow the Shown event and in the add accessor, add a code to show a message box or throw exception if a handler added to the event.

In the following example, I've added ThrowExceptionOnSubscribingShownEvent property to the base form which is true by default which means it throws the exception on subscribing the Shown event.

public bool ThorwExceptionOnSubscribingShownEvent { get; set; } = true;

public new event EventHandler Shown
{
    add
    {
        if (ThorwExceptionOnSubscribingShownEvent)
            throw new InvalidOperationException("Shown event is deprecated.");

        base.Shown += value;
    }
    remove
    {
        base.Shown -= value;
    }
}

Option 2 - Finding event handler list for Shown event

As an option for run-time, you can override OnShown method and using reflection, get EVENT_SHOWN field and using it, get the event handler list of Shown event. Then you can check if the event handler list is not empty, throw an exception.

In the following example, I've added ThrowExceptionOnSubscribingShownEvent property to the base form which is true by default which means it throws the exception on subscribing the Shown event. You can set it to false when needed in derived forms:

public partial class BaseForm : Form
{
    public BaseForm()
    {
        InitializeComponent();
    }

    public bool ThrowExceptionOnSubscribingShownEvent { get; set; } = true;
    protected override void OnShown(EventArgs e)
    {
        if (!DesignMode)
        {
            var EVENT_SHOWN = typeof(Form).GetField("EVENT_SHOWN",
                BindingFlags.NonPublic | BindingFlags.Static)
                .GetValue(null);
            var handlers = Events[EVENT_SHOWN]?.GetInvocationList();
            if (ThrowExceptionOnSubscribingShownEvent && handlers?.Length > 0)
                throw new InvalidOperationException("Shown event is deprecated.");
        }
        base.OnShown(e);
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
0

It's probably possible using reflection, but it would be rather messy. A better tactic would be to hide the Shown event like this:

        [Obsolete("Don't use this event, use my custom one")]
        public new event EventHandler Shown;

Then anything that tries to use this event will generate compiler warnings.

Bryce Wagner
  • 2,640
  • 1
  • 26
  • 43
  • Well this works, but now i cannot hide the warning in those few forms that are allowed a Show event for some reason – GuidoG May 02 '19 at 13:03
  • Note that this creates a new event that's not hooked up to anything, so the ones that should register for Shown will no longer get called. This means you need to create another event for those to hook into, and call that event from "protected override OnShown(EventArg e)" method. – Bryce Wagner May 02 '19 at 22:27
  • but still the developer cannot overrwite and hide the message in some cases. This is not what I am after, sorry – GuidoG May 03 '19 at 06:06