giovedì 12 giugno 2014

Windows Phone 8.1 e i pulsanti hardware

Windows Phone 8.1 è un enorme passo avanti rispetto al passato verso una reale unificazione del codice sorgente tra la piattaforma desktop e la piattaforma mobile. Unificando i controlli e utilizzando pattern come MVVM per disgiungere completamente la componente visuale da quella logica è possibile scrivere degli applicativi il cui modello è comune e dove solo le pagine hanno comportamenti specifici per la piattaforma su cui stanno girando oppure, grazie agli stati visuali, addirittura avere le viste in comune per ogni piattaforma e variare il posizionamento dei componenti in base al form factor. Poi, ovviamente, un controllo per Windows Phone verrà renderizzato e gestito diversamente dall'OS rispetto allo stesso controllo per Windows 8.1, però in linea di massima allo sviluppatore questo dovrebbe importare poco se non rispetto al form factor. Il sistema di input è tutto a carico dell'OS.

Con Windows Phone 8.1 il ciclo di vita dell'applicativo è stato cambiato a favore dello stesso modello di Windows 8.1 Desktop. In un progetto Win81 che utilizza le WinPRT (Windows Phone RT), il pulsante hardware "back" viene gestito dell'OS come il mezzo di uscita dall'applicativo. Questo comportamento è profondamente differente rispetto a Windows Phone 7.1/8 e potrebbe creare problemi nella conversione di alcune applicazioni. La soluzione al nostro problema di retrocompatibilità è, però, decisamente semplice.

In un progetto WinPRT i pulsanti hardware sono gestiti dalla classe HardwareButtons che espone una serie di eventi relativi ai pulsanti di back, volume e camera. Tramite questa classe, possiamo scrivere un controllo dedicato alla gestione del pulsante di "indietro" secondo il vecchio comportamento che troviamo nei Windows Phone 7.1 e 8 prima generazione:

  public class PhoneButtonsAwarePage
        : Page
    {
        #region .ctor

        public PhoneButtonsAwarePage()
            : base()
        {
            this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Required;
            HardwareButtons.BackPressed += HardwareButtons_BackPressed;
            HardwareButtons.CameraPressed += HardwareButtons_CameraPressed;
        }

        

        ~PhoneButtonsAwarePage()
        {
            try
            {
                HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
                HardwareButtons.CameraPressed -= HardwareButtons_CameraPressed;
            }
            catch(Exception)
            {

            }
        }

        #endregion

        #region Methods

        protected virtual void OnBackPressed(BackPressedEventArgs e)
        {
            if (this.Frame.CanGoBack)
            {
                e.Handled = true;
                this.Frame.GoBack();
            }
            else
                e.Handled = false;
        }

        protected virtual void OnCameraPressed(CameraEventArgs e)
        {            
        }

        #endregion

        #region Event Handlers

        private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
        {
            this.OnBackPressed(e);
        }

        private void HardwareButtons_CameraPressed(object sender, CameraEventArgs e)
        {
            this.OnCameraPressed(e);
        }        

        #endregion
    }


Basterà poi scambiare la pagina standard con questa nuova classe nello XAML e il gioco è fatto.

<common:PhoneButtonsAwarePage x:Class="Test.Views.TestPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:Test.Views"
      xmlns:common="using:Test.Common"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d"
      RequestedTheme="Light"
      Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>

    </Grid>
</common:PhoneButtonsAwarePage>

Il nostro applicativo seguirà ora la regola: "finchè ci sono elementi nella backstack torna indietro, altrimenti esci". Ovviamente il metodo di gestione dei pulsanti è scritto come virtual, in modo da poter gestire l'override per ogni esigenza particolare.

Nessun commento:

Posta un commento