-3

I have two forms here and I want to call the function from one to the other in c# winform. I use events to do this, but they do not work. Every time I call changeTheme (), it throws me a System.NullReferenceException error: 'Object reference not set to an instance of an object.'

I tried to call her through the instance of the Main_form form, but it did not work either. I also tried the events, but when I added a function to make it so it was set to null again. But I'd like to do it with an event.

public delegate void statusChange();

public partial class Settings_form : Form
{
    public event statusChange changeTheme;

    //Here is some function, variables declaration and code

    private void UseDarkMode_chk_CheckedChanged(object sender, EventArgs e)
    {
        //Some code
        SettingsClass.UseDarkMode = this.UseDarkMode_chk.Checked;
        //if (changeTheme != null)
            changeTheme();
    }
}



public partial class Main_form : Form
{

    private void Form1_Load(object sender, EventArgs e)
    {

        callChangeTheme();
    }

    private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Settings_form settings_Form = new Settings_form();
        settings_Form.Show();
    }


    public void callChangeTheme()
    {
        Settings_form settings_Form = new Settings_form();
        settings_Form.changeTheme += new statusChange(chooseOtherTheme);
    }

    public void chooseOtherTheme()
    {
        if (SettingsClass.UseDarkMode)
            ToDarkMode();
        else ToLightMode();
    }

    public void ToDarkMode()
    {
        this.BackColor = Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(28)))), ((int)(((byte)(28)))));
    }

    public void ToLightMode()
    {
         this.BackColor = Color.FromArgb(((int)(((byte)(241)))), ((int)(((byte)(241)))), ((int)(((byte)(241)))));
    }
}
Ur-fault
  • 35
  • 5

2 Answers2

0

The null reference exception is happening because nothing is subscribed to your event.

Generally you'd create an event like this:

public event EventHandler<EventArgs> MyEvent;

It's a lot easier to read than the older event/delegate style but works in exactly the same way.

And fire it like this:

MyEvent?.Invoke(this, EventArgs.Empty);

That way it will only fire if you have subscribers. Again analogous to the if != null fire older style.

With that out of the way, there is a simpler way you can achieve what you want without events.

If you create a derived form and have the change code implemented there you can create the rest of your forms out of that then just call the change code directly:

Your new base form:

public MyDerivedForm : Form
{
    public MyDerivedForm()
    {
        InitializeComponent();
    }

    public void ChangeTheme(bool usedarkmode)
    {
        if (usedarkmode)
            ToDarkMode();
        else
            ToLightMode();
    }

    public void ToDarkMode()
    {
        this.BackColor = Color.FromArgb(28, 28, 28);
    }

    public void ToLightMode()
    {
        this.BackColor = Color.FromArgb(241, 241, 241);
    }
}

I've simplified your FromArgb calls. All your casting was completely superfluous.

Now derive all your other forms from MyDerivedForm:

public MainForm : MyDerivedForm
{
}

Just add a new form to the project and change the : Form to : MyDerivedForm

In your Settings_form you can just loop over all your opened forms and call the ChangeTheme function on each one which will then switch between light and dark mode.

public Settings_form: MyDerivedForm
{
    public Settings_form()
    {
        InitializeComponent();
    }

    private void UseDarkMode_chk_CheckedChanged(object sender, EventArgs e)
    {
        //Some code
        SettingsClass.UseDarkMode = this.UseDarkMode_chk.Checked;

        foreach(MyDerivedForm form in Application.OpenForms.OfType<MyDerivedForm>())
        {
            form.ChangeTheme(SettingsClass.UseDarkMode);
        }
    }
}
Handbag Crab
  • 1,488
  • 2
  • 8
  • 12
0

One big issue I notice is here:

public void callChangeTheme()
{
    Settings_form settings_Form = new Settings_form();
    settings_Form.changeTheme += new statusChange(chooseOtherTheme);
}

You're creating a new instance of Settings_form every time you call this method, but you never actually do anything with the instance - the only time you call Show() is on a completely different instance:

private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
{
    Settings_form settings_Form = new Settings_form();
    settings_Form.Show();
}

If you want to act Settings_form from your main form, you should be sure that you're always acting on the same instance.

Also, please do be mindful of subscribing and unsubscribing events in a way that guarantees that you don't accidentally end up with a memory leak. You can see more details on this here: Why and How to avoid Event Handler memory leaks?