Still confused about passing data between forms (or classes)

A

AMP

Hello,

I have this in form1:
namespace Pass
{
public partial class Form1 : Form
{
public Form2 form2;
public Form1()
{
InitializeComponent();


}

private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.Show();
}

public void label1_Click(object sender, EventArgs e)
{

}

}
}


and I have this in form 2:
namespace Pass
{
public partial class Form2 : Form
{
public Form1 form1;
public Form2()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
form1.label1.Text = "I changed for you";
}
}
}

When I push the button in form1 I create and show form 2,
but when I push the button in form 2 , I get an error that it doesnt
know about form 1 anymore.
The label in form 1 is public.

Besides an explanation about what is wrong, I would like a good
explanation about passing classes and class properties around so any
class doesnt have a problem "seeing"them.

Much, Much Thanks
Mike
 
N

Nicholas Paldino [.NET/C# MVP]

Mike,

Why not just attach a property to your Form2 class like so:

public Form1 Form1
{
get
{
return form1;
}
set
{
form1 = value;
}
}

Then, when you create Form2, you do this:

Form2 form2 = new Form2();
form2.Form1 = this;
form2.Show();

Hope this helps.
 
A

AMP

This doesnt work.I'm probobly missing something.
I posted a question a few years ago concerning the same thing.And if I
remember correctly, I need to have a Field in both forms that reference
each other.
If you know of any working examples(samples) in c# online I would like
to know the urls.
I guess I need commented code.
Thanks
Mike


Mike,

Why not just attach a property to your Form2 class like so:

public Form1 Form1
{
get
{
return form1;
}
set
{
form1 = value;
}
}

Then, when you create Form2, you do this:

Form2 form2 = new Form2();
form2.Form1 = this;
form2.Show();

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

AMP said:
Hello,

I have this in form1:
namespace Pass
{
public partial class Form1 : Form
{
public Form2 form2;
public Form1()
{
InitializeComponent();


}

private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.Show();
}

public void label1_Click(object sender, EventArgs e)
{

}

}
}


and I have this in form 2:
namespace Pass
{
public partial class Form2 : Form
{
public Form1 form1;
public Form2()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
form1.label1.Text = "I changed for you";
}
}
}

When I push the button in form1 I create and show form 2,
but when I push the button in form 2 , I get an error that it doesnt
know about form 1 anymore.
The label in form 1 is public.

Besides an explanation about what is wrong, I would like a good
explanation about passing classes and class properties around so any
class doesnt have a problem "seeing"them.

Much, Much Thanks
Mike
 
B

Bill Woodruff

:

"This doesnt work.I'm probobly missing something. I posted a question a few
years ago concerning the same thing.And if I remember correctly, I need to
have a Field in both forms that reference each other. If you know of any
working examples(samples) in c# online I would like to know the urls. I
guess I need commented code."

.... snipped for, I hope, clarity and brevity ...

Mike, you should take any response from Nicholas Paladino
10-to-the-twentieth-power more seriously than any response from me, but this
is an area where I initially struggled, and then later simply learned to
relax : it wasn't as hard as I had made it in my head. Your mileage may
vary.

Consider you have a WinForm app that creates an instance of the basic Form1
at run-time. Take a look at your program.cs file where you'll see :

Application.Run(new Form1());

You add another WinForm, Form2, to your project in Visual Studio or whatever
IDE.

In the body of the Form2 Class definition you insert the 'Form1 property as
shown by Nicholas.

Now you define a 'Load EventHandler for Form1, inside that handler you
insert a pointer to Form1 itself into the property of Form2 named Form1.
There are other places where you could put that initialization code, but the
Load event is a common sense starting point.

That's what Nicholas is showing you in this code fragment : (I'm just
wrapping his code in a Load event handler)

// by declaring form2 here we make it available anwhere in the scope of this
Class (Form1)
private Form2 form2;

// the Load event is called automatically when Form1 is instantiated in the
Program.cs class in the Main routine of the application
private void Form1_Load(object sender, EventArgs e)
{
// set 'form2 to a new instance of the WinForm Class named Form2
form2 = new Form2();

// by assigning to the Form1 property of the new instance of Form2,
you are automatically using its 'set method.
// 'this will automatically refer to the running instance of Form1
itself
form2.Form1 = this;

// now show form2 : you have to make it appear ... but that could be
done later as required
form2.Show();
}


Now you may be thinking how can you get a pointer in Form1 to Form2 : well,
that one just requires you create a variable in Form1 that you can use
anywhere in Form1. Obviously if you create the 'form2 variable inside the
Load event handler, it will be scoped only to the Load event. That's why we
declare form2 outside the Load event.

Apologies to you and Nicholas if I have introduced any confusion into the
discussion.

best, Bill Woodruff
dotScience
Chiang Mai, Thailand
 
A

AMP

Thanks,
Im almost there...And I really appreciate all your help.THANKS
I can get the textbox in form1 to change from the button in form2
But... I have just a few more questions: I have commented the code with
my questions
First, the code...
Form 1

public partial class Form1 : Form
{
Q1->public Form2 form2; //Why are we holding a reference to form2
here?

public Form1()
{
InitializeComponent();



}

private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
Q2-> form2.propForm1 = this; //What is this doing?
form2.Show();

}

public void label1_Click(object sender, EventArgs e)
{

}

public void button2_Click(object sender, EventArgs e)
{
form2.label1.Text = "I changed for you also";
}

}
}


Form2:
public partial class Form2 : Form
{
Q3-> public Form1 form1; //Why the reference AND the following
property?
public Form1 propForm1
{
get
{
return form1;
}
set
{
form1 = value;
}



}



public Form2()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
form1.label1.Text = "I changed for you";
}
}
}


Q4-> How do I change the text in Form1. (The label is public)
 
T

travisj

I have a question about this that perhaps someone could enlighten me
about. For some time now I have been passing the reference from one
form to the other via the constructor of the second form as follows:

namespace Pass
{
public partial class Form1 : Form
{
public Form2 form2;
public Form1()
{
InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2(this);
form2.Show();
}
}

and then my second form would look like this:

namespace Pass
{
public partial class Form2 : Form
{
public Form1 form1;
public Form2(Form1 f1)
{
this.form1 = f1;
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
form1.label1.Text = "I changed for you";
}
}

}

Is there anything inherently wrong with the way I am doing things? It
has been working fine, I just want to make sure I am getting myself in
the habit of proper coding techniques.

Thanks,
Travis Calvert
 
B

Bruce Wood

travisj said:
I have a question about this that perhaps someone could enlighten me
about. For some time now I have been passing the reference from one
form to the other via the constructor of the second form as follows:

namespace Pass
{
public partial class Form1 : Form
{
public Form2 form2;
public Form1()
{
InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2(this);
form2.Show();
}
}

and then my second form would look like this:

namespace Pass
{
public partial class Form2 : Form
{
public Form1 form1;
public Form2(Form1 f1)
{
this.form1 = f1;
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
form1.label1.Text = "I changed for you";
}
}

}

Is there anything inherently wrong with the way I am doing things? It
has been working fine, I just want to make sure I am getting myself in
the habit of proper coding techniques.

Thanks,
Travis Calvert

Generally this is a bad idea. It comes with two problems.

First, you can only ever use a Form2 in conjunction with a Form1. If,
someday, you discover that it would be useful to have a Form2 working
together with a Form3, you're hooped.

Second, Form2 knows intimate details about how Form1 is put together.
If someday you decide that label1 shouldn't be a label after all, but a
RichTextBox (because you want to display something with fancy fonts or
formatting) then you're hooped.

There are two ways to improve your design. I always use the second, not
the first, but it depends upon your needs. Your current design is what
is called "very tightly coupled": a FOrm2 works _only_ with a Form1 and
knows about the internals of Form1.

The first alternative is less tightly coupled, so it's better, but not
optimal. First, you should replace a direct reference to
form1.textBox1.Text with a property. Second, you should create an
interface that declares that property. So:

public interface IHasGreeting
{
string GreetingText { get; set; }
}

Now you say that Form1 implements this interface:

public class Form1 : Form, IHasGreeting
{
...
public string GreetingText
{
get { return this.textBox1.Text; }
set
{
if (value == null) { throw new
ArgumentNullException("value"); }
this.textBox1.Text = value;
}
}
}

Finally, you say that Form2 will work with any form that implements
IHasGreeting:

public class Form2 : Form
{
IHasGreeting form1;

public Form2(IHasGreeting greetingForm)
{
this.form1 = greetingForm;
}

private void button1_Click(object sender, EventArgs e)
{
this.form1.GreetingText = "Hello world";
}
}

Of course, "GreetingText" should be some name descriptive of what the
thing is.

Notice that this does two things: first, Form2 no longer knows how
Form1 displays its text; second, Form2 will work with _any object_ that
implements IHasGreeting, whether it be a Form1, a Form3, or some other
object.

The second way involves even more loose coupling. This is the method I
tend to use. Have Form2 raise an event when something interesting
happens (the user presses the Hello button) and offer a property from
which a caller can fetch any required information. Form1 then
subscribes to this event and does whatever it wants to with the
information.

public class Form2 : Form
{
private string _greeting = "";

public event System.EventHandler UserSaidHello;

public string UserGreeting { get { return this._greeting; } }

private void button1_Click(object sender, EventArgs e)
{
this._greeting = "Hello world.";
if (UserSaidHello != null) { UserSaidHello(this,
System.EventArgs.Empty); }
}
}

public class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.UserSaidHello += new
System.EventHandler(form2_UserSaidHello);
form2.Show();
}

private void form2_UserSaidHello(object sender, System.EventArgs e)
{
Form2 f2 = (Form2)sender;
this.textBox1.Text = f2.UserGreeting;
}
}

Now Form2 is completely ignorant of the environment in which it is
being used. It notifies any interested parties when the user clicks the
button, and offers a property that interested parties can read when the
event happens. Any object can use Form2: just subscribe to the event.

One refinement to this second approach is to create a custom event
arguments type that passes the greeting string as part of the event,
but this is necessary only in certain multithreading scenarios, in
which the UserGreeting property could change between the time that the
event is raised and the time that the event handler fetches the
property value.

Either of these two approaches--an interface or an event--is better
than passing a form reference to another form, from an O-O point of
view.
 
T

travisj

Mr. Wood,

Thank you for taking the time to elaborate. Your sharing of knowledge
is greatly appreciated.

Travis Calvert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top