(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows 8.1: Application Views improvements

(2 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
0 comments   /   posted on Nov 26, 2013
Categories:   Windows 8

Tweet

To me, one of the most useful features in Windows 8 is the application's snapping which lets me to see up to two applications at the same time on the screen. On my tablet and in the desktop there are often reasons to snap an application on the side (e.g. skype is a good candidate for snapping) and continue to work, on the main screen, with the desktop or another application. In the first release of Windows 8 this feature is still limited by some constraints. You can snap only one application (for a total of 2 side by side) and the snapped app is always 320 pixel wide, no matter the size of your monitor.

With Windows 8.1 these constraints have been changed to improve the snapping. Depending on the size of the screen you can now snap up to 4 applications and the size is now freely decided using a splitter between the applications. These improvements required some new features to be added to the developer toolset and in this article I'll show you the magic around the improved Application View management.

Application View and the basics

Application Views is the object that lets you manage the area where the application is hosted. It exists since the very first release of the operationg system, but due to the new improvements in this field, it has gained a set of new functions. To get an instance of the current application view you have to use the GetForCurrentView method as shown below.

   1: var applicationView = ApplicationView.GetForCurrentView();

Differently from the previous version, where the static class only exposed the current state, this instance, which directly refers to the area of the current application, contains a number of useful properties. The Id is an unique identifier directly related to a new feature which I'll discuss in the next part of the article and the same is for Title that lets you give (and read) a title for the view that will be shown, for example, in the thumbnail list of running apps that appears when you swipe the left side of the screen. Other useful properties are related to the current state of the application:

  • AdjacentToLeftDisplayEdge and AdjacentToRightDisplayEdge: these properties inform if the view is currently snapped and is adiacent to one of the screen edges. It is useful to dock controls according to the detected position.
  • IsFullScreen: it is true when the app fills the entire screen.
  • IsOnLockScreen: this inform if the application is no the lock screen of Windows
  • IsScreenCaptureEnabled: this read/write property allows to prevent the user to take screenshoots of the application canvas. This let you protect your rights from unwanted copies and disclosures.
  • TerminateAppOnFinalViewClose: This property determines if the application should terminate when its last view is closed.
  • Orientation: As expected you can also detect the current orientation of the screen between Landscape and Portrait.

The important to know is that the application view does not have nothing to do with the current page. It is much more related to the container of the pages. As a consequence you can take a reference to the application view once and use it in all the pages of the application. Please note that the property ApplicationView.Value has been deprecated and should not be used.

To dinamically handle the application view changes you should rely on Windws size changes. This event is raised also when the orientation changes or when the view is resized because of a snapping or unsnapping. Thanks to this you can update the application layout according to a combination of the values of these properties:

   1: public sealed partial class MainPage : Page
   2: {
   3:     private ApplicationView ApplicationView { get; set; }
   4:  
   5:     public MainPage()
   6:     {
   7:         this.InitializeComponent();
   8:         this.ApplicationView = ApplicationView.GetForCurrentView();
   9:         Window.Current.SizeChanged += Current_SizeChanged;
  10:     }
  11:  
  12:     protected override void OnNavigatedTo(NavigationEventArgs e)
  13:     {
  14:         this.UpdateVisualState();
  15:         base.OnNavigatedTo(e);
  16:     }
  17:  
  18:     private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
  19:     {
  20:         this.UpdateVisualState();
  21:     }
  22:  
  23:     private void UpdateVisualState()
  24:     {
  25:         this.txtView.Text = this.ApplicationView.Orientation.ToString();
  26:     }
  27: }

Working with multiple views

One new and interesting feature that comes with Window 8.1 is the capability to open multiple views from a single application. This is someway similar to spawning multiple windows in a desktop application but these does not appears in popup. The additional views instead are snapped or also they can fill the entire screen and hide the main application view. As the proof of fact the spawned application views work like an autonomous application.

To create a new aplication view you have to use the CoreApplication class paying attention to the context of the thread where you work. This infact determine the scope of the Window.Current property that you can use to initialize the new view. Here is a simple snippet that creates a new view:

   1: private async System.Threading.Tasks.Task<int> CreateNewView()
   2: {
   3:     CoreApplicationView newView = CoreApplication.CreateNewView();
   4:     int newViewId = 0;
   5:  
   6:     await newView.Dispatcher.RunAsync(
   7:         CoreDispatcherPriority.Normal,
   8:         () =>
   9:         {
  10:             Frame frame = new Frame();
  11:             frame.Navigate(typeof(SecondaryPage));
  12:             Window.Current.Content = frame;
  13:             newViewId = ApplicationView.GetForCurrentView().Id;
  14:         });
  15:  
  16:     return newViewId;
  17: }

As you can see, after having create the view with you need to attach its dispatcher to synchronize to its thread. When the labda is called you are in the context of the new view thread and the Window.Current points to the new application view Window. So, as you do usually in the app.xaml.cs you can creae a new frame and navigate to a page. Also pay attention that the call to GetForCurrentView here points to the new view so its Id is returned to the main thread.

After this code has run the view has been created and initialized but it is still hidden. To display the view you have to activate it using the ApplicationViewSwitcher class. It suffice a simple line of code:

   1: bool shown = 
   2:     await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId, ViewSizePreference.UseLess);

The TryShowAsStandaloneAsync method gets the id of the view and a parameter that determines its initial size. This method has a numer of overloads that are useful to position the new view. In these overloads you can detemine not only the size of the new view but also the size of the exiting one. A combination of ViewSizePreference lets you make the main view small and the new one big or instead make them divide the space half and half. Do your tryies to get the result that mostly respect your needs.

Then, you may need to close the secondary view. This is done using the SwitcAsync method in the ApplicationViewSwitcher that let you move between the views. You always have to specify the destination view and the starting view together with a parameter that says how to the switch behaves. Using the ConsolidateViews switch you ask the system to close the from view. This also means you are destroying the view and it should be removed from your management constructs.

Animate the transitions

Additional application views are for sure an interesting opportunity for the cases where you need to simulate multi-document application, having secondary view spawned in answer to different documents opened. This way you can create a single logic handling a document and then create a new view and start this logic with a reference with the document itself.

Give that we are in a Windows Store app that, by definition, should be graphically appealing, fast and fluid as the pillar says, the team added the capability to use animations to make the switch between views someway much more fluid and beautiful. The sole support to this feature is from a method called "PrepareForCustomAnimatedSwitchAsync" that simply acquires the same parameters of TryShowAsStandaloneAsync, but simply prepares the ui to a subsequent switch of view. The whole animation must be handled directly from your code.

This makes the work subtly complicated because the views must be created with the effect in mind and prepared for the switching operations. On the other side is geves you the most of the control so you are not constrained to a fading animation (as the example shows), but you can apply you fantasy to get the best. So first of all you have to create the storyboards in the xaml:

   1: <Page.Resources>
   2:     <Storyboard x:Name="fadeOut">
   3:         <FadeOutThemeAnimation Duration="00:00:01.00" Storyboard.TargetName="root" Completed="fadeOut_Completed" />
   4:     </Storyboard>
   5: </Page.Resources>

In this example I'll show how to handle a fading animation from the MainPage to the secondary. The main page will be faded out and then replaced by the SecondaryPage. In the code behind you can handle this in different ways. In my case I simply drive the animation from the main page but, if you want also the secondary page to fade-in when entering, the best will be to make each page to drive his half of the animation.

   1: TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
   2:  
   3: private void fadeOut_Completed(object sender, object e)
   4: {
   5:     tcs.SetResult(true);
   6: }
   7:  
   8: private System.Threading.Tasks.Task FadeOut()
   9: {
  10:     fadeOut.Begin();
  11:     return tcs.Task;
  12: }
  13:  
  14: private async void Button_Click(object sender, RoutedEventArgs e)
  15: {
  16:    var newView = await CreateNewView();
  17:  
  18:    bool shown = await ApplicationViewSwitcher.PrepareForCustomAnimatedSwitchAsync(
  19:        newView.Id, this.ApplicationView.Id, ApplicationViewSwitchingOptions.SkipAnimation);
  20:  
  21:    if (!shown)
  22:    {
  23:        await this.FadeOut();
  24:  
  25:        int fromId = this.ApplicationView.Id;
  26:  
  27:        await newView.ApplicationView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
  28:            async () =>
  29:            {
  30:                await ApplicationViewSwitcher.SwitchAsync(newView.Id, fromId, ApplicationViewSwitchingOptions.SkipAnimation);
  31:            });
  32:    }
  33: }

The code here calls the PrepareForCustomAnimatedSwitchAsync method then starts the animation asynchronously. Once the animation completes, the task is closed (see the SetResult) and the control returns to the main thread. In this moment the interface has been faded out so, waitin the signal from the new view's dispatcher, its thread calls the SwitchAsync method that does the final part of the view switching.

The operation is not so easy as expected but the effect may be beautiful to see. You can imagine to move object, apply a zoom, or simply use a fading animation as in my code. But the switching needs to be carefully planned and the framework does a little to help you.

Application switching and protocols

Once you understand the reason of creating multiple views, it become really useful to split parts of the logic to handle document specific tasks. In this context you may find useful to handle protocol or file association to directly open a secondary view. This is really easy to be implemented if you simply handle the protocol (or file) activation and you do the switch to the right view.


Subscribe

Comments

No comments

Add Comment

Login to comment:
  *      *       

From this series