Need Help with Multi Form handling

  • Thread starter Thread starter Tim Geiges
  • Start date Start date
T

Tim Geiges

Since I am being challenged with learning c# I figured I could pass
some of the pain on to you guys :-)
I have another question(this one is important for me to fix before I
can get my app to Beta)

My app (an image viewer) opens with a Main form with a file explorer if
you open the program with the exe, but opens with the ImageView form if
you double click an image file, if you want to see the Main form once
the ImageView is open the menu has a Show Main option, and that works,
but if I click it again from the ImageView window it opens another
instance of Main form, and the same with when I open an image from the
file explorer every time I click another file it opens another
ImageView form instead of reusing the same one.

Can someone help point me in the right direction.
I appreciate all the help I have recieved, you guys rock.

Thanks,
Tim Geiges
 
Hi Tim

I have been looking for an elegant solution to this for a bit... but I
really can't say I've found one.

However, I had to solve the same problem with an application of mine that
had MDI children. The way I tackled this was to go through all of the MDI
children of my form... check their names to see if I had allready open an
instance of a form with a specific name. If there was, I would use the
focus method of that form since we get a reference of the object from the
form's MDI children collection. If there wasn't, I create a new instance of
the required form.

I don't have any code off-hand, but if you are really interested I could go
and look at my old codes. I have not have a need for such a thing for a
while so my memory is a bit rusty.

hope that help!
 
Does anyone have an example of how to check if a form is already open,
and not open a new one, and refresh the contents of the existing form,
so I can update the picture in the picturebox, instead of opening a new
window
 
Read up on the Singleton pattern. You want to do something similar,
although you can't use it precisely as it is, because Visual Studio
needs to instantiate a copy of your form in order to be able to show it
in the design window. So, you can use a "cheating" version of the
Singleton pattern in each applicable form:

public class ImageView : Windows.Forms.Form
{
private static ImageView singleton = null;

public static ImageView GetImageView()
{
if (ImageView.singleton == null)
{
ImageView.singleton = new ImageView();
}
return ImageView.singleton;
}

public void Dispose()
{
ImageView.singleton = null;
}

... rest of your form code...
}

Then you never say "new ImageView()" anywhere in your code... you just
call ImageView.GetImageView() whenever you want it. If it doesn't
already exist it will be created; if it does, you will be given the one
that already exists.

When you dispose of the form, it clears the "singleton" pointer so that
next time you call GetImageView() it will create a new ImageView form.

I'm not 100% certain about the Dispose code... whether it will be
invoked at the appropriate time. However, this is the basic idea.

You can do this in every form that you require to have only one
instance.
 
Bruce, Thank you, this works the way I want except the Dispose() part
does not get invoked when I close the current ImageView Window so I
can't open another image yet

anyone know how I can tell a form was closed so I can set
ImageView.singleton back to null so I can open the form again
 
Cool I fixed it by adding these to the ImageView Form.
now when I close an image I can open a new one.
Thanks again for all the help.


using System.ComponentModel;

protected override void OnClosing(CancelEventArgs e)
{
ImageView.singleton = null;
}
 
By the way, you can make your form a real singleton by making the
constructor private... I just realized that Visual Studio will still be
able to instantiate the form in design mode, even with a private
constructor. Then you'll be sure that no other form in your application
is bypassing the static Get... method.
 
Also is it bad form to maybe create an invisible listview in my second
form and have it populate itself, then use the data from that list
instead of just trying to read from the Main form?

My guess is that yes this is bad form, but this is the only way I can
think of that I know would solve my issue, but I'll wait to hear from
you guys, since I always get great help from this group

thanks again,
Tim
 
I"ve been thinking about this all weekend. :)

What you need is an implementation of the Model-View-Controller
architecture for your user interface. Don't panic: you don't need to go
whole hog and implement something tremendously sophisticated. Here is
what you shoud do, in a nutshell.

1. Separate your data—the list of images—from your user interface
handling logic. Make a separate class that holds your list of images
(and, logically, a class that holds information about each image).
Don't be concerned if, at the beginning, these classes seem pretty
thin. As you work through your design you will find various operations
that the classes should offer to your user interfaces (the main form
and the image viewer) that would make their jobs much, much easier. In
the end your "model" classes will probably be the biggest part of your
application.

2. Have your "model" (the list of images and the individual image
class) expose events that happen whenever something interesting happens
inside the model. So, for example, if your user changes the "current
image" in the main form, then it sets the "current" image in the image
list object, and that object then fires a CurrentImageChanged event.

3. Connect the events from the "model" classes to your screen controls.
There are two ways of doing this: simple-minded or sophisticated. For
now, I recomment simple-minded. It's more coding, but it's easier to
understand and easier to get working.

Simple-minded: Create event handlers in your forms that subscribe to
the events from your model. So, in your main form, whenever the model
fires a CurrentImageChanged event, maybe you highlight a different file
name (or maybe you do nothing, because it's already been taken care of
by the UI control). In your ImageViewer, whenever the model fires a
CurrentImageChanged event, change to display the new image. Then make
more event handlers in your forms to respond to user actions on the
screen controls (you probably already have those), and call method in
your "model" classes to take the action that the user wants done.

Sophisticated: You can do all of this with .NET's DataBinding classes,
which means you write much less code. Beware, though: DataBindings are
non-trivial and temperamental. That's why I recommend you start with
your own event handlers and hand-coding, for now.

This may seem like a lot of work, but the beauty of it becomes evident
when you consider this:

User clicks on main view, and clicks on a new image in the image list
in the main view. The event handler for the UI control picks up on the
mouse click, or SelectedIndexChanged, or whatever, and as a result sets
the models CurrentImage property. This causes the model to fire
CurrentImageChanged. Any other views you have open (probably just your
ImageViewer) are listening for this event, and their
...._CurrentImageChanged event handlers run. In the ImageViewer, this
causes the viewer to change the image that is currently showing.

You can expand this to as many views as you wish. From the user's point
of view, one action in one form can result in all of the views
changing, "like magic."
From a philosophical standpoint, what you're saying is this: all of my
forms (the main form and the image viewer) are just different views
into the same data: the list of images. So, I have classes that
represent that list of images, and represent individual images.
Whatever the UI needs to do to that list, it does by calling this
"model". Whatever the UI needs to show, it does by listening to the
"model" and responding to events coming from that "model". The UI
_never_ directly connects a button somewhere to a display changing
somewhere else. Buttons and user-modifiable controls _always_ do their
work by going through the model: user action → event handler →
method call / property set in the model → model event → event
handlers → changes to screen display. That way, all the visual stuff
on the screen is on the same footing, and responds in the same way to
changes in the data.

Often, model-view-controller is overkill for simple screens. However,
for your example, where you have two forms looking at the same data,
it's a natural fit. Read up on it (just search for "model view
controller") and give it a try!
 
Back
Top