In this tutorial, we'll cover some of the core concepts of Windows Phone development, such as asynchronous programming, navigation, and managing orientation changes. We'll also take a quick look at the life cycle of a typical Windows Phone application.
Asynchronous Programming
Nowadays, asynchronous programming is a required skill for developers. In the past, most applications worked with a synchronous approach: the user started an operation and, until it was completed, the application was frozen and completely unusable.
This behavior isn’t acceptable today, especially in the mobile world. Users wouldn’t buy a phone that doesn’t allow them to answer a call because an application is stuck trying to complete an operation.
There are two approaches in Windows Phone to manage asynchronous programming: callbacks
and the async/await
pattern.
Callbacks
In most cases, especially in Windows Phone 8, callbacks have been replaced with asynchronous methods that use the async and await pattern. However, there are some APIs that still use the callback approach, so it’s important to learn it.
Callbacks are delegate methods that are called when an asynchronous operation is terminated. This means that the code that triggers the operation and the code that manages the result are stored in two different methods.
Let’s look at the following example of the WebClient
class, one of the basic APIs of the framework that performs network operations like downloading and uploading files:
private void OnStartDownloadClicked(object sender, RoutedEventArgs e) { WebClient client = new WebClient(); client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); client.DownloadStringAsync(new Uri("http://wp.qmatteoq.com", UriKind.Absolute)); Debug.WriteLine("Download has started"); } void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { MessageBox.Show(e.Result); }
The file download (in this case, we’re downloading the HTML of a webpage) is started when we call the DownloadStringAsync()
method, but we need to subscribe to the DownloadStringCompleted
event, which is triggered when the download is complete, to manage the result. Usually, the event handler (the callback method) has a parameter that contains the result of the request. In the previous sample, it’s called e
and its type is DownloadStringCompletedEventArgs
.
Notice the message “Download has started” that is written in the Visual Studio Output
window. Since the method is asynchronous, the message will be displayed immediately after the download has started since the code will continue to run until the download is completed. Then, the execution moves to the callback method.
Async and Await
The callback approach is hard to read. Unlike synchronous code, the flow of execution “jumps” from one method to another, so a developer can’t simply read line after line to understand what’s going on. In addition, if you need to write a custom method that starts a network operation and returns the downloaded file, you simply can’t do it because the logic is split in two different pieces.
The async and await pattern was introduced in C# 5.0 to resolve these issues. The Windows Runtime is heavily based on this approach and most of the APIs we’re going to see in this series use it.
When we use the async
and await
keywords, we’re going to write sequential code as if it’s synchronous—the compiler will execute one row after the other. To better understand what happens under the hood, keep in mind that when we start an asynchronous operation, the compiler sets a bookmark and then quits the method. This way, the UI thread is free and users can keep interacting with the application. When the asynchronous operation is completed, the compiler goes back to the bookmark and continues the execution.
The async and await pattern is based on the Task
class, which is the base return type of an asynchronous method. A method can return:
Task
if it’s avoid
method: The compiler should wait for the operation to be completed to execute the next line, but it doesn’t expect a value back.Task<T>
if the method returns a value. The compiler will wait for the operation to be completed and will return the result (whose type isT
) to the main method, which will be able to perform additional operations on it.
Let’s see an example. We’re going to add to our project a library called Async for .NET, which has been developed by Microsoft and is available on NuGet. Its purpose is to add async and await support to old technologies that don’t support it since they’re not based on C# 5.0, like Windows Phone 7 or Silverlight. It’s also useful in Windows Phone 8 applications, since it adds asynchronous methods to APIs that are still based on the callback pattern.
One of these APIs is the WebClient
class we’ve previously seen. By installing this library we can use the DownloadStringTaskAsync()
method which supports the new pattern. This method’s return type is Task<string>
. This means that the operation is asynchronous and it will return a string.
private async void OnStartDownloadClicked(object sender, RoutedEventArgs e) { WebClient client = new WebClient(); string result = await client.DownloadStringTaskAsync("http://wp.qmatteoq.com"); MessageBox.Show(result); }
First, let’s note how to use this new syntax. Any method that contains an asynchronous method has to be marked with the async
keyword. In this case, it’s an event handler that is invoked when the user presses a button.
Next, we need to add the await
keyword as a prefix of the asynchronous method. In our example, we’ve placed it before the method DownloadStringTaskAsync()
. This keyword tells the compiler to wait until the method is completed before moving on.
When the asynchronous method is started, you can assume that the compiler has set a bookmark and then quit the method because the application is still responsive. When the download is completed, the compiler returns to the bookmark and continues the execution. The download’s result is stored in the result
variable, whose value is displayed on the screen using a MessageBox
.
As you can see, even if the code under the hood is asynchronous and doesn’t freeze the UI, it appears synchronous: the code is executed one line at a time and the MessageBox
isn’t displayed until the DownloadStringTaskAsync()
method has finished its job.
The Dispatcher
Sometimes, especially when you have to deal with callback methods, the operations are executed in a background thread, which is different from the thread that manages the UI. This approach is very helpful in keeping the UI thread as free as possible so that the interface is always fast and responsive.
Sometimes a background thread may need to interact with the user interface. For example, let’s say a background thread has completed its job and needs to display the result in a TextBlock
control placed in the page. If you try to do it, an UnauthorizedAccessException
error with the message “Invalid cross-thread access”will be displayed.
The reason for this error is that a background thread isn’t allowed to access the controls in a page since they are managed by a different thread. The solution is to use a framework’s Dispatcher
class. Its purpose is to dispatch operations to the UI thread from another thread. This way, you can interact with XAML controls without issues because the thread is the same. The following sample illustrates how to use it:
Dispatcher.BeginInvoke(() => { txtResult.Text = "This is the result"; })
You simply have to pass the Action
that needs to be executed on the UI thread as a parameter of the BeginInvoke()
method of the Dispatcher
class. In the previous sample, the Action
is defined using an anonymous method
.
Tip: Anonymous methods are called such because they don’t have a specific name—they simply define the operations to be performed.
Dispatcher
is not needed when you work with the async and await pattern because it makes sure that even if the operation is executed in one of the free threads available in the thread pool, the result is always returned in the UI thread.
Navigation
Another important concept to learn when you develop a Windows Phone application is navigation. In most cases, your application will be made of different pages, so you need a way to move from one page to another.
The framework offers a built-in navigation system, which can be managed using the NavigationService
class.
private void OnGoToPage2Clicked(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/Pages/Page2.xaml", UriKind.Relative)); }
The navigation system provides, in every page, two events that can be managed to intercept the navigation events: OnNavigatedTo()
is triggered when you move from another page to the current page; OnNavigateFrom()
is triggered when you move from the current page to another page. Another important page event that can be subscribed is Loaded
, which is triggered when the page is completely loaded. It’s commonly used to load the data that needs to be displayed on the page.
public partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { Debug.WriteLine("Page is loaded"); } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); } protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); } }
Passing Parameters to Another Page
A common requirement when dealing with navigation is to pass a parameter to another page, for example, a master/detail scenario where you select a list item in the master page and display its details in a new page.
The navigation framework offers a built-in way to pass simple parameters like strings and numbers that is inherited directly from the web world: query string parameters. They’re added directly to the URL of the page where you want to redirect the user, as shown in the following sample:
private void OnGoToPage2Clicked(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/Pages/Page2.xaml?id=1", UriKind.Relative)); }
You’ll be able to retrieve the parameter in the landing page by using the OnNavigatedTo
event and the NavigationContext
class, as in the following sample:
protected override void OnNavigatedTo(NavigationEventArgs e) { if (NavigationContext.QueryString.ContainsKey("id")) { int id = int.Parse(NavigationContext.QueryString["id"]); MessageBox.Show("The id is " + id); } }
The NavigationContext
class offers a collection called QueryString
, which contains all the available parameters. You’ll be able to get the value by using its key (which is the parameter’s name).
In some cases, simple parameters aren’t enough. Sometimes you need to pass complex objects to another page. The master/detail scenario is, also in this case, a good example. In many situations, to properly populate the detail page, you need access to the whole object that has been selected in the list.
A good approach to this is to pass the detail page a plain parameter that can be used to identify the selected item, like a unique identifier. Then, in the OnNavigatedTo
event handler of the detail page, load the item with the received identifier from your data collection (which can be a database or a remote service).
Manipulating the Navigation Stack
Every application has its own navigation stack, which is the list of pages that the user has moved through while using the application. Every time the user navigates to a new page, it’s added to the stack. When the user goes back, the last page from the stack is removed. When one page is left in the stack and the user presses the Back button, the application is closed.
The NavigationService
class offers a few ways to manipulate the stack. In the beginning, there’s a specific property called BackStack
which is a collection of all the pages in the stack. When we discuss Fast App Resume later in this article, we’ll see one of the available methods to manipulate the stack: RemoveBackEntry()
, which removes the last page from the stack.
Another important method is GoBack()
, which redirects the user to the previous page in the stack. Its purpose is to avoid creating circular navigation issues in your application.
The image below illustrates an example of circular navigation and how to correct it. Let’s say that you have an application made by two pages, a main page and a settings page. You choose to use the Navigate()
method of the NavigateService
class for every navigation. The user navigates from the main page to the settings page, and again to the main page.
The issue here is that every time you call the Navigate()
method, you add a new page to the navigation stack. When the user is on the main page and presses the Back button, he or she expects to quit the app. Instead, the second time, the user will be redirected to the Settings page since the previous navigation added the page to the stack.
The correct approach is to use the GoBack()
method. Instead of adding a new page to the stack, this method simply redirects the user to the previous one. The result will be the same—the user, from the settings page, is taken back to the main page—but since there are no pages added to the stack, the application will behave as expected. If the user presses the Back button, the app will be closed.
Intercepting the Navigation: The UriMapper Class
Later in the series we’ll deal with different situations where the application is opened with a special Uri
, such as using the Speech API or data sharing.
In these cases, we’re going to use a navigation feature called UriMapper
, which is a class that can act as a middle man in every navigation operation. When the user navigates from one page to another (the starting page can be also be the phone’s Home screen), the class is able to intercept it and redirect the user to another page if needed.
To create a UriMapper
-based class, simply add a new class to your project. It has to inherit from the UriMapperBase
class. It will require you to implement the MapUri()
method, which is invoked during navigation as shown in the following sample:
public class UriMapper: UriMapperBase { public override Uri MapUri(Uri uri) { string tempUri = HttpUtility.UrlDecode(uri.ToString()); if (tempUri.Contains("/FileTypeAssociation")) { //Manage the selected file. return new Uri("/Pages/FilePage.xaml", UriKind.Relative); } else { return uri; } } }
The MapUri()
method takes in the source Uri
and needs to return the new Uri
to redirect the user. In the previous sample, we checked whether the source Uri
contained a specific string (in this case, it’s one that belongs to the data sharing scenario we’ll see later in this series). In the affirmative case, we redirect the user to a specific page of the application that is able to manage the scenario; otherwise, we don’t change the navigation flow by returning the original Uri
.
After you’ve created a UriMapper
class, you’ll have to assign it to the UriMapper
property of the RootFrame
object that is declared in the App.xaml.cs
file. You’ll have to expand the region called Phone application initialization
(which is usually collapsed), and change the InitializePhoneApplication()
method like in the following sample:
private void InitializePhoneApplication() { if (phoneApplicationInitialized) return; // Create the frame but don't set it as RootVisual yet; this allows the // splash screen to remain active until the application is ready to render. RootFrame = new PhoneApplicationFrame(); RootFrame.UriMapper = new UriMapper(); RootFrame.Navigated += CompleteInitializePhoneApplication; // Handle navigation failures. RootFrame.NavigationFailed += RootFrame_NavigationFailed; // Handle reset requests for clearing the backstack. RootFrame.Navigated += CheckForResetNavigation; // Ensure we don't initialize again. phoneApplicationInitialized = true; }
The Application Life Cycle
Mobile applications have a different life cycle than traditional desktop applications due to their different requirements, like power management and performance optimization. The traditional multitasking approach that you experience in Windows doesn’t fit well to the mobile experience: the necessary power would drain the battery very quickly. Plus, if you open too many applications, you can suffer severe performance issues that will degrade the user experience.
The following figure explains the life cycle Microsoft has introduced for Windows Phone applications to satisfy the required conditions:
When an application is running, it can be suspended at any time. For example, the user can press the Start button or tap a notification to open another application. In this case, the application is “frozen” (the dormant
state); it’s preserved in memory, but all the running threads and operations are stopped. In this status, the application is using system memory, but the CPU is free. This way, other applications can use the available resources without suffering performance issues.
When the user decides to go back to the application (by using the Back button or the task switcher), its instance is restored from memory and the previous threads and operations are restarted.
If users play with their device for a long time, too many applications may be opened and there won’t be enough memory left to keep other applications suspended. In this case, the operating system can start to “kill” longer-running applications to free some memory for the newly opened apps—the older apps are moved into a tombstoned
state. To give users the same smooth experience as when apps are simply suspended, developers have the ability to save the state of the app when it is tombstoned and restore it later. When users open a tombstoned app, they will find the application in the exact previous state, as if it’s never been closed.
The tombstoning experience was the only one available in Windows Phone 7, but it often led to a bad user experience. Because the app was killed, the application always needed to start from scratch, causing longer loading times. In Windows Phone 7.5, Microsoft introduced the Fast Application Switching concept that has been translated into the current life cycle, where apps are put in a dormant state and are killed only if needed.
Based on this information, we can understand that applications aren’t able to run in the background—when an application is suspended, all of its running operations are canceled. Later in this series, we’ll look at available techniques for executing some operations even when the app is not running.
As a developer, you are not notified by the operating system when an application is tombstoned. This is why, in the schema shown above, you can see that the save state operation is made every time the application is suspended. You’ll always have to deal with it, since you won’t know in advance whether your app will be tombstoned.
Instead, the restore operation is made only if the application has been tombstoned. When the app is in a dormant state, the entire process is stored in memory, so there’s no data loss when the app is restored.
Since tombstoning isn’t deterministic, Visual Studio offers a way to test it. By default, applications are moved to the dormant state when suspended. You can change this behavior by right-clicking on your project and choosing Properties. In the Debug section you’ll find the Tombstone upon deactivation while debugging option. When it’s selected, applications will always be tombstoned when they’re suspended, so you can test that everything works fine and no data is lost in this scenario.
Controlling the Life Cycle
You can control the application life cycle thanks to the PhoneApplicationService
class, which is declared in the App.xaml
file as a lifetime object.
<Application.ApplicationLifetimeObjects><shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated"/></Application.ApplicationLifetimeObjects>
As you can see, the PhoneApplicationService
class is registered to manage four different events that are available in the App.xaml.cs
file:
Application_Launching
is invoked when the app starts for the first time.Application_Closing
is invoked when the app is completely closed. It only happens when the user presses the Back button in the application’s main page.Application_Activated
is invoked when the app is resumed from a suspended state.Application_Deactivated
is invoked when the app is suspended.
Remember the “save state” and “restore state” operations in the previous figure? Usually, they’re managed in these events. State is saved when the Application_Deactivated
event occurs, and it’s restored when the Application_Activated
event occurs.
Specifically, one of the parameters of the Application_Activated
event handler contains important information—it shows whether the application comes from a dormant or tombstoned state as demonstrated in the following sample:
private void Application_Activated(object sender, ActivatedEventArgs e) { if (e.IsApplicationInstancePreserved) { Debug.WriteLine("The app was dormant"); } else { Debug.WriteLine("The app was tombstoned"); } }
The key is the IsApplicationInstancePreserved
property of the ActivatedEventArgs
object, which is a Boolean. If it’s true, the app was in a dormant state; otherwise, it was killed, and it’s time to restore the data we’ve previously saved.
The PhoneApplicationService
class can also be useful to store the state of your application when it’s suspended. In fact, it offers a property called State
that is a collection whose type is Dictionary<string, object>
. It can be used to save any object that is identified by a key.
Typically, you’re going to save data in the State
property when the app is suspended, and restore the data when the app is resumed from a tombstoned state.
However, there are some important things to keep in mind:
- It’s best to save data as soon as possible and not only when the
Application_Deactivated
event is raised. Unexpected bugs or other errors can cause users to lose data during the execution. - The content of the
State
property is kept in memory only if the app is resumed; if the user decides to open the application from scratch (for example, by tapping on its Tile instead of using the Back button), the collection is erased and the saved data will be lost. If you need to persist the data across multiple executions, it’s better to save to the local storage, which we’ll cover later in this series.
Fast App Resume
The life cycle previously described has a flaw: users can resume a suspended application only by using the Back button or the task switcher. If they pin a Tile for the application on the Start screen and tap on it, a new instance of the app will be opened and the suspended one will be terminated.
Windows Phone 8 has introduced a new feature called Fast App Resume, which can be activated to address the flaw previously described. Regardless of the opening point, if there’s a suspended instance, it will always be used.
Supporting Fast App Resume requires a bit of work because, by default, the Windows Phone template is made to use the old life cycle, even when the feature is activated.
The first step is to modify the manifest file, and unfortunately, it’s one of the situations where the visual editor isn’t helpful. In fact, we’ll need to manually edit the file. To do this, simply right-click the WMAppManifest.xml file inside the Properties folder and choose the View code option.
You’ll find a node called DefaultTask
that tells the application which page to load first when the app starts. You’ll need to add an attribute called ActivationPolicy
to set its value to Resume
, like the following sample:
<Tasks><DefaultTask Name ="_default" NavigationPage="MainPage.xaml" ActivationPolicy="Resume" /></Tasks>
What happens when users tap on the main Tile of the application and the Fast App Resume has been enabled? The operating system triggers two navigations: the first one is toward the last opened page in the application, and the second one is toward the main page of the application, since the application Tile is associated with it through the default navigation Uri.
At this point, you have two choices:
- You can keep using the old approach. In this case, you have to remove the last visited page from the back stack; otherwise you’ll break the navigation system. In fact, when users are on the main page of the application and press the Back button, they expect to quit the application, not go back to an old page.
- You can support Fast App Resume. In this case, you have to stop the navigation to the main application page so that users are taken to the last visited page of the application.
The default Windows Phone 8 templates contain an implementation of the first approach. Open the App.xaml.cs
file and look for a method called InitializePhoneApplication()
, which takes care of initializing the frame that manages the various pages and the navigation system. You’ll find that the application subscribes to an event called Navigated
of the RootFrame
class, which is triggered every time the user has moved from one page of the application to another.
The method that is assigned as the handler of this event is called ClearBackafterReset()
, which has the following definition:
private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) { // Unregister the event so it doesn't get called again. RootFrame.Navigated -= ClearBackStackAfterReset; // Only clear the stack for 'new' (forward) and 'refresh' navigations. if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh) return; // For UI consistency, clear the entire page stack. while (RootFrame.RemoveBackEntry() != null) { ; // Do nothing. } }
This method does exactly what was previously described: the navigation to the main page is not canceled but, using the RemoveBackEntry()
method of the RootFrame
class, the page stack of the application is cleaned.
Take note of the NavigationMode
property: it specifies the status of the navigation, like New
when users navigate to a new page, or Back
when users go back to a previous page. The key status to manage Fast App Resume is Reset
, which is set when users are navigating to the main application page but an old instance of the app is being used.
We’re going to use the NavigationMode
property together with some changes to the original code. The first step is to change the Navigated
event handler to simply store, in a global Boolean property of the App.xaml.cs
class, whether the NavigationMode
is reset. We’re going to use this information in another event handler. In fact, we need to subscribe to the Navigating
event of the RootFrame
class. This event is similar to the Navigated
one, except that it is triggered before the navigation starts and not after. This difference is important for our purpose, since we have the chance to cancel the navigation operation before it’s executed.
Here is what we do in the Navigating
event handler:
void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e) { if (reset && e.IsCancelable && e.Uri.OriginalString == "/MainPage.xaml") { e.Cancel = true; reset = false; } }
In this event, we wait for a specific condition to happen: the NavigationMode
is Reset
and navigation to the main page is triggered. This situation occurs when users tap on the main Tile and an instance of the app is already in memory. The first navigation redirects to the last visited page, and the second one (the Reset
mode) redirects to the main page. It’s this scenario that we need to manage. By setting the Cancel
property of the method’s parameter, we abort the navigation to the main page and leave the user on the last-visited page of the app. The experience is exactly the same as when the user returns to the application using the Back button.
Here is how the complete code required to implement Fast App Resume looks in the App.xaml.cs
file:
private bool reset; // Do not add any additional code to this method. private void InitializePhoneApplication() { if (phoneApplicationInitialized) return; // Create the frame but don't set it as RootVisual yet; this allows the // splash screen to remain active until the application is ready to render. RootFrame = new PhoneApplicationFrame(); RootFrame.Navigated += CompleteInitializePhoneApplication; // Handle navigation failures. RootFrame.NavigationFailed += RootFrame_NavigationFailed; // Handle reset requests for clearing the backstack. RootFrame.Navigated += RootFrame_Navigated; RootFrame.Navigating += RootFrame_Navigating; // Ensure we don't initialize again. phoneApplicationInitialized = true; } void RootFrame_Navigated(object sender, NavigationEventArgs e) { reset = e.NavigationMode == NavigationMode.Reset; } void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e) { if (reset && e.IsCancelable && e.Uri.OriginalString == "/MainPage.xaml") { e.Cancel = true; reset = false; } }
You may be wondering why all this effort is needed to support Fast App Resume. Why isn’t it automatically implemented by the operating system? The answer is that Fast App Resume isn’t suitable for every application—you have to be very careful when you decide to support it, because you can ruin the user experience if you don’t implement it well.
For example, if your users spend most of the time in the main page of your application (for example, a social networking app), they probably prefer to go straight to the Home page when they open the application, instead of resuming what they were doing before.
Here are two tips for improving the Fast App Resume experience:
- If your application has many pages and a complex navigation hierarchy, add to the inner pages a quick way to go back to the home page (like a button in the Application Bar).
- Add a timing condition. If the application hasn’t been used recently, disable Fast App Resume and redirect the user to the home page.
Manage Orientation
Typically, a Windows Phone device is used in portrait mode, but there are some scenarios where users can benefit from landscape mode. For example, if your application offers a way to insert long text, it can be more convenient for users to type using the landscape keyboard. Alternatively, in other scenarios, you can use the landscape mode to provide the content with a different layout.
By default, every new page added to a Windows Phone is displayed in portrait mode and does not support the landscape mode. When you rotate the phone, nothing happens. The orientation behavior is controlled by two attributes of the PhoneApplicationPage
node in the XAML:
<phone:PhoneApplicationPage x:Class="Webinar.Rest.MainPage" SupportedOrientations="Portrait" Orientation="Portrait">
- The
SupportedOrientations
property defines which orientations are supported by the page. To support both orientations, you need to set the value toPortraitOrLandscape
. - The
Orientation
property defines the default orientation of the page.
Once you’ve set the SupportedOrientations
property to PortraitOrLandscape
, the page’s layout will automatically adapt to landscape mode when the phone is rotated.
If you want further control (for example, because you want to deeply change the page’s layout between portrait and landscape modes), the APIs offer a page event called OrientationChanged
that is raised every time the phone is rotated from portrait to landscape mode and vice versa. The event is exposed directly by the PhoneApplicationPage
class, so you can subscribe it in the XAML, as in the following sample:
<phone:PhoneApplicationPage x:Class="Webinar.Rest.MainPage" SupportedOrientations="Portrait" Orientation="Portrait" OrientationChanged="MainPage_OnOrientationChanged">
The event handler that will be generated in the code will return the information about the new orientation. You can use it to move or change the aspect of the controls placed in the page. The following sample shows how to set a different Height
of a Button
control, according to the detected orientation:
private void MainPage_OnOrientationChanged(object sender, OrientationChangedEventArgs e) { if (e.Orientation == PageOrientation.PortraitUp || e.Orientation == PageOrientation.PortraitDown) { Button1.Height = 100; } else { if (e.Orientation == PageOrientation.LandscapeLeft || e.Orientation == PageOrientation.LandscapeRight) { Button1.Height = 500; } } }
Conclusion
If you’re new to Windows Phone development, this article is very important, because we’ve learned some basic core concepts that we’re going to use again in later installments of this series.
Here is a quick recap:
- Asynchronous programming is must-have knowledge for mobile developers. We’ve learned how callbacks and the new async and await pattern will help you keep the user interface fast and responsive.
- It’s highly unlikely that your application is made of just one page, so we’ve learned how to support navigation between different pages and how to correctly manage the navigation flow.
- Application life cycle is another key concept. You have to understand how a Windows Phone application works under the hood to correctly manage all the multitasking scenarios. We’ve talked about Fast Application Switching, an improvement introduced in Windows Phone 7.5 to make the suspending and resuming process faster, and Fast App Resume, a new Window Phone 8 feature that improves the resuming experience.
This tutorial represents a chapter from Windows Phone 8 Succinctly, a free eBook from the team at Syncfusion.