lunedì 4 luglio 2016

C# for n00bs, part one

Introduction to C# for N00bs who wants to start coding

It's a long time since the introduction of C# (read C Sharp) language at the beginning of the 00s. Sixteen years have passed since the introduction of .NET and C#, and the language is still in its evolution cycle. The last release, C# 6.0, was introduced just eleven months ago. 

C# is multi paradigm language as:
  • it's imperative
  • it's generic
  • it's object oriented
  • can be used for function programming
  • it's component oriented
also
  • it's strongly typed
  • it's declarative
Nearly all of these characteristics will be seen later in the article. C# is also an ISO Standard (ISO/IEC 23270:2006) and an ECMA Standard (ECMA-334), so everyone can develop its personal implementation.

It's all about data and instructions to use it

Nearly every programming language is based on two fundamental concepts: data and instructions. The first it's about "what" we're working with. The second one it's about "how and when" we're working with.

Just imagine a flow like this:
  1. Take a pot.
  2. Fill it with 250 ml of water.
  3. Place the pot on fire.
A developer will see the pot and the water as the data part of the flow, and the list above as the instructions. It's easy uh?

When developing a software, you need to "declare", aka tell the machine which data types to use and how to call them. You know, if you have one pot, it's just "pot". When you have seven pot, you must call them "Doc", "Grumpy", and so on because you need and unique identifier for each pot. Once "declared", data con be used in instructions. So you can "fill Grumpy with 250 ml of Water". Simply enough, uh?

Giving a first definition of "object" let's say it's the virtual correspondence to a real life object, like a pot, or a more abstract concept, like "communication" or "signal". An object is the sum of data and instruction used to define, or reproduce, the wanted behaviour of an element.

Introduction to data types

You've expected this. "Can I use only pots in my software?". Of course not. You have a set of basic types, the so called "simple" types, that are used to build more complex data. And you have objects, the complex data itself. 

Simple types

byte: the smallest numeric type. It's just, well, one byte, or 8 bits if you want. Can represent values just between 0 and 255. It's not signed, and it is one of the base types used in computer sciences. When you talk about data, you talk about one or aggregation of bytes.

int: it's a numeric type, represents a number between -2,147,483,648 and 2,147,483,647, with sign of course. It's a 32 bit numeric type. For now, just take it as a dogma.

long: it's another numeric type. It's just like int, but represents a number between -9,223,372,036,854,775,808 and 9,223,372,036,854,775,807. Long it's also signed as you can see. It's a 64 bit numeric type.

float: the first numeric type that supports fractional parts. It's used to say "floating point types", with the point used as usual for separation between decimal and fractional part. The point it's "floating" because the position is not fixed on the number. Example: 2.34 or 23.4. The point "floats" in memory. Float can represent numbers between ±1.5^−45 and ±3.4^38, with a precision of 7 digits. That's a lot. Float it's a 32 bit signed floating point number.

double: double it's just like float, but can represent numbers between ±5.0 × 10^−324 and ±1.7 × 10^308, with a precision of 16 digits. Double it's huge. It's a 64 bit signed floating point number.

string: friend of so much devs, a string represent the dev concept of "text". Strings store textual data in memory and allow text manipulation. It differs from other simple types for great degree, as it's also and object. But for now just take it, a string is a text bunch of data.

Complex data

You can combine the simple data types above to construct much more complex custom data types. These are structures, classes, enumerations and interfaces. We cannot talk now about them, as we must first cover other aspects of the language.

Special mention: namespaces

C# empathizes separation of concerns parading, which means that your program will be separated in small pieces of code built exactly to address separate concerns. This separation it's done not only at object level, it's obvious that a pot cannot be a car. It's also done using namespaces. Think at them like drawers. I will put in "Network" namespace all my objects related to network communications, and "Animations" everything related to animations in my graphic interface. So a namespace is a container used to organize and limit access to objects in your application.

It's all for now. Next time we will start coding the first very basic stuff. We will start talking about the basic structure of a program then start with some basic computations and data access. Enjoy!

martedì 4 novembre 2014

Navigation service nelle Windows Store App e in Windows Phone 8.1 con approccio MVVM

Introduzione all'approccio MVVM rispetto alla componente viewmodel


In una applicazione MVVM scritta correttamente il livello view model e le viste dovrebbero risultare completamente indipendenti. Questo significa che all'interno della classe che implementa il view model non dovrebbe esserci alcun riferimento alla struttura visuale della presentation. La comunicazione dovrebbe avvenire tramite databindings, behaviors e commands invocati direttamente dalla vista sul data context. Dove possibile, viene preferito l'uso delle interfacce.
Questo approccio permette il test indipendente della vista, del viewmodel e del model, ma ha anche come controindicazione un aumento della complessità del codice, sia per quanto riguarda la parte concettuale di progettazione, ovvero la nuvola delle relazioni di chiamata tra le varie proprietà del viewmodel e la vista, sia banalmente per quanto riguarda la quantità di codice scritto. E' evidente che un approccio del genere applicato allo sviluppo di una app per effettuare la moltiplicazione di due numeri è puro suicidio, a meno di avere codice già pronto e riutilizzabile.

La problematica della navigazione nelle app Windows Store e Windows Phone


Al contrario delle applicazioni classiche per desktop che fanno uso di finestre, gli applicativi mobile per Windows Phone e le app per Windows Store mettono a disposizione una sola area, detta Frame, dove vengono visualizzati i contenuti dell'applicativo come pagine, alla stregua di un sito internet contenente elementi più ricchi graficamente e con accesso diretto al dispositivo. La navigazione a pagine permette di avere una cache di navigazione in entrambe le direzioni, indietro e avanti, e la garanzia del focus totale dell'utente rispetto ai contenuti attualmente visualizzati dal frame. Questo approccio, seppur ostico da implementare inizialmente da parte del programmatore, è di facile comprensione per quanto riguarda l'aspetto dell'esperienza di utilizzo dell'applicativo.

Utilizzando un pattern basato sugli eventi e utilizzando l'approccio classico code-behind per le pagine, per fare una analogia scrivendo il nostro codice come se l'applicativo fosse un website ASP.NET, l'implementazione della navigazione risulta banale. All'interno della singola finestra corrente esposta dall'app identifichiamo l'elemento root che rappresenta il frame e questo ci andrà a esporre i metodi di navigazione, sostanzialmente GoBack(), GoForward() e Navigate(), insieme ai metodi ausiliari CanGoBack() e CanGoForward(). Il funzionamento del frame risulta essere autoesplicativo.

Ma nel caso di MVVM ci troveremmo di fronte a una implementazione che crea dipendenza rispetto al namespace delle viste e al frame di navigazione, anch'esso da considerare parte della componente view. La dipendenza sul frame è evidente, in quanto è l'oggetto che implementa i metodi di navigazione, mentre quella sulle vista risulterebbe necessaria perché Navigate richiede un Type come argomento per determinare la pagina da inizializzare e navigare.
Le soluzioni che ci vengono in mente sono solo due. La prima è implementare la navigazione nel code-behind della vista. E noi vorremmo evitare il più possibile l'uso del code-behind. Preferiamo manutenere lo XAML piuttosto che un insieme di metodi di una classe parziale. La seconda è trovare un modo per inserire nel viewmodel la navigazione rispettando però la sua indipendenza dalla componente visuale.

Il navigation service, ovvero "come ti standardizzo il problema".


La soluzione in realtà è relativamente semplice. Il viewmodel deve essere progettato in modo da essere indipendente. Così facendo sarà possibile anche effettuare dei test sulle classi del vm in maniera automatica. Allora come si fa a far navigare una classe che non ha dipendenze sulla vista, quando tutti i template implementano i servizi di navigazione sulla classe della pagina? Ci aiutano le interfacce.

Una eventuale dipendenza su un oggetto che implementa una interfaccia di navigazione ci interesserebbe poco. Infatti, basterebbe usare direttamente l'interfaccia nel viewmodel e il layer che implementa i metodi di navigazione sarebbe per la nostra classe del tutto trasparente. In più, potremmo virtualmente utilizzare una implementazione per ogni piattaforma con una compilazione condizionale. Potremmo scegliere un approccio rispetto a un altro in fase di inizializzazione in base ad alcune regole da noi dettate. Il comportamento non cambierebbe mai, il viewmodel avrà sempre i suoi GoBack(), GoForward() e Navigate() disponibili, a prescindere dal comportamento del layer sottostante. In uno unit test, ad esempio, potremmo usare una classe dummy per la navigazione che andrà a fornire una simulazione degli input al viewmodel per poter testare determinati comportamenti. 

Sfortunatamente, o fortunatamente, non è esposta una interfaccia INavigationService dal framework .NET o da WinRT. E' presente solo INavigate, che descrive il metodo Navigate() standard. Implementeremo noi la nostra versione dell'interfaccia, in base alle esigenze della nostra app.
Innanzitutto, a mio parere la cosa migliore è mettere le classi di navigazione in un namespace specifico. Nel mio caso, semplicemente Navigation.

INavigationService.cs

public interface INavigationService
{
    #region Events

    event NavigatedEventHandler Navigated;
    event NavigationFailedEventHandler NavigationFailed;

    #endregion

    #region Methods

    bool CanGoBack();
    bool CanGoForward();
    void GoBack();        
    void GoForward();
    void Navigate(Type page);
    void Navigate(Type page, object parameter);
    void Navigate(String page);
    void Navigate(String page, object parameter);

    void ClearBackStack();
    
    #endregion
}

La nostra interfaccia permetterà la navigazione e la cancellazione della cache di navigazione e informerà tramite evento l'esito delle richieste ricevute.

Esistono tre overloads di funzione. Il primo e il secondo sono per mantenere la compatibilità con gli oggetti frame standard. Il terzo e il quarto per permettere di disgiungere e ottimizzare la navigazione verso una pagina dalla parte visuale, ma questo si vedrà in dettaglio nell'implementazione.

Implementiamo INavigationService: WindowsNavigationService.cs

L'implementazione di INavigationService per le applicazioni Windows Store e Windows Phone, che chiameremo WindowsNavigationService, fa uso della reflection per disgiungere dalla componente visuale e ottimizzare il codice di navigazione. Abbiamo due approcci, uno è quello di implementare un attributo custom NavigableViewAttribute, oppure di implementare una interfaccia INavigableView. In entrambi i casi non cambia il sistema per riconoscere all'interno del nostro assembly le viste: utilizzando la reflection, otteniamo un handle al nostro assembly. A questo punto, tramite LINQ, passiamo al setaccio tutti i defined types che implementano l'interfaccia, o che hanno applicato il custom attribute che abbiamo implementato. Nel primo caso, il codice risulta secondo me più semplice e leggibile. Otteremo così tutti i Types adatti alla navigazione. Inserendo quanto enumerato all'interno di un Dictionary di tipo <String, Type>, con la chiave String rappresentata solitamente dal nome della classe, quindi della vista, otterremo un sistema di navigazione disgiunto dall'implementazione della nostra app che automaticamente riconosce le viste disponibile e ne permette l'utilizzo semplicemente "chiamandole per nome".
E' utile anche implementare una classe base astratta NavigationService che esponga una proprietà statica Default dove in fase di inizializzazione dell'applicativo andremo a memorizzare il sistema di navigazione di default dell'architettura che stiamo utilizzando.

L'implementazione di WindowsNavigationService è la seguente:

 public class WindowsNavigationService
        : NavigationService
    {        
       

        #region Fields

        private Frame currentFrame = null;

        #endregion

        #region Properties

        protected Frame Frame
        {
            get
            {
                if (Window.Current != null)
                {
                    if (Window.Current.Content != null && Window.Current.Content is Frame)
                    {
                        if (Window.Current.Content != this.currentFrame)
                        {
                            if (this.currentFrame != null)
                            {
                                try
                                {
                                    this.currentFrame.Navigated -= CurrentFrame_Navigated;
                                    this.currentFrame.NavigationFailed -= CurrentFrame_NavigationFailed;
                                }
                                catch
                                {

                                }
                            }

                            this.currentFrame = Window.Current.Content as Frame;
                            this.currentFrame.Navigated += CurrentFrame_Navigated;
                            this.currentFrame.NavigationFailed += CurrentFrame_NavigationFailed;
                        }
                    }
                }

                return this.currentFrame;
            }
        }        

        #endregion

        #region .ctor

        public WindowsNavigationService()
            : base()
        {

        }

        #endregion

        #region Methods

        public override bool CanGoBack()
        {
            bool result = false;

            if (this.Frame != null)
                result = this.Frame.CanGoBack;

            return result;
        }

        public override void GoBack()
        {
            if (this.Frame != null)
                this.Frame.GoBack();
        }

        public override void Navigate(string page)
        {
            Type pageType = null;

            if (String.IsNullOrEmpty(page))
                throw new ArgumentNullException("page");

            if (this.viewsDictionary != null)
            {
                if (this.viewsDictionary.ContainsKey(page))
                    pageType = this.viewsDictionary[page];
            }

            if (pageType != null)
                this.Navigate(pageType, null);
        }

        public override void Navigate(Type page, object parameter)
        {
            if (page == null)
                throw new ArgumentNullException("page");

            if (this.Frame != null)
                if (parameter == null)
                    this.Frame.Navigate(page);
                else
                    this.Frame.Navigate(page, parameter);                
        }

        #endregion

        #region Event Handlers

        private void CurrentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            this.OnNavigationFailed(this, e);
        }

        private void CurrentFrame_Navigated(object sender, NavigationEventArgs e)
        {
            this.OnNavigated(this, e);
        }


        #endregion


Mentre la classe base astratta NavigationService, che svolge un ruolo fondamentale, è implementata mediante questo codice:

 public abstract class NavigationService
        : INavigationService
    {
        #region Singleton

        private static readonly object syncLock = new object();
        private static INavigationService defaultNavigationService = null;

        public static INavigationService Default
        {
            get
            {
                return NavigationService.defaultNavigationService;
            }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("navigationService");

                lock (NavigationService.syncLock)
                {
                    if (NavigationService.defaultNavigationService != value)
                        NavigationService.defaultNavigationService = value;
                }
            }
        }

        #endregion

        #region Events

        public event NavigatedEventHandler Navigated = null;
        public event NavigationFailedEventHandler NavigationFailed = null;

        #endregion

        #region Fields

        protected Dictionary<String, Type> viewsDictionary = null;

        #endregion

        #region Properties

        public String[] Views
        {
            get
            {
                String[] result = null;

                if (this.viewsDictionary != null)
                    result = this.viewsDictionary.Keys.ToArray();

                if (result == null)
                    result = new String[] { };
                return result;
            }
        }

        #endregion

        #region .ctor

        public NavigationService()
        {
            this.OnInitialized();
        }

        #endregion

        #region Methods

        protected virtual void OnInitialized()
        {
            this.viewsDictionary = new Dictionary<string, Type>();
            this.PopulateViewsDictionary();
        }

        protected virtual void PopulateViewsDictionary()
        {
            Assembly currentAssembly = null;
            TypeInfo[] viewsTypeInfos = null;

            if (this.viewsDictionary == null)
                throw new NullReferenceException("viewsDictionary");
            else
            {
                if (this.viewsDictionary.Count > 0)
                    this.viewsDictionary.Clear();
            }

            currentAssembly = this.GetType().GetTypeInfo().Assembly;
            viewsTypeInfos = currentAssembly.DefinedTypes.Where(dt => dt.ImplementedInterfaces.Any(ii => ii == typeof(INavigableView))).ToArray();
            foreach(TypeInfo ti in viewsTypeInfos)
            {
                Type viewType = null;
                String viewName = null;

                viewName = ti.Name;
                viewType = ti.AsType();
                this.viewsDictionary.Add(viewName, viewType);
            }
        }

        public virtual bool CanGoBack()
        {
            throw new NotImplementedException();
        }

        public virtual bool CanGoForward()
        {
            throw new NotImplementedException();
        }

        public virtual void GoBack()
        {
            throw new NotImplementedException();
        }

        public virtual void GoForward()
        {
            throw new NotImplementedException();
        }

        public virtual void Navigate(Type page)
        {
            throw new NotImplementedException();
        }

        public virtual void Navigate(Type page, object parameter)
        {
            throw new NotImplementedException();
        }

        public virtual void Navigate(string page)
        {
            throw new NotImplementedException();
        }

        public virtual void Navigate(string page, object parameter)
        {
            throw new NotImplementedException();
        }

        public virtual void ClearBackStack()
        {
            throw new NotImplementedException();
        }

        protected void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            if (this.NavigationFailed != null)
                this.NavigationFailed(sender, e);
        }

        protected void OnNavigated(object sender, NavigationEventArgs e)
        {
            if (this.Navigated != null)
                this.Navigated(sender, e);
        }


        #endregion

        #region Event Handlers

        
        
        #endregion

    }


ultima, e meno importante, l'interfaccia con la quale identifichiamo le viste nel progetto:

 public interface INavigableView
    {
    }

Utilizzando questi tre oggetti il sistema di navigazione è perfettamente funzionante.

Ultime considerazioni


Nell'interfaccia INavigationService sono presenti due eventi, con handlers definiti come NavigatedEventHandler e NavigationFailedEventHandler. Queste due classi sono definite nel namespace Windows.UI.Xaml.Navigation. Volendo disgiungere completamente l'interfaccia dalle componenti XAML del .NET Framework, basterà ridefinire la classi nel nostro progetto. Ovviamente, aumentare il carico di lavoro ha senso se e solo se sappiamo già che i nostri oggetti potrebbero venire utilizzati in progetti in cui XAML potrebbe non essere disponibile, come ad esempio ASP.NET MVC. In questi casi è possibile tentare di standardizzare la navigazione, ma è logico supporre che molti oggetti di supporto del framework andranno riscritti e inclusi nel nostro progetto.

Informazioni sull'esempio

Allegato a questo articolo rilascerò una Universal App Windows Phone 8.1 / Windows 8.1 di esempio. I metodi di navigazione non risulteranno tutti implementati, ma solamente Navigate(String) e Navigate(Type, Object). Il primo, perchè risulta il più semplice da utilizzare e obiettivamente il più utilizzato. Il secondo perchè è la fondamenta su cui si basa l'implementazione di tutti gli altri metodi, che sono semplici derivazioni del primo sul secondo.

Upload dell'archivio di esempio a breve.

domenica 15 giugno 2014

About the Windows Phone 8.1 hardware buttons

Windows Phone 8.1 is a huge step forward compared to the past towards a real unification of the source code between the desktop and mobile platform. Unifying the controls and start using programming patterns as MVVM to uncouple the visual component from the model logic it is now possible to write applications which is in common with desktop and mobile scenarios and where only the pages have specific behaviors for the platform on which are running or, through Visual States, apps can even have common views for each platform and component placement will only vary depending on the form factor. Then, of course, a control for Windows Phone will be rendered and operated differently from the OS than the same control for Windows 8.1, though in principle the developer should matter little if compared to the form factor. The input system is entirely handled by the OS.

With Windows Phone 8.1 the lifecycle of the application has been changed in favour of the same Windows 8.1 Desktop model. In a Win81 project that uses the new WinPRT (Windows Phone RT), the hardware back button is handled by the OS as this means that common behavior is the exit from the application. This behavior is profoundly different than Windows Phone 7.1/8 and could create problems in the conversion of some applications. The solution to our compatibility problem is, however, very simple.

In a WinPRT project hardware buttons are handled by the HardwareButtons class that exposes a set of events related to back, volume and camera buttons. Through this class, we can write a control dedicated to the management of the "back" button according to the old behavior that we find in the Windows Phone 7.1 and 8 first generation:

  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
    }

Then just swap the standard page with this new class in XAML and you're done.

<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>

Our application will follow the rule: "as long as there are items in the backstack, go back, otherwise exit." Obviously the management method of the buttons is written as virtual, so you can handle the override for any special requirements of your app.

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.

giovedì 23 gennaio 2014

Cenni su XAML

Cenni su XAML

In questo articolo inizieremo a introdurre il linguaggio di markup XAML, diventato ormai una pietra miliare nello sviluppo di applicativi per Microsoft Windows. Questo argomento si collega direttamente all'implementazione del pattern MVVM in Microsoft .NET, in quanto fornisce gli strumenti base per l'implementazione dei comandi e per legare l'interfaccia grafica al modello logico dell'applicativo.

lunedì 13 gennaio 2014

Lambda expressions - IL e blando performance test a pari condizioni di esecuzione - parte 1

Lamba expressions e IL

Era da tempo che mi chiedevo come il compilatore gestisse una funzione lambda. Esistono diverse possibilità al riguardo, tra cui una generazione a Runtime tramite dynamic methods. Oggi ho messo mano al disassemblatore .NET, alla ricerca di una risposta concreta.

mercoledì 8 gennaio 2014

Introduzione alle funzioni lambda in C#

Introduzione alle funzioni lambda (lambda expressions)

Nei linguaggi di programmazione ad alto livello vengono spesso introdotte particolari tipi di funzioni, dette funzioni anonime o funzioni lambda. Rimanendo su un discorso relativamente semplice, le lambda trovano il loro utilizzo come valore di argomento passato ad altre funzioni. Per loro stessa natura sono una sorta di funzioni annidate, ovvero funzioni dichiarate all'interno di altre funzioni, di cui condividono la visibilità locale delle variabili. Questo le rende particolarmente adatte a query o alberi di espressioni per funzioni di livello superiore. Tratteremo gli alberi di espressioni in un post dedicato. A grandi linee sono una rappresentazione a grafo di una serie di istruzioni imperative da eseguire, che possono essere popolati e compilati a runtime.
Utilizzando una variabile dove il puntatore alla funzione viene memorizzato, possono essere rese ricorsive.

Personalmente trovo le lambda una componente fondamentale della programmazione moderna. Permettono di scrivere codice molto compatto, sopratutto quando sono necessari degli handlers che verranno utilizzati sporadicamente dove il codice da scrivere risulta particolarmente semplice, e quindi di rendere più leggibile il nostro codice e a volte di generare IL maggiormente ottimizzato. Le lambda sono anche indispensabili per lo sviluppo utilizzando query LINQ, funzionalità diventata indispensabile nella manipolazione di strutture dati complesse.