Grafici con WPF e LINQ

Aggiornato l’articolo su come creare grafici partendo da zero tramite WPF e LINQ per includere alcune nuove peculiarità del .NET Framework 4.0.

BlurredText clearText

Testo più chiaro con TextOptions.TextFormattingMode="Display"

antialiased_thumb edgeLayoutRound
Grafici più definiti con UseLayoutRounding (precedentemente veniva disabilitato solamente l’Anti-Aliasing dei bordi)

Progetto scaricabile in formato Visual Studio 2010

Leggi l’articolo aggiornato al 17/08/2010

NHibernate 3

NHibernate, famoso ORM per .NET ha raggiunto lo stadio Alpha1 per la terza release.

Tante le novità, quelle che ho trovato personalmente più utili sono la compatibilità con l’esecuzione Medium Trust in applicazioni web ASP.NET (niente più ricompilazioni con modifiche apposite ad ogni nuova versione, evviva!) ed un nuovo supporto a LINQ totalmente riscritto per una maggiore flessibilità.

Le modifiche da apportare per provare il supporto a LINQ della nuova versione sono solamente il cambio di un paio di righe di codice:

NHibernate 2.x

NHibernateOldLinq

NHibernate 3.x

NHibernateNewLinq

Il nuovo supporto rende inoltre possibile scrivere query come:

NHibernateLinqDateYear

Verrà prodotta in automatico la query SELECT * FROM Events WHERE YEAR(Date)=2009

NB: La query è stata abbreviata sostituendo tutti i nomi dei campi con l’asterisco e inserendo direttamente l’anno che in realtà viene passato come parametro per renderla più corta e leggibile in questo articolo.

Fino alla versione 2.x scrivere una query equivalente richiedeva l’utilizzo di codice SQL (nativo o tramite ICriteria) o HSQL.

Potete scaricare questa nuova versione all’indirizzo http://sourceforge.net/projects/nhibernate

WPF e il 3D (ottava parte) – Cubo multi-texture da codice

Indice degli articoli su WPF e il 3D

Nel precedente articolo abbiamo visto come creare un cubo multi-texture (ovvero con materiali diversi su ogni faccia) utilizzando esclusivamente XAML, il risultato era un codice abbastanza prolisso e poco riutilizzabile. Realizziamo ora un componente che sia semplice da utilizzare, alla fine dovremmo poter scrivere solamente il seguente codice XAML:

xamlCode

NB: Per poter aggiungere alle proprietà il supporto al Binding dobbiamo utilizzare nel componente le Dependency Property

Il MultiTexturedCube essendo un oggetto 3D per poter essere visualizzato dovrà essere inserito tra i Children (di tipo Visual3D) di un ViewPort3D, deriviamo quindi da ModelVisual3D il nostro componente.

Il nostro componente avrà necessità di sapere come costruire il cubo quindi dovrà contenere i modelli 3D (GeometryModel3D) delle facce del cubo da visualizzare. I  modelli come visto nei precedenti articoli avranno una geometria che sarà inizializzata nel costruttore del componente in modo analogo a come avevamo fatto tramite XAML, ecco un esempio di codice:

meshCode

Infine per poter essere visualizzati assieme i modelli dovranno essere raggruppati tramite un Model3DGroup che verrà impostato nella proprietà Content del componente, ereditata da ModelVisual3D.

Model3DGroup

Per poter impostare il materiale da XAML creiamo le varie Dependency Property inserendo come PropertyChangedCallback un evento che modifichi il materiale della corrispondente faccia. Questo “giro” è necessario in quanto tramite Dependency Property non è possibile esporre la proprietà di un altro oggetto (il modello 3D) direttamente.

DependencyProperty

Il diagramma finale del nostro componente è il seguente:

MultiTexturedCubeDiagram

Riutilizzare il componente è molto semplice, è possibile creare ad esempio un dado derivando da MultiTexturedCube e assegnando nel costruttore i materiali contenenti i numeri del dado, in questo modo non sarà neppure necessario specificare tutti i materiali di volta in volta. Non è difficile neppure estendere il componente, continuando l’esempio del dado è possibile aggiungere la proprietà Numero che una volta impostata applica un’animazione alla proprietà Trasform che ruota il dado con il numero scelto verso l’alto.

Scarica il codice sorgente dell’articolo

NB: Nel codice dell’articolo è presente solamente il codice per una singola faccia ove è analogo per le rimanenti facce.

Visualizzare al volo un array in una griglia

I controlli griglia di Windows Forms (DataGridView) e WPF (DataGrid) non permettono di visualizzare “al volo” correttamente insiemi di elementi di tipi come int, float, string, etc.. perché non espongono il loro valore come una proprietà.

Il seguente codice per esempio

int[] myArray = new int[] { 1, 2, 3 };

dataGrid1.ItemsSource = myArray;

mostrerà solamente una griglia con tre righe vuote.

Una lista di elementi di tipo string invece visualizzerà nella griglia solamente le lunghezze delle stringhe ma non il loro contenuto proprio perché la prima proprietà della classe string è Lenght. Molto spesso però la necessità è di visualizzare l’effettivo testo della stringa.

Per ovviare rapidamente al problema possiamo creare un Extension Method che aggiungerà a tutti gli insiemi enumerabili (di tipo IEnumerable<T>) un metodo chiamato ToPropertyData che ritornerà i valori degli elementi dell’insieme esposti come proprietà di un oggetto contenitore chiamato DataContainer.

Per visualizzare correttamente un array di int sarà necessario solamente scrivere il codice

int[] myArray = new int[] { 1, 2, 3 };

dataGrid1.ItemsSource = myArray.ToPropertyData();

ed il gioco è fatto.

DataGridArray

il codice dell’Extension Method:

public static class ExtensionMethodHelper

{

    public class DataContainer<T>

    {

        T data;

        public T Data { get { return data; } }

        public DataContainer(T value)

        {

            this.data = value;

        }

    }

    /// <summary>

    /// Convert array of data into array of DataContainer class that expose data as property

    /// </summary>

    /// <remarks>Useful with DataGrid(View)</remarks>

    public static List<DataContainer<TSource>> ToPropertyData<TSource>(this IEnumerable<TSource> source)

    {

        List<DataContainer<TSource>> result = new List<DataContainer<TSource>>();

        foreach (var item in source)

        {

            result.Add(new DataContainer<TSource>(item));

        }

        return result;

    }

}

questo Extension Method è valido solamente per visualizzare i valori in una griglia in modo rapido (ad esempio per controllare determinati valori in fase di debug) ma non supporta la sincronizzazione con l’insieme di origine (nell’esempio l’insieme myArray).

WPF e il 3D (settima parte) – Cubo multi-texture

Indice degli articoli su WPF e il 3D

Nel precedente articolo abbiamo visto come colorare un oggetto 3D ed abbiamo trattato le problematiche di mappatura con oggetti 2D chiamati texture.

In questo articolo prendiamo invece in considerazione l’applicazione di più materiali, uno per faccia, ad un unico modello 3D: in questo caso un cubo che abbiamo già visto come creare.

Multi-textured cube

WPF permette di associare ad ogni GeometryModel3D un solo materiale per la vista frontale ed un solo materiale per la vista di retro, per superare questa limitazione possiamo seguire diverse strade:

- Creare una texture unica formata dall’unione delle varie texture e mappare ogni punto di conseguenza 

Texture
Esempio di texture unica per creare un effetto multi-texture

Questo stratagemma seppur altamente performante comporta difficoltà nel simulare materiali “dinamici” come ad esempio video o materiali con applicati dei VisualBrush

- Suddividere il modello 3D in tante parti

Questa è la soluzione che offre più flessibilità in quanto rende possibile cambiare singolarmente i vari materiali.

Un esempio di cubo 3D suddiviso in più parti (suddiviso nelle 6 facce) è il seguente:

sampleXamlMultiTexturedCube

Come si può notare all’interno di un singolo ModelVisual3D (che dovrà poi essere inserito all’interno di un Viewport3D) è definito un Model3DGroup che contiene i vari pezzi (GeometryModel3D) con applicati diversi materiali. I dati veri e propri sono inseriti all’interno della sezione Resource del ViewPort3D per questioni di compattezza e riutilizzo.

Resource
Una parte dei dati del cubo 3D all’interno della sezione Resource del Viewport3D

Questa soluzione comporta però un codice Xaml molto prolisso e poco riutilizzabile, vedremo nel prossimo articolo come creare un componente altamente riutilizzabile ed estendibile ereditando dalla classe ModelVisual3D.  

Scarica il codice sorgente dell’articolo

Massimizzare le finestre sopra la Barra delle applicazioni in Windows 7

In Windows XP esisteva nelle Proprietà della barra delle applicazioni e del menù Start un’opzione chiamata Sempre in primo piano che poteva essere deselezionata e permetteva alle applicazioni massimizzate di poter essere davanti anche alla barra delle applicazioni.

ProprietaBarraApplicazioniWXp ProprietaBarraApplicazioniW7
Windows Xp Windows 7

In Windows 7 questa opzione è purtroppo scomparsa ed ora le finestre appaiono tutte inevitabilmente sotto alla trasparenza della barra delle applicazioni:

wxp w7
Windows Xp con l’opzione Sempre in primo piano disabilitata

Windows 7

A volte però si può avere la necessità di ricreare il comportamento disponibile in Windows Xp nella propria applicazione.

Visto che l’opzione non esiste più si può ricorrere ad un piccolo “trucco” chiamando la seguente funzione all’avvio del proprio programma:

codes

Il codice sostanzialmente consiste nell’impostare tramite alcune chiamate di Windows uno stile non in primo piano per la Shell_TrayWnd ovvero la TaskBar o barra delle applicazioni.

W7Over

La soluzione però non è valida quando la finestra viene massimizzata dall’utente, a differenza di Windows XP infatti le finestre rimangono sopra alla barra delle applicazioni.

MaximizedW7
Finestre massimizzate in Windows 7, nonostante il codice precedente le finestre massimizzate non copriranno la barra delle applicazioni

Una soluzione migliore e più semplice per estendere a tutto schermo le finestre massimizzate è disabilitare il MaximizeBox.

Impostando a false il MaximizeBox (in applicazioni Windows Forms) e massimizzando da codice con l’istruzione WindowState = FormWindowState.Maximized le finestre appariranno infatti a pieno schermo massimizzate.

maximized
Finestra massimizzata via codice in Windows 7 e con la proprietà MaximizeBox = False, la barra delle applicazioni risulta coperta.

Purtroppo con applicazioni WPF non si dispone di una proprietà MaximizeBox ma si può ovviare impostando WindowStyle a None “perdendo” però la barra del titolo dell’applicazione.

WPF 3D Labs

Imparare la teoria del 3D è certamente interessante ma quello che serve maggiormente è la pratica.

Inauguro una nuova sezione del blog che verrà mano a mano arricchita con nuovi laboratori interattivi dove sarà possibile “smanettare” concentrandosi sul 3D anziché sui dettagli. Non dovrete creare nuovi progetti o pensare a creare assi virtuali per orientarvi nel mondo 3D. Potete imparare i principi fondamentali da subito senza tanti fronzoli e direttamente dal vostro Browser! (richiede installato il .Net Framework 3.5)

Ogni laboratorio contiene una piccola descrizione, un link che porta ad un articolo di approfondimento e un tutorial interattivo che spiega passo passo i concetti importanti.

Buon divertimento!

WPF 3D Labs

Trascinando e tenendo premuto il tasto destro del mouse è possibile ingrandire/rimpicciolire la schermata 3D nel WPF 3D Labs. Col tasto sinistro è possibile invece ruotare la schermata 3D.

WPF e il 3D (sesta parte)

Indice degli articoli su WPF e il 3D

I pennelli di WPF

Per colorare un cubo di Rosso abbiamo assegnato al nostro modello 3D (creato in precedenza) il materiale DiffuseMaterial con la proprietà Brush impostata a Red tramite codice XAML.

DiffuseMaterialBrush

Così facendo dietro le quinte è stato utilizzato il pennello predefinito Brushes.Red che altro non è che un Brush (parola che in italiano si può tradurre letteralmente in pennello) di tipo SolidColorBrush (colore uniforme) con la proprietà Color impostata su Red. Avremmo potuto scrivere anche il seguente codice XAML per ottenere lo stesso risultato:

DiffuseMaterialSolidColorBrush

Scrivendo il codice in quest’ultima forma è possibile sostituire il tipo SolidColorBrush con qualsiasi pennello, vediamo quali WPF ci fornisce:

SolidColorBrush come abbiamo visto ci permette di colorare con un colore a tinta unita
LinearGradientBrush permette di colorare con sfumature lineari
ImageBrush permette di disegnare un’immagine
RadialGradientBrush permette di colorare con sfumature radiali
DrawingBrush permette di disegnare un disegno 2D (o un oggetto Drawing)
VisualBrush   permette di disegnare un oggetto visualizzabile (o un oggetto Visual)
I pennelli sono ordinati dal più al meno performante.

WPF è estremamente coerente e permette di utilizzare su oggetti sia 2D sia 3D tutti i pennelli.

Blend 
Tramite Expression Blend è possibile impostare visualmente qualsiasi pennello e vederne un anteprima applicata sull’oggetto anche se tridimensionale

 

Coloriamo oggetti 3D coi pennelli

L’uso di pennelli avanzati pone il problema di mappare eventuali immagini 2D (chiamate texture) sulle superfici tridimensionali, per risolverlo dobbiamo inserire delle coordinate chiamate TextureCoordinates nelle nostre geometrie.

Ad esempio il seguente pennello LinearGradientBrush genera un gradiente dal bianco al nero passando per il rosso:

LinearGradientBrush

Per colorare un cubo col gradiente di esempio oltre ad impostarlo come materiale (vedere I pennelli di WPF ad inizio articolo) dobbiamo provvedere a mappare ogni punto alle corrispondenti coordinate della texture che come possiamo notare utilizzano il sistema di riferimento 2D. La mappatura si concretizza tramite la proprietà TextureCoordinates della geometria MeshGeometry3D

texture TextureCoordinates

Il codice XAML per brevità è relativo alla sola faccia centrale del cubo

Debug Post-Mortem step by step con Visual Studio 2010

Se la nostra applicazione va in errore fuori dal nostro ambiente di sviluppo e non riusciamo a riprodurre il problema (seguendo eventualmente la procedura indicata dal nostro cliente) iniziano inevitabilmente i… dolori!

Spesso l’unica arma di cui disponiamo con applicazioni scritte in codice gestito è lo StackTrace ovvero la sequenza di funzioni che sono state chiamate prima della manifestazione del fatidico errore ma nella maggior parte dei casi non basta a capire dove si è verificato realmente il problema, serve una completa istantanea dello stato dell’applicazione (o memoria del processo) che comprenda sia la cronologia delle funzioni chiamate sia i valori delle variabili interne.

Nel mondo Windows l’istantanea si traduce in Mini Dumps e Full Dumps, in poche parole istantanee di parte della memoria del processo e istantanee della memoria del processo assieme alla memoria degli altri moduli (anche di sistema) caricati.

Il vantaggio nell’uso di Mini Dumps si traduce in dimensioni minori, solamente alcune sezioni della memoria del processo sono salvate, moduli come user32.dll non sono salvati poiché è possibile recuperare una copia dei file dal CD di Windows della corrispondente versione.

Fino ad oggi WinDbg (Windows Debugger) con SOS.dll (Son of Strike, un’estensione per il debugging di applicazioni gestite) erano la lunga e dura strada da intraprendere che richiedeva parecchio studio e dedizione per riuscire a scoprire la causa dell’errore partendo dal Dump del crash.

Visual Studio 2010 apre nuove strade al debug Post-Mortem ovvero al debug di applicazioni dopo l’errore, permette infatti di aprire i file dump del crash di applicazioni gestite e visualizzarne lo stato(stack, variabili locali, etc..) senza utilizzare SOS e rendere quindi più rapido e confortevole il debug.

Per poter eseguire il debug dobbiamo disporre oltre che al file dump (.dmp) del crash anche dei sorgenti e del file dei simboli (.pdb) corrispondente ai binari dell’applicazione.

NB: E’ buona norma conservare sempre i file .pdb e i sorgenti delle release distribuite a terzi della nostra applicazione.

Passiamo adesso alla pratica e vediamo un caso pratico di debug “Post-Mortem”:

Apriamo Visual Studio 2010 e creiamo una nuova applicazione Windows Forms 4.0 inserendo del semplice codice a scopo dimostrativo che generi un’errore di divisione per zero:

1

Eseguiamo in modalità Release la nostra applicazione e alla segnalazione dell’eccezione da parte di Visual Studio salviamo il Dump andando su Debug/Save Dump As.., in scenari reali dovremo modificare la nostra applicazione per creare automaticamente un Dump in caso di crash e spedircelo se il cliente acconsente o più semplicemente potremmo registrarci a WinEqual per poter ricevere i dump della segnalazione standard di errori di Windows.

2

3
Il dump del crash può raggiungere centinaia di megabyte

Utilizzando Windows Vista o Windows 7 possiamo anche creare tramite Task Manager (Gestione Attività) il MiniDump del processo scegliendo Create Dump file (Crea file di dettagli) dalla scheda Processi.

NB: Il dump così creato non è però utilizzabile dalla versione Visual Studio 2010 Beta 1. La strada suggerita è lanciare UserDump in caso di eccezioni per catturare il dump della propria applicazione in "produzione".

12

Creiamo ora una nuova soluzione vuota in Visual Studio per analizzare il nostro file di dump

4

Aggiungiamo alla soluzione un nuovo elemento esistente facendo click destro sulla soluzione nel Solution Explorer e scegliendo Add Existing Item.

5

Indichiamo il file di crash del dump salvato in precedenza.

6

Verrà automaticamente mostrata una schermata con alcune informazioni sul file Dump, indichiamo però prima di iniziare il Debug la cartella contenente il file .pdb della nostra applicazione cliccando su Set symbol paths (se non visibile subito sarà necessario scorrere la finestra verso destra).

8

Nella finestra di dialogo Symbols che apparirà clicchiamo sull’icona della cartella per indicare la posizione del nostro file .pdb.

9

Clicchiamo infine start debugging (la grossa freccia verde) per iniziare ad analizzare l’applicazione proprio dallo stato in cui avevamo salvato il file dump

7 

L’esperienza di debug sarà simile ad un normale debug in fase di sviluppo (con alcune limitazioni), andando col mouse sopra alle variabili appariranno i valori contenuti. Se richiesto indichiamo la posizione dei file sorgenti necessari per visualizzare il codice (dovranno ovviamente essere la stessa versione dell’eseguibile crashato)

10

Cliccando sull’icona alla destra del valore possiamo inserire dei commenti per migliorare la collaborazione con gli altri sviluppatori se al progetto hanno partecipato più persone.

11

Le nuove funzionalità di debug di Visual Studio 2010 rappresentano un grande passo in avanti per colmare il gap con il debug post-mortem di applicazioni native e sicuramente si renderanno molto utili in scenari client/server dove costituiranno un insostituibile aiuto allo sviluppatore.

WPF e il 3D (quinta parte)

Indice degli articoli su WPF e il 3D

Dopo aver acquisito manualità con triangoli e quadrati nello spazio 3D è giunto il momento di creare una geometria che renda finalmente “giustizia” al 3D, costruiremo un cubo e aggiungeremo al nostro programma la possibilità di navigare all’interno dello spazio tridimensionale ingrandendo/rimpicciolendo e ruotando la scena col mouse.

 

Costruiamo un Cubo

Come visto nel precedente articolo per costruire un quadrato occorrono 2 triangoli, in un cubo sono presenti 6 quadrati (uno per ogni faccia) ma non serviranno 6x4=24 punti distinti ma solamente 8 punti visto che molti punti saranno condivisi da più facce.

Di seguito uno schema dei punti essenziali necessari per costruire il nostro cubo:

Cubo

Ogni faccia necessiterà di due triangoli come evidenziato nella seguente immagine:

CuboColori

Come per il singolo quadrato basterà inserire tutti i punti univoci nella collezione Positions e inserire gli indici per creare i triangoli desiderati uno dopo l’altro. WPF ogni 3 indici creerà un triangolo (in XNA questa modalità di disegno in cui ogni gruppo di tre vertici definisce un triangolo è detta TriangleList).

Volendo centrare la base del cubo nell’origine i punti univoci sono:

Positions
0 (0.5, 0, 0.5)
1 (0.5, 1, 0.5)
2 (-0.5, 1, 0.5)
3 (-0.5, 0, 0.5)
4 (0.5, 0, -0.5)
5 (0.5, 1, -0.5)
6 (-0.5, 1, -0.5)
7 ( -0.5, 0, -0.5)

Gli indici dei triangoli invece sono rappresentati dalla seguente tabella:

TriangleIndices
Index Value Index Value Index Value
0 0 12 1 24 6
1 1 13 5 25 7
2 3 14 2 26 2
3 1 15 5 27 3
4 2 16 6 28 2
5 3 17 2 29 7
6 5 18 5 30 4
7 1 19 4 31 0
8 0 20 7 32 3
9 4 21 6 33 7
10 5 22 5 34 4
11 0 23 7 35 3
Ogni triangolo nella tabella ha un colore diverso e la tabella è suddivisa in 3 colonne per visualizzare i 12 triangoli necessari per rappresentare i 6 quadrati costituenti le facce del cubo

Il codice XAML per creare il modello 3D (di materiale rosso) sarà dunque:

 xaml_cube

Aggiungendo il codice al programma visto negli articoli precedenti avremmo il nostro Cubo 3D renderizzato nella nostra applicazione.

 

Aggiungiamo il supporto alla navigazione delle nostre scene 3D

Per rendere maggiormente accattivante la sensazione di profondità della scena è necessario aggiungere il supporto alla “personalizzazione” della telecamera da parte dell’utente per poter visualizzare come meglio crede gli oggetti 3D. Per aggiungere questa funzionalità in modo rapido ed efficace utilizzeremo la libreria open-source (creata da Microsoft) 3D Tools for the Windows Presentation Foundation che fornisce utili classi per estendere il supporto 3D di WPF.

Dopo aver scaricato la libreria in formato binario dal sito CodePlex all’indirizzo http://www.codeplex.com/3DTools procediamo ad aggiungere un riferimento nel file nostro progetto tramite il menù Project/Add reference/Browse e indicando il file 3DTools.dll scaricato.

Per poter usare nella nostra applicazione la libreria dovremmo aggiungere un namespace come evidenziato dalla prima riga cerchiata in rosso nel codice (sotto).
Per aggiungere la funzionalità di navigazione 3D basterà ora decorare il controllo ViewPort3D col TrackballDecorator fornito dai 3D Tools.

xaml_3dtools

Il risultato è immediato e avviando l’applicazione sarà possibile ruotare il cubo tenendo premuto il tasto sinistro del mouse e ingrandire/rimpicciolire trascinando avanti e indietro il mouse tenendo il tasto destro premuto.

3DCube 

Scarica il codice sorgente dell’articolo

Nel prossimo articolo vedremo come “dipingere” sul cubo ed entreremo nelle problematiche relative all’applicazione di più materiali ad un singolo GeometryModel3D. Queste conoscenze ci torneranno utili per colorare di diversi colori ogni faccia e costruire una riproduzione fedele del Cubo di Rubiks.

«settembre»
domlunmarmergiovensab
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789