Calling windows forms from a class in C#

J

Jon Hyland

Ok, I'm a little rusty on this, it should be a simple problem but I
can't figure it out. How can I handle form events in my main code
page??

I'm creating a Windows App in C#. Rather than make my main form the
startup object, I'd rather put my Main() function in a class or code
file. Why? Because thats what I always do in standard C++ or VB. In
my opinion, writing all my application logic in the form itself is
sloppy and only for quick and dirty apps.

So what I did was create a class called MyMain, put my Main() function
in it, and set my startup object to that class. In the Main()
function I am creating an instance of my main form (MainForm) and
showing it.

Here's my Main funciton (in my class)

//main entry point for application
[STAThread]
static void Main()
{
//init the context
context = new ApplicationContext();

//set the idle event handler
Application.Idle += new EventHandler(AppIdle);

//any other inits
//..

//display main form
if(context.MainForm == null)
{
try
{
context.MainForm = new NexusForm();
context.MainForm.Show();
}
catch (Exception error)
{
MessageBox.Show(error.Message, "", MessageBoxButtons.OK,
MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
Application.Exit();
}
}
}

When I run the application, the main form is displayed as expected.
Also, when I close the form, the application closes. My question is
this... I want to be able to fire off other functions in my class
(MyMain) from the Form events. For example, if I had a command
button, and I clicked on it, it would fire off the event handler for
that button. From that function all I want to do is call the real
function, which would reside in my main class (its parent object). I
don't want any functionality in this event.

I can't create an instance of my main class from the form -- the form
is already a child of that class. How would I do it? I tried
something like this:

this.Parent.MyRealFunction();

however, it doesn't work.

All the examples I can find concerning windows forms in .NET are
putting all the application logic in their main form. This does not
help me, I want my app independant of whatever forms I chose to
instanciate.

Thanks in advance,
Jon
 
S

Stefan

Hi Jon
Try to set the startup project in the projects properties
to your startup class
 
D

Daniel O'Connell

Jon Hyland said:
Ok, I'm a little rusty on this, it should be a simple problem but I
can't figure it out. How can I handle form events in my main code
page??

I'm creating a Windows App in C#. Rather than make my main form the
startup object, I'd rather put my Main() function in a class or code
file. Why? Because thats what I always do in standard C++ or VB. In
my opinion, writing all my application logic in the form itself is
sloppy and only for quick and dirty apps.

I agree with this mostly, but I see no problem with writing the form level
application code in the form. Things like event handling, etc that is very
specific to one form should be handled in the form rather than creating a
different class to do it. That approach will likely cause you more grief
than is nessecery. While moving the main out to its own class helps keep
things seperate, I think that is about all you should move out.

Instead, you should be seperating your core application code, the logic and
functionality that makes the app useful (outside of the UI of course) into
another class, or possibly another assembly if that is appropriate. This way
you can easily write the forms or other interfaces that interact with the
core of the application.
So what I did was create a class called MyMain, put my Main() function
in it, and set my startup object to that class. In the Main()
function I am creating an instance of my main form (MainForm) and
showing it.

Here's my Main funciton (in my class)

//main entry point for application
[STAThread]
static void Main()
{
//init the context
context = new ApplicationContext();

//set the idle event handler
Application.Idle += new EventHandler(AppIdle);

//any other inits
//..

//display main form
if(context.MainForm == null)
{
try
{
context.MainForm = new NexusForm();
context.MainForm.Show();
}
catch (Exception error)
{
MessageBox.Show(error.Message, "", MessageBoxButtons.OK,
MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
Application.Exit();
}
}
}

When I run the application, the main form is displayed as expected.
Also, when I close the form, the application closes. My question is
this... I want to be able to fire off other functions in my class
(MyMain) from the Form events. For example, if I had a command
button, and I clicked on it, it would fire off the event handler for
that button. From that function all I want to do is call the real
function, which would reside in my main class (its parent object). I
don't want any functionality in this event.

I can't create an instance of my main class from the form -- the form
is already a child of that class. How would I do it? I tried
something like this:

this.Parent.MyRealFunction();

however, it doesn't work.

As far as the form is concerned, the form is not a child of your created
class. The parent refers to the parent or containing control, if one exists,
not the object that instantiated it.
From what i'm reading here, you need a way to get your MyMain class from the
form. There are two problems I see, one is you are not creating an instance
of MyMain (Main() is a static member and does not require a class instance,
no instance of MyMain exists at this point), and the other is your not
publishing the reference in any manner. You should create an instance of
MyMain like so:

MyMain m = new MyMain(); //of course, use the proper constructor for your
purposes

and perhaps pass m into your form's constructor. Or you could use the
singleton pattern and expose the class via a static property or method. Jon
Skeet has an excellent article on this pattern at
http://www.pobox.com/~skeet/csharp/singleton.html
 
J

Jon Hyland

Sorry, I forgot a line in the code when I pasted it into the
message... it does call Application.Run(context), or else the
application wouldn't start. As for casting Parent to the type of my
class, how would I do that? I tried this but it didn't work:

//the button clicked event on my form
private void button1_Click(object sender, System.EventArgs e)
{
(NexusMain)this.Parent.TestButtonClicked();
}

I get this error on compile: Only assignment, call, increment,
decrement, and new object expressions can be used as a statement.

I'm hoping I don't have to make my form the startup object. I
shouldn't have to do that, I'd like the freedom to load whatever forms
I want to load, for example a splash screen, registration password,
whatever, if I want, before my main form is displayed (if it is
displayed). I can do that in C++ and standard VB easily. In VB, it
is as simple as creating a code page (not a class, however), and
putting the Main() function in that code page. The differance was,
this code page was not a class, so I could call its methods directly
from my form.
 
D

Daniel O'Connell

inline:
Jon Hyland said:
Sorry, I forgot a line in the code when I pasted it into the
message... it does call Application.Run(context), or else the
application wouldn't start. As for casting Parent to the type of my
class, how would I do that? I tried this but it didn't work:

//the button clicked event on my form
private void button1_Click(object sender, System.EventArgs e)
{
(NexusMain)this.Parent.TestButtonClicked();
}

I get this error on compile: Only assignment, call, increment,
decrement, and new object expressions can be used as a statement.

I reiterate: the Parent property of a Control class holds the container or
parent Control, not the instantiating object. To get at that object you will
need to provide it in some manner, as a parameter to a constructor or via a
static property.
Secondly, your Main call does not exist in an instance, it is a static
method. Until you create an instance of NexusMain, none exists.
I'm hoping I don't have to make my form the startup object. I
shouldn't have to do that, I'd like the freedom to load whatever forms
I want to load, for example a splash screen, registration password,
whatever, if I want, before my main form is displayed (if it is
displayed). I can do that in C++ and standard VB easily. In VB, it
is as simple as creating a code page (not a class, however), and
putting the Main() function in that code page. The differance was,
this code page was not a class, so I could call its methods directly
from my form.

"Nicholas Paldino [.NET/C# MVP]" <[email protected]>
 
D

Daniel O'Connell

Jon Hyland said:
Sorry, I forgot a line in the code when I pasted it into the
message... it does call Application.Run(context), or else the
application wouldn't start. As for casting Parent to the type of my
class, how would I do that? I tried this but it didn't work:

//the button clicked event on my form
private void button1_Click(object sender, System.EventArgs e)
{
(NexusMain)this.Parent.TestButtonClicked();
}

I get this error on compile: Only assignment, call, increment,
decrement, and new object expressions can be used as a statement.
Oh, forgot to mention, this is happening because you are trying to cast the
return type of this.Parent.TestButtonClicked() to NexusMain, instead of
casting this.Parent.
Something akin to
((NexusMain)this.Parent).TestButtonClicked();
would be the proper code, but it won't work in this case anyway because
parent does not reference an instance of NexuMain.
I'm hoping I don't have to make my form the startup object. I
shouldn't have to do that, I'd like the freedom to load whatever forms
I want to load, for example a splash screen, registration password,
whatever, if I want, before my main form is displayed (if it is
displayed). I can do that in C++ and standard VB easily. In VB, it
is as simple as creating a code page (not a class, however), and
putting the Main() function in that code page. The differance was,
this code page was not a class, so I could call its methods directly
from my form.

"Nicholas Paldino [.NET/C# MVP]" <[email protected]>
 

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