Cruces
Cruces

Reputation: 3129

Trying to close a form after the next one is shown in C# cf

I've been studying Android lately and I tried to port one of its functions to C# compact framework.

What I did is create an Abstract class that I call Activity. This class looks like this

  internal abstract class Activity
  {
      protected Form myForm;
      private static Activity myCurrentActivity = null;
      private static Activity myNextActivity = null;

      internal static void LoadNext(Activity nextActivity)
      {
         myNextActivity = nextActivity;
         if (myNextActivity != null)
         {
            myNextActivity.Show();
            if (myCurrentActivity != null)
            {
               myCurrentActivity.Close();
               myCurrentActivity = null;
            }
            myCurrentActivity = myNextActivity;
            myNextActivity = null;
         }
      }

      internal void Show()
      {
        //PROBLEM IS HERE
         Application.Run(myForm);
         //myForm.Show();
         //myForm.ShowDialog();
        //
      }

      internal void Close()
      {
         myForm.Close();
      }


      internal void GenerateForm()
      {
      ///Code that uses the Layout class to create a form, and then stores it in myForm
      //then attaches click handlers on all the clickable controls in the form
      //it is besides the point in this problem
      }

      protected abstract void Click(Control control);
      //this receives all the click events from all the controls in the form
      //it is besides the point in this problem

   }

The problem I have is with running the part of the Show() command

Basically all my classes implement the above class, load an xml file and display it. When I want to transition to a new class/form (for example going from ACMain to ACLogIn) I use this code

Activity.LoadNext(new ACLogIn);

Which is supposed to load the next form, show it , and unload the current form

I have tried these solutions (in the Show() method) and here is the problem with each one

  1. using myForm.ShowDialog()
    This works, but blocks execution, which means that the old form does not close, and the more I move between the forms the more the process stack increases

  2. using myForm.Show()
    This works, closes the old form after the old one is shown, but immediately after that closes the program and terminates it

  3. using Application.Run(myForm)
    This works only on the first form loaded, when I move to the next form, it shows it then throws an exception saying "Value does not fall within the expected range"

Can someone help me fix this or find an alternative?

Upvotes: 6

Views: 766

Answers (2)

Peter Ritchie
Peter Ritchie

Reputation: 35869

Application.Run is generally used with the overload that takes a Form parameter. This would be the "main" form that would be responsible for starting/showing other forms. This "main" form could be "hidden". But, I think that's a little awkward.

Alternatively, you don't need a main form, you can use Application.Run() to start a message pump to process Windows messages; but, then the thread is busy processing messages and cannot show dialogs (they must be shown in the thread that is running Application.Run). You can get around this by creating one or more form objects before calling Application.Run and these form objects could create a Timer object that would call Form.Show() or Form.ShowDialog() on the Timer.Tick event handler so that for form is shown after the call to Run. I think this is a little awkward as well.

Both of these solutions kind of circumvent the way you're expected to use Windows and WinForms; so, I think you need to think about re-designing this application to work with the way that Windows and .NET works.

Upvotes: 1

ctacke
ctacke

Reputation: 67198

If you're really after creating your own framework for this navigation, you need to re-work you thinking. The Form instance passed into Application.Run must never close - when it does, Application.Run finishes execution and (typically) your static void Main entry point exits and the app terminates.

What I would propose is that you change your Activity to either being a UserControl:

public abstract class Activity : UserControl
{
  .... 
}

or Composing one

public abstract class Activity
{
    private UserControl m_control;
  .... 
}

Then instead of closing and showing Forms, parent all of the Activities inside the main Form as a container.

As fair warning, this is going to get complex when you start wanting to show things in a Tab motif instead of a Stack, or having split views. Frameworks seem simple to create, but they're not so I'd at least consider using something already done unless you have compelling reasons to want to roll your own.

Upvotes: 5

Related Questions