为什么 C# 中的事件会触发多次?

3

我在这里查看了类似的问题,但答案与我的问题无关。

我是C#的新手,正在使用Windows表单。

ScreenShot

如屏幕截图所示,我有form1、UserControl1和UserControl2。

  • Form1有两个按钮(ShowUserControl1和ShowUserControl2)和DataGridView。

  • UserControl1有一个“AddRow”按钮和一个文本框。

  • UserControl2没有任何内容。

我点击“ShowUserControl2”按钮,ShowUserControl2出现,然后我点击“ShowUserControl1”按钮,ShowUserControl1出现,接着我在UserControl1中的文本框中输入文本,然后点击“AddRow”,一个新行被添加并且运行正常。

现在问题来了:

当我点击“ShowUserControl1”,然后点击“ShowUserControl2”,再次点击“ShowUserControl1”,然后输入文本,再点击一次“AddRow”,DataGridView中就会同时添加两行。如果我点击“ShowUserControl1”三次,然后点击一次“AddRow”,DataGridView中就会同时添加三行,以此类推。

我认为Form1中的事件处理程序(HandleTheEvent)会被执行多次,因为我在“ShowUserControl1”之间多次切换用户控件。如何防止事件多次触发?请帮忙解决。 谢谢。

Form1:

public partial class Form1 : Form
{

    UserControl1 UC1 = new UserControl1();
    UserControl2 UC2 = new UserControl2();

    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        //add user controls when form loads
        Controls.Add(UC1);
        Controls.Add(UC2);
    }


    private void ShowUC(Control value)   // Show/hide User Controls
    {
        UC1.Visible = false;
        UC2.Visible = false;

        value.Visible = true;

     }


    public void HandleTheEvent(object sender, EventArgs e) //deal with the event
    { 

        dataGridView1.Rows.Add(1, UC1.ReturnData, 3);

    }


    private void ShowUserControl1_Click(object sender, EventArgs e)
    {


        ShowUC(UC1); //show User Control1
        UC1.UserControl1Event += new EventHandler(HandleTheEvent);


    }

    private void ShowUserControl2_Click(object sender, EventArgs e)
    {
        ShowUC(UC2); //show User Control2
    }
}

UserControl1:

public partial class UserControl1 : UserControl
{

    public event EventHandler UserControl1Event;

    public UserControl1()
    {
        InitializeComponent();
    }


    public string ReturnData 
    {
        get { return textBox1.Text; }

    }
    private void AddRow_Click(object sender, EventArgs e)
    {
        UserControl1Event(this, e);

    }
}

4
您正在订阅并非取消订阅。请尝试UC1.UserControl1Event -= new EventHandler(HandleTheEvent); UC1.UserControl1Event += new EventHandler(HandleTheEvent); - Giorgi Nakeuri
@ Giorgi Nakeuri。您能告诉我应该把您提供的代码放在哪里吗?谢谢。 - naouf
1个回答

5
控件只创建一次,但每次调用 ShowUserControl1_Click 时,您都会重新绑定事件。这意味着当 UserControl1Event 事件被触发/调用时,HandleTheEvent 将被多次调用。事件是处理程序列表。
private void ShowUserControl1_Click(object sender, EventArgs e)
{


    ShowUC(UC1); //show User Control1


    UC1.UserControl1Event += new EventHandler(HandleTheEvent);


}

你应该在构造函数中绑定事件:

public partial class Form1 : Form
{

    UserControl1 UC1 = new UserControl1();
    UserControl2 UC2 = new UserControl2();

    public Form1()
    {
        InitializeComponent();

        UC1.UserControl1Event += new EventHandler(HandleTheEvent);
    }

不要忘记在这里检查是否已经分配了UserControl1Event事件:
private void AddRow_Click(object sender, EventArgs e)
{
    // here!
    if(UserControl1Event != null)
        UserControl1Event(this, e);
}

@ Jeroen van Langen。你的代码像魔法一样奏效 :)。但我有两个问题:第一,我可以在窗体加载时绑定事件而不是构造函数吗?因为在窗体加载时也可以工作。第二个问题:既然在Form1的构造函数中已经分配了事件,为什么我们还要检查事件是否已分配。请给我建议。谢谢。 - naouf
@naouf,(1)您可以在任何地方绑定事件,但应该只绑定一次。我喜欢在构造函数中绑定它们,因为这样我就确定它只被调用了一次。(2)你想要实现的其中一个目标是重用你的代码。这一次你使用了这个事件,下一次你可能不想使用那个事件。(例如;你并不总是处理每个控件上的mousedown事件)如果您没有将处理程序绑定到事件,则在触发/引发/调用它时会出现“NullReferenceException”。这是因为您正在调用一个空指针作为委托。 - Jeroen van Langen
@ Jeroen van Langen。讲解得非常清楚,非常感谢。 - naouf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接