how to do a call back between forms

  • Thread starter Thread starter edepperson
  • Start date Start date
E

edepperson

I've been looking for an answer to this problem and have seen the same
question posted on other forums... but still no answer. My background
is Delphi2 - 7 and I used to do this all the time with method pointers
and callbacks. I am currently using VS2005.

here is the scenario

frmMain is created with a label and a button.
frmSecond is a new class, possibly a different namespace, and has a
textbox.

When you click the button on frmMain, frmSecond is created and shown.
( not necessarily modal)

I do NOT want to add a reference to frmSecond for frmMain.

I DO want to have frmMain notified of any event/user action on
frmSecond. For example, as you type text into frmSecond.textbox, that
same text is displayed in the label on frmMain.

1) is this possible, if so how would I do it?
2) is this necessary for encapsulation? (I think it should be, but
when you transition between languages, you need to learn to think a
different way. So if I'm thinking about this all wrong, please tell
me)

depperson
 
There are multiple ways of doing this.
try this
class frmMain : Form
{
......
void LoadfrmSecond()
{
frmSecond frm2 = new frmSecond();
frm2.Show();
}
}

Does this answer your question
 
There are multiple ways of doing this.
try this
class frmMain : Form
{
.....
void LoadfrmSecond()
{
frmSecond frm2 = new frmSecond();
frm2.Show();

}
}

Does this answer your question

No, I know how to do that. What I don't know how to do is have
frmMain notified when an event takes place on frmSecond unless I add
frmMain to the references for frmSecond.

Here is a super abbreviated way to do it in delphi

frmSecond
Type
TsendString = procedure (s : string) of Object;

frmSecond = class (Tobject)
// published
private
fsendString : TsendString
procedure DoSomething;
public
property sendString : TsendString read fsendString write
fsendString;
end

implementation
procedure TfrmSecond.DoSomething;
begin
fsendString( keystroke value); // not really the way it was, just
trying to be short
end;

// now here is how it was used from frmMain

frmMain
declarations & fields

implementation

TfrmMain.ButtonClick(Sender : TObject)
begin
frmSecond := TfrmSecond.Create(self);
frmSecond.sendString := GetAString;
frmSecond.Show;
end;

procedure TfrmMain.GetAString(s : string);
begin
label.caption := label.caption + s;
end;

The reason I want this is frmSecond had zero dependancy on frmMain.

The reason it worked is the method in frmMain had a parameter
footprint identical to the public property sendString in frmSecond.
Basically what you did was assign the address of frmMain.GetAString to
frmSecond.sendString.

depperson
 
I must have misread the I DO and I DO not part
Here is a implementation that you are looking at

Both your forms will have to be initiated from inside a outside class
This class (and may be your forms also) will have delegates that will
talk to the functions inside your forms

Read into delegates in C#. They can be thought of as equivalent to C++
function pointers but in reality are much more powerful and object
oriented.
 
You may also be looking at a Multi Threaded architecture here since
you are dealing with multiple forms
I'd also suggest some reading into Thread Safety with Multi Threaded
Windows Form Applications

Sorry, but example code would have to include an entire project
 
I must have misread the I DO and I DO not part
Here is a implementation that you are looking at

Both your forms will have to be initiated from inside a outside class
This class (and may be your forms also) will have delegates that will
talk to the functions inside your forms

Read into delegates in C#. They can be thought of as equivalent to C++
function pointers but in reality are much more powerful and object
oriented.
now we're on the same page! any sample code. I've been studying on
delegate, but frankly I'm having a hard time getting my kludgy old
mind around it. ;-)
 
depperson

try creating an event for frmSecond and having frmMain subscribe to that
event.

james
 
The only good way to understand delegates is to practice them.

Ok, here is the example project

Program.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class Program
{
static void Main(string[] args)
{
MainClass MC = new MainClass();
MC.InitClasses();
MC.TestMessageToA();
MC.TestMessageToB();
}
}
}

MainClass.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class MainClass
{

public delegate void CallFromA(string x);
public delegate void CallFromB(string x);
private CallFromA CFA;
private CallFromA CFB;
public MainClass()
{

}
public void InitClasses()
{
ClassA A = new ClassA();
ClassB B = new ClassB();
CFA = new CallFromA(A.CallFromMain);
CFB = new CallFromA(B.CallFromMain);
}
public void TestMessageToA()
{
CFA("This arrived from Main");
}
public void TestMessageToB()
{
CFB("This arrived from Main");
}
public static void CallFromAB(string x)
{
Console.WriteLine("Message Displayed in Main:\t" + x);
}

}
}


ClassA.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class ClassA
{
public delegate void CallToMain(string x);
CallToMain CTM;
public ClassA()
{
CTM = new CallToMain(MainClass.CallFromAB);
CTM("Object from ClassA is Created");
}
public void CallFromMain(string x)
{
Console.WriteLine("Message Displayed in A:\t" + x);
}
~ClassA()
{
CTM("Object from ClassA is Destroyed");
}
}
}

ClassB.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class ClassB
{
public delegate void CallToMain(string x);
CallToMain CTM;
public ClassB()
{
CTM = new CallToMain(MainClass.CallFromAB);
CTM("Object from ClassB is Created");
}
public void CallFromMain(string x)
{

Console.WriteLine("Message Displayed in B:\t" + x);
}
~ClassB()
{
CTM("Object from ClassB is Destroyed");
}
}
}
 
The only good way to understand delegates is to practice them.

Ok, here is the example project

Program.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class Program
{
static void Main(string[] args)
{
MainClass MC = new MainClass();
MC.InitClasses();
MC.TestMessageToA();
MC.TestMessageToB();
}
}

}

MainClass.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class MainClass
{

public delegate void CallFromA(string x);
public delegate void CallFromB(string x);
private CallFromA CFA;
private CallFromA CFB;
public MainClass()
{

}
public void InitClasses()
{
ClassA A = new ClassA();
ClassB B = new ClassB();
CFA = new CallFromA(A.CallFromMain);
CFB = new CallFromA(B.CallFromMain);
}
public void TestMessageToA()
{
CFA("This arrived from Main");
}
public void TestMessageToB()
{
CFB("This arrived from Main");
}
public static void CallFromAB(string x)
{
Console.WriteLine("Message Displayed in Main:\t" + x);
}

}

}

ClassA.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class ClassA
{
public delegate void CallToMain(string x);
CallToMain CTM;
public ClassA()
{
CTM = new CallToMain(MainClass.CallFromAB);
CTM("Object from ClassA is Created");
}
public void CallFromMain(string x)
{
Console.WriteLine("Message Displayed in A:\t" + x);
}
~ClassA()
{
CTM("Object from ClassA is Destroyed");
}
}

}

ClassB.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Deligates
{
class ClassB
{
public delegate void CallToMain(string x);
CallToMain CTM;
public ClassB()
{
CTM = new CallToMain(MainClass.CallFromAB);
CTM("Object from ClassB is Created");
}
public void CallFromMain(string x)
{

Console.WriteLine("Message Displayed in B:\t" + x);
}
~ClassB()
{
CTM("Object from ClassB is Destroyed");
}
}

}

now we're on the same page! any sample code. I've been studying on
delegate, but frankly I'm having a hard time getting my kludgy old
mind around it. ;-)- Hide quoted text -

- Show quoted text -

Thanks. I'll also be trying Swindoll's suggestion for an event. I
figure if I keep digging at it, sooner (hopefully) or later I'll
comprehend. I sure appreciate the help
depperson
 
depperson

try creating an event for frmSecond and having frmMain subscribe to that
event.

Noting, of course, that whether you explicitly reference frmMain, have
frmMain provide a delegate directly to frmSecond, or have frmMain add a
delegate to an event used by frmSecond, in all cases frmSecond retains
some kind of reference to frmMain.

IMHO, the basic design goal isn't practical. The second form could, upon
needing to signal something to the main form, search all open forms for
the application and somehow pick the one to signal. But it would still
need to make some assumptions about the nature of the form (for example,
checking for a specific class so that it knows a particular method is
available for calling).

At some level, the second form *must* have some sort of dependency on any
other forms it's going to communicate with. Whether that's in the form of
an explicit reference, an implicit reference, or simply some code design
dependency, the dependency exists.

Oh, and by the way...don't get distracted by the "multi-threading" comment
someone else made. There's no multi-threading going on unless you
explicitly put the second form in a second thread. Otherwise, both forms
use the same thread.

Pete
 
Noting, of course, that whether you explicitly reference frmMain, have
frmMain provide a delegate directly to frmSecond, or have frmMain add a
delegate to an event used by frmSecond, in all cases frmSecond retains
some kind of reference to frmMain.

IMHO, the basic design goal isn't practical. The second form could, upon
needing to signal something to the main form, search all open forms for
the application and somehow pick the one to signal. But it would still
need to make some assumptions about the nature of the form (for example,
checking for a specific class so that it knows a particular method is
available for calling).

At some level, the second form *must* have some sort of dependency on any
other forms it's going to communicate with. Whether that's in the form of
an explicit reference, an implicit reference, or simply some code design
dependency, the dependency exists.

Oh, and by the way...don't get distracted by the "multi-threading" comment
someone else made. There's no multi-threading going on unless you
explicitly put the second form in a second thread. Otherwise, both forms
use the same thread.

Pete

Well, I figured out how to do it with delegates, and I don't think
frmSecond has any open dependancies on frmMain. Even though there is
not barrier to a circular reference, I'm not doing it, and this
approach makes frmSecond truly portable.

heres what I did.

in frmSecond declare
public delegate void CallToMain(string x);
public CallToMain CTM;

then on a key event do this:
private void tbEntry_KeyUp(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if (CTM != null)
CTM(e.KeyData.ToString());
}

now in frmMain, where creating frmSecond, it will look like this
private void button1_Click(object sender, System.EventArgs e)
{
FrmSecond f = new FrmSecond ();
f.CTM = new Form2.CallToMain(setText);
f.Show();
}

and method setText looks like this:
private void setText(string s)
{
lblcount.Text = lblcount.Text + s;
}

Granted, this isn't very pretty, and is functionally useless, but its
what I wanted, and frankly, I think the design accomplishes its
purposes

depperson
 
[...]
and method setText looks like this:
private void setText(string s)
{
lblcount.Text = lblcount.Text + s;
}

Granted, this isn't very pretty, and is functionally useless, but its
what I wanted, and frankly, I think the design accomplishes its
purposes

Is "setText()" declared in your main form or the second form?

Based on your original statement about what you wanted to do, I assume
it's declared in your main form. And that's exactly the reference to the
main form that exists within your second form that I'm talking about. In
your second form, you have a delegate instance that points to the method
"setText()" in the main form. But the delegate itself refers to the main
form instance you used to create the delegate.

You don't have an *explicit* reference to the main form in the second
form, but you most definitely have a reference. That was my point.
There's no way to do anything in the main form without having a reference
*somewhere* in the main form. You can either store that reference, or you
can derive it every time you need it (by searching all of the existing
form instances), but you have to have it.

I don't see the point of the code you posted, not in the context of your
stated goal.

In your original post, you said that you wanted the main form to be
notified of soemthing that happened in the second form. The code you
posted doesn't do that.

Pete
 
[...]
In your original post, you said that you wanted the main form to be
notified of soemthing that happened in the second form. The code you
posted doesn't do that.

Of course, this last paragraph of mine is poorly constructed. What I
meant is that the original goal seemed to be that you wanted the main form
to be notified of something that happened, without storing a reference to
the main form in the second form. It's the second part of that goal that
is not addressed by the code you posted.

Sorry for any confusion.

Pete
 
Noting, of course, that whether you explicitly reference frmMain, have
frmMain provide a delegate directly to frmSecond, or have frmMain add a
delegate to an event used by frmSecond, in all cases frmSecond retains
some kind of reference to frmMain.

IMHO, the basic design goal isn't practical. The second form could, upon
needing to signal something to the main form, search all open forms for
the application and somehow pick the one to signal. But it would still
need to make some assumptions about the nature of the form (for example,
checking for a specific class so that it knows a particular method is
available for calling).

At some level, the second form *must* have some sort of dependency on any
other forms it's going to communicate with. Whether that's in the form of
an explicit reference, an implicit reference, or simply some code design
dependency, the dependency exists.

I think you misunderstand what the OP means by "dependency". I believe
that what the OP means is that there should be no static dependency:
the second form's code should not have to "know about" the first form
as such. I believe that he means... the usual meaning of "dependency".

I doubt that the OP objects to the second form having some sort of
reference or pointer to the first form at run time as an event
subscriber. This does not introduce maintenance / scoping problems in
the code. I believe that's the point.

Anyway, for my money the "correct" way to solve this problem is to
have the second form publish an event and a property. Whenever
something of interest happens on the second form it raises the event.
Any subscribers are then at liberty to query the property / properties
in order to get information from the second form.

The first form then subscribes to the event and, whenever it's raised,
reads the second form's property in order to get the current text from
it.

IMHO this is a more general solution than the delegate one: it uses an
idiom that pervades Windows Forms: controls raise events when
properties change. Interested parties can subscribe to the events and
use the properties to get information out of the control.
 
I think you misunderstand what the OP means by "dependency". I believe
that what the OP means is that there should be no static dependency:
the second form's code should not have to "know about" the first form
as such. I believe that he means... the usual meaning of "dependency".

Only the OP can clarify what he meant. However, he specifically wrote "I
do NOT want to add a reference to frmSecond for frmMain". The word
"reference" has a very specific meaning in this context, and absent any
explicit statement that it's being used for something else, it seems to me
that one ought to assume it means what it always means.

The word "dependency" was one that I introduced. It can mean a variety of
things, but in this situation what it means (or could mean) doesn't really
relate to the original post, since the OP didn't use that word.

I do agree with you that using an event that the main form can subscribe
to seems like a very natural and appropriate way to solve the issue. But
in that case (as in other solutions) there is a reference to the main form
stored (added) in the second form. Even though I think it's the right way
to do what the OP wants, it's not clear that it fits his stated goal.

The fact is, the original post was poorly written. This is a common
problem here (and pretty much anywhere else that people are allowed to
write in and ask questions). It's very hard to say for sure _what_ the OP
actually wants to do, since one has to reinterpret the question and make
assumptions contrary to the obvious definitions of words used in the post
in order to come up with an answer that fits within the qualification of
"good coding practices".

When this happens, some times it means that the OP wants to do something
that isn't a good coding practice. Other times it means that the OP wants
to follow good coding practices, but simply hasn't stated their question
correctly. Unfortunately, either way one has to make an assumption about
the post, and whatever the assumption there is always a chance it's the
wrong one. :(

I don't know that I made the correct assumption, but neither have I seen
any evidence yet to suggest that I didn't. Frankly, I think it's a good
thing that multiple people make different assumptions and answer the
question different ways. That way, hopefully at least _someone_ winds up
writing something that's useful to the OP. :)

Pete
 
Only the OP can clarify what he meant. However, he specifically wrote "I
do NOT want to add a reference to frmSecond for frmMain". The word
"reference" has a very specific meaning in this context, and absent any
explicit statement that it's being used for something else, it seems to me
that one ought to assume it means what it always means.

The word "dependency" was one that I introduced. It can mean a variety of
things, but in this situation what it means (or could mean) doesn't really
relate to the original post, since the OP didn't use that word.

I do agree with you that using an event that the main form can subscribe
to seems like a very natural and appropriate way to solve the issue. But
in that case (as in other solutions) there is a reference to the main form
stored (added) in the second form. Even though I think it's the right way
to do what the OP wants, it's not clear that it fits his stated goal.

The fact is, the original post was poorly written. This is a common
problem here (and pretty much anywhere else that people are allowed to
write in and ask questions). It's very hard to say for sure _what_ the OP
actually wants to do, since one has to reinterpret the question and make
assumptions contrary to the obvious definitions of words used in the post
in order to come up with an answer that fits within the qualification of
"good coding practices".

When this happens, some times it means that the OP wants to do something
that isn't a good coding practice. Other times it means that the OP wants
to follow good coding practices, but simply hasn't stated their question
correctly. Unfortunately, either way one has to make an assumption about
the post, and whatever the assumption there is always a chance it's the
wrong one. :(

I don't know that I made the correct assumption, but neither have I seen
any evidence yet to suggest that I didn't. Frankly, I think it's a good
thing that multiple people make different assumptions and answer the
question different ways. That way, hopefully at least _someone_ winds up
writing something that's useful to the OP. :)

Pete

The fact is, the original post was poorly written. This is a common
problem here (and pretty much anywhere else that people are allowed
to
write in and ask questions). It's very hard to say for sure _what_
the OP
actually wants to do, since one has to reinterpret the question and
make
assumptions contrary to the obvious definitions of words used in the
post
in order to come up with an answer that fits within the qualification
of
"good coding practices".

Thats hard. The fact is, if "the original post was poorly written" it
was done so because I didn't know how to ask the question. Not
because I didn't know what I wanted to accomplish. So I would
encourage you not to be so harsh on the learner or so elitist in your
response. It always falls to the teacher to try to understand where
the student is and instruct them to where they need to be. If you
don't want to do that, you shouldn't presume to be a teacher.

A second fact is, I want to know the best way to accomplish my
objective. I don't think I would have spent two weeks asking
questions and searching the net and finally posting on a few use group
if I wasn't interested in resolving in the best manner possible that
follows OOP principles.

Finally, just a question -- I'm curious. Once you saw what I was
trying to accomplish, why didn't you respond with a sample of "here's
a better way to do what you are trying to do" and the principles of
why? I think it might have required less typing and it certainly
would have been helpful.

My hats off to Karim and Swindell for their help
 
Thats hard. The fact is, if "the original post was poorly written" it
was done so because I didn't know how to ask the question. Not
because I didn't know what I wanted to accomplish.

No doubt YOU know what you want to accomplish. However, *I* still don't
and I doubt anyone else reading this thread does either. Furthermore,
knowing what you want to accomplish and being able to do that are two
different things. It is still not clear that what you want to accomplish
is within the realm of possibility.

However, since you refuse to elaborate on your question, I guess we'll
never know.
So I would
encourage you not to be so harsh on the learner or so elitist in your
response. It always falls to the teacher to try to understand where
the student is and instruct them to where they need to be. If you
don't want to do that, you shouldn't presume to be a teacher.

It also falls on the student to show some humility when it becomes
apparent that they need more information than that which they asked for,
and to acknowledge that there is room for improvement in learning how to
do things. If you don't want to do that, you shouldn't presume to be a
student.

The fact is, before my reply to Bruce to which you took the time to reply,
I made two other posts -- one in direct reply to your own -- pointing out
the discrepancy between what you claim to want to do and what is actually
possible. You have had ample opportunity to clarify your question, and
yet you instead choose to find the one post where some offense might be
taken if one is looking to do so and respond to that.
A second fact is, I want to know the best way to accomplish my
objective. I don't think I would have spent two weeks asking
questions and searching the net and finally posting on a few use group
if I wasn't interested in resolving in the best manner possible that
follows OOP principles.

Then why aren't you paying attention to the suggestions given you here?
Finally, just a question -- I'm curious. Once you saw what I was
trying to accomplish, why didn't you respond with a sample of "here's
a better way to do what you are trying to do" and the principles of
why?

Because I *still* don't know what you're trying to do. The solution you
posted does not match the stated goal. Until you resolve the discrepancy
by explaining what it is you *really* want to do, there's not much I can
do to help you.

I *did* take the time to point out *why* the solution you posted does not
match the stated goal, but you've shown no inclination to acknowledge that
discrepancy, nor have you shown any inclination to resolve it by
explaining either a) that you stated your goal incorrectly and that a
reference to the main class is indeed fine with you, or that b) your
posted solution turns out to not achieve the goal of avoiding a reference
to the main class after all.
I think it might have required less typing and it certainly
would have been helpful.

The help is there, should you take the chip off your shoulder, actually
read what's posted, and respond in a way that allows those of us posting
to refine our answers.
My hats off to Karim and Swindell for their help

James made an assumption (possibly correct, possibly not) about what
you're trying to do. But your posted solution does not follow his
suggestion, nor would either solution posted meet your stated goal of not
wanting a reference to the main class in the secondary class. Karim's
suggestion isn't helpful IMHO, but if it is you should explain why it is
as that would help us understand better what it is you're really trying to
do.

You left out Bruce, who suggested substantially the same thing that James
did and took the time to elaborate on *why* it's a good suggestion. You
don't appear to have taken either suggestion as a solution to your problem.

In other words, you took the time to complain about the responses you've
given, but you still haven't bothered to clarify what it is _you actually
want to do_, nor do you seem to have noticed that I have posted my own
messages in this thread aimed solely at trying to help you.

Forgive me if I find your attitude overly defensive and lacking in the
kind of humility that someone who is truly trying to learn would have.
This isn't a daycare where your every need is to be catered to or where
everyone here should be expected to hold your hand. Some people are
willing to hold your hand, no doubt, but if you aren't prepared also for
people who are just going to tell you how it is while at the same time
doing their best to navigate the bewildering array of what passes for a
question here, then you would be better off to find a different source for
answers.

Here's a suggestion: when someone points out to you that your question
doesn't make sense, your next action should be to try to reword the
question so that it does make sense, using the feedback regarding the
question you've received so far. When you've done that and you are
*still* getting grief, then you might have cause to complain. Until then,
you don't really seem to be as student-like as you claim to be.

Pete
 
Back
Top