Link to home
Start Free TrialLog in
Avatar of awilderbeast
awilderbeastFlag for United Kingdom of Great Britain and Northern Ireland

asked on

object ref not set to instance of object accessing controls on another form...

hi all, simimlar to a question i just asked which i thought i got but maybe im still doing something wrong...

FORM 1 has a panel in it and a winforms ribbon

the errors i get when i debug the app are

private Athena.Home _MainForm; < is NULL
_ButtonCoEdit = new RibbonButton(_MainForm.HomeRibbon, (uint)RibbonMarkupCommands.cmdButtonCoEdit); < Object Ref not set to instance of object

there is not code in form 1 relating to this code, do i need to add something?
or dose code 2 need altering?

thanks
################### FORM2 ############################
namespace Athena.Companies
{
    public enum RibbonMarkupCommands : uint
    {
        cmdButtonCoEdit = 1051,

    }

    public partial class FrmCompanyList : Form
    {


        private RibbonButton _ButtonCoEdit;
        private Athena.Home _MainForm;

        public FrmCompanyList()
        {
            InitializeComponent();

            Athena.Home RibCtrl = new Athena.Home();

            _ButtonCoEdit = new RibbonButton(_MainForm.HomeRibbon, (uint)RibbonMarkupCommands.cmdButtonCoEdit);
            _ButtonCoEdit.ExecuteEvent += new EventHandler<ExecuteEventArgs>(_EditCompany);
        }

Open in new window

Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Look at the example I gave you in the last question.

You have declared a variable whose type is "Athena.Home", and whose name is "_MainForm", but you haven't assigned anything to this variable.  You need to pass a "Athena.Home" variable into the constructor of your FrmCompanyList form, and then you can assign that parameter to the _MainForm variable.  Whatever code shows form 2 needs to provide a reference to form 1.

How & when are you opening each form?

// Using modifed form 2 snippet below, both these methods for 
// showing form 2 will fail because the constructor requires
// you pass a reference to form 1
new FrmCompanyList().Show;
// Or...
FrmCompanyList form2 = new FrmCompanyList();
form2.Show();

Open in new window


// Something like this works...
Form1 frm1 = new Form1();
frm1.Show();
new FrmCompanyList(frm1).Show();

Open in new window

################### FORM2 ############################
namespace Athena.Companies
{
    public enum RibbonMarkupCommands : uint
    {
        cmdButtonCoEdit = 1051,

    }

    public partial class FrmCompanyList : Form
    {


        private RibbonButton _ButtonCoEdit;
        private Athena.Home _MainForm;

        public FrmCompanyList(Athena.Home MainForm)
        {
            InitializeComponent();

            _MainForm = MainForm;

            Athena.Home RibCtrl = new Athena.Home();

            _ButtonCoEdit = new RibbonButton(_MainForm.HomeRibbon, (uint)RibbonMarkupCommands.cmdButtonCoEdit);
            _ButtonCoEdit.ExecuteEvent += new EventHandler<ExecuteEventArgs>(_EditCompany);
        }

Open in new window

Your problem is that the variable _MainForm is null and you are trying to access its property HomeRibbon in the line:

_ButtonCoEdit = new RibbonButton(_MainForm.HomeRibbon,  ...
Avatar of awilderbeast

ASKER

this is hard for me, im not getting it

Athena.Home is the name of the Home Form (FORM 1)

so what i was trying to do is make FORM1 (Athena.Home) accessible by all other forms in the application
ASKER CERTIFIED SOLUTION
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
################### FORM2 ############################
namespace Athena.Companies
{
    public enum RibbonMarkupCommands : uint
    {
        cmdButtonCoEdit = 1051,

    }

    public partial class FrmCompanyList : Form
    {


        private RibbonButton _ButtonCoEdit;
        private Athena.Home _MainForm; // <-- this declares a variable of type Athena.Home, but by itself never assigns an Athena.Home object to that variable

        public FrmCompanyList(Athena.Home MainForm) // <-- Constructor has been modified to take 1 parameter, whose type is "Athena.Home" and whose name is "MainForm"
        {
            InitializeComponent();

            _MainForm = MainForm; // <-- This assigns the private class-level _MainForm variable whatever instance of the object that MainForm points to

            Athena.Home RibCtrl = new Athena.Home();

            _ButtonCoEdit = new RibbonButton(_MainForm.HomeRibbon, (uint)RibbonMarkupCommands.cmdButtonCoEdit);
            _ButtonCoEdit.ExecuteEvent += new EventHandler<ExecuteEventArgs>(_EditCompany);
        }

Open in new window

thanks that helps a lot, begining to understand it all now!

you should teach! unless you already do lol

so as in my codes below

Athena.Home i have send that form as a constructor yes
then
FrmCompanyList recieves it and is able to use it with the included type in that page?

on FrmCompanyList as ive declared _MainForm = MainForm; and its in a public class, does that mean the other functions on my CompanyList form are able to read it?

as im having problems with the _EditCompany function, mainly that it doesnt do anything when i click the button
only thing i can think of is that _MainForm, is not declared in editcompany?

thanks for your help
//FrmCompanyList

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RibbonLib;
using RibbonLib.Controls;
using RibbonLib.Controls.Events;
using RibbonLib.Interop;

namespace Athena.Companies
{
    public enum RibbonMarkupCommands : uint
    {
        cmdButtonCoEdit = 1051,

    }

    public partial class FrmCompanyList : Form
    {
        private RibbonButton _ButtonCoEdit;
        private Athena.Home _MainForm;

        public FrmCompanyList(Athena.Home MainForm)
        {
            InitializeComponent();

            _MainForm = MainForm;

            _ButtonCoEdit = new RibbonButton(_MainForm.HomeRibbon, (uint)RibbonMarkupCommands.cmdButtonCoEdit);
            _ButtonCoEdit.ExecuteEvent += new EventHandler<ExecuteEventArgs>(_EditCompany);
        }

        void _EditCompany(object sender, ExecuteEventArgs e)
        {
            MessageBox.Show("Edit Button Clicked");
            _MainForm.HomeRibbon.SetModes(1);
            _MainForm.HomeRibbon.SetModes(2);

            Athena.Companies.FrmCompanyEdit CompEditFrm = new Athena.Companies.FrmCompanyEdit(); 
            _MainForm.BodyPanel.Controls.Clear();
            CompEditFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            _MainForm.BodyPanel.Controls.Add(CompEditFrm);
            CompEditFrm.Show();

        }

        private void FrmCompanies_Load(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Maximized;
            // TODO: This line of code loads data into the 'dataSetCompanies.CompanyInfo' table. You can move, or remove it, as needed.
            this.companyInfoTableAdapter.Fill(this.dataSetCompanies.CompanyInfo);
            

        }
    }
}

Open in new window

//Athena.Home FORM

void _LoadCompanyList(object sender, ExecuteEventArgs e)
        {
            HomeRibbon.SetModes(1);
            Athena.Home HomeFrm = new Athena.Home();
            Athena.Companies.FrmCompanyList CompFrm = new Athena.Companies.FrmCompanyList(HomeFrm); 
            CompFrm.TopLevel = false;
            BodyPanel.Controls.Clear();
            CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            BodyPanel.Controls.Add(CompFrm);
            
            CompFrm.Show();

        }

Open in new window

Sorry to be long-winded, it's a little difficult for me trying to explain some of these abstract concepts...

Note that on line 6 in your second snippet you're creating a new Athena.Home object, which is what you're passing to the FrmCompanyList constructor on line 7.

Remember that forms are just like any other object.

So, if you write:
Athena.Home frm1 = new Athena.Home(); // Declare a variable named "frm1" of type Athena.Home, and assign a new instance to it
Athena.Home frm2 = new Athena.Home() // Declare ANOTHER variable named "frm2", and assign ANOTHER, SECOND instance to it

frm1.Text = "This is the first form";
frm2.Text = "";

frm1.Show();

SomeFictionalMethod(frm2);

void SomeFictionalMethod(Athena.Home theForm)
{
    MessageBox.Show(theForm.Text);
}

Open in new window


Then the second Athena.Home form in the above example will never be shown, and the fake method is going to show an empty text box.  Likewise, the form you created on line 6 is never shown, and when you pass it to FrmCompanyList then _MainForm ends up being equal to the never-shown form.  So when EditCompany runs it is affecting the panel on the never-shown Athena.Home form, and not the Athena.Home form's that's actually open.

If you put _MainForm.Show(); on line 50 (just as an experiment, this isn't your fix) in your first snippet then you'll see the form with the panel whose contents you've changed.  You will also see a brand-new FrmCompanyList every time LoadCompanyList runs.

Since _LoadCompanyList is inside the Athena.Home class, you can use the this keyword to represent the current INSTANCE of that class, so the short answer is: in your _LoadCompanyList snippet above, delete line 6 and change line 7 to:
Athena.Companies.FrmCompanyList CompFrm = new Athena.Companies.FrmCompanyList(this);

Open in new window


Here's a simple, but 100% complete, WinForms app you might want to play around with (since it doesn't really do anything, it's not cluttered with a bunch of code), just to get a sense how some objects behave - try putting breakpoints in and stepping through the code one line at a time.
using System;
using System.Windows.Forms;

static class Program
{
	/// <summary>
	/// The main entry point for the application.
	/// </summary>
	[STAThread]
	static void Main()
	{
		Application.EnableVisualStyles();
		Application.SetCompatibleTextRenderingDefault(false);
		Application.Run(new Form1());
	}
}

public class Form1 : Form
{
	public Label Label1;

	public Form1()
	{
		// The "this" keyword when used inside a class
		// refers to this instance of this class, see http://msdn.microsoft.com/en-us/library/dk1507sz(VS.80).aspx
		this.SuspendLayout();

		this.Name = "Form1";
		this.Text = "Form1";

		// Use a FlowLayoutPanel to add our controls to, so we don't have to position them manually
		FlowLayoutPanel panel = new FlowLayoutPanel();
		panel.Dock = DockStyle.Fill;
		panel.FlowDirection = FlowDirection.TopDown;

		// Put a label on the form just so we know which one we're looking at when the progrma runs
		panel.Controls.Add(new Label() { Text = "This is Form1" });

		// Create our other controls, and add them to the panel
		Label1 = new Label();
		panel.Controls.Add(Label1);

		Button ShowForm2Button = new Button();
		ShowForm2Button.Text = "Form 2";
		ShowForm2Button.Click += new EventHandler(ShowForm2Button_Click);
		panel.Controls.Add(ShowForm2Button);

		Button ShowForm3Button = new Button();
		ShowForm3Button.Text = "Form 3";
		ShowForm3Button.Click += ShowForm3Button_Click;
		panel.Controls.Add(ShowForm3Button);

		Button ObjectsButton = new Button();
		ObjectsButton.Text = "Objects";
		ObjectsButton.Click += ObjectsButton_Click;
		panel.Controls.Add(ObjectsButton);

		// Add the panel to the form
		this.Controls.Add(panel);

		this.ResumeLayout();
	}

	void ShowForm2Button_Click(object sender, EventArgs e)
	{
		Form2 frm2 = new Form2(this);
		frm2.Show();
	}

	void ShowForm3Button_Click(object sender, EventArgs e)
	{
		for (int i = 0; i < 5; i++)
		{
			Form3 frm = new Form3();
			frm.Show();
		}
	}

	void ObjectsButton_Click(object sender, EventArgs e)
	{
		SomeObject someObj1 = new SomeObject();
		someObj1.SomeTextProperty = "Test Object 1";

		SomeObject someObj2 = new SomeObject();
		someObj2.SomeTextProperty = "Test Object 2";

		someObj1.SomeObjectMethod();
		someObj2.SomeObjectMethod();
	}

	public static void SomeMethod(SomeObject obj)
	{
		MessageBox.Show(obj.SomeTextProperty);
	}
}

public class Form2 : Form
{
	private Button SendMessageToForm1Button;
	private TextBox MessageToSendTextBox;
	private Form1 _form1; // Declare variable to hold a reference to form1

	public Form2(Form1 theForm)
	{
		// Setup controls on this form, like above
		this.SuspendLayout();

		this.Name = "Form2";
		this.Text = "Form2";

		FlowLayoutPanel panel = new FlowLayoutPanel();
		panel.Dock = DockStyle.Fill;
		panel.FlowDirection = FlowDirection.TopDown;

		panel.Controls.Add(new Label() { Text = "This is form 2." });

		MessageToSendTextBox = new TextBox();
		panel.Controls.Add(MessageToSendTextBox);

		SendMessageToForm1Button = new Button();
		SendMessageToForm1Button.Text = "Send Message to Form 1";
		SendMessageToForm1Button.Click += new EventHandler(SendMessageToForm1Button_Click);
		panel.Controls.Add(SendMessageToForm1Button);

		this.Controls.Add(panel);

		this.ResumeLayout();

		// Save the reference to form 1, that was passed in as "theForm",
		// to the variable whose type is Form1 and name is _form1;
		_form1 = theForm;
	}

	void SendMessageToForm1Button_Click(object sender, EventArgs e)
	{
		_form1.Label1.Text = MessageToSendTextBox.Text;
	}
}

public class Form3 : Form
{
	static Random random = new Random();

	public Form3()
	{
		SuspendLayout();

		Label label = new Label();
		label.Name = "Label1";
		label.Dock = DockStyle.Fill;
		label.Text = "This is a useless form.\r\nTHIS instance of Form3 is unique/independant of every other instance of Form3.\r\nThis is a random number:" + random.Next(0, 1001);
		label.AutoSize = true;
		label.Font = new System.Drawing.Font("Tahoma", 16, System.Drawing.FontStyle.Bold);
		Controls.Add(label);

		ResumeLayout();
	}
}

public class SomeObject
{
	private string _someTextProperty;
	public string SomeTextProperty
	{
		get { return _someTextProperty; }
		set { _someTextProperty = value; }
	}

	public void SomeObjectMethod()
	{
		Form1.SomeMethod(this);
	}
}

Open in new window

thanks for that, helps alot, been playign with the program for a bit now and i think im begining to understand how all this stuff works!

just wonder if you could offer your advice and guidance on this one last topic

what ive been trying to do and am wondering if is plausable is...

im using ribbon for winforms and i have some main buttons that open subforms in the panel below the ribbon on the home form, as you can probably tell from the code

what i then did is for buttons relating to a particular form was to insert them there and add the events for the button that is relevant to the form, for example

Form-HOME
ButtontoCompanyForm | ButtontoClientForm

Form-Company
ButtonToEditCompany | ButtonTOAddCompany | ButtonTODeleteCompany

so i would have 2 ribbonbuttons on the Form-Home in the class and have click events for them

then on Form-Company i would have the 3 button events relating to Companies

it was so the Home Form doesnt hold all the code for all the buttons, i thought it made sense that relevant buttons where only registered on relevant forms?

but what has just happened when i was testing it out
i clicked ButtontoCompanyForm > then clicked > ButtonToEditCompany
all is fine
i then clicked > HomeButton > then clicked > ButtontoCompanyForm > again
this time after clicking ButtontoCompanyForm i got a ribbon error
"an item with the same key has already been added"

im not sure why this error has happened but a good guess would be becuase im creating some sort of loop of events in the form load?

when we load a form into a panel via show then do a panel.clear() is that form still open?, if so im guessing thats the problem?

thankyou for your time

>> an item with the same key has already been added
I'm not particularly familiar with Ribbons, so I can't offer much specific guidance in that area, I will say though that this error generally means you're trying to add a duplicate item to a collection that requires each item be unique.

>> when we load a form into a panel via show then do a panel.clear() is that form still open?

Yes.  It's just not in the panel anymore.
thats what the problem probably is then

how would you suggest i get arround it?
we have quite a dlilmea with this

i was going to ask if there was a way to close all open forms on click but then we where giong to use tabs to display multiple forms

is there a way to detect if a form is open and it is is show it and not create a new one?

im guessing frmo the code below that nre ComFrm object has already been created and is getting created again when i click it which the ribbons not happy with

Thanks for your help
rivate void _LoadCompanyList(object sender, ExecuteEventArgs e)
        {
            HomeRibbon.SetModes(1);
            Athena.Companies.FrmCoList CompFrm = new Athena.Companies.FrmCoList(this); 
            CompFrm.TopLevel = false;
            BodyPanel.Controls.Clear();
            CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            BodyPanel.Controls.Add(CompFrm);
            
            CompFrm.Show();

        }

Open in new window

i found this but have errors

says "the type or namespace ComFrm could not be found"

am i going the right way?

Thanks
private void _LoadCompanyList(object sender, ExecuteEventArgs e)
        {
            HomeRibbon.SetModes(1);   
            Athena.Companies.FrmCoList CoList = Application.OpenForms["Athena.Companies.FrmCoList"] as CompFrm ;
            if (CompFrm != null)
            {
                CompFrm.TopLevel = false;
                BodyPanel.Controls.Clear();
                CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                BodyPanel.Controls.Add(CompFrm);
                CompFrm.Show();
            }
            else
            {
                CompFrm = new Athena.Companies.FrmCoList(this);
                CompFrm.TopLevel = false;
                BodyPanel.Controls.Clear();
                CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                BodyPanel.Controls.Add(CompFrm);
                CompFrm.Show();
            }
        }

Open in new window

ok i fixed that code (below)
still getting the error, the error occurs on this code from the ribbon.cs file, was wondering if that would help

        /// <summary>
        /// Adds a ribbon control to the internal map
        /// </summary>
        /// <param name="ribbonControl">ribbon control to add</param>
        internal void AddRibbonControl(IRibbonControl ribbonControl)
        {
            _mapRibbonControls.Add(ribbonControl.CommandID, ribbonControl);
        }<-- ERROR HERE!
private void _LoadCompanyList(object sender, ExecuteEventArgs e)
        {
            HomeRibbon.SetModes(1);
            Athena.Companies.FrmCoList CompFrm = Application.OpenForms["Athena.Companies.FrmCoList"] as Athena.Companies.FrmCoList;
            if (CompFrm != null)
            {
                CompFrm.TopLevel = false;
                BodyPanel.Controls.Clear();
                CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                BodyPanel.Controls.Add(CompFrm);
                CompFrm.Show();
            }
            else
            {
                CompFrm = new Athena.Companies.FrmCoList(this);
                CompFrm.TopLevel = false;
                BodyPanel.Controls.Clear();
                CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                BodyPanel.Controls.Add(CompFrm);
                CompFrm.Show();
            }
        }

Open in new window

this is my new code which does get the right form but theres an error in this now :S

InvalidOpernationException was unhandled by user code
Collection was modified; enumeration operation may not execute.

this is on line 1
private void _LoadCompanyList(object sender, ExecuteEventArgs e)
        {
            HomeRibbon.SetModes(1);           
            foreach (Form OpFrms in Application.OpenForms)
            {
                if (OpFrms.Name == "FrmCoList")
                {
                    OpFrms.Activate();
                    return;
                }
                else {
                    Athena.Companies.FrmCoList CompFrm = new Athena.Companies.FrmCoList(this);
                    CompFrm.TopLevel = false;
                    BodyPanel.Controls.Clear();
                    CompFrm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                    BodyPanel.Controls.Add(CompFrm);
                    CompFrm.Show();
                }
            }
        }

Open in new window