C# windows 表单引用控件 - NullReferenceException

C# windows forms reference control - NullReferenceException

谁能解释为什么我在创建新 Button 并尝试引用它时得到 NullReferenceException?创建按钮并指定名称工作正常,但引用它却不行。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DragNDrop_1
{
public partial class Form1 : Form
{
    //Variables----------------------------------------------------------------------
    int ButtonID = 100;
    bool isDraggingButton = false;
    public Form1()
    {
        InitializeComponent();
    }
    //----------------------------------------------------------------------Variables
    private void btn_addButton_Click(object sender, EventArgs e)
    {
        AddButton();
    }

    public void AddButton()
    {
        Button b = new Button();
        b.Name = "Button" + ButtonID.ToString();
        b.Text = "Button" + ButtonID.ToString();
        b.Location = new Point(ButtonID, ButtonID);
        ButtonID = ButtonID + 100;
        pnl_DragNDrop.Controls.Add(b);
        isDraggingButton = true;
    }

    private void DragTimer_Tick(object sender, EventArgs e)
    {
        if (isDraggingButton == true)
        {
            Point mouse = PointToClient(MousePosition);
            this.Controls["Button" + ButtonID.ToString()].Location = new Point(mouse.X + 20, mouse.Y + 20);

        }
    }

}
}

定时器中出现异常,我在其中尝试引用最后创建的按钮。我阅读了一些关于此异常的线程,但我仍然无法发现错误。 是的,我知道这很麻烦,我应该适当地创建一个自定义循环或 de-/re- 激活计时器,但这仅用于测试目的。请注意,我是 C# 和 Windows 表单的新手。

编辑:正如 Lukasz M 所解释的,这是一个关于所有权的问题(也许术语不正确,这是我能想到的最好的德英翻译)。这既不是线程 I "duplicated" 中问题的焦点,也不是答案中提到的。如果是的话,我不得不质疑我的英语水平。不管怎样,我只是想澄清一下,我确实阅读了线程,但无法找到解决方案。也许只是缺乏英语和 C# 技能,但我很确定这不是重复的。

这是因为在 AddButton 方法中您创建了按钮,但没有将其直接添加到表单的控件中,而是添加到 pnl_DragNDrop.Controls 集合中。

你可以尝试改变这个:

this.Controls["Button" + ButtonID.ToString()].Location = new Point(mouse.X + 20, mouse.Y + 20);

对此:

pnl_DragNDrop.Controls["Button" + ButtonID.ToString()].Location = new Point(mouse.X + 20, mouse.Y + 20);

它应该可以正常工作。

另一种方法是将 b 按钮保存在 class 字段中,而不是方法中的变量。这样,您可以在不同的方法中引用控件,而无需通过 IdControls 集合中找到它。您可能还想添加多个具有不同 Id 值的按钮,因此存储和引用创建的按钮的具体实现可能取决于实际用例。

更新

为了使代码实际工作,还请注意,在您创建 b 控件之后,您修改了用于组成其名称的变量:

ButtonID = ButtonID + 100;

然后,在DragTimer_Tick方法中你使用修改后的值重建控件的名称,但它已经不同了,所以找不到控件。

按名称搜索控件时,您可以保存 ButtonID 的先前值或保存用作按钮名称的整个字符串(如评论中所述),以便能够使用它来查找稍后控制。