0

I'm trying to update my data on a main form whenever I change some option in a secondary form.

Possible solution:

Make the method public on Form1 (the main form) like this:

public void updatedata()
{
//data update
}

And then call it on the secondary form:

Form1.updatedata()

This doesn't work and I believe it's because he is trying to update the Form2

I'm using partial classes, but I'm not very well versed on them.

public partial class Form1 : Form
{
  public Form1()
  {
  InitializeComponent();
  }
}

And the secondary one:

 public partial class formOpConfig : Form
{
   private Form1 Opener { get; set; }



    public formOpConfig(Form1 opener)
    { //initialize component
    }
}
ng80092b
  • 621
  • 1
  • 9
  • 24

3 Answers3

1

I feel like surely there is a duplicate question to match this one. But I have been unable to find it.

Given the code you posted, your attempt probably would have worked had you used Opener.updatedata() instead of Form1.updatedata(). But that still would not have been the best solution.

Commenter John Saunders is correct, the right way to do this is to declare an event in formOpConfig, and then have Form1 subscribe to it. That looks more like this:

public partial class formOpConfig : Form
{
    public event EventHandler UpdateData;

    private void SomethingHappens()
    {
        // do stuff...
        OnUpdateData();
        // maybe do other stuff too...
    }

    private void OnUpdateData()
    {
        EventHandler handler = UpdateData;

        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

The above declares an event, and raises that event (invokes the handlers) at the appropriate time (i.e. when SomethingHappens()).

public partial class Form1 : Form
{
    private void OpenConfigForm()
    {
        OpenConfigForm opConfig = new formOpConfig();

        opConfig.UpdateData += (sender, e) => updatedata();
    }

    // Note that this method is private...no one else should need to call it
    private void updatedata()
    {
        //data update
    }
}

Here, Form1 subscribes to the event when it creates the instance of formOpConfig (I am assuming Form1 is what creates that instance), and when its handler is invoked, it calls the updatedata() method you've already written.

In this way, the two classes remain decoupled; i.e. they are not actually dependent on each other, more than they need to be (in particular, the formOpConfig class doesn't need to know anything about Form1).

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Very nice answer, But why do I have to use the `sender` and `e` keywords? I ask this because I was opening the `Form2` using a `toolstrip` option which already used them. I had to create a separate form like your `OpenConfigForm()` to be able to use your solution. I was opening it on `private void configuraçãoToolStripMenuItem_Click(object sender, EventArgs e)` – ng80092b May 04 '15 at 00:54
  • `(sender, e) => updatedata()` is a "lambda expression", and is the actual event handler for the `UpdateData` event in my example. The `sender` and `e` are the required arguments for the handler. You can do the same thing without an `OpenConfigForm()` method...just move the code from my example into your `..._Click` event handler method instead. I can't offer anything more specific than that, because your question doesn't include the code where you are opening the `formOpConfig` form. – Peter Duniho May 04 '15 at 02:04
1

A good way to do this is to use an Event.

This allows you to decouple the forms because they do not even need a reference to each other; basically an event is a way for your second form to tell whoever might be listening (without having to exactly know who) that something of interest happened, and to give them some information about that interesting event that they can use.

The linked article will give you much more detail than the below, which is just a quick idea of how to do it; I would recommend working through the tutorial!

The mechanism by which this occurs is that anyone who wants to know about interesting events on Form2 has to subscribe to the corresponding event on Form2; then whenever Form2 wants to tell its listeners that something has happened, it invokes any event handlers that have been attached to the event.

Because an event can have multiple handlers, it's a really excellent way to keep components in your application decoupled.

Quick demo

(note: code below is off top of head so not tested, no error handling, etc.)

First of all, you need to declare a class that can be used to send the interesting data to listening parties. This class has to inherit from System.EventArgs

public class InterestingEventArgs:EventArgs
{
   public string AnInterestingFact {get;private set;}
   public InterestingEventArgs(string fact)
   {
     AnInterestingFact =fact;
   }
}

It doesn't matter where you declare this as long as it's visible to both Form1 and Form2.

Next, you have to declare an event on Form2, it needs to be public and should look like this:

public event EventHandler<InterestingEventArgs> SomethingInterestingHappened;

Now you need to decide when you are going to tell interested parties about this event. Let's suppose you have a button on Form2 and you want to raise the event when you click it. So in the Click handler for the button, you might have code like this:

public void btnRaiseEvent_Clicked(object sender, EventArgs e)
{
   var fact= txtFact.Text;
   var handler = SomethingInterestingHappened;
   if (handler!=null)
   {
      handler(this,new InterestingEventArgs(fact));
   }
}

and finally here is how the code might look from Form1 when you are launching Form2, let's say you click a button on Form1 to launch Form2:

public void btnShowForm2_Clicked(object sender, EventArgs e)
{
   var child = new Form2();
   child.SomethingInterestingHappened+=OnSomethingInterestingHappened;
   child.Show();
}

Finally you need to write an event handler on Form1 that will be called when the event is raised:

void OnSomethingInterestingHappened(object sender, InterestingEventArgs e)
{
   MessageBox.Show("Did you know? " + e.AnInterestingFact);
}
Community
  • 1
  • 1
Stephen Byrne
  • 7,400
  • 1
  • 31
  • 51
0

It looks like you have passed in a reference to a Form1 object in the constructor. Use it:

public partial class formOpConfig : Form
{
    private Form1 Opener { get; set; }

    public formOpConfig(Form1 opener)
    { 
        Opener = opener;
    }

    private void updateForm1()
    {
        Opener.updatedata();
    }
}

Form1 is a class, not an object. You can say Form1.updatedata() if you make updatedata() a static method of the Form1 class, but that is probably not compatible with the rest of your code.

Douglas Zare
  • 3,296
  • 1
  • 14
  • 21