Form Lifetime






Form Lifetime

Although the user can't see a form until either Show or ShowDialog is called, a form comes into existence as soon as a form object is instantiated. From there, its lifetime is measured by a series of events that you can handle to control, manage, or just be notified as appropriate. Figure illustrates the sequence of these events, from form construction to form closure.

4. Form Lifetime Event Sequence


We now explore a form's lifetime in detail.

Form Opening

A new form object begins waking up when its constructor is executed, which in turn calls InitializeComponent to create and initialize all the child controls. InitializeComponent is Designer-generated, and consequently it's a bad idea to put custom code into it because the Designer is likely to throw it away. However, if you'd like to add other controls or change anything set by the InitializeComponent method, you can do so from the constructor after the call to InitializeComponent:

public Form1() {
   InitializeComponent();

   // Adding a control
   Button anotherButton = new Button();
   this.Controls.Add(anotherButton);

   // Changing a property to something not known at design-time
   this.Text = DateTime.Now.ToString();
}

When either Form.Show or Form.ShowDialog is called, that's the new form's cue to show itself and all its child controls. To be notified just before this happens, you handle the Load event:

// Form1.cs
partial class Form1 : Form {
  ...
  void Form1_Load(object sender, EventArgs e) {
    MessageBox.Show('Loading Form1!');
  }
}

// Form1.Designer.cs
partial class Form1 {
  ...
  void InitializeComponent() {
    ...
    this.Load += this.Form1_Load;
    ...
  }
}

The Load event is useful for doing any final initialization right before a form is shown. Also, the Load event is a good place to restore any main form settings that need to be remembered from one application session to the next, such as size and location. [4]

[4] How to save and restore main form settings is discussed in Chapter 15: Settings.

When a form is loaded for the first time, it becomes the active form, which is the foreground form that receives keyboard input. It's at this point that a form fires the Activated event:

// Form1.cs
partial class Form1 : Form {
  ...
  void Form1_Activated(object sender, EventArgs e) {
    MessageBox.Show("Form1 activated!");
  }
}

// Form1.Designer.cs
partial class Form1 {
  ...
  void InitializeComponent() {
    ...
    this.Activated += this.Form1_Activated;
    ...
  }
}

After activation, a form broadcasts that opening has completed by firing the Shown event:

// Form1.cs
partial class Form1 : Form {
  ...
  void Form1_Shown(object sender, EventArgs e) {
    MessageBox.Show("Form1 shown!");
  }
}

// Form1.Designer.cs
partial class Form1 {
  ...
  void InitializeComponent() {
    ...
    this.Shown += this.Form1_Shown;
    ...
  }
}

The story doesn't end here; after a form has finally completed opening, users may switch between your application and others many times.

Form Deactivation and Reactivation

When a user switches away from your application, such as by using Alt+Tab, the current form deactivates and fires the Deactivate event. One reason to handle Deactivate is to pause any activity that can't continue without user involvement, such as game play:

// Form1.cs
partial class Form1 : Form {
  ...
  void Form1_Deactivate(object sender, EventArgs e) {
     this.game.Pause();
  }
}

// Form1.Designer.cs
partial class Form1 {
  ...
  void InitializeComponent() {
    ...
    this.Deactivate += this.Form1_Deactivate;
    ...
  }
}

When users switch back to the application, the Activated event is fired again, allowing you to resume any activity you may have paused when the form deactivated:

// Form1.cs
partial class Form1 : Form {
  ...
  void Form1_Activated(object sender, EventArgs e) {
    this.game.Resume();
  }
}

If you write code to handle the Activated and Deactivate events, it needs to be sensitive to the fact that they can be fired multiple times, unlike the other events in a form's lifetime.

Whether a form is active or not is independent of its visibility, which you can change by toggling its Visibility property or by calling either the Hide or the Show method. Hide and Show are helper methods that set the Visible property as appropriate:

void hideButton_Click(object sender, EventArgs e) {
  this.Hide(); // Set Visible property indirectly
  this.Visible = false; // Set Visible property directly
}

As you might expect, there is an event that you can handle as your form flickers in and out of visual reality. It's called VisibleChanged.

Form Closing

When forms outlive their usefulness, users close them in one of several ways. Figure illustrates the ways provided by Windows automatically, including System Menu | Close, Alt+F4, or the close box.

5. System-Provided Mechanisms for Closing a Form


If a form is a main form, it will likely have a menu strip. In this case, you can follow Windows UI consistency by providing either an Exit menu item or, in the case of an MDI child form, a Close menu item. Both of these are normally situated in the File menu, as shown in Figure.

6. Application-Provided Mechanisms for Closing a Form


In either case, closing the form is handled from the appropriate menu item's Click event handler by a call to the Form's aptly named Close method:

void exitToolStripMenuItem_Click(object sender, EventArgs e) {
  this.Close(); // Close this form
}

Whichever approach you use, it is possible that an application could prematurely end processing and potentially leave data in an inconsistent state. You can give users the option to change their minds by handling the FormClosing event and setting FormClosingEventArgs.Cancel to true or false as appropriate:

void Form1_FormClosing(object sender, FormClosingEventArgs e) {
  DialogResult result = MessageBox.Show(
    "Abort your game?", "Game In Progress", MessageBoxButtons.YesNo);
  e.Cancel = (result == DialogResult.No);
}

FormClosing is also the best place to serialize the properties of a form that you need to remember when the form is reopened, including size and location (as discussed in Chapter 15). On the other hand, the FormClosed event is merely a notification that the form has already gone away even though the form is still visible when FormClosed is fired: [5]

[5] FormClosing and FormClosed supercede Closing and Closed from previous versions of .NET, which are retained to support backward compatibility for applications built before Windows Forms 2.0.

void Form1_FormClosed(object sender, FormClosedEventArgs e) {
  MessageBox.Show("Your game was aborted");
}

If you need contextual information about who initiated the form closure, you can query the CloseReason property of both FormClosingEventArgs and FormClosed EventArgs:

void Form1_FormClosed(object sender, FormClosedEventArgs e) {
  MessageBox.Show(
    "Your game was aborted: " + e.CloseReason.ToString());
}

CloseReason can be one of several values:

enum CloseReason {
   None, // No reason given, or could not be determined
   WindowsShutDown, // Windows is closing (ShutDown or Logoff)
   MdiFormClosing, // MDI parent form is closing
   UserClosing, // User closed (close box or Alt+F4)
   TaskManagerClosing, // Task Manager | End Task
   FormOwnerClosing, // Owner form is closing
   ApplicationExitCall // Application.Exit invoked
}

After FormClosed has been fired, and if form closure wasn't canceled, the form fires the Deactivated event one last time before it winks out of existence.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows