Introduzione Finalmente, il mio nuovo PC con Windows Vista è operativo, anche se a causa dell'UAC ho avuto una notevole serie di problemi, non provocati dallo UAC in quanto tale, ma dal fatto che le applicazioni attualmente da noi utilizzate per lo sviluppo non sono ancora in grado di lavorare correttamente secondo la nuova filosofia degli utenti non Amministratori. Ma non siamo qui per disquisire dello UAC... Sulla mia macchina ho installato Visual Studio 2005 Professional, ovviamente il suo SP1, il suo ultimo SDK, Il framework 3.0 era già installato, infine ho aggiunto le WPF Extensions For Visual Studio 2005 Osserviamo cosa è accaduto in Visual Studio 2005. Nuovi Modelli in Visual Studio Ora, all'interno di Visual Studio trovo alcuni modelli di progetto nuovi e alcuni modelli di elemento nuovi 
Vi sono quattro tipi di progetto nuovo forniti con le estensioni per il framework 3.0: - Windows Application (WPF)
- XAML Browser Application (WPF)
- WCF Service Library
- Custom Control Library (WPF)
Potremo quindi provare a realizzare una applicazione Windows, una applicazione per il Browser, una libreria di servizi WCF e una libreria di controlli WPF. Come primo passo nel Framework 3.0, proveremo a osservare il primo dei quattro modelli, e vedere cosa ci mette a disposizione quando lo utilizziamo. 
Per quel che riguarda i modelli di elementi, possiamo osservare che ci sono sette nuovi oggetti: - Flow Document (WPF)
- Page (WPF)
- PageFunction (WPF)
- ResourceDictionary (WPF)
- User Control (WPF)
- Window (WPF)
- Custom Control (WPF)
Una lista piuttosto scarna ma che incuriosisce, presto ci cimenteremo nell'osservazione e nel test di questi oggetti e delle loro funzionalità. La prima applicazione WPF Generando la nostra prima applicazione, usiamo il Modello Windows Application, vediamo che appare una familiare finestra simile alle nostre Windows Forms, che si chiama Window1 al posto di Form1, e per prima cosa guardiamo l'insieme dei tools fornito. Possiamo notare come sembrano esserci le cose a cui siamo abituati, quali Button, CheckBox, ComboBox, Image, Label, ListBox, RadioButton, Richtextbox, TextBox, ma ci sono alcuni controlli nuovi, come InkCanvas, Inkpresenter, Slider, e altri che troviamo zone dei Common Container e dei menu e toolbar: Canvas, DocumentViewer, StackPanel, ToolbarTray. Tutti oggetti che spero potremo sperimentare molto presto, per ora, direi che continueremo l'osservazione dell'ambiente e delle cose che il modello ci ha costruito. Se osserviamo nel solution explorer cosa ci è stato generato, rispetto a quanto usualmente troviamo in una applicazione windows forms troviamo alcune cose familiari, come la cartella Properties (C#) o MyProject (VB) e al suo interno le usuali Assembly Info, Resources e Settings. Però basta che esaminiamo i Reference automaticamente inseriti alla generazione del progetto per trovare molte cose nuove: PresentationCore, PresentationDesignDeveloper, PresentationFramework, ReachFramework, System.IdentityModel, UIAutomationProvider, UIAutomationTypes, WindowsBase. Tutti Assembly che non ci sono familiari, visto che usualmente per Windows Forms usiamo solo references con System come prefisso ed eventualmente Microsoft. A questo punto facciamo un giro su MSDN a cercare notizie. Consiglio a tutti la lettura dell'articolo che traccia l'architettura con cui è costruito Windows Presentation Foundation, da cui riporto lo schema di base del funzionamento della nuova libreria di oggetti dedicati alla presentazione di contenuti tramite interfaccia visuale: 
Osservando il disegno, possiamo scoprire che PresentationCore e PresentationFramework sono le due librerie di base su cui è costruito WPF. Per PresentationDesignDeveloper, non ho trovato una presentazione ufficiale, ma un paragrafo solamente: è la parte di WPF che contiene le features specifiche dedicate agli sviluppatori, sicuramente ne scopriremo qualcosa proseguendo nello studio di WPF. La libreria ReachFramework è collegata ai documenti XPS e al loro trattamento e per quanto ho scoperto, ha funzionalità che permettono di visualizzarli su diversi Sistemi Operativi. System.IdentityModel è una libreria che si occupa di autenticazione e security, e presumo sia parte di Card Space o ad esso collegata. UIAutomationProvider è una dll piuttosto interessante, nella definizione che trovate su MSDN viene indicato che fornisce servizi di automazione dell'interfaccia utente per poter accedere alla maggior parte degli oggetti del desktop e costruire programmi di aiuto ai diversamente abili e comunque ai programmi che devono accedere in modo automatico ad elementi della UI del sistema operativo. Invito chi è interessato ad approfondire questo tipo di tecnologia a leggere l'articolo che ho collegato e quelli ad esso collegati sulle pagine di MSDN. UIAutomationTypes, è parte dello stesso framework per la costruzione di applicazioni accessibili e per dare accessibilità ai componenti del desktop. Vi rimando all'articolo già collegato per saperne di più. WindowsBase è citata come assembly contenente molte delle classi base di WPF e se la osservate con l'Object Browser potete notare come contenga tutti i namespace di base, quali System.Windows, System.Windows.Input ecc. E' quindi fra le core library di WPF. Continuando ad osservare il Solution Explorer, possiamo vedere come nella nostra applicazione siano stati generati due files con estensione XAML e due con estensione CS o VB, App.xaml e App.cs (vb),Window1.xaml e Window1.cs (vb). E possiamo vedere come Window1.xaml è visualizzata dal designer come una Form. Pertanto possiamo affermare che le Forms di WPF si chiamano Windows nello standard dei modelli. Andiamo a vedere cosa troviamo dentro ai files. <Application x:Class="DnwCiao.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"StartupUri="Window1.xaml"><Application.Resources>Application.Resources>Application> <Application x:Class="App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"StartupUri="Window1.xaml"><Application.Resources>Application.Resources>Application> //C# Codebehindusing System;
using System.Windows;
using System.Data;
using System.Xml;
using System.Configuration;
namespace DnwCiao
{
/// /// Interaction logic for App.xaml/// public partial class App : System.Windows.Application
{
}
} ' VB Codebehind' Interaction logic for App.xaml
Partial Public Class App
Inherits System.Windows.Application
End Class Possiamo osservare come la classe App sia definita in C# come una classe derivata da System.Windows.Application, e nel suo file XAML sia indicato un attributo x:Class (dove x è solo l'abbreviazione del namespace come specificato dall'attributo xmlns:x), e questo attributo indica come si chiama la classe di cui XAML è la porzione di markup. Se esaminiamo invece lo XAML collegato a VB notiamo l'assenza del Namespace, probabilmente a causa della funzionalità di RootNamespace che in VB pone il Namespace di base a livello di progetto quindi includendo automaticamente tutto nel primo livello di Namespace senza bisogno di dichiararlo. Possiamo notare anche come nel codebehind, C# o VB non ci sia scritto alcun tipo di codice che colleghi la classe App alla classe Window1, però possiamo rilevare che nel markup è indicato un attributo: StartupUri="Window1.xaml" e questo ci fa capire come questo attributo indichi all'applicazione qual'è la finestra che deve aprire quando parte. Se lo cerchiamo su MSDN infatti troviamo proprio questa definizione, la proprietà StartupUri definisce l'elemento della User Interface che viene visualizzato alla partenza dell'applicazione. Passiamo ad analizzare la classe Window1 (Nell'immagine la Window e lo XAML del progetto C#). 
<Window x:Class="Window1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="DnwCiaoVb" Height="300" Width="300"><Grid>Grid>Window> Come possiamo notare, in questo caso il Root Element di XAML è Window e il Designer ci propone anche la rappresentazione Visuale del markup, mostrandoci quindi che l'uso primario di XAML è proprio quello di rappresentare tutto ciò che è visuale in una applicazione WPF. Possiamo constatare come anche in questo file, c'è l'attributo Class che indica Namespace e Nome della classe C# (E solo il nome della classe in VB) collegata a questa porzione di XAML. Verifichiamo anche che ci sono 2 attributi di dimensione, Height e Width, un Title il cui valore è ciò che è scritto sul titolo della finestra, inoltre c'è un tag vuoto con su scritto Grid. Vediamo cosa c'è invece nel codebehind della nostra form... oops Window: using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace DnwCiao
{
/// /// Interaction logic for Window1.xaml/// public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
}
}
} ' Interaction logic for Window1.xaml
Partial Public Class Window1
Inherits System.Windows.Window
Public Sub New()
InitializeComponent()
End SubEnd ClassSe pure in realtà non vi sia quasi nulla dentro al codice, ci sono molti namespaces che sono stati automaticamente inseriti nel nostro file C# mentre non sono stati inseriti in VB. Presumo che chi ha generato il modello abbia inserito i namespaces più utilizzati nel codebehind di una Window, mentre per VB probabilmente per rimanere in linea con i modelli Winforms non ci sono Namespaces predefiniti. Siccome sono curiosa, ho cercato dove si trova InitializeComponent, ma non c'è un file .designer collegato alla nostra form. Ho verificato se vi fossero dei files non visualizzati attivando il flag di visualizzazione di tutto il contenuto sul solution explorer, ma non vi sono file nascosti. Anche andando a controllare direttamente sulla cartella del progetto non ho trovato nulla, allora ho utilizzato la funzione GoToDefinition di Visual Studio (Tasto destro sulla chiamata al metodo e sul menu contestuale lo trovate). Mi è apparsa una nuova finestra, con una partial class C# contenente il codice di seguito riportato: namespace DnwCiao {
/// /// Window1/// public partial class Window1 : System.Windows.Window, System.Windows.Markup.IComponentConnector {
private bool _contentLoaded;
/// /// InitializeComponent///
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri(
"/DnwCiao;component/window1.xaml", System.UriKind.Relative);
System.Windows.Application.LoadComponent(this, resourceLocater);
}
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(
"Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
void System.Windows.Markup.IComponentConnector.Connect(
int connectionId, object target) {
this._contentLoaded = true;
}
}
} '------------------------------------------------------------------------------' ' This code was generated by a tool.' Runtime Version:2.0.50727.312'' Changes to this file may cause incorrect behavior and will be lost if' the code is regenerated.' '------------------------------------------------------------------------------Option Strict Off
Option Explicit OnImports System
Imports System.Windows
Imports System.Windows.Automation
Imports System.Windows.Controls
Imports System.Windows.Controls.Primitives
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Ink
Imports System.Windows.Input
Imports System.Windows.Markup
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Media.Effects
Imports System.Windows.Media.Imaging
Imports System.Windows.Media.Media3D
Imports System.Windows.Media.TextFormatting
Imports System.Windows.Navigation
Imports System.Windows.Shapes
''''''Window1''' _
Partial Public Class Window1
Inherits System.Windows.Window
Implements System.Windows.Markup.IComponentConnector
Private _contentLoaded As Boolean''''''InitializeComponent''' _
Public Sub InitializeComponent() _
Implements System.Windows.Markup.IComponentConnector.InitializeComponent
If _contentLoaded ThenReturnEnd If
_contentLoaded = trueDim resourceLocater As System.Uri = New _
System.Uri("/DnwCiaoVb;component/window1.xaml", _
System.UriKind.Relative)
System.Windows.Application.LoadComponent(Me, _
resourceLocater)
End Sub"Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")> _
Sub System_Windows_Markup_IComponentConnector_Connect _
(ByVal connectionId As Integer, ByVal target As Object) _
Implements System.Windows.Markup.IComponentConnector.Connect
Me._contentLoaded = trueEnd SubEnd Class [Nota: In VB sono state riportate qui tutte le clausole Imports (using di C#) che invece in C# sono nella partial class per lo sviluppatore.] L'editor mostra questo file come un qualsiasi file C# o VB e mi dice che si chiama: ...\DnwCiao\DnwCiao\obj\Debug\Window1.g.cs
...\DnwCiao\DnwCiaoVb\obj\Debug\Window1.g.vb Quindi, il file generato automaticamente dal designer si trova nascosto all'interno della cartella Obj.Debug, e se andiamo a curiosarvi ancora un pochino, troveremo delle altre cose in questa cartella. 
Oserei dire che i programmatori di Visual Studio amano il Nascondino! In questo caso è a fin di bene, infatti non ci stanno nascondendo cose che dovremmo poter modificare, ma le classi parziali che sono autogenerate dal sistema, in modo che non le modifichiamo per errore e poi non capiamo perché le nostre modifiche sono state eliminate, nel momento in cui queste classi vengono rigenerate. Se siete stati attenti ed avete esaminato bene cosa c'è nei files predisposti dal Modello che abbiamo utilizzato per generare il progetto, avete certamente notato che manca una cosa fondamentale, il metodo statico Main, l'entry point del programma. Ebbene no, anche se non si vede c'è e se apriamo il file App.g.cs (vb), lo troveremo in tutto il suo splendore: //Contenuto di: App.g.csnamespace DnwCiao {
/// /// App/// public partial class App : System.Windows.Application {
/// /// InitializeComponent///
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
#line 4 "..\..\App.xaml"this.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);
#line default#line hidden
}
/// /// Application Entry Point.///
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main() {
DnwCiao.App app = new DnwCiao.App();
app.InitializeComponent();
app.Run();
}
}
} '------------------------------------------------------------------------------' ' This code was generated by a tool.' Runtime Version:2.0.50727.312'' Changes to this file may cause incorrect behavior and will be lost if' the code is regenerated.' '------------------------------------------------------------------------------Option Strict Off
Option Explicit OnImports System
Imports System.Windows
Imports System.Windows.Automation
Imports System.Windows.Controls
Imports System.Windows.Controls.Primitives
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Ink
Imports System.Windows.Input
Imports System.Windows.Markup
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Media.Effects
Imports System.Windows.Media.Imaging
Imports System.Windows.Media.Media3D
Imports System.Windows.Media.TextFormatting
Imports System.Windows.Navigation
Imports System.Windows.Shapes
''''''App'''
Partial Public Class App
Inherits System.Windows.Application
''''''InitializeComponent''' _
Public Sub InitializeComponent()
#ExternalSource("..\..\App.xaml",4)
Me.StartupUri = New System.Uri("Window1.xaml", System.UriKind.Relative)
#End ExternalSourceEnd Sub''''''Application Entry Point.''' _
Public Shared Sub Main()
Dim app As App = New App
app.InitializeComponent
app.Run
End SubEnd Class Ci sono parecchie cose che incuriosiscono in questa partial class nascosta, per ora è opportuno che ci accontentiamo di sapere che c'è! Sarà bene anche annotare, osservando ciò che ufficialmente è a disposizione del programmatore, che un programma WPF non è proprio così semplice come potrebbe sembrare . Un po' di programmazione Datoche abbiamo esaminato minuziosamente tutto ciò che c'è di interessante nel nostro progetto WPF, penso che a coloro che usano il nostro primo programma, siano dovuti educati saluti. Andiamo quindi ad osservare la lunga lista delle property della Window1 e modifichiamo il suo Title, sostituendo l'attuale valore con uno più consono. Poi cambiamo anche la forma alla finestra, e impostiamo la sua dimensione a 70 x 384 dal designer, possiamo verificare come le property Height e Width nel codice XAML sono aggiornate automaticamente. Visto che siamo lanciati, impostiamo FontSize = 18 nelle property del progetto, osservando come questo valore sarà riportato in XAML come un attributo del tag Window. Considerato che: non sappiamo usare i controlli, non sappiamo come si gestiscono gli eventi, e osservando Visual Studio non sembra esservi il familiare Tab con la lista eventi per la Window, usiamo il poco che sappiamo per modificare il nostro progetto in modo che possa salutare gli utenti: namespace DnwCiao
{
/// /// Interaction logic for Window1.xaml/// public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
this.Content = string.Format("Ciao {0}", Environment.UserName);
}
}
} ' Interaction logic for Window1.xaml
Partial Public Class Window1
Inherits System.Windows.Window
Public Sub New()
InitializeComponent()
me.Content = string.Format("Ciao {0}", Environment.UserName)
End SubEnd ClassPer ottenere l'effetto visibile nell'immagine seguente, nel costruttore della nostra finestra, ho scritto this. (Me.) e ho cercato la property più plausibile per scrivere qualcosa sulla Finestra, la sola che sembrava poter essere usata allo scopo, era Content, Usiamo la familiare classe Environment per Leggere lo Username dell'utente loggato e quindi salutiamo come i bravi bambini. 
Conclusioni Anche solo osservando lo scheletro di progetto costruito dal Modello base di WPF Windows Application, possiamo concludere che imparare ad usare WPF non sarà semplicemente aggiungere una serie di nuovi controlli a quelli che conosciamo. Infatti, riguardando il file Window1.XAML dalla finestra del designer non troviamo il tab degli eventi, nella property grid e leggendo le property della Window ci sono molte cose sconosciute. Non solo, se pure all'interno della Window esiste un Tag Grid che se cliccato mostra delle property nella apposita finestra, se andiamo sul CodeBehind e scriviamo: this.G Intellisense non ci mostra alcun Grid o Grid1 e questo potrebbe già iniziare a spaventarci un pochino. Ma da persona curiosa e avendo già sperimentato il passaggio dalla programmazione C a C# e OOP, quindi un salto tecnologico che definirei una scalata all'everest, direi che non ci lascieremo spaventare dal Monte WPF, anche perché MSDN, un po' come fa il CAI per i sentieri alpini, ci fornisce Guide e mappe per permetterci di non perderci durante l'arrampicata. Quindi teniamo in mente il motto che Paul Adams pone sulla sua Guida Galattica per Autostoppisti: Non Fatevi prendere dal panico Alla prossima puntata, dove proveremo a scrivere codice e a cercare dove sono nascosti e come usare gli eventi delle WPF Windows, come aggiungere dei controlli e come vederli dall'interno della Window per pilotarne l'input e l'output. Il progetto utilizzato per il codice dimostrativo può essere scaricato in Area Risorse oppure direttamente a questo link.
Per qualsiasi Feedback, Ulteriore domanda, Chiarimento, oppure se trovate qualche errore usate direttamente il form dei commenti in calce a questo articolo oppure scrivete all'autrice . |