-
Xamarin Forms for Windows Phone devs – Navigation and application lifecycle
One of the core concepts when you create a mobile application is navigation: it’s unlikely that an app is made by just one page, so you need to provide a way to the user to move from one page to the other. We’ve already seen, in the previous post, that the base navigation infrastructure for Xamarin Forms is provided by the NavigationPage class: by encapsulating a basic ContentPage page into a NavigationPage, we’ll be able to navigate from one page to another using the Navigation property, regardless of the platform where the application is running.
###
###
Navigate to another page
We’ve already seen that, to proper support navigation, we need to encapsulate our page into a NavigationPage. From a Windows Phone developer point of view, this operation is completely transparent to the user: a standard ContentPage and a ContentPage encapsulated into a NavigationPage will look exactly the same, since Windows Phone doesn’t provide a visual way to navigate through the different pages of the applications. The navigation is managed by the Back key, which is a physical button. In Android and iOS, instead, we can notice immediately if we’re using a NavigationPage or not: in the first case, in fact, the application will display an header with the name of the page and an arrow to go back to the previous page, if existing. The following image shows the same ContentPage on Android: the first one is directly displayed, the second one, instead, is embedded into a NavigationPage first. This is an important difference to understand if you’re coming to the Windows Phone world.
In the previous post we’ve seen the basic way to navigate from one page to the other: by using the PushAsync() method of the Navigation property, which requires as parameter the new page where we want to redirect the user.
private async void OnNavigateClicked(object sender, EventArgs e) { await Navigation.PushAsync(new DetailView()); }
This code is the equivalent of calling the Navigate() method of the Frame class in a Windows Store app or the NavigationService class in a Silverlight app.
This sample assumes that our project has a page called DetailView: by passing a new instance to the PushAsync() method, we’ll redirect the user to this page. Again, in Windows Phone you’ll just be redirected to a new page and, to go back, you’ll just have to use the Back button; on Android and iOS, instead, the header will change and it will display, other than the page title, a virtual back button to redirect the user to the previous page. The following image will help you to understand the difference:
In case you want to provide in your page an additional button to redirect the user to previous page, you can use the PopAsync() method of the Navigation class, like in the following sample:
private async void OnNavigateBackClicked(object sender, EventArgs e) { await Navigation.PopAsync(); }
###
The previous code is the equivalent of the GoBack() method exposed by the Frame class in a Windows Store app or the NavigationService class in a Silverlight app.
Displaying a modal view
Android and iOS has the concept of “modal view”, which is a full screen page that is displayed on top of navigation stack. The difference with a standard navigation is that the navigation bar will be hidden and the page will use the whole screen: the only way to go back to the previous page is by using the Back button (in Android) or by adding a dedicated button in the page, that will invoke a specific method offered by the Navigation class. To display a page in modal view, you’ll have to use the PushModalAsync() method, like in the following sample:
private async void OnModalViewClicked(object sender, EventArgs e) { await Navigation.PushModalAsync(new DetailView()); }
The following image shows the difference between a navigation to the DetailView page using the PushAsync() method (on the left) and the PushModalAsync() method (on the right): as you can see, the right page doesn’t have the navigation bar at the top.
On Windows Phone, the PushModalAsync() method and the PushAsync() one has the same effect: since Windows Phone doesn’t have the concept of modal view, the PushModalAsync() method will simply redirect the user to the new page, allowing him to go back to the previous one simply by pressing the Back button. If you want to manually dismiss a modal view and redirect the user to the previous page, you can use the PopModalAsync() method:
private async void OnBackClicked(object sender, EventArgs e) { await Navigation.PopModalAsync(); }
###
Combining different page’s types
In the previous post we’ve seen that Xamarin Forms offers different types of pages, like TabbedPage or CarouselPage, which were set directly as starting page of our application by assigning them to the MainPage property of the App class. However, we can also combine different page types, to create more complex navigation patterns. For example, we could have a NavigationPage that redirects the user to a TabbedPage, like in the following example:
private async void OnTabbedPageClicked(object sender, EventArgs e) { TabbedPage tabbedPage = new TabbedPage(); tabbedPage.Children.Add(new DetailView()); tabbedPage.Children.Add(new AnotherView()); await Navigation.PushModalAsync(tabbedPage); }
With this code, the user will be redirected from the current page to another page that will display two different sections: one connected to the DetailView page, the other one to the AnotherView page. Vice versa, we could have a TabbedPage that contains, as children, a NavigationPage, so that we can perform additional navigations from that page:
public class App : Application { public App() { TabbedPage tabbedPage = new TabbedPage(); NavigationPage navigationPage = new NavigationPage(new MainView()); tabbedPage.Children.Add(navigationPage); tabbedPage.Children.Add(new AnotherView()); this.MainPage = tabbedPage; } }
This way, the first section of the tab control (which is a MainView page) will allow the user to navigate to another page of the application (like a detail page). The following image shows a NavigationPage displayed inside a tab:
Again, you won’t notice instead any difference in the Windows Phone application: you will just see a Pivot control with two items, one for the MainView and one for the AnotherView pages.
The only thing to keep in mind, in this scenario, is that the TabbedPage takes, as label for the tab, the title of the page: in this case, since we’re not directly setting as tab content the ContentPage, but we have wrapped it into a NavigationPage, we have also to set its Title property, otherwise the tab label will be empty. This is the proper code:
public class App : Application { public App() { TabbedPage tabbedPage = new TabbedPage(); NavigationPage navigationPage = new NavigationPage(new MainView()) { Title = "Main page"}; tabbedPage.Children.Add(navigationPage); tabbedPage.Children.Add(new AnotherView()); this.MainPage = tabbedPage; } }
Page navigation
One common requirement in a mobile application is to detect is moving towards the current page or he’s navigating away to go to another page. This approach is very well known to Windows Phone developers: Windows Store apps, in fact, offer the OnNavigatedTo() and OnNavigatedFrom() events, which are often used to load data or to unsubscribe to event handlers. The OnNavigatedTo() event is especially useful to load the data to display in the current page: since it’s an event handler, we can use it also to invoke asynchronous method with the async / await pattern (which, instead, is not possible in the page’s constructor).
These two events are mapped in Xamarin Forms with the OnAppearing() method (that is invoked when the page is being displayed) and the OnDisappearing() method (that is invoked when the user is moving away from the current page):
public partial class MainView { public MainView() { InitializeComponent(); } protected override void OnAppearing() { Debug.WriteLine("Page is appearing"); } protected override void OnDisappearing() { Debug.WriteLine("Page is disappearing"); } }
The application lifecycle
If you’re a Windows Phone developer, you should be familiar with the concept of application’s lifecycle. To satisfy the typical requirement of a mobile environment (performance, battery consumption, etc.) all the mobile platform applies constraints to the operations that an application can perform in background. On all the platforms, typically, when an application isn’t in foreground anymore is suspended and it doesn’t have the chance to perform operation: this scenario is managed using other approaches, like background tasks in Windows Phone.
Xamarin Forms has added three methods in the shared App class to properly manage the application’s lifecycle, in case you need to perform additional operations when the app is launched, suspended or resumed. The following sample shows how to declare and use these events:
public class App : Application { protected override void OnStart() { Debug.WriteLine("Application started"); } protected override void OnSleep() { Debug.WriteLine("Application suspended"); } protected override void OnResume() { Debug.WriteLine("Application resumed"); } }
If you are a Windows Phone developer, these events should be familiar to you:
- OnStart() is called when the application is launched from scratch.
- OnSleep() is called when the application is suspended.
- OnResume() is called when the application is resumed. It’s important to highlight that this method is invoked only when a previous instance of the app was kept in memory and it’s restored: for example, on Windows Phone, in case of tombstoning (so the process was terminated by the operating system due to low resources) you’ll trigger the OnStart() method at startup and not the OnResume() one. </ul>
Wrapping
In this posts we’ve seen the basic concept of navigation and application’s lifecycle management and how they compare to the Windows Phone approach. In the next posts, we’ll start to see how to create a real application using the MVVM pattern. As usual, you can find the samples used in this post on GitHub: https://github.com/qmatteoq/XamarinFormsSamples</font>
</font></font>
- OnResume() is called when the application is resumed. It’s important to highlight that this method is invoked only when a previous instance of the app was kept in memory and it’s restored: for example, on Windows Phone, in case of tombstoning (so the process was terminated by the operating system due to low resources) you’ll trigger the OnStart() method at startup and not the OnResume() one. </ul>
- OnSleep() is called when the application is suspended.
in
- OnStart() is called when the application is launched from scratch.
-
Xamarin Forms for Windows Phone devs – A brief introduction
Mobile cross platform development is one of the hottest topics nowadays. The market offers to consumers three major mobile platforms (iOS, Android and Windows Phone), each of them based on its own technologies, patterns and tools. iOS is based on Objective-C or Swift as programming language and uses XCode as development tool; Android is based on Java as programming language and uses Eclipse as development tool (even if there are many other alternatives); in the end, Windows Phone is based on C#, VB.NET or HTML / JS and uses Visual Studio as development tool.
Consequently, if you’re a mobile company and you want to create applications that target all of them, you’ll need three dedicated teams, each of them with their own skills and knowledge. Unfortunately, not all the companies can afford such an investment, especially if mobile development isn’t the core business: for example, you’re a web agency that would like to offers to their customers, other than a website, also a companion application; or maybe you’re an enterprise company and you want to provide mobile tools to your employees, regardless of the mobile device they have.
Consequently, many software companies have tried to find new approaches to allow developers to create applications that are able to share as much as code as possible between all the platforms, so that the development teams don’t need to create three completely different applications from scratch. Currently, there are two approaches to achieve this goal:
- Web based apps: this approach is based on HTML and Javascript technologies, which are executed on the phone using a WebView control that is embedded into the app. Thanks to tools like Apache Cordova (previously known as PhoneGap), you’re able to access to some of the native features of the platform (like storage, sensors, etc.) by using Javascript APIs. This approach is based on the principle “write once and run everywhere”: you’re going to create a single application, that will run on every platform without any change.
- Xamarin: this approach allows developers to use Microsoft technologies and tools (C#, Visual Studio, the .NET Framework) to create native application for all the platforms. We’re going to analyze better in this post how it works and which are the differences compared to web based apps.</ul>
What is Xamarin?
Xamarin is a company founded by Miguel De Icaza, which gathered together all the teams that created Mono, MonoTouch and Mono for Android, which are the open source implementations of the .NET framework that can run on platforms different than Windows. With Xamarin tools, you’ll be able to create applications for iOS and Android by using C# as a programming language and Visual Studio (or Xamarin Studio) as a development environment. All the iOS and Android APIs have been translated into C# classes and objects which, under the hood, are compiled into native code. Which are the main advantages of using Xamarin instead of a web approach based on tools like Apache Cordova?
- Performance: the biggest downside of web based apps is that are executed in a WebView, so they don’t offer the same performance of a native app. In addition, the application’s performances change a lot based on the operating system’s version, since typically every new release improves the browser’s performance and compatibility with the latest web technologies.
- Design: the “write once and run everywhere” approach is great because it minimizes the amount of work for developers, but it reduces the quality of the design and the user experience. Every platform has its own visual style and guidelines, so it’s impossible to create an application with a common visual layout that looks good on each platform.
- Features: since web apps are based on the “write once and run everywhere” approach, tools like Cordova are able to offer to developers only a minimum set of APIs that are in common between every platform. You won’t be able to use features that, instead, are specific for each platform, like live tiles on Windows Phone or background activities in Android.</ul> ###
What is not Xamarin?
The most important concept to understand is that Xamarin isn’t a “write once and run everywhere” platform. When you develop web apps, you can virtually know nothing about the technical details of the different mobile platforms: creating a web app is just like creating a website, with the only exception that you’ll be able to interact with the hardware thanks to libraries like Cordova. Xamarin, instead, requires a good knowledge of each platform and how the main features are implemented, like the navigation framework, the application’s lifecycle, the design language, etc. A good example is how the design of the application’s pages is defined: you’ll have to design three different interfaces using the specific platform tools, like XAML for Windows Phone or the XCode designer for iOS.
Consequently, Xamarin isn’t a technology to create mobile apps for each platform without having to learn the basics like with web apps, but it will help you to:
- Reuse your business logic: by using technologies like Portable Class Libraries (PCL), you’ll be able to write the logic just once (like services to interact with a database or a REST service) and to reuse it in every platform.
- Reuse your existing skills: you’ll still have to learn the basic concepts of developing apps for iOS and Android, but you won’t have to learn a new programming language in the process. You’ll be able to reuse your existing .NET and C# knowledge.</ul> Another important consideration to do is that Xamarin isn’t the best cross platform solution for everyone: if you’re already a Microsoft developer, it’s for sure the best technology out there to reuse your skills to create applications for all the main mobile platforms. However, if you’re an iOS or Android developer is definitely a good investment, but it will require you more time to assimilate it, since you’ll have to learn a new programming language in the process: C#.
In the end, Xamarin isn’t very cheap, so it’s more suitable for professionals and big development teams. Currently, there are three available plans:
- Starter, which is free but it has many limitations. It doesn’t offer integration with Visual Studio, it doesn’t support Xamarin Forms, it has a limitation in the size of the app that you can create, etc.
- Indie, which costs 25 $ per month and it’s dedicated to indie developers. The biggest downside of this plan is that it doesn’t support Visual Studio integration.
- Business, which is the most popular plan. It costs 83 $ per month and it includes all the available features, from Xamarin Forms to Visual Studio integration.</ul> Xamarin offers also an Enterprise plan that includes the same tools of the Business plan, in addition to advanced services like One Business Day support, a dedicated Technical Account Manager, etc.
However, during the recent Connect() event by Microsoft, Xamarin has announced that in 2015 is going to release a new Starter edition, with less limitations and integrated with Visual Studio 2013 Community, the free Professional version recently released by Microsoft for independent developers and small companies.
What is Xamarin Forms?
We’ve learned that using Xamarin requires a good knowledge of each platform, especially when it comes to design the user interface and to manage the navigation. This way, we are able to create applications that follows the specific platform’s guidelines. However, this approach is very expensive for a single developer, since it requires to learn and master every design technology: Windows Phone is based on XAML, Android on its own XML dialect while iOS uses a visual tool called Interface Builder.
Xamarin Forms is a recent technology created by Xamarin in order to partially solve this problem: it offers a new way to create the application’s interface by using the XAML language, which should be already familiar to Windows Phone and Windows developers. Xamarin Forms offers a set of controls (which are represented by a XML tag) that, at runtime, are converted into the most appropriate native control: this way, we’ll be able to define the user interface just once, but the application will continue to have the native look on each platform. For example, if you need to grab the input from the user, Xamarin Forms offers a control called Entry, which is rendered as a TextBox in Windows Phone, as an EditText in Android and as an UITextField in iOS.
With Xamarin Forms, the development approach is very similar to the Windows and Windows Phone one: every page is composed by a XAML file (which contains the layout definition) and a code behind file (which contains the code that interacts with the user interface). You have also access to all the most important XAML features, like binding, converters, styles, behaviors, etc. If you already have a good experience in developing Windows Store and Windows Phone apps like me, Xamarin Forms is for sure the easiest way to reuse your knowledge to create mobile applications for all the platforms.
In the next posts we’ll see, in details, how to create an application using Xamarin Forms, with a strong focus on the MVVM pattern: since this pattern makes easier to separate the user interface from the logic, it will greatly help us to reuse the same code on all the platforms.
What do you need to start with Xamarin Forms?
The basic requirements to start with Xamarin Forms are the Xamarin tools, which can be downloaded from http://www.xamarin.com. Then, you have two ways to use it: with Xamarin Studio, which is the development environment created by Xamarin, or Visual Studio 2013. However, the second one is the only solution that can be used to create applications for all the platforms: Xamarin Studio, in fact, supports only Android and iOS, while with Visual Studio you’ll be able to create a project that targets also Windows Phone. However, Xamarin Studio, unlike Visual Studio 2013, is available also for OS X.
If you want to build applications for iOS you’ll need also a Mac, since Windows doesn’t have the required runtime: however, Xamarin includes a tool called Xamarin Build Host, which can be installed and launched on a Mac that is in the same network of our Windows computer. Visual Studio will be able to connect to it and to use it to build the iOS application and, eventually, to deploy it on the emulator or on a phone that is connected to the Mac.
The Android runtime, instead, can run just fine both on Windows and OS X, so there aren’t special requirements. The only problem you’ll have to deal with is the Android emulator: the native one created by Google is really bad, since it offers really poor performances. Consequently, many companies have created alternative emulators, with the goal to offer better performances and additional tools: Xamarin itself offers an emulator called Android Player, which can be downloaded from https://xamarin.com/android-player. Another good alternative is Genymotion, which is free for personal use. The downside of these emulators is that they are based on VirtualBox, the virtualization technology by Oracle, which doesn’t play well with Hyper-V, which is the Microsoft virtualization technology used for the Windows Phone emulators. Consequently, you have two ways if you want to test your Xamarin Forms app both on Windows Phone and Android:
- Use a real Android device and keep using the Windows Phone emulator.
- If you’re reading this post, you probably are a Windows or Windows Phone developer. Consequently, it’s very likely that you already have a Windows Phone device for testing, but not an Android one. Scott Hanselman explains in this post how to change your computer’s bootloader so that you can launch Windows with Hyper-V disabled, without having to completely uninstall it: this way, you’ll be able to launch the Android emulator and keep using a Windows Phone device for testing.</ul> However, there’s another alternative: Visual Studio 2015 Preview, in fact, includes a very fast Android emulator. Since it’s based on Hyper-V, it can run side by side with the Windows Phone emulator. The only downside of this approach is that you’ll need to use preview software: other than installing the Preview version of Visual Studio 2015, in fact, you’ll need also to switch to the Xamarin beta channel, since the current stable version supports only Visual Studio 2013. To do that, you’ll need to open Xamarin Studio or Visual Studio (after you’ve installed the Xamarin Tools) and, in the Settings, check for updates: by default, Xamarin is set to use the Stable channel, but you can switch to get updates from the beta or alpha ones.
Wrapping up
In this post we’ve seen what are Xamarin and Xamarin Forms and why it can be a great solution for Microsoft developers to create applications for all the mobile platforms. This post was just a theoretical introduction to this platform: in the next ones we’ll start to see some code and how to create our first cross platform app reusing the skills we’ve acquired by developing apps for Windows and Windows Phone.
- Indie, which costs 25 $ per month and it’s dedicated to indie developers. The biggest downside of this plan is that it doesn’t support Visual Studio integration.
- Design: the “write once and run everywhere” approach is great because it minimizes the amount of work for developers, but it reduces the quality of the design and the user experience. Every platform has its own visual style and guidelines, so it’s impossible to create an application with a common visual layout that looks good on each platform.
- Xamarin: this approach allows developers to use Microsoft technologies and tools (C#, Visual Studio, the .NET Framework) to create native application for all the platforms. We’re going to analyze better in this post how it works and which are the differences compared to web based apps.</ul>
in
- Web based apps: this approach is based on HTML and Javascript technologies, which are executed on the phone using a WebView control that is embedded into the app. Thanks to tools like Apache Cordova (previously known as PhoneGap), you’re able to access to some of the native features of the platform (like storage, sensors, etc.) by using Javascript APIs. This approach is based on the principle “write once and run everywhere”: you’re going to create a single application, that will run on every platform without any change.
-
Prism and Universal Windows apps – Layout management
In the previous posts we’ve seen that one of the requirements to setup the Prism infrastructure is to change the Views in our application so that, instead of inheriting from the Page class, we inherit from the VisualStateAwarePage one. One of the features offered by this class is the layout management support: by using visual states, we’ll be able to easily manage the different visual layouts that the application can take advantage of.
Unfortunately, at the moment, this feature is supported only in Windows 8 applications. The VisualStateAwarePage offers, automatically, three different visual states:
- DefaultLayout is the standard layout that is used when the application is displayed in landscape mode (which is the default one on Windows 8 devices).
- PortraitLayout is the layout that is used when the application is displayed in portrait mode.
- MinimalLayout is the layout that is used when the application is resized and its width reaches a value that it’s not enough anymore to display the standard layout, so we need to change it.
Let’s see how to implement these scenarios.
Managing the portrait layout
Thanks to the visual states approach, we’ll be able to change the layout by simply specifying, using the XAML, the differences compared to the standard layout. Let’s see the following sample:
<storeApps:VisualStateAwarePage x:Class="Prism_LayoutManagement.Views.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Prism_LayoutManagement.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:storeApps="using:Microsoft.Practices.Prism.StoreApps" xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm" mc:Ignorable="d" mvvm:ViewModelLocator.AutoWireViewModel="True" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="DefaultLayout"/> <VisualState x:Name="PortraitLayout"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonsPanel" Storyboard.TargetProperty="Orientation"> <DiscreteObjectKeyFrame KeyTime="0" Value="Vertical" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <StackPanel x:Name="ButtonsPanel" Orientation="Horizontal"> <Button Content="Button 1" /> <Button Content="Button 2" /> <Button Content="Button 3" /> <Button Content="Button 4" /> </StackPanel> </Grid> </storeApps:VisualStateAwarePage>
The page simply contains four Button controls, which are placed inside a StackPanel which Orientation property is set to Horizontal. This means that, when the page is displayed using the default layout (which is the landscape mode), the four buttons are displayed one near the other. Our goal is to change this layout so that, when the application is used in portrait mode, the buttons are displayed one below the other.
Let’s introduce the VisualStateManager, which is the class that is able to manage the different visual states of a control. Each visual state matches one of the possible status of the control: for example, the Button control uses a visual state to define how it should look like when it’s pressed. As we’ve already mentioned, the best advantage of this approach is that we won’t have to define the whole layout of the control every time, but it’s enough to define the differences between one state and the other. For example, the Pressed state of the Button control simply specifies that, compared to the standard layout, the background of the button should be white instead of black, while the text should be black instead of white.
We use the same approach to manage the different layouts of the page: inside the VisualStateManager we’ve added inside the main Grid, we add a list of VisualState items, each one with a specific name that follows the Prism conventions. The standard one is called DefaultLayout: it’s empty, since it’s the base definition of the page. Then we create a new one for the portrait mode, which name is PortraitLayout: inside it, by using animations, we specify the differences with the default layout. In our sample, we define a Storyboard with a single ObjectAnimationUsingKeyFrames animation, which simply changes the value of the Orientation property of the StackPanel: from Horizontal to Vertical. If we would have needed to change other controls, we would have simply added other animations inside the Storyboard.
If you want to test the code we’ve written, you can use the Windows 8 simulator: in the Debug dropdown menu, simply choose Simulator instead of Local machine. The simulator, in fact, offers an option to simulate the rotation of the device, which is very useful if you’re developing and testing your application on a traditional computer.
Managing the resize of the application
If you’re a Windows 8 user, you should be familiar with the concept of “snapped”: you have the chance to keep multiple applications opened at the same time and to place them side by side. In Windows 8.1, this feature has been improved: if, in Windows 8, the snapped view had a fixed size, in Windows 8.1 the user is able to resize the width of the application to virtually any size, until it reaches a minimum width (by default it’s 500px, but it could be changed to 320px).
As developers, we need to correctly manage this scenario, so that we can provide a good user experience, regardless of the size of the application. The first step to achieve this goal is to create a fluid layout, by using controls (like Grid) that are able to adapt their content to the window’s size. This way, if the user resizes the application, the layout will automatically adapt to display as more content as possible. If you’re familiar with web development, this approach is very similar to the responsive design concept that applies to websites, so that they can automatically adapt to the screen’s size (pc, tablets, smartphones, etc.).
However, this step isn’t enough: if the application’s window becomes too small, it can be hard to display the content by using the same layout and control we’re using with the standard layout. The easiest way to manage this scenario is to use, again, visual states: when the application’s size goes below a minimum width that, according to our design, isn’t enough anymore to properly display the content, we switch to another layout.
This goal is reached in the same way we’ve seen before to manage the portrait mode: by defining a new visual state, identified by the key MinimalLayout, with the difference with the default layout. Let’s take a look at the following sample:
<storeApps:VisualStateAwarePage x:Class="Prism_LayoutManagement.Views.MinimumWidthPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Prism_LayoutManagement.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:storeApps="using:Microsoft.Practices.Prism.StoreApps" xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm" mvvm:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d"> <storeApps:VisualStateAwarePage.Resources> <CollectionViewSource Source="{Binding Path=Persons}" x:Name="PersonsCollection"/> </storeApps:VisualStateAwarePage.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="DefaultLayout"/> <VisualState x:Name="MinimalLayout"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="GridPersons" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ListPersons" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <GridView ItemsSource="{Binding Source={StaticResource PersonsCollection}}" SelectionMode="None" IsItemClickEnabled="True" Margin="120, 0, 12, 0" x:Name="GridPersons" > <GridView.ItemTemplate> <DataTemplate> <Grid HorizontalAlignment="Left" Width="250" Height="250"> <Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"> <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/> </Border> <StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}" Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/> <TextBlock Text="{Binding Surname}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/> </StackPanel> </Grid> </DataTemplate> </GridView.ItemTemplate> <GridView.ItemsPanel> <ItemsPanelTemplate> <ItemsWrapGrid GroupPadding="0,0,70,0"/> </ItemsPanelTemplate> </GridView.ItemsPanel> </GridView> <ListView ItemsSource="{Binding Source={StaticResource PersonsCollection}}" Visibility="Collapsed" x:Name="ListPersons"> <ListView.ItemTemplate> <DataTemplate> <StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}" Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/> <TextBlock Text="{Binding Surname}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> </storeApps:VisualStateAwarePage>
The page contains two controls to display collections: GridView and ListView. Then, in the page resources, I’ve defined a CollectionViewSource object, which is connected to a collection in the ViewModel. As you can see, both controls are connected to the same CollectionViewSource: the result is that both of them are displaying the same data. However, there’s an important difference: by default, the GridView control is displayed, while the ListView one is hidden (you can notice that the Visibility property is set to Collapsed). This means that, when the application is used in full screen, we display the data using a GridView control, which fits best this scenario, since it uses a horizontal navigation approach.
The VisualStateManager in the page, however, defines a visual state called MinimalLayout, which executes two animations, which interact with the Visibility property of the controls: the first one hides the GridView, while the second one displays the ListView. This way, when the application is resized to a size that would make the GridView impossible to use and read, we switch to a ListView control, which instead is easier to use also with a small size, since it displays the data with a vertical layout.
By default, the minimum width is set to 500px: this means that, when the application is resized to less than 500px, the MinimalLayout visual state will trigger. Vice versa, when the size of the application goes back to 500px or more, the DefaultLayout is restored. If you want to change this value, it’s enough to change a property offered by the VisualStateAwarePage class called MinimalLayoutWidth. The following sample shows how to set it, in the XAML, to change the minimum width to 800px:
<storeApps:VisualStateAwarePage x:Class="Prism_LayoutManagement.Views.MinimumWidthPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Prism_LayoutManagement.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:storeApps="using:Microsoft.Practices.Prism.StoreApps" xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm" mvvm:ViewModelLocator.AutoWireViewModel="True" MinimalLayoutWidth="800" mc:Ignorable="d"> <!-- content of the page --> </storeApps:VisualStateAwarePage>
If you want to play with this feature remember that, by default, the minimum width of the Windows Store app is 500px: this means that, by default, you won’t be able to trigger the visual state, since you can’t resize the application to less than 500px. However, in the manifest file, in the Application section, you’ll find an option called Minimum width that will enable to you to change it to 320 px (which was the size of the old snapped view in Windows 8).
Wrapping up
As you usual, you can find the sample project used for this post on GitHub at https://github.com/qmatteoq/Prism-UniversalSample. Just remember that, this demo only, will contain just the Windows 8.1 demo, since the feature described in this post works only in Windows 8.1.
Index of the posts about Prism and Universal Windows apps
- The basic concepts
- Binding and commands
- Advanced commands
- Navigation
- Managing the application’s lifecycle
- Messages
- Layout management
Sample project: https://github.com/qmatteoq/Prism-UniversalSample
in
subscribe via RSS