Application Life-cycle Management in Windows 8
- 4/15/2013
Launching
When you create a new Windows Store application using the Visual Studio template, you will end up with a solution containing one project with a default page called MainPage.xaml and a class that represents the application defined in the App.xaml.cpp and App.xaml.h files. WinRT invokes the method called OnLaunched immediately after creating the application instance. You can override this method in your application to perform some activities.
Understand the OnLaunched event
In this procedure, you will start coding the event handlers for application events.
Create a new application project. To do so, open Visual Studio 2012 and select New Project from the File menu (the sequence can be File | New | Project for full-featured versions of Visual Studio). Choose Visual C++ in the Templates tree and then Windows Store from the list of installed templates. Then choose Blank App (XAML) from the list of available projects.
Name the new project ALMEvents, and then choose a location on your file system and accept the default solution name. When you’ve finished, click OK.
As you learned in Chapter 3, the Windows Store Application template provides a default page (MainPage.xaml), an application entry point in the App class (App.xaml.cpp and App.xaml.h files), and a default application description in Package.appxmanifest.
Open the App.xaml.cpp file and scroll down until you can see the OnLaunched method.
This method is called by WinRT when the user launches the application. An application is launched when the user clicks the application tile. The default code inside the method simply instantiates a new Frame class, sets it as the current content, and then navigates to the main page, calling the Navigate method on the frame and passing the MainPage class. The last line activates the current content that is the Main Page. The code also contains a test to check for the presence of an existing frame (meaning the application is already running), which will be explained later in this chapter.
The following snippet shows the OnLaunched method:
void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) { auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content); // Do not repeat app initialization when the Window already has content, // just ensure that the window is active if (rootFrame == nullptr) { // Create a Frame to act as the navigation context and associate it with // a SuspensionManager key rootFrame = ref new Frame(); if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) { // TODO: Restore the saved session state only when appropriate, // scheduling the final launch steps after the restore is // complete } if (rootFrame->Content == nullptr) { // When the navigation stack isn't restored, navigate to the // first // page, configuring the new page by passing required // information as a navigation parameter if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) { throw ref new FailureException( "Failed to create initial page"); } } // Place the frame in the current Window Window::Current->Content = rootFrame; // Ensure the current window is active Window::Current->Activate(); } else { if (rootFrame->Content == nullptr) { // When the navigation stack isn't restored, navigate to the // first // page, configuring the new page by passing required information // as a navigation parameter if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) { throw ref new FailureException( "Failed to create initial page"); } } // Ensure the current window is active Window::Current->Activate(); } }
Add the following two lines just at the beginning of the method, before the rest of the code, as presented in the previous step:
auto dia = ref new Windows::UI::Popups::MessageDialog( "App OnLaunched", "ALM Events"); dia->ShowAsync(); .....
The first line instantiates the MessageDialog class, passing to it the content and the title as string parameters. This class represents what in the past was called a message box. The second line of code shows the message dialog box in the default location and begins an asynchronous operation for processing the dialog box, and then calls the Start method to start the operation.
Press F5 to start the application or deploy the application as you learned in Chapter 3, and tap or click the application tile. The following image shows the message dialog box.
As you can see, the dialog box is shown full screen, and it displays the title and the content passed as parameters in the class constructor.
Click or tap the Close button to close the dialog box. You will see a completely black page—this is because the default page presents nothing.
Press the Windows button to open the Start screen (you can also move the mouse in the lower-left corner of the screen and choose Start from the Start menu).
Scroll right until you find the ALMEvents application, and tap or click the application tile to launch it again. The application is already running, and you will not see the dialog box; in fact, WinRT does not call the OnLaunched method on the application when the application instance is already loaded.
This behavior is significantly different than in previous versions of Windows, where the system started a new instance of the application each time the user launched it. In Windows 8, there can be only one instance running at the same time. When the user launches an already running application, WinRT just brings the application to the foreground.
Close the application by pressing Alt+F4 and repeat steps 5–7 to verify the application flow again.
The parameter received by the OnLaunched method is of type LaunchActivatedEventArgs, a class that implements the IActivatedEventArgs interface you saw in Chapter 3. This interface is implemented by different classes that serve as event arguments for different activation events. The first property of the interface is Kind, and it can assume one of the values defined in the ActivationKind enumeration. This property lets the developer ask for the kind of launch. For instance, if the application is launched by the user, this property will be ActivationKind.Launch; if the application is launched by the system when the user selects it as search target, the property will be ActivationKind.Search; if the application is activated to receive something from other applications using a Share contract, the property will be ActivationKind.ShareTarget. There are two different methods in the base class to react to this activation. You will see these differences in this chapter.
Show the launch kind
In this procedure, you will change the code of the previous procedure to show the activation kind.
Replace the code you inserted in the previous procedure for the OnLaunched method to create a message that contains the activation kind as follows. You will need to insert the lines in bold:
Platform::String^ message = "App Launched: " + args->Kind.ToString(); auto dia = ref new Windows::UI::Popups::MessageDialog(message, "ALM Events"); dia->ShowAsync ...
The first line uses the Kind property of the event args to build the message text, and the second line presents it in a message dialog box.
Run the application, deploying it from the Build menu, and start the application by clicking the application tile on the Start screen. You will see the dialog box presenting the message “App Launched: Launch.”
Click the Close button and do not close the application.
Go to the Start screen and click the application tile. You won’t see any messages because the application is already running.
Close the application using Alt+F4.
Understand the previous state
In this procedure, you will modify the code for the OnLaunched method to test the execution state for the previous launch of the application. If the user closes the application normally, the previous execution state will be ClosedByUser, telling you that everything went well for the user. If the user has never launched the application, the previous execution state will be NotRunning.
Change again the first line of the OnLaunched event to build a more detailed message that shows the activation kind and the previous execution state by replacing the first line of the method with the one shown in the following code excerpt (bold line):
Platform::String^ message = "App Launched: " + args->Kind.ToString() + " - Previous State: " + args->PreviousExecutionState.ToString(); auto dia = ref new Windows::UI::Popups::MessageDialog(message, "ALM Events"); dia->ShowAsync(); ...
Deploy the application using the Deploy menu item on the Build menu.
Start the application by launching it from the Start screen.
Verify that the message “App Launched: Launch – Previous State: ClosedByUser” displays, meaning the application was closed by you previously (if, in fact, you closed it in the previous procedure). The message can be “App Launched: Launch – Previous State: NotRunning” if the application was closed immediately before. Try it closing and launching it from the Start screen quickly.
Close the application using Alt+F4.
Modify MainPage.xaml by adding two buttons and their corresponding click events in the Grid control as follows:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Orientation="Horizontal" VerticalAlignment="Top"> <Button Click="Crash_Click" Content="Crash" /> <Button Click="Close_Click" Content="Close" /> </StackPanel> </Grid>
The first one will be used to perform an invalid operation that causes a crash of the application. The second will be used to gracefully close the application from code.
Implement the event handlers for the Crash and the Close click events (highlighted in bold) using the following code in the MainPage.xaml.h (Listing 4-1) and MainPage.xaml.cpp (Listing 4-2) files, respectively.
Listing 4-1 Code-behind file for the App class: MainPage.xaml.h
#pragma once #include "MainPage.g.h" namespace ALMEvents { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public ref class MainPage sealed { public: MainPage(); protected: virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; private: void Crash_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); void Close_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); }; }
Listing 4-2 Code-behind file for the App class: MainPage.xaml.cpp
#include "pch.h" #include "MainPage.xaml.h" using namespace ALMEvents; using namespace Platform; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Navigation; // The Blank Page item template is documented at // http://go.microsoft.com/fwlink/?LinkId=234238 MainPage::MainPage() { InitializeComponent(); } /// <summary> /// Invoked when this page is about to be displayed in a Frame. /// </summary> /// <param name="e">Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page.</param> void MainPage::OnNavigatedTo(NavigationEventArgs^ e) { (void) e; // Unused parameter } void ALMEvents::MainPage::Crash_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) { int a = 10; int b = 0; int c = a / b; } void ALMEvents::MainPage::Close_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) { Application::Current->Exit(); }
Deploy the application by right-clicking the project in the solution and choosing Deploy from the context menu.
Launch the application from the Start screen, click Close on the dialog box, and click the Crash button on the main page. The application should crash, returning to the Start screen in a few seconds. Be patient.
Launch the application again from the Start screen. The dialog box will show NotRunning as the previous state.
Close the dialog box and then click the Close button to gracefully close the application.
Launch the application again from the Start screen to verify that the dialog box shows NotRunning as the previous state.
Close the dialog box and then close the application by using Alt+F4 or swiping your mouse or finger from the upper-center of the screen to the lower-center to close the application in the canonical way.
Wait for at least 20 seconds and then launch the application again from the Start screen to verify that the dialog box shows ClosedByUser as the previous state.
To summarize, an application receives a call to the OnLaunched method from WinRT when the user launches the application and the application is not already running. This method receives the launch kind and the previous state. Also note that there can be only one instance of a Windows Store application in Windows 8.