Re: How to pass information, classes between forms in Windows Application mode



On Jul 22, 11:54 am, Jon Skeet [C# MVP] <sk...@xxxxxxxxx> wrote:

Alternatively, Form2 could have a parameterless constructor and you
could set properties, or call methods to pass it the information.
Constructors aren't the only way to pass information between objects.


What are the other ways? Passing a class that has a method X that
accepts other classes is of course one way, but for all practical
purposes it's the same as the parameterized copy constructor, with the
important difference of course that you can call this method X many
times, not just once. Another way is the inheritance of forms, Form2:
Form1 as you discuss below and as I further comment below. Another
way maybe is the publisher-subscriber events/delegates model? But I'm
not sure, since Forms, unlike Console mode, has some tricks to it
(discussed below).


I'm not entirely sure you're correct [UPDATE: after running the tests
below, I'm sure that a person--not you--but a person who says an
object that is passed to Form2 using the parametric constructor of
Form2 from Form1 is not passing the true object but a copy of the
object is not correct]

You're neither passing "the true object" nor a copy of the object.
You're passing a reference to the object.

Yes, because we're dealing with a managed language C#. Is that your
point? OK. A small point but noted.


if you say myClass2_that_exists_in_Form2 cannot
"actually refer to the Form1.myClass1 'variable' from Form2, since we
are passing by value, so it must refer to it.

No, not at all. You have passed the current value of the variable as
the argument. If you change the value of Form1.myClass1, there will be
no way for Form2 to retrieve it. It doesn't have access to the
*variable*.

Not true. You might have something else in mind. I am finding out
that both in what I call the non-inherited model of Form1: Form and
Form2: Form, where I use a parameterized constructor to pass the
class2 that has the information in it, and the inhereited model of
Form2: Form1, that you suggested, I am getting "data binding" between
the two forms in both directions. That is, with one small, trivial
bug exception that I discuss below with inherited controls, I am
getting both the public variable arr2 of Class2 to 'update' in both
the Form1 (parent) and Form2 (child) when I make a change to arr2 in
either parent or child forms (Forms 1 or Form 2, respectively). That
is data binding in both directions. It's working. The small
exception? When I inherit forms, Form 2 gets all the controls from
Form1 (which BTW is very confusing and I would never do this in
practice, but it's just a demo), and because of some obscure way form
controls are instantiated, or perhaps something else, when I try and
update arr2 using the inherited child form control button (but not the
parent form control button), I get an 'old' value. But this is a
minor bug or rather just an inherited control problem, or some small
thing. The main thing is that using my system or your system I am
getting data binding in both directions.


But I think you're
trying to say [THIS IS WHAT I TESTED BELOW--IT MAY NOT BE WHAT YOU
WERE SAYING, BUT IT WAS INTERESTING FOR ME--RL] it cannot permanently
change the variables (let's assume they are all public) in
Form1.myClass1 since we are not using the 'ref' keywords to pass by
reference.

Passing by reference would effectively give temporary (i.e. duration of
the constructor) access to the variable, yes.

But, even using non-pass-by-reference or pass-by-value, I'm getting
data binding in both directions, between parent and child (forms 1 and
2), like I said above. Even with pass-by-value when you change the
arr2[0] element of array arr2 in the child, the parent form shows it
also being changed, and when you change it in the parent the child
form class (which as a different name, but, we agree, it's the same
reference to the same object) also changes. In short, data binding in
both directions; it's working, insofar as I can tell.

However, you can't take
an arbitrary reference to an instance of Form1 and access its myClass1
variable from Form2, while the variable is private.

Yes. You keep saying this, and this is a newbie point well taken, but
we (I) am beyond that. One funny thing I keep forgetting is that C#
likes to always express access modifiers everywhere, with no access
modifier being private by default. But for this example I set
everything to public, using keyword 'public'. Everything, so this
point is moot? (but see the note at the end here about 'class0')


But, as we know, if you add the "ref" keyword, and with a
helper function we can change a class (we can put the helper function
in another class, or as a standalone function, that accepts 'ref
Class2'), however, the issue here is (and this may or may not be what
you have in mind) whether to use the above example
"myClass2_that_exists_in_Form2" can permanently change any public
variable in class "passClass2[1]_from_Form1", via changes made in
Form2, rather than Form1. [CHANGED TO '2' from '1' to be consistent]

Reference parameters do effectively change the situation somewhat, but
it's important to note that Form2 doesn't really know that it's
Form1.myClass1 that's been passed to it by reference. It could be a
local variable, or a variable from something completely different.

It could be, but for some reason, like I said, when you change the
parameter in Form 2, form Form1 is also updated, even when the forms
are not inherited. If you feel this fact is shocking, unjustified,
unexplained or whatever, let me know and I'll post the code. I think
it's routine myself--just conventional data binding when you pass one
class (or variable) to another. I'll tell you what I feel is
shocking, below (keep reading--keyword 'class0' and 'nested classes').


<snip>

Rather than me explaining reference parameters here, I suggest you read
my article on them:http://pobox.com/~skeet/csharp/parameters.html

This is the article that I mentioned that I already have btw. It
doesn't explain much for this forms example.


You still seem confused about the difference between passing a
reference by value and passing a parameter *by* reference. Changing the
*contents* of an object doesn't change the value of a variable which
refers to that object.

Agreed. So? I don't seem confused over that.


You should adjust your meaning of the word variable then. And no, a
class *object* isn't being declared - a *variable* is being declared.
Just because there's a variable doesn't mean any object is necessarily
being created. The variable may have a null value, or refer to an
object which was created elsewhere. For instance:

StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = sb1;

That has declared two variables, but only one object has been created.

Good point. I'll use variable then.

OK, here is what I found "shocking". I took your suggestion and for
one version of this program I used inheritance, like I said above, as
in Form1: Form and Form2: Form1 <--note the inheritance (the other
version, which also works, uses two 'independent' forms Form1: Form
and Form2: Form). Both the inherited and non-inherited versions use
the parametricized constructor to pass classes 1 and 2, but,
crucially, I added a third class, class 0, that was nested. This
class 0 was nested and declared public (twice) within Form1, and thus
could be 'seen' (by Intellisense, and ultimately by the program)
unlike declared Classes 1 and 2 (using "Add" to the Solution), which
had their own modules/translation units, unnested, outside of Form1.

Specifically, consider 'nested' class 0 as follows, which is properly
seen by base Form 1 and derived Form2. Comments //!! below

namespace MDIForms
{

public partial class Form1 : Form
{
Class1 myClass1; //though these are public, do they now become
'private' since no keyword public? That is the question!
Class2 aNew2Class; // " "

public Class0 myClass0; // !! keyword 'public' required!!
Shocking, no?!!

//note!!! 'FORWARD DECLARATION STEP' - required that keyword 'public'
be used here: public Class0 myClass0;/!! note this!!! nested class
'myClass0' will not be seen in Form2:Form1 if you don't use access
modifier keyword public here, even though public declared for this
class Class0 below! Further, you CANNOT comment out this line
(program won't compile)

public class Class0 //DEFINITION/CONSTRUCTION STEP - a nested
class within the public partial class Form1 : Form
{
public string str01;
public int interger01;
public Class0()
{
str01 = "hi";
interger01 = 1;

}
public Class0(int i, string s)
{
str01 = s;
interger01 = i;
}

}


public Form1()
{

InitializeComponent();

myClass0 = new Class0(47,"heyClass0base"); //!!
instantiation of the public nested class myClass0

}

private void clikMeNewFToolStripMenuItem_Click(object sender,
EventArgs e)
{

Form2 frm2 = new Form2(myClass1, aNew2Class); //!! note:
parameterized constructor does NOT send myClass0, but since public and
since nested within Form1, which is inherited by Form2, it is 'seen'
in Form2

frm2.Show();
}

// NOW TURNING TO Form2:

public Form2(Class1 passClass1, Class2 passClass2)
{
myClass2 = passClass2;
myNewClass1 = passClass1;

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)
{
string temp = myClass0.str01; //!! note--class0 *is* seen
by Form2, because it's a nested public class in base class Form1

MessageBox.Show("Class 0 from form2!: " + temp); //shows
"Class 0 from form2!: heyClass0base"
}

//////////////// END

The point: class 0 instantiated in the base class Form1 can only be
seen in derived class Form 2 iff three conditions are met:

(1) it must be nested within Form1

(2) it must be declared as public during the DEFINITION/CONSTRUCTION
STEP above

(3) importantly, it must in the declaration (what I call the FORWARD
DECLARATION STEP above) before the class is defined/constructed, be
declared as "public".

Perhaps, and I could use your input, the problem 'earlier' in this
thread is that classes 1 and 2, which are not nested, are not
explictly declared prior to the Form1 contructor with the keyword
'public', and, though in their respective modules I declare them as
'public', this makes them 'private' somehow when declared within Form
1 without the keyword 'public' (that is truly shocking if true).

Thanks for your help so far. I look forward to your reply.

RL
.