Gianni Giaccaglini

Tricks & mini applics on WPF
posts - 46, comments - 0, trackbacks - 0

Creazione automatica di una griglia (Grid) XAML

 

Creazione automatica di una griglia (Grid) XAML

Il pannello Grid di una Window WPF (Page in VB 2012), sovente il più comune in tali ambienti, richiede tediose operazioni digitatorie, necessarie in particolare per definirne le righe e colonne. Sto parlando della parte che va dalla tag <Grid.RowDefinitions> alla tag </Grid.ColumnDefinitions>. L’ideuzza di cui parla questa sciocchezzuola consiste nell’utilizzare macro VBA per ottenerla in un intervallo dello spreadsheet, fissando in partenza il numero di righe e di colonne, una prassi sempre raccomandabile in un “progetto”.

IL MODELLO EXCEL IN PAROLA CreaGrigliaWPF.xlsm (compresso nell'omonimo .zip) SI PUO' SCARICARE da
http://www.giannigiaccaglini.it/download/CreaGrigliaWPF.zip

   

Nota. In fondo a questo post ho poi aggiunto una soluzione più avanzata e personalizzabile, che aggiunge anche un tipico insieme di stili (tag <Style ... > ecc.) relativi a controlli Button.

 

La sezione basilare, posta sulla destra del foglio di lavoro, si presenta così:

Griglia

Schema base

 

        <Grid.RowDefinitions>

 

            <RowDefinition />

 

        </Grid.RowDefinitions>

 

        <Grid.ColumnDefinitions>

 

            <ColumnDefinition />

 

        </Grid.ColumnDefinitions>

 

Sono stati inoltre assegnati due nomi: IntestSchema e SchemaBase rispettivamente alla cella che contiene “Griglia” e all’intervallo formato dalle sei celle sottostanti la cella con su scritto “SchemaBase”. Il contenuto di SchemaBase (ottenuto una tantum tramite copia/incolla da una griglia XAML) corrisponde alle definizioni essenziali relative a una griglia 1 x 1, con tanto di opportuni spazi rientranti su ciascuna tag.

Sulla sinistra del foglio si hanno due celle denominate NumRig e NumCol, ove l’utente inserisce i nomeri di riga e colonna desiderati, più un pulsante connesso alla routine che stiamo per vedere. Ipotizzando NumRig = 4 e NumCol = 3 la macro prossimo ventura produrrà questo risultato sotto la cella “Griglia”:

 

Griglia

        <Grid.RowDefinitions>

            <RowDefinition />

            <RowDefinition />

            <RowDefinition />

            <RowDefinition />

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition />

            <ColumnDefinition />

            <ColumnDefinition />

        </Grid.ColumnDefinitions>

Come tutti comprendono, si possono copiare tali celle e incollarle nel modulo XAML inserendole fra le tag <Grid> e </Grid>. Il marchingegno poggia su due fondamenti:

a)      Un intervallo Excel viene regolarmente accettato come una serie di tag (cosa che a pochi, me compreso, supporrebbero);

b)      XAML suddivide automaticamente in parti uguali le altezze delle righe e le larghezze delle colonne in relazione alle dimensioni della Window o Page.

A quel punto il progettista dovrà proseguire ridimensionando eventualmente la Window o Page e/o assegnando altezze e dimensioni con modalità ben note (almeno si spera...).

Il codice VBA

Lo fornisco, in sostanza, come ricetta. Pertanto in quel che segue descriverò in prevalenza quel che succede.

 Inoltre il modello scaricabile offre anche l’alternativa di aggiungere stili tipici ma qui, per semplicità, descrivo un codice “essenziale” relativo al caso più semplice.

Nota. Le varie routine VBA sono ospitate nel modulo Foglio1 (perché chi l’ha detto che si debba sempre ricorrere a Modulo1, Modulo2 eccetera?

La routine connessa al pulsante è la seguente:

Sub CreaGriglia()

  With Range("IntestSchema").Offset(1)

    Range(.Cells(1), .End(xlDown)).Clear

    If Range("NumRig") = 0 And Range("NumCol") = 0 Then Exit Sub

    Range("SchemaBase").Copy .Cells(1)

  End With

  GestRighe

  GestColonne

End Sub

La parte incastonata fra With ed End With  ripulisce tutto quel che c’è sotto la zona “IntestSchema” e se i numeri di righe e di colonne indicati sono entrambi nulli fuoriesce nullafacente dalla Sub, altrimenti copia lo SchemaBase a partire dalla cella sottostante “IntestSchema”. Infine la palla viene passata alla routine GestRighe e GestColonne:

Private Sub GestRighe()

  Dim Rigadef As Range

  Dim Nr As Integer

  Nr = Range("NumRig")

  Set Rigadef = Range("IntestSchema").Cells(3)

  Scegli Rigadef, Nr

End Sub 

Private Sub GestColonne()

  Dim Rigadef As Range

  Dim Nr As Integer, Nc As Integer

  Nr = Range("NumRig")

  Nc = Range("NumCol")

  Dim pos As Integer

  pos = IIf(Nr = 0, 3, Nr + 5)

  Set Rigadef = Range("IntestSchema").Cells(pos)

  Scegli Rigadef, Nc

End Sub

 

La prima pone in Nr il valore della cella “NumRig” poi fissa in RigaDef  la cella posta in tre righe sotto “IntestSchema” , individuando così la tag <RowDefinition />, infine richiama la routine Scegli con argomenti RigaDef e Nr.

La Sub GestColonne compie operazioni preliminari analoghe ma un po’ più complicate in quanto deve tener conto dei vari casi creati dalla GestRighe che precede (in particolare quando, con Nr = 0, viene eliminato l’intero blocco delle definizioni di riga da <Grid.RowDefinitions> a </Grid.RowDefinitions> . Ne lascio il commento ai più esperti, dico solo che GestColonne si conclude evocando Scegli con argomenti RigaDef e Nc (numero colonne).

Ecco infine la sospirata routine Scegli chiamata in gioco da quelle testé descritte:

Private Sub Scegli(Rigadef As Range, N As Integer)

  Select Case N

  Case 0

    ' MsgBox "0" ' Usata per debug

    With Rigadef 'Range("IntestSchema")

      Range(.Cells(0), .Cells(2)).Delete xlUp

    End With

  Case 1

    Exit Sub

  Case Is > 1

    ' MsgBox ">1" ' Per debug

       For i = 1 To N - 1

      Rigadef.Insert Shift:=xlDown

    Next

    With Rigadef

      Set RigheDest = Range(.Cells(-N + 2), .Cells(0))

      .Copy RigheDest

    End With

  End Select

End Sub

Tempo e spazio stringono  e a costo di esser tacciato di sadismo ne affido interamente l’esegesi ai più bravi e interessati.

Nota. Una soluzione alternativa un po’ pedestre potrebbe consistere nell’aggiunta, una dopo l’altra, delle tag conseguenti i valori scelti dall’utenti Nr e Nc. Più semplice della mia? Forse ma dopo essermici impelagato tale variante non mi lusinga.

Forse m'illudo ma penso che questo pur modesto contributo apra la strada ad altri più avanzati, mirati alla preparazione preliminare di template XAML compositi ma abbastanza tipici.

 

L’alternativa griglia + stili (personalizzabili)

Aprendo il modello CreaGrigliaWPF.xlsm si noterà anzitutto la presenza, sulla sinistra di due pulsanti, etichettati “Crea solo Griglia” e, rispettivamente, “Crea Griglia e Stili” di chiara semantica. Portandosi a destra, in  colonna E fa mostra di sé i seguenti codici XAML, relativi a stili tipici e – ripeto e insisto – da personalizzare, adattandoli a proprie esigenze dopo opportuni esperimenti:

 

Stili

       <Grid.Resources>

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

                <Setter Property="Margin" Value="130,75,0,0"/>

                <Setter Property="Width" Value="255" />

                <Setter Property="Height" Value="85" />

                <Setter Property="FontFamily" Value="Tahoma" />

                <Setter Property="FontSize" Value="30" />

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="VerticalAlignment" Value="Top" />

                <Setter Property="Background" Value="DarkBlue" />

            </Style>

        </Grid.Resources>

Sto parlando a gente che mastica la lingua “csamel” ergo capirà che si tratta di stili tipici relativi a controlli Button. Aggiungo solo che i tag Setter più critici sono quelli evidenziati che possono creare imprevisti specie con valori elevati di righe e colonne della Grid (che comunque vanno “aggiustati” a mano nel progetto). Passi per quelli delle proprietà Width e Height ma il Setter più critico è quello del “Margin”, al punto che ne consiglierei l’eliminazione.

Tutto il codice VB

Lo riporto per intero per pura comodità dei più pigri-ma-esperti, con commenti del tutto stringati.

Private Sub GestRighe()

  Dim Rigadef As Range

  Dim Nr As Integer

  Nr = Range("NumRig")

  Set Rigadef = Range("IntestSchema").Cells(3)

  Scegli Rigadef, Nr

End Sub

 

Private Sub GestColonne()

  Dim Rigadef As Range

  Dim Nr As Integer, Nc As Integer

  Nr = Range("NumRig"): Nc = Range("NumCol")

  Dim pos As Integer

  pos = IIf(Nr = 0, 3, Nr + 5)

  Set Rigadef = Range("IntestSchema").Cells(pos)

  Scegli Rigadef, Nc

End Sub

 

Private Sub Scegli(Rigadef As Range, N As Integer)

  Select Case N

  Case 0

   With Rigadef 'Range("IntestSchema")

      Range(.Cells(0), .Cells(2)).Delete xlUp

    End With

  Case 1

    Exit Sub

  Case Is > 1

       For i = 1 To N - 1

      Rigadef.Insert Shift:=xlDown

    Next

    With Rigadef

      Set RigheDest = Range(.Cells(-N + 2), .Cells(0))

      .Copy RigheDest

    End With

  End Select

End Sub

 

Private Sub CreazioneGriglia(SoloGriglia As Boolean)

  With Range("IntestSchema").Offset(1)

    Range(.Cells(1), .End(xlDown)).Clear

    With Range("IntestSchemaFinale").Offset(1)

      Range(.Cells(1), .End(xlDown)).Clear

    End With

    If Range("NumRig") = 0 And Range("NumCol") = 0 Then Exit Sub

    Range("SchemaBase").Copy .Cells(1)

  End With

  GestRighe

  GestColonne

  If SoloGriglia Then Exit Sub ' Crea solo la griglia

  ' Crea anche gli stili:

  With Range("IntestSchema").Offset(1)

    Range(.Cells(1), .End(xlDown)).Name = "Griglia"

  End With

  CopiaStiliEtGriglia

End Sub

 

Private Sub CopiaStiliEtGriglia()

   With Range("IntestSchemaFinale").Offset(1)

    Range(.Cells(1), .End(xlDown)).Clear ' Repetita...

    Range("Stili").Copy .Cells(1) ' Copia gli stili

    Range("Griglia").Copy .End(xlDown).Offset(1) ' Accoda Griglia

  End With

End Sub

 

Sub CreaGriglia()

  CreazioneGriglia (True)

End Sub

 

Sub CreaGrigliaEtStili()

  CreazioneGriglia (False)

  Range("IntestSchemaFinale").Select

End Sub

Dal confronto con la soluzione ridotta si nota presto che la novità principale è la routine CreazioneGriglia dotata di argomento booleano SoloGriglia. Essa rassomiglia, ma  con varianti che lascio all’auto-esegesi, alla CreaGriglia di cui sopra fino all’istruzione GestColonne inclusa, dopo di che discrimina coi valori True / False del predetto booleano l’Exit Sub rispetto alla prosecuzione con l’aggiunta degli stili. Imitando, forse deprecabilmente, Tacito mi limito a dire che la novità più saliente è la sub CopiaStiliEtGriglia per la quale è doveroso segnalare che “IntestSchemaFinale” è il nome pre-assegnato alla cella F2 con su scritto non a caso “Schema finale” , mentre “Stili” è il nome, giustappunto, degli stili da <Grid.Resources> (cella E3 nel foglio di lavoro) a </Grid.Resources> (cella E14)

Operativamente il cerchio si chiude con CreaGriglia e CreaGrigliaEtStili connesse ai due pulsanti fatidici, a loro volta evocanti CreazioneGriglia con True e False rispettivamente. I nomi utilizzati sono, direi, auto-esplicativi per cui mi limito a far notare che la seconda routine copia gli Stili e vi accoda l’intervallo “Griglia”, secondo l’ordine usuale in XAML, infine seleziona la cella denominata “IntestSchemaFinale”, che essendo posta molto a destra è opportuno sia portata alla vista dell’utente.

Che a questo punto – è ovvio ma non guasta ribadirlo  – potrà tipicamente in un nuovo progetto, diciamo Windows 8, eseguire queste mosse: 1. copiare il codice XAML dal modello Excel, 2. Incollarlo con Ctrl+V fra le tag <Grid> e </Grid> verificando l’effetto che fa; 3. Definire i propri Button collocandoli nelle celle della Grid, usandone lo stile predefinito ma, ripeto, adattabile, agendo nei Setter necessari della sezione “stilistica”.

Nota. L’estensione a stili più complessi, relativi putacaso a TextBox e/o TextBlock è lasciata agl’interessati, magari escogitando più astuti automatismi...

 

Per osservazioni:
giannigiac@tin.it

Print | posted on mercoledì 13 febbraio 2013 20:51 |

Feedback

No comments posted yet.

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 2 and 1 and type the answer here:

Powered by:
Powered By Subtext Powered By ASP.NET