我有点在这里支持自己。
我有一系列从父级继承的UserControl,它包含一些方法和事件来简化操作,因此我不必编写几乎相同代码的行和行。像你一样做。父级不包含其他控件。
我想要做的只是在父UserControl中有一个事件处理程序,它只执行父控件可以执行的操作(即,有条件地调用事件,如父事件中定义的事件)。然后我将这个事件处理程序连接到我的子控件中的所有输入框,子控件将解析输出的任务并告诉父控件是否抛出该事件。漂亮干净,没有重复的复制粘贴代码(对我来说总是会导致错误)。
这是我的问题。 Visual Studio认为我太聪明了一半,并警告我“方法'CheckReadiness'[父级中的事件处理程序]不能是事件的方法,因为这个类派生的类已经定义了方法。”是的,Visual Studio,这就是重点。我希望拥有一个只处理子类抛出的事件的事件处理程序,它唯一的工作就是让我能够连接子代,而不必编写一行代码。我不需要那些额外的处理程序 - 我需要的所有功能都可以自然地调用,因为子进程处理用户输入。
我不确定为什么Visual Studio现在开始抱怨这个(因为它让我以前做过),而且我不确定如何让它消失。最好,我想这样做而不必定义一个只调用CheckReadiness的方法。造成这种警告的原因是什么原因导致它在一小时前没有出现,如何在不使用所有儿童课程的小手柄的情况下让它消失?
答案 0 :(得分:7)
声明父方法virtual,在子类中覆盖它并调用
base.checkReadyness(sender, e);
儿童班内的(或其除名)。这允许未来的设计演变,如果你想在调用父事件处理程序之前做一些特定的错误检查代码。您可能不需要为每个控件编写数百万个这样的事件处理程序,您只需编写一个,将所有控件挂钩到此事件处理程序,然后调用父事件处理程序。
我注意到的一件事是,如果所有这些代码都放在一个dll中,那么你可能会遇到尝试从dll中调用事件处理程序的性能损失。
答案 1 :(得分:3)
我刚刚遇到过这个,我同意你觉得你正在做的一切都是正确的。将虚拟方法声明为最佳解决方案,而非解决方案。
正在做的是有效的 - 一个只存在于派生类中的控件,派生类将一个事件处理程序附加到该控件的一个事件中。处理事件的方法在基类中定义的事实既不在这里也不在那里,它在绑定到事件时可用。事件没有附加到两次或任何愚蠢的事情,它只是在定义处理事件的方法的位置。
绝大多数它绝对不是虚方法 - 我不希望方法被派生类覆盖。非常令人沮丧,在我看来,dev-studio中的一个错误。
答案 2 :(得分:2)
我也经历过这个问题,因为在早期版本的VS中,你可以继承"继承"事件处理程序。因此,我发现的解决方案,而不必覆盖方法只是在窗体的初始化阶段的某处分配事件处理程序。在我的例子中,在构造函数中完成(我确定OnLoad()也可以工作):
public MyForm()
{
InitializeComponent();
btnOK.Click += Ok_Click;
}
... Ok_Click处理程序驻留在基本表单中。值得深思。
答案 3 :(得分:1)
我刚刚遇到了Merus首次提出的确切问题,并且像其他发布回复的人一样,我不清楚为什么VS(我现在使用的是Visual C#2010 Express)对象定义了事件处理程序在基类中。我发布响应的原因是,在通过使基类代码成为派生类只在其(基本上是空的)事件处理程序中调用的受保护方法来解决问题的过程中,我对基础进行了重构重命名。类方法并注意到VS设计师停止了抱怨。也就是说,它重命名了事件处理程序注册(因此它不再遵循VS设计者使用ControlName_EventName命名事件处理程序的约定),这似乎满足了它。当我尝试通过在相应的VS事件中输入名称来针对派生类控件注册(现在重命名的)基本事件处理程序时,设计器在派生类中创建了一个新的事件处理程序,然后我将其删除,从而使派生的类控件保持注册状态到基类(事件处理程序)方法。 Net,正如您所期望的那样,C#找到了我们想要做的事情。当你遵循设计师的事件处理程序命名约定时,只有VS设计师不喜欢它。我认为设计师不需要那样工作。任何时间,继续进行。
答案 4 :(得分:0)
如果您的事件已在您的父类中定义,则无需在子类中重新连接它。这将导致事件发生两次。
确认这是否正在发生。 HTH:)
答案 5 :(得分:0)
MSDN上的这篇文章应该是一个很好的起点:Overriding Event Handlers with Visual Basic .NET。看一下如何处理派生条款可能导致派生类中的问题部分。
答案 6 :(得分:0)
为什么不在父类中将该方法声明为虚拟,然后您可以在派生类中重写它以添加额外的功能?
答案 7 :(得分:0)
忘记它是一个事件处理程序,只是在子类中进行适当的常规方法覆盖。
答案 8 :(得分: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中的代码,但即使没有检查它也能正常工作。