我可以在父表单中知道继承的表单是否已订阅Show事件吗?

时间:2019-05-02 12:03:59

标签: c# winforms inheritance visual-inheritance

我的winforms框架中有以下表单

  • FormBase(从Form继承)
  • FormBaseList(从FormBase继承)
  • FormBaseDetail(从FormBase继承)

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

现在FormBaseList中存在事件FormBaseList_Shown(通过在VS的属性窗口中双击该事件)

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

那有可能吗?

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

我希望这个解释清楚

编辑

这个想法是,当开发人员使用Show事件时,他必须得到警告(在设计时或运行时)。如果他认为他确实需要Show方法,那么他应该能够对此特定表格设置警告

4 个答案:

答案 0 :(得分:1)

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

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

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

通过订阅基础的原始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的内容和定义成员变量的代码块将自动生成,并且您在设计器中的所有手动更改.cs将丢失。但是,如果将#pragma放在文件的顶部和底部,则它是安全的,不会从designer.cs中删除。

答案 1 :(得分:1)

要在运行时引发异常或显示消息框,您可以使用以下选项:

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

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

选项1-显示阴影事件,并将代码添加到add

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

在下面的示例中,我将ThrowExceptionOnSubscribingShownEvent属性添加到默认的true基本形式中,这意味着它在订阅Shown事件时引发异常。

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字段并使用它,获取Shown事件的事件处理程序列表。然后您可以检查事件处理程序列表是否不为空,引发异常。

在下面的示例中,我将ThrowExceptionOnSubscribingShownEvent属性添加到默认的true基本形式中,这意味着它在订阅Shown事件时引发异常。您可以根据需要以派生形式将其设置为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);
    }
}

答案 2 :(得分:0)

使用反射可能是可能的,但是会很混乱。更好的策略是隐藏Shown事件,如下所示:

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

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

答案 3 :(得分:0)

除了布莱斯·瓦格纳(Bryce Wagner)的答案外,您还可以在属性窗口和编辑器中隐藏“显示的事件”:

    [Obsolete("Don't use this event, use my custom one")]
    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)] // Hide from editor
    [System.ComponentModel.Browsable(false)] // Hide from properties window
    public new event EventHandler Shown;

EditorBrowsable似乎仅适用于从其他解决方案导入的dll