Pulsanti in forma di frecce e ruotati in quattro direzioni

Nella maggior parte degli esempi i pulsanti (oggetti Button) si presentano magari colorati e dipinti in molti modi  e con svariate sfumature, però la loro forma è rettangolare. Peraltro associare ad essi una shape non è difficile, anche se il convento WPF in prima battuta sembrerebbe che fornisca due sole figure geometriche, l’ellisse e – di nuovo! – il rettangolo, al più con angoli arrotondati.

Presto si scopre che, a dirla tutta, la classe Windows.Shapes è dotata di altri figli oltre a Rectangle ed Ellypse, tra cui Line, Path, Polyline e Polygon. Quest’ultima con un po’ di pazienza permette il tracciamento di una figura chiusa descritta mediante i successivi punti, rappresentati da coordinate cartesiane del contenitore, ove l’asse X procede da sinistra a destra mentre l’asse X va dall’alto in basso.

Definire una freccia (piena) orientata a destra

In pratica mi interessavano dei pulsanti-frecciati,  di foggia simile a quella dei cartelli stradali ed efficaci per esempio in problemi di navigazione e simili.

Partiamo con una freccia piena . Aiutandomi alla buona con un foglio a quadretti ho ottenuto il codice XAML seguente:

<Polygon Stroke="Blue" Fill="Gold"

  Points="20,60 80,60 80,70 100,55 80,40 80,50 20,50"

  Margin="1,0,12,12" Grid.RowSpan="3" />

 

Che di fatto corrisponde alla freccia con riempimento dorato posta nella cella zero di una griglia di tre righe:

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="110*" />

            <RowDefinition Height="110*" />

            <RowDefinition Height="110*" />

        </Grid.RowDefinitions>

 . . . eccetera . . .

    </Grid>

 

 

Nota. Per indicare i punti del poligono- Points = “. . . “  ho qui utilizzato la sintassi che elenca ciascun punto con una coppia x,y.

Frecce rivolte nelle altre direzioni, usando uno stile ad hoc del Button

Per questi scopi ho subito respinto l’idea di ripetere il lavoro sulla carta quadrettata, perché alla pazienza c’è un limite. Analogamente ho scartato il ricalcolo delle coordinate, eventualmente a run-time, procedimento possibile ma tedioso (e per giunta poco chiaro). Presto comunque ho pensato che la cosa  più semplice è quella di sfruttare la proprietà RotateTransform , a sua volta figlia di RenderTransform, con l’attributo Angle posto rispettivamente a 180, -90 e 90 ottenendo così  la freccia rivolta a sinistra, in alto e in basso, rispettivamente.

 

Nota. Detto en passant, il presente post costituisce un esempio pratico, pedestre, di queste a altre proprietà consimili, che altrimenti potrebbero esser viste quasi come uno sfizio estetizzante.

 

Le operazioni appena detta si possono compiere manualmente, copiando il Button con freccia sinistra e incollandolo altrove,  apportando poi al nuovo venuto la rotazione richiesta, impostata sempre a manina. Ma la classica lampadina si è accesa, nottetempo: diamine, è più semplice ed elegante utilizzare uno stile a sua volta comprendente un ControlTemplate nel quale stabilire la shape poligonale mostrata poc’anzi. Il codice XAML è subito visto:

<Window x:Class="Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="380" Width="302">

   

    <Window.Resources>

        <Style x:Key="pulsFreccia" TargetType="Button">

            <Setter Property="MinHeight" Value="100" />

            <Setter Property="MinWidth" Value="100" />

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="Button">

                        <Polygon Stroke="Black" Fill="Blue

                         Points="20,60 80,60 80,70 100,55 80,40 80,50 20,50"

                         Height="249" Width="266" Margin="0,12,12,0" Grid.RowSpan="3" />

                    </ControlTemplate>

                </Setter.Value>               

            </Setter>

        </Style>

    </Window.Resources>

 

Tale stile denominato pulsFreccia (ricordarsene più avanti) comprende tra i suoi Setter uno con Property=”Template” che a sua volta incastona nella tag di valore (Setter.Value) il ControlTemplate di tipo Button che- infine! – definisce il nostro Polygon frecciato, di dimensioni e orientamento (destro), direi, default.

A questo punto esaminiamo le prime tag a valle delle Grid.RowDefinitions:

        <Polygon Stroke="Blue" Fill="Gold"

           Points="20,60 80,60 80,70 100,55 80,40 80,50 20,50"

           Margin="1,0,12,12" Grid.RowSpan="3" />

        <Rectangle Fill="Chartreuse" Name="Rectangle1"

          Stroke="#FF190000" Width="84" Margin="173,57,23,13" />

        <Rectangle Fill="Chocolate" Margin="105,12,98,59" Name="Rectangle2"

          Stroke="#FF190000" />

        <Button Name="FrecciaDxt" Style="{StaticResource pulsFreccia}"  Grid.Row="1"

           Margin="22,8,144,8"/>

 

Nota. Per carità, non si sottilizzi né ci si scandalizzi sui valori adottati come quelli relativi ai margini. Questo è solo uno studio preliminare, didattico...

Come è subito chiaro, le prime tre figure inserite nella prima cella della griglia sono il poligono già visto più due rettangoli (infilati lì tanto per confronto). Segue, nella seconda cella (Grid.Row=”1”), un Button poligonale dall’eloquente nome “FrecciaDxt”,  che pesca i suoi caratteri dallo stile in questione, mediante l’attributo specifico (per la cui sintassi rimando ai manuali e agli esempi MSDN):

Style="{StaticResource pulsFreccia}"

Subito sotto troviamo le definizioni degli altri tre pulsanti freccia (e già che ci siamo includo anche le tag di chiusura Grid e Window):

        <Button Name="FrecciaSin"  Style="{StaticResource pulsFreccia}" Grid.Row="1"

            Margin="277,113,-141,13">

            <Button.RenderTransform>

                <RotateTransform Angle="180" />

            </Button.RenderTransform>         

        </Button>

        <Button Name="FrecciaSu" Style="{StaticResource pulsFreccia}"  Grid.Row="2"

                Margin="6,119,159,-117">

            <Button.RenderTransform>

                <RotateTransform Angle="-90" />

            </Button.RenderTransform>

        </Button>

        <Button Name="FrecciaGiu" Style="{StaticResource pulsFreccia}"  Grid.Row="2"

                Margin="280,1,-114,1">

            <Button.RenderTransform>

                <RotateTransform Angle="90" />

            </Button.RenderTransform>   

        </Button>

    </Grid>

</Window>

I nomi “FrecciaSin”, “FrecciaSu” e “FrecciaGiu” sono parlanti e chiare le rispettive collocazioni – il primo nella stessa cella della FrecciaDxt, gli altri e uno accanto all’altro a riga 2 – e per capire tutto basterà dunque esaminare le tag Button.RenderTransform che incapsulano delle RotateTransform con tre scontati attributi Angle.

Ultima osservazione. Per semplicità ho indicato nello stile impostazioni essenziali, ma il bello degli stili & template è che possono essere arricchiti a volontà (con sfumature e magari trigger che agiscono quando si sfiora un pulsante) ottenendo un flessibilità e un risparmio di codice che anche questo esempio ribadisce.

Tutto il listato XAML

Lo riporto qui sotto per comodità dei più pigri.

<Window x:Class="Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="380" Width="302"> 

    <Window.Resources>

        <Style x:Key="pulsFreccia" TargetType="Button">

            <Setter Property="MinHeight" Value="100" />

            <Setter Property="MinWidth" Value="100" />

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="Button">

                        <Polygon Stroke="Black" Fill="Blue

                         Points="20,60 80,60 80,70 100,55 80,40 80,50 20,50"

                         Height="249" Width="266" Margin="0,12,12,0" Grid.RowSpan="3" />

                    </ControlTemplate>

                </Setter.Value>               

            </Setter>

        </Style>

    </Window.Resources>

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="110*" />

            <RowDefinition Height="110*" />

            <RowDefinition Height="110*" />

        </Grid.RowDefinitions>

        <Polygon Stroke="Blue" Fill="Gold"

           Points="20,60 80,60 80,70 100,55 80,40 80,50 20,50"

           Margin="1,0,12,12" Grid.RowSpan="3" />

        <Rectangle Fill="Chartreuse" Name="Rectangle1"

           Stroke="#FF190000" Width="84" Margin="173,57,23,13" />

        <Rectangle Fill="Chocolate" Margin="105,12,98,59" Name="Rectangle2"

           Stroke="#FF190000" />

        <Button Name="FrecciaDxt" Style="{StaticResource pulsFreccia}"  Grid.Row="1"

           Margin="22,8,144,8"/>

        <Button Name="FrecciaSin"  Style="{StaticResource pulsFreccia}" Grid.Row="1"

           Margin="277,113,-141,13" Grid.RowSpan="2">

            <Button.RenderTransform>

                <RotateTransform Angle="180" />

            </Button.RenderTransform>         

        </Button>

        <Button Name="FrecciaSu" Style="{StaticResource pulsFreccia}"  Grid.Row="2"

           Margin="6,119,159,-117">

            <Button.RenderTransform>

                <RotateTransform Angle="-90" />

            </Button.RenderTransform>

        </Button>

        <Button Name="FrecciaGiu" Style="{StaticResource pulsFreccia}"  Grid.Row="2"

           Margin="280,1,-114,1">

            <Button.RenderTransform>

                <RotateTransform Angle="90" />

            </Button.RenderTransform>   

        </Button>

    </Grid>

</Window>