Pare proprio che "Cider", che altri non è che il nome in codice per le estensioni WPF per Visual Studio 2005, sia rimasto un passo indietro rispetto a WPF stesso. All'uscita del Framework 3.0 di ieri infatti non è corrisposta l'uscita della versione definitiva di questo importante componente. La CTP di Novembre, che ieri si è accompagnata alla RTM del Framework nei vari link che si sono trovati in giro infatti soffre di qualche problema, il primo di tutti quello che impedisce di dichiarare namespace custom all'interno di file XAML. Semplicemente il farlo è indispensabile, ma fa scoppiare il designer e qualche volta anche l'intellisense. Sinceramente speravo che con l'uscita della release definitiva di Windows Presentation Foundation si riuscisse a dare uno strumento per usarla in modo produttivo, ma con Expression ancora in beta e "Cider" in CTP temo dovremmo ancora attendere molto.


Kiran Kumar ha rilascito la versione draft di un importante documento che si propone come una whitepaper sulle performances di Windows Presentation Foundation. Il documento è di importanza estrema per chi intenda ottenere delle prestazioni decenti dalle applicazioni sviluppate su questa piattaforma.

Link: WPF Performance Whitepaper


Il DataBinding in Windows Presentation Foundation da molte possibilità che un tempo richiedevano la realizzazione di controlli appositamente ideati. Ad esempio volendo posizionare degli elementi creati a partire da una collection che ne contenga le coordinate, ci può venire in aiuto il controllo che fa da base alla normale ListBox. Mi riferisco a ItemsControl, che può essere personalizzato facilmente a questo scopo. Ecco un esempio di codice XAML:

<Window x:Class="WindowsApplication1.Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:domain="clr-namespace:WindowsApplication1"
    Title="WindowsApplication1" Height="300" Width="300">
  <Window.Resources>
    <DataTemplate x:Key="template">
      <Ellipse Width="20" Height="20" Fill="Blue" />
    </DataTemplate>
  </Window.Resources>
  <Window.DataContext>
    <domain:Class1 />
  </Window.DataContext>
  <ItemsControl ItemTemplate="{StaticResource template}" ItemsSource="{Binding Path=Items}">
    <ItemsControl.ItemContainerStyle>
      <Style>
        <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
        <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
      </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <Canvas Background="Red" IsItemsHost="True" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</Window>

Il controllo è stato configurato per fare in modo che il suo Panel principale sia creato di tipo Canvas cioè il controllo di Layout che in WPF consente il posizionamento assoluto dei suoi controlli figlio. Inoltre ad ogni elemento creato, in accordo con quanto descritto dal DataTemplate viene impostato uno style che posiziona l'elemento alle giuste coordinate. Eseguendo il codice si otterranno dei pallini posizionati in accordo con le coordinate espresse dalla fonte dati.


<Window x:Class="WindowsApplication1.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:domain="clr-namespace:WindowsApplication1"
Title="WindowsApplication1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="template">
<Ellipse Width="20" Height="20" Fill="Blue" />
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<domain:Class1 />
</Window.DataContext>
<ItemsControl ItemTemplate="{StaticResource template}" ItemsSource="{Binding Path=Items}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Red" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Window>


Ecco un ottimo editor XAML da sostituire a XamlPad. L'editor oltre ad avere un aspetto piacevole funziona davvero bene. E' dotato tra le altre cose di una libreria di Snippet utili per evitare di riscrivere sempre le stesse cose. 

Link: KaXaml

Technorati tags: , ,

Diversamente da quanto avveniva con le vecchie WindowsForm, XAML consente un controllo molto più raffinato del layout del contenuto di una Window. Alcune librerie di terze parti, come ad esempio le SyncFusion avevano cercato di introdurre delle logiche di disposizione dei contenuti diverse dal posizionamento assoluto, ma la maggior parte delle volte si era costretti a combattere con Dock e Anchor per cercare di disporre i controlli in modo che mantenessero un aspetto coerente durante il ridimensionamento. XAML introduce una logica basata su Panel. Un Panel è una zona che suddivide un'area in diverse porzioni secondo una logica specifica del Panel stesso. Esistono diverse tipologie di Panel che applicano ognuno un diverso tipo di logica:

StackPanel: consente di disporre il contenuto in una riga orizzontale o verticale

DockPanel: dispone i controlli secondo una logica analoga a quella della proprietà Dock di WindowsForms

WrapPanel: dispone i controlli l'uno a fianco all'altro andando a capo quando una riga viene riempita

Grid: consente di disporre i controlli con una logica tabulare in modo analogo al GridBagLayout di Java

Canvas: consente di specificare la posizione dei controlli mediante coordinate assolute

Ognuno di questi Panel che ho appena descritto richiederebbe un post dedicato per spiegarne bene le caratteristiche, tanta è la loro flessibilità. Per ora ci invito a considerare la bellezza di questo tipo di approccio che permette di annidare i pannelli l'uno nell'altro in modo pressochè illimitato. A scelta quindi si potrà inserire un DockPanel in uno StackPanel, e al suo interno inserire una Grid. Naturalmente si tratta di un esempio come molti se ne potrebbero fare, ma in realtà la libertà è massima. I pannelli così disposti si adatteranno autonomamente alle dimensioni della Window causando il ridimensionamento di tutto il contenuto.


Il passaggio a XAML segna un punto importante. Finalmente le Form assumono un nome più attinente a quello che in realtà sono diventando Window. In realtà però anche nuovi attori entrano sulla scena. Alla normale Windows che appare a tutti gli effetti analoga a quello che un tempo erano le Form, sono spuntate le Page il cui nome tradisce l'analogia con le pagine di un sito web. La loro caratteristica è quella di introdurre un nuovo modo di fruire le applicazioni windows, più simile appunto alla navigazione in un sito web, grazie alla presenza di pulsanti analoghi a quelli di un browser. E' evidente che questo tipo di finestre sono adatte ad applicazioni particolari, ma l'averle come compagne apre la strada a molte belle soluzioni che metteno assieme la semplicità di una applicazione web assieme alla potenza delle applicazioni Windows.

Continuando con le new entry in questo ristretto club troviamo una bella sorpresa. Le PageFunction rappresentano quella categoria di finestre che tipicamente pullulano nelle applicazioni e che hanno lo scopo di raccogliere scelte rapide come ad esempio può essere una finestra di login, oppure un anagrafica. La cosa che ho apprezzato di esse è l'implementazione che utilizza i generics per tipizzare fortemente il tipo valore di ritorno. Ad esempio nel caso di una form di Login potremmo pensare di definirla così:

public class LoginPage : PageFunction<Credentials>
{
}

Naturalmente ci dovremmo aspettare che la pagina restituisca una istanza di classe contenente le informazioni di Login immesse. Infine WPF istituisce una nuova FlowDocument page che serve a contenere documenti definiti attraverso l'uso di XPS.

powered by IMHO 1.3


 Curiosamente è possibile inserire più di un file di definizione dell'applicazione all'interno di un progetto XAML. E' evidente però che uno e solo uno dovrà essere preso in considerazione dal compilatore e quindi determinare l'entry point dell'applicazione stessa. Scrutando nel codice generato da visual studio si vede chiaramente che nulla cambia in come una applicazione WindowsForms viene avviata. Infatti se si curiosa nella parte privata del codebehind nella cartella /obj si scopre che il metodo Main() pur essendo stato finalmente nascosto allo sviluppatore, continua a rimanere l'unico punto di partenza valido per il runtime.

Un effetto collaterale strano di questo è che - almeno nella RC-1 del .NET Framework 3.0 - l'opzione nelle preferenze del progetto che normalmente governa l'entry point dell'applicazione non ha in realtà alcun effetto. Anche se la si lascia vuota l'applicazione partirà lo stesso dal primo file App.xaml che è stato generato da visual studio, trascurando del tutto ogni altro file creato in seguito. Occorre fare un po' di attenzione per capire bene come fare a cambiare l'entry point dell'applicazione. Tale opzione è per così dire nascosta nel menu mostrato nella figura a lato. Solo un file dell'applicazione potrà ricevere la BuildAction di tipo ApplicationDefinition facendo in modo così che il metodo Main() venga spostato al suo interno. Questo menu non ha alcun tipo di intelligenza. E' possibile così impostare l'attributo più di una volta oppure su di file che non hanno le caratteristiche adeguate ad essere entry point (ad esempio una Window) senza ottenere errori fino alla fase di compilazione.


Mi ci è voluto un po' a capirlo, probabilmente perchè sono abituato alle pagine ASP.NET che usano una cartella temporanea per generare i file CodeBeside. Nel caso di una applicazione XAML, le porzioni di codice "partial" che saranno generate si possono trovare nella cartella /obj che in effetti considerando la programmazione Windows Forms è anche il posto più ovvio. Ecco un pezzo di codice che mostra tale file:

using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;


namespace wpf1 {
    
    
    
/// 


    /// App
    
/// 

    public partial class App : System.Windows.Application {
        
        
/// 
        /// InitializeComponent
        
/// 

        
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
        
public void InitializeComponent() {
            
            
#line 4 "..\..\App.xaml"
            this
.StartupUri = new System.Uri("Page1.xaml", System.UriKind.Relative);
            
            
#line default
            #line hidden
        
}
        
        
/// 
        /// Application Entry Point.
        
/// 

        
[System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        
public static void Main() {
            wpf1.App1 app = 
new wpf1.App();
            app.InitializeComponent();
            app.Run();
        }
    }
}

Il codice in se non è nulla di speciale per chi ha già avuto occasione di vedere quello generato per una applicazione ASP.NET. In definitiva nella InitializeComponent() il codice non fa altro che ricalcare il contenuto del file XAML per istanziare i controlli necessari a riprodurne quanto definito. In questo spezzone ad esempio viene assgnata la proprietà StartupUri con quanto immesso nel relativo attributo. Interessante notare che è possibile aggiungere a piacere altri XAML che estendano la classe Application, ma solo quello che contiene il metodo Main sarà quello che può andare in esecuzione. Gli altri semplicemente non saranno utilizzabili. Almeno a prima vista...

powered by IMHO 1.3


Stamane ho cominciato ad esplorare un po' più approfonditamente Window Presentation Foundation e ho deciso di iniziare a buttare giù i concetti che ho chiarito, sperando di fare cosa utile ai miei lettori.

Per iniziare da quello che appare essere il principio, per prima cosa vorrei chiarire cos'è una applicazione WPF. Dopo un po' che si mette il naso in una applicazione basata su XAML, la cosa che appare chiara è che una applicazione può essere parificata ad un unico documento XML che descrive le varie parti che la compongono. Naturalmente in realtà queste parti si trovano in file separati, ma l'impressione generale che si ottiene è che essi potrebbero stare tranquillamente assieme. Dico questo non per puro scopo accademico. Considerando una applicazione XAML come un unico document XML l'approccio con cui ci si avvicina ad esso assume una connotazione più organizzata. Così la prima curiosità che viene in mente, o almeno che è venuta in mente a me, è capire quale è la radice di questo gigantesco documento.

Manco a dirlo il nodo principale è <application>. All'interno di un progetto WPF è presente un solo nodo Application.

<Application
    x:Class
="wpf1.App"
    
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
StartupUri="Page1.xaml">
<
/Application>

Tralasciando le definizioni di namespace che dovrebbero essere chiare a chiunque abbia usato XML, rimangono l'attributo Class e StartupUri. Il primo definisce qual'è la classe codebehind che rappresenta l'applicazione e il secondo definisce qual'è la pagina/finestra di partenza. La parte che assomiglia alla programmazione web è proprio questa. Ogni singolo elemento ha una classe codebehind che lo rappresenta. In fase di compilazione poi il codice XAML viene compilato alla stessa stregua di una pagina web.

powered by IMHO 1.3