【问题标题】:"Object reference not set..." exception when adding control to another form将控件添加到另一个表单时出现“未设置对象引用...”异常
【发布时间】:2016-02-15 20:18:38
【问题描述】:

当用户单击当前位于面板 (UserControl1) 中的 UserControl 上的按钮时,我想将 UserControl (UserControl2) 添加到另一个表单 (MainForm) 的面板中。单击此按钮时,UserControl2 应替换 UserControl1 作为面板的内容。

我已经尝试弄清楚如何使用事件在 UserControl1MainForm 之间进行通信,但我只是不知道从哪里开始,因为我找不到一个可以轻松适应我的示例特殊情况(向面板添加控件)。

THIS 问题类似,但不太适合我想要做的事情(或者至少我不知道如何让它适应我想要做的事情)

我试过这个方法,没有报错,但是我的按钮什么也没做:

主窗体:

    private void SubscribeToEvent(MyUserControl1 Button_Click)
    {
        MyUserControl1 CurrentClass = new MyUserControl1();
        CurrentClass.Button.Click += new EventHandler(this.ButtonClickHandler);
    }

    private void ButtonClickHandler(object sender, EventArgs e)
    {
        MyUserControl2 MainPanelControls = new MyUserControl2();
        MainPanel.SuspendLayout();
        MainPanel.Controls.Clear();
        MainPanel.Controls.Add(MainPanelControls);
        MainPanel.ResumeLayout();
    }

用户控制1:

    public void Button_Click(object sender, EventArgs e)
    {
        //... Not sure what I'm missing here
    }

我也尝试过这种方法,这次尝试实现类似于我的问题顶部附近的链接中描述的方法。我知道这些显然是错误的(否则我不需要问这个问题),但我没有足够的知识来自己解决这个问题:

用户控制1:

    public MyUserControl1()
    {
        InitializeComponent();
    }

    private MainForm mainForm = null;
    public MyUserControl1(Form callingForm)
    {
        mainForm = callingForm as MainForm;
        InitializeComponent();
    }

//...

    private void Button_Click(object sender, EventArgs e)
    {
        MyUserControl2 MainPanelControls = new MyUserControl2();
        mainForm.MainPanel.SuspendLayout();
        mainForm.MainPanel.Controls.Clear();
        mainForm.MainPanel.Controls.Add(MainPanelControls);
        mainForm.MainPanel.ResumeLayout();
    }

现在,当我单击Button 时,我在mainForm.MainPanel.SuspendLayout(); 处收到"Object reference not set to an instance of an object" 错误(或任何过去的错误)。

我也尝试过修改 Joh 的答案,但最终得到了相同的空引用异常,这次是在 ButtonClickedToMainForm(this, e);Button_Click 事件中,我不确定是否需要创建 ButtonClickedToMainForm 的实例,或者如何正确地做到这一点(如果不是别的,那就是)。

我有一种感觉,我可能只是将其中一些代码放在了错误的位置,所以我希望更有经验的人可以帮助我解决这个问题。

更新

这是我实施 Joh 答案的尝试,对此我太陌生了,我不太确定我在哪里搞砸了:

主窗体:

namespace MyProject
{
public delegate void ButtonClickToMainForm(object sender, EventArgs e);

public partial class MainForm : Form
{

    public MainForm()
    {
        InitializeComponent();
        UserControl1 userControl1 = new UserControl1();
        userControl1.Button1Clicked += userControl1_Button1Clicked;
    }

    private void userControl1_Button1Clicked(object sender, EventArgs e)
    {
        try
        {
            UserControl2 MainPanelControls = new UserControl2();
            MainPanel.SuspendLayout();
            MainPanel.Controls.Clear();
            MainPanel.Controls.Add(MainPanelControls);
            MainPanel.ResumeLayout();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
  }
}

用户控制1:

public partial class UserControl1: UserControl
{
    public event ButtonClickToMainForm Button1Clicked;

    public UserControl1()
    {
        InitializeComponent();
    }

    private void OnButton1Clicked(object sender, EventArgs e)
    {
        Button1Clicked?.Invoke(this, e);
    }

    private void Button1_Click(object sender, EventArgs e)
    {
        Button1Clicked(this, e);  //"Object reference not set to an instance of an object."
    }
}

我确定这是我在 UserControl1 上缺少的一些简单的东西,我只是不确定是什么。

【问题讨论】:

  • 有关组件间通信的 Winforms 惯用语的详细信息,请参阅标记的副本(UserControlForm 子类在这里工作相同)。首先,您应该考虑使用事件,以避免耦合组件的实现。如果您在查看相关信息(包括但不限于标记的重复信息)后仍然遇到问题,请提供一个很好的问题minimal reproducible example,清楚地显示您尝试过的内容,以及有关该代码的作用和方式的准确信息这与您想要的不同。
  • 抱歉,我认为这样做可能有点过头了。我阅读了描述如何使用事件来处理表单之间通信的答案中的副本,但我根本无法理解。我什至不确定从哪里开始才能将其实施到我的项目中。我想我会继续寻找其他地方。还是谢谢。
  • 我已经编辑了我的问题,并提供了有关我遇到的问题的更多信息。
  • @PeterDuniho 有没有办法让它不被标记为重复?我已经浏览了链接的问题,但无法找到一种方法来调整其中发布的任何内容以适应我的特定问题。我看不到使用字符串完成我需要的方法,这似乎是您链接的所有答案的基础。谢谢。
  • 第一:虽然汉斯被列在修订历史中,但我不确定这是否算作“编辑”了帖子;因此,他可能会或可能不会通过 @ 语法在此处收到带有评论的通知(您必须找到他撰写、编辑或评论过的帖子)。第二:你并没有真正编辑你的问题,只是在一件接一件的事情上添加。如果你编辑它,你会更成功地让别人认真对待这个问题,重新设计它,使它有一个单一的、简单的代码示例,一个措辞准确的问题,考虑到你的所有进展已经做到了这一点。

标签: c# events controls panel subscribe


【解决方案1】:

这是一个委托事件的简单示例。当您在所有用户控件中实现它时,它应该可以解决您的问题。

用户控制:

//Create a delegate
    public delegate void ButtonClickToMainForm(object sender, EventArgs e);

    public partial class UserControl1 : UserControl
    {
        //Your own event based on created delegate
        public event ButtonClickToMainForm ButtonClickedToMainForm;

        public UserControl1()
        {
            InitializeComponent();
        }

       //This method will invoke your event
        private void OnButtonClickedToMainForm(object sender, EventArgs e)
        {
            ButtonClickedToMainForm?.Invoke(this, e);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //On button1_Click this will fire the event on mainform
            OnButtonClickedToMainForm(this, e);
        }

和主窗体:

 public Form1()
        {
            InitializeComponent();
            //Subscribe to event from your usercontrol
            userControl11.ButtonClickedToMainForm += UserControl11_ButtonClickedToMainForm;
        }

        //Button on userControl1 has been clicked
        private void UserControl11_ButtonClickedToMainForm(object sender, EventArgs e)
        {
            //do your things here...
        }

希望这会有所帮助。

【讨论】:

  • 我想我已经在我的代码中正确地放置了所有这些,但由于某种原因,userControl11.ButtonClickedToMainForm += UserControl11_ButtonClickedToMainForm; 我得到“非静态字段需要对象引用,方法,或财产”
  • 我尝试使用UserControl1 CurrentPanel = new UserControl1(); 在我的主窗体上创建UserControl1 的实例,这解决了我遇到的错误,但是现在当我单击按钮切换面板中的控件时,我得到了我的button_click 事件上的System.NullReferenceException 用户控件ButtonClickedToMainForm(this, e);
  • 另外,在主窗体而不是用户控件中创建委托会更好吗?因为它会被多个控件使用
  • 你在哪里调用:ButtonClickedToMainForm(this, e) 确保参数“this”和“e”不为空。
  • 在 button1_click 事件上。我如何确定这些参数不为空?抱歉,这是我第一次使用委托,我仍在努力了解如何正确使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2013-05-17
  • 1970-01-01
相关资源
最近更新 更多