First, I suggest you study the references Sergey provided to you in his reply, particularly study his example of the use of an Interface to selectively expose fields, properties, or methods of one object/entity/Form/whatever to another.
Also, OriginalGriff has a series of three articles, published in September 2013, on CodeProject, that cover different ways one Form can communicate with another. Here's a link to the first article: [
^]. I strongly suggest you study his excellent articles.
I'll show you another way, in this response, to achieve your goal. Using this technique, you'll insert a pointer to a method in the instance of Form1 into the instance of Form3, so the instance of Form3 can use it directly. Note that in this technique the definition of the method in the instance of Form1 can be declared as 'private.
Here's the definition of the method in the code for the instance of Form1 (the Main Form):
public void MethodCalledFromForm3(string s1, string s2)
{
MessageBox.Show("function called from Form3 result: " + s1 + s2);
}
To make this usable within the instance(s) of Form3 you create we define a template in Form3's code for a method, using .NET's 'Action object [
^]:
public Action<string, string> MethodInForm1ToCall;
We have now created a kind of "socket" in Form3 instances into which can be plugged a reference (pointer) to any Method that takes two string arguments, and returns 'void. Technically, an Action is a form of 'Delegate, which you'll learn about as you study the MSDN link; its counterpart that takes a variable number number of arguments and returns a value of some Type, is 'Func.
So, how do we get the method in Form1 whose "signature" matches-up with our "socket" in Form3 "plugged-in" to the instances of Form3 ? It's really easy:
Form3 InstanceOfForm3 = new Form3();
private void Form1_Load(object sender, System.EventArgs e)
{
InstanceOfForm3.MethodInForm1ToCall = MethodCalledFromForm3;
}
You'll note that I have deliberately not tried to match what you are doing in your code in what's shown here; the reason for this is I hope to make a more generally useful example.
Now, let's put it all together in a "big-picture-view:"
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Form2 InstanceOfForm2 = new Form2();
private Form3 InstanceOfForm3 = new Form3();
private void Form1_Load(object sender, System.EventArgs e)
{
InstanceOfForm2.PropertyInstanceOfForm3 = InstanceOfForm3;
InstanceOfForm3.MethodInForm1ToCall = MethodCalledFromForm3;
}
private void button1_Click(object sender, System.EventArgs e)
{
InstanceOfForm2.Show();
}
private void MethodCalledFromForm3(string s1, string s2)
{
MessageBox.Show("function called from Form3 result: " + s1 + s2);
}
}
In Form2:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public Form3 PropertyInstanceOfForm3 { set; get; }
private void button1_Click(object sender, EventArgs e)
{
PropertyInstanceOfForm3.Show();
}
}
In Form3:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
public Action<string, string> MethodInForm1ToCall;
private void button1_Click(object sender, EventArgs e)
{
MethodInForm1ToCall("I was triggered ", "by clicking the Button in the instance of Form3");
}
}
In this example Form2 and Form3 instances are created
once, in Form1's code. Form1's code
injects a reference to the instance of Form3 into Form2, and
injects, as explained in detail above, the pointer to the method in Form1 into Form3.
If you can understand what's going on here, you should be able to easily adapt this for your code. In your specific case the 'Action template (delegate) will take no arguments, and you will need to insert the Method on Form1 that matches the Action into Form3
each time you create a new version of it.
Please feel free to ask questions by comments on this answer.