12

我有点把自己逼到了一个角落。

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

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

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

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

4

9 回答 9

7

将父方法声明为virtual,在子类中重写并调用

base.checkReadyness(sender, e);

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

我注意到的一件事是,如果所有这些代码都放在一个 dll 中,那么您可能会在尝试从 dll 中调用事件处理程序时遇到性能损失。

于 2008-09-18T06:57:10.687 回答
3

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

正在执行的操作是有效的 - 仅存在于派生类中的控件,并且派生类将事件处理程序附加到该控件的事件之一。处理事件的方法在基类中定义的事实既不存在也不存在,它在绑定到事件时可用。该事件没有被附加到两次或任何类似的傻事,这只是处理事件的方法在哪里定义的问题。

绝对不是虚拟方法——我不希望该方法被派生类覆盖。非常令人沮丧,在我看来,这是 dev-studio 中的一个错误。

于 2009-02-19T14:59:58.777 回答
2

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

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

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

于 2016-06-07T17:23:51.343 回答
1

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

于 2012-03-08T16:40:58.760 回答
0

如果您的事件已在父类中定义,则无需在子类中重新连接它。这将导致事件触发两次。

请确认这是否是正在发生的事情。HTH :)

于 2008-09-18T06:45:58.313 回答
0

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

于 2008-09-18T06:49:21.470 回答
0

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

于 2008-09-18T06:52:55.783 回答
0

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

于 2008-09-18T07:09:28.757 回答
0

以下是我为以几种相似的形式调用基本方法所做的工作,每一种都具有一些常见的额外功能:

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

在我看来,省略使用正确的固定按钮名称的可能性与不手动连接继承的处理程序的可能性相同。

请注意,您可能需要测试 this.DesignMode 以便完全跳过 VS Designer 中的代码,但即使没有检查,它对我来说也能正常工作。

于 2012-07-28T20:41:50.680 回答