如果继承的表单订阅了 Show 事件,我可以在父表单中知道吗?

Can i know in the parent Form if an inherited Form has subscribed to the Show event?

我的 winforms 框架中有以下表单

现在应用程序中的每个表单都继承自上述 3 个之一。
例如 FormCustomerList 将继承自 FormBaseList

现在 FormBaseList 事件 FormBaseList_Shown 存在(通过在 VS 的属性 window 中双击它)

我想知道 FormBaseList_Show 的代码中是否存在事件 FormCustomerList_Show(再次在属性 window 中双击它)。

这可能吗?

那我为什么要这个?
因为框架中的某些更改要求表单不再使用 Shown 事件,而是使用自定义事件。
如果开发人员将 Show 事件添加到表单,我想捕捉并向开发人员显示警告,如果确实需要,他可以设置一个 属性 来隐藏此警告。
此警告不需要在设计时显示,在运行时就足够了。但如果在设计时可能的话,那将是一个奖励。
那么这可以做到吗,是否有更好的方法来做到这一点?

我希望这个解释清楚

编辑

想法是,当开发人员使用 Show 事件时,他必须收到警告(在设计时或运行时)。如果他觉得他真的需要 Show 方法,他应该能够为这个特定的表单设置警告关闭

用反射大概可以,但是会比较乱。更好的策略是像这样隐藏 Shown 事件:

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

然后任何尝试使用此事件的东西都会生成编译器警告。

您应该隐藏 Shown 事件并以这种方式弃用它:

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

您已将其标记为过时,它将在您构建解决方案时在编译时在错误列表 window 中显示警告。

此外,通过订阅基地的原始 Shown 活动,活动将继续按预期进行。

要禁用警告,请在已订阅事件的表单的 designer.cs 文件顶部添加以下代码行:

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

并将此行添加到底部:

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

注意:在其他文件中,除了designer.cs文件,只用#pragma包围事件处理程序订阅就足够了。但是对于 designer.cs,您不能包围事件处理程序订阅,因为通过在设计器中更改任何内容,InitializeComponent 的内容和定义成员变量的代码块将自动生成,并且您的所有手动更改在 designer.cs 中将丢失。但是如果你把 #pragma 放在文件的顶部和底部,它是安全的并且不会从 designer.cs.

中删除

要在 运行 时抛出异常或显示消息框,您有以下选项:

  • 隐藏Shown事件,在add部分抛出异常(除非已设置跳过标志)。
  • 使用反射查找 Shown 事件的事件处理程序列表并检查是否有附加到该事件的处理程序。

在这两种解决方案中,布尔值 属性 可用于覆盖派生形式中的行为。

选项 1 - Shadowing Shown 事件并将代码添加到 add

您可以隐藏 Shown 事件并在 add 访问器中添加代码以显示消息框或在事件中添加处理程序时抛出异常。

在下面的示例中,我将 ThrowExceptionOnSubscribingShownEvent 属性 添加到默认为 true 的基本表单中,这意味着它会在订阅 [=12= 时抛出异常] 事件。

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;
    }
}

选项 2 - 查找 Shown 事件的事件处理程序列表

作为运行时间的一个选项,你可以覆盖OnShown方法并使用反射,获取EVENT_SHOWN字段并使用它,获取[=12]的事件处理程序列表=] 事件。然后你可以检查事件处理程序列表是否不为空,抛出异常。

在下面的示例中,我将 ThrowExceptionOnSubscribingShownEvent 属性 添加到默认为 true 的基本表单中,这意味着它会在订阅 [=12= 时抛出异常] 事件。您可以在派生形式中需要时将其设置为 false

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