mercoledì 31 marzo 2010

Rilasciata la IE 9 Platform Preview

E’ stata rilasciata la IE9 Platform Preview, una sorta di applicazione in cui gira il nuovo motore di IE9 per poter confrontare le prestazioni con gli attuali motori di rendering.

Per scaricare ed installare la preview potete andare sul sito http://ie.microsoft.com/testdrive/Default.html.

In questo sito troverete anche i test drive che possono essere eseguiti con il consueto browser e sono anche disponibili nella preview per effettuare un confronto diretto.

Buon divertimento.

MSDN cambia aspetto!!

Non so se qualcuno se ne è già accorto (credo di si, perché di solito in queste cose arrivo dopo “i fuochi”), ma MSDN LIbrary ha cambiato aspetto:

image

Personalmente non dispiace affatto!!

Technorati Tag:

domenica 28 marzo 2010

Recuperare le informazioni di mapping delle entità in Linq2SQL

In questo piccolo post vorrei mostrarvi un modo per recuperare, dato il tipo di un oggetto generato con il designer di Lnq2SQL, la tabella di mapping e le eventuali colonne di mapping delle singole proprietà.

Quando generiamo il modello dei dati in Linq2SQL, l’ambiente di sviluppo crea per noi il codice VB.NET per la definizione delle classi che mappano le nostre tabelle e il DataContext per accedere alla banca dati.

Supponiamo di avere una tabella di clienti:

imagee di generare il modello Linq2SQL. In questo caso Visual Studio genera per noi una classe Clienti:

  1. <Table(Name:="dbo.Clienti")> _
  2. Partial Public Class Clienti
  3.     Implements System.ComponentModel.INotifyPropertyChanging,  _
  4.                 System.ComponentModel.INotifyPropertyChanged
  5.  
  6.     .
  7.     .
  8.  
  9.     <Column(Storage:="_IDCliente", AutoSync:=AutoSync.OnInsert, DbType:="Int NOT NULL IDENTITY", IsPrimaryKey:=True, IsDbGenerated:=True)> _
  10.     Public Property IDCliente() As Integer
  11.         .
  12.         .
  13.     End Property
  14.  
  15.     <Column(Storage:="_CodiceCliente", DbType:="Char(10) NOT NULL", CanBeNull:=False)> _
  16.     Public Property CodiceCliente() As String
  17.         .
  18.         .
  19.     End Property
  20.  
  21.     <Column(Storage:="_DescrizioneCliente", DbType:="NVarChar(100) NOT NULL", CanBeNull:=False)> _
  22.     Public Property DescrizioneCliente() As String
  23.         .
  24.         .
  25.     End Property
  26.  
  27.     .
  28.     .
  29.  
  30. End Class

Come possiamo osservare, la classe e le proprietà della stessa, vengono decorate con appositi attributi che mappano la classe e i suoi membri sulla tabella e sui campi della banca dati.

In particolare TableAttribute (Table nel precedente codice) associa la classe alla tabella (“dbo.Clienti” nell’esempio precedente) mentre ColumnAttribute (Column nel precedente codice) associa una proprietà ad un campo della banca dati.

Per recuperare, quindi, a runtime i parametri di mapping delle classi con la banca dati, possiamo recuperare gli attributi di cui sopra.

Per fare questo possiamo utilizzare i due seguenti metodi di estensione:

  1. Imports System.Runtime.CompilerServices
  2. Imports System.Data.Linq.Mapping
  3.  
  4. Public Module Linq2SqlModule
  5.     <Extension()> _
  6.     Public Function GetLinq2SqlTable(ByVal objectType As Type) As String
  7.         Dim retval As String = Nothing
  8.         Try
  9.             Dim attrib = CType(objectType.GetCustomAttributes(GetType(TableAttribute), _
  10.                                                               True).FirstOrDefault(),  _
  11.                                                               TableAttribute)
  12.             If attrib IsNot Nothing Then
  13.                 retval = attrib.Name
  14.             End If
  15.         Catch ex As Exception
  16.             retval = Nothing
  17.         End Try
  18.         Return retval
  19.     End Function
  20.  
  21.     <Extension()> _
  22.     Public Function GetLinq2SqlField(ByVal objectType As Type, _
  23.                                      ByVal propertyName As String) As String
  24.         Dim retval As String = Nothing
  25.         Try
  26.             Dim entityProp = (From p In objectType.GetProperties() _
  27.                              Where String.Compare(p.Name, propertyName, True) = 0 _
  28.                              Select p).FirstOrDefault()
  29.             If entityProp IsNot Nothing Then
  30.                 Dim attrib = CType(entityProp.GetCustomAttributes(GetType(ColumnAttribute), _
  31.                                                                   True).FirstOrDefault(),  _
  32.                                                                   ColumnAttribute)
  33.                 If attrib IsNot Nothing Then
  34.                     retval = attrib.Storage.Replace("_", "")
  35.                 End If
  36.             End If
  37.         Catch ex As Exception
  38.             retval = Nothing
  39.         End Try
  40.         Return retval
  41.     End Function
  42. End Module

 

venerdì 26 marzo 2010

DotNetCampania 4U

Vorrei fare un plauso ai ragazzi di DotNetCampania per l’evento che si è tenuto oggi a Salerno.

Ben organizzato, sessioni interessanti e buona affluenza!

Bravi e complimenti!!

 

mercoledì 24 marzo 2010

Appunti di WPF – Quattordicesima Puntata – Comandi

WPF mette a disposizione una infrastruttura per la gestione dei comandi (cioè delle funzionalità che stanno dietro i controlli di una finestra applicativa) decisamente più evoluta rispetto a quella presente nelle Windows Forms in cui tale gestione è demandata ad un utilizzo oculato dei gestori di eventi.

In una applicazione ben progettata, il task applicativo che sta dietro ad un comando, non dovrebbe essere direttamente eseguito all’interno di un gestore di evento ma  in maniera disgiunta da questo.

Il comando applicativo, quindi, dovrebbe essere astratto rispetto al gestore di evento che lo gestisce in modo che sia molto facile fornire agli utenti nuovi controlli che eseguono lo stesso task.

Il modello dei comandi di WPF è composto dai seguenti pilastri:

· Commands : un comando rappresenta un task applicativo e contiene le informazioni necessarie per conoscere quando tale comando può essere eseguito o meno. Un comando non contiene il task vero e proprio (che, di solito, è contenuto in una apposita classe);

· Command Bindings : il command binding lega il comando all’effettiva logica applicativa. Grazie al command binding un comando può essere utilizzato in differenti punti della nostra applicazione;

· Sources : sono i controlli che generano il comando (button, menu, etc., etc.);

· Targets : sono gli elementi per cui il comando viene eseguito. Ad esempio l’apertura della lista delle stampanti in un comando Print.

L’interfaccia ICommand (contenuta nel namespace System.Windows.Command) definisce il comportamento di un comando. Questa interfaccia definisce i seguenti metodi ed eventi:

  1. Public Interface ICommand
  2.     ' Events
  3.     Custom Event CanExecuteChanged As EventHandler
  4.  
  5.     ' Methods
  6.     Function CanExecute(ByVal parameter As Object) As Boolean
  7.     Sub Execute(ByVal parameter As Object)
  8. End Interface

Il metodo Execute() contiene il task da eseguire mentre il metodo CanExecute() viene richiamato dal framework quando lo stesso framework ha la necessità di conoscere se il comando può essere eseguito o meno. Infine, l’evento CanExecuteChanged() viene invocato quando lo stato del comando cambia.

Possiamo definire un nostro comando implementando l’interfaccia ICommand ma possiamo utilizzare la classe RoutedCommand che ci mette a disposizione una serie di metodi accessori (come, ad esempio, la gestione del bubbling del comando che permette al comando di navigare la gerarchia dei controlli WPF fino a trovare l’opportuno gestore) che semplificano la realizzazione del comando.

Altra classe fondamentale per la gestione dei comandi è la RoutedUICommand che deriva dalla RoutedCommand ma che fornisce la possibilità di definire un testo del comando (con eventuale localizzazione del testo).

WPF_14_Comandi_Fig1

Il framework WPF ci mette a disposizione una serie di comandi predefiniti (che troviamo nella maggior parte delle applicazioni Windows) e che possono essere utilizzati senza dover usare direttamente la classe RoutedUICommand. Per accedere a questi comandi possiamo utilizzare le classi ApplicationCommands (per i normali comandi quali Copy, Paste, Open, New, etc., etc.), NavigationCommands (per i comandi di navigazione), EditingCommand (per i comandi di edit dei documenti), ComponentCommands e MediaCommands.

Vediamo ora, come eseguire un comando.

Per prima cosa abbiamo bisogno è una sorgente, cioè un oggetto che implementa l’interfaccia ICommandSource.

L’interfaccia ICommandSource prevede i seguenti membri:

· Command : oggetto ICommand che l’ICommandSource deve eseguire;

· CommandParameter : permette di inviare un qualsiasi oggetto al comando;

· CommandTarget : oggetto da cui il comando è effettivamente eseguito.

Il terzo pilastro per la gestione dei comandi in WPF è il CommandBinding. Il command binding permette di legare il comando al controllo o ai controlli che lo eseguono.

Cominciamo a vedere un esempio di interfaccia XAML con l’utilizzo di un comando:

  1. <Window x:Class="MainWindow"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="MainWindow" Height="350" Width="525">
  5.     <Window.CommandBindings>
  6.         <CommandBinding Command="Print"
  7.             Executed="PrintCommand_Executed"
  8.             CanExecute="PrintCommand_CanExecute"></CommandBinding>
  9.     </Window.CommandBindings>
  10.     <Grid>
  11.         <Grid.RowDefinitions>
  12.             <RowDefinition Height="20" />
  13.             <RowDefinition Height="*" />
  14.             <RowDefinition Height="Auto" />
  15.         </Grid.RowDefinitions>
  16.         <Menu Grid.Row="0">
  17.             <MenuItem Command="Print" VerticalAlignment="Center"></MenuItem >
  18.         </Menu>
  19.         <StackPanel Grid.Row="2">
  20.             <Button Command="Print"
  21.                 Content="{Binding Path=Command.Name, RelativeSource={RelativeSource Self}}"></Button>
  22.         </StackPanel>
  23.     </Grid>
  24. </Window>

Se eseguiamo l’applicazione, osserviamo che i due controlli sono disabilitati:

WPF_14_Comandi_Fig2Questo perché il framework, quando deve capire qual è lo stato del comando esegue il metodo PrintCommand_CanExecuted che, in questo caso, restituisce il valore di default (che è quello dello stato non abilitato).

Per attivare il comando ci basta scrivere il seguente codice:

  1. Private Sub PrintCommand_CanExecute(ByVal sender As System.Object,
  2.                                     ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)
  3.     e.CanExecute = True
  4. End Sub
  5.  
  6. Private Sub PrintCommand_Executed(ByVal sender As System.Object,
  7.                                   ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)
  8.     MessageBox.Show("Print")
  9. End Sub

Il primo dei due gestori di evento comunica al framework che il comando è sempre attivo (e.CanExecute=true) mentre il secondo gestore esegue il comando.

Il risultato è il seguente:

WPF_14_Comandi_Fig3 In un’applicazione reale, lo stato del comando dipenderà dallo stato dell’applicazione.

I vantaggi sono notevoli: non dobbiamo implementare il codice che aggiorna lo stato dei controlli in base allo stato del comando, aggiungere nuovi controlli che eseguono lo stesso comando è una banalità e, infine, il task applicativo non è inserito nel gestore dell’evento dei controlli disaccoppiando il codice dall’interfaccia.

Inoltre, come possiamo osservare dal precedente XAML, anche il testo che appare nei controlli è standardizzato e un’eventuale localizzazione coinvolgerebbe tutti i controlli dello stesso comando in un colpo solo.

Il binding dei comandi si può eseguire anche da codice come mostrato di seguito:

  1. Dim binding = New CommandBinding(ApplicationCommands.Close)
  2. With binding
  3.     AddHandler .CanExecute, AddressOf Close_CanExecute
  4.     AddHandler .Executed, AddressOf Close_Executed
  5. End With

E’, possibile, inoltre eseguire un comando direttamente da codice utilizzando l’istruzione:

  1. ApplicationCommands.Print.Execute(Nothing, targetElement)

Esistono , infine, alcuni controlli che hanno già dei specifici comandi predefiniti. Un esempio di questo è il TextBox. Quando inseriamo il controllo TextBox in una pagina, abbiamo la possibilità di inserire dei comandi tipo Edit, Paste e Undo la cui attivazione è gestita direttamente dal framework in base al fatto che un utente selezioni del testo, abbia del testo nella clipboard o annulli l’ultima operazione. Ad esempio:

  1. <Window x:Class="Toolbar"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="Toolbar" Height="300" Width="300">
  5.     <Grid>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="Auto"></RowDefinition>
  8.             <RowDefinition Height="*"></RowDefinition>
  9.         </Grid.RowDefinitions>
  10.         <ToolBar>
  11.             <Button Command="Copy">Copy</Button>
  12.             <Button Command="Paste">Paste</Button>
  13.             <Button Command="Undo">Undo</Button>
  14.         </ToolBar>
  15.         <StackPanel Grid.Row="1" Margin="10">
  16.             <TextBox>
  17.                 <TextBox.Background>
  18.                     <RadialGradientBrush>
  19.                         <GradientStop Color="cyan" Offset="1"></GradientStop>
  20.                         <GradientStop Color="white" Offset="0"></GradientStop>
  21.                     </RadialGradientBrush>
  22.                 </TextBox.Background>
  23.             </TextBox>
  24.         </StackPanel>
  25.     </Grid>
  26. </Window>

WPF_14_Comandi_Fig4

Per finire questo tutorial vediamo come creare rapidamente un comando custom.

Supponiamo di voler implementare il comando di Export. Definiamo la seguente classe:

  1. Public Class ExportCommand
  2.  
  3.     Private Shared _Export As RoutedUICommand
  4.  
  5.     Shared Sub New()
  6.         Dim inputs As New InputGestureCollection()
  7.         inputs.Add(New KeyGesture(Key.E, ModifierKeys.Control, "Ctrl+E"))
  8.         _Export = New RoutedUICommand("Export", "Export", GetType(ExportCommand), inputs)
  9.     End Sub
  10.  
  11.     Public Shared ReadOnly Property Export As RoutedUICommand
  12.         Get
  13.             Return _Export
  14.         End Get
  15.     End Property
  16.  
  17. End Class

Per utilizzare questo comando è necessario importare il namespace della nostra applicazione e impostare l’apposito binding come mostrato nel seguente XAML:

  1. <Window x:Class="Export"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     xmlns:l="clr-namespace:WpfApplication"
  5.     Title="Export" Height="300" Width="300">
  6.     <Window.CommandBindings>
  7.         <CommandBinding Command="l:ExportCommand.Export"
  8.                         Executed="CommandBinding_Executed"
  9.                         CanExecute="CommandBinding_CanExecute"></CommandBinding>
  10.     </Window.CommandBindings>
  11.     <Grid>
  12.         <Button Command="l:ExportCommand.Export">Export</Button>
  13.     </Grid>
  14. </Window>


Scarica la versione PDF dell'articolo. Scarica la versione Amazon Kindle dell'articolo.

lunedì 22 marzo 2010

Appunti di WPF – Tredicesima Puntata – Le trasformazioni geometriche

WPF mette a disposizione delle classi che permettono di modificare le figure geometriche applicando loro delle trasformazioni geometriche.

Una trasformazione geometrica è una funzione che trasforma un punto del piano, appartenente ad una figura, in un altro punto del piano.

Il framework ci mette a disposizione un certo numero di classi tutte derivate dalla classe Transform presente nel namespace System.Windows.Media:

WPF_13_Trasformazioni_Fig1

La classe Transform implementa l’interfaccia Freezeable (perché lo fa una delle sua classi padre) che prevede un meccanismo di notifica dei cambiamenti di stato che permette di aggiornare in tempo reale le figure geometriche a cui è agganciata.

In particolare, le classi di trasformazione hanno lo stesso significato:

· TranslateTransform : implementa la traslazione delle immagini cioè una trasformazione che, in sostanza, sposta le coordinate dell’origine del riferimento cartesiano in cui è disegnata la figura geometrica;

· RotateTransform : implementa la rotazione della figura geometrica;

· SkewTransform : implementa la deformazione della figura geometrica;

· ScaleTransform : implementa lo zoom della figura geometrica;

· MatrixTransform : permette di definire una trasformazione complessa.

· TransformGroup : permette di raggruppare più trasformazioni assieme.

Alla base di tutti i tipi di trasformazioni c’è la MatrixTransform ma WPF ci mette a disposizione delle classi “scorciatoia” per semplificarci la vita.

Per poter applicare una trasformazione ad un elemento che deriva da UIElement possiamo agire sulle proprietà RenderTransform o LayoutTransform.

Quando impostiamo la RenderTransform, questa viene applicata dopo che il layout è stato composto, quindi le eventuali “deformazioni” dell’elemento a cui è applicata non influenzano il layout complessivo della finestra.

Se impostiamo, invece, la LayoutTransform, questa viene applicata prima di comporre il Layout il che comporta che tale layout è influenzato dalla trasformazione.

La seguente interfaccia  ha due StackPanel con due Button il primo dei quali è sottoposto ai due tipi di trasformazione:

WPF_13_Trasformazioni_Fig2

Per capire come funzionano i diversi tipi di trasformazione, vediamo alcuni esempi pratici con dello XAML.

TranslateTransform

  1. <Window x:Class="TranslateTransform"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="TranslateTransform" Height="480" Width="640">
  5.     <Grid>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="Auto" />
  8.             <RowDefinition Height="*" />
  9.         </Grid.RowDefinitions>
  10.         <StackPanel>
  11.             <Slider Name="sliderX" Minimum="0" Maximum="{Binding ElementName=Canvas, Path=ActualWidth}" Value="0" Margin="2"></Slider>
  12.             <Slider Name="sliderY" Minimum="0" Maximum="{Binding ElementName=Canvas, Path=ActualHeight}" Value="0" Margin="2"></Slider>
  13.         </StackPanel>
  14.         <Canvas Grid.Row="1" Name="Canvas">
  15.             <Polygon Stroke="black"
  16.                  Points="50,50  100,0 200,100 100,200 0,100 50,50 150,50 150,150 50,150"
  17.                  FillRule="EvenOdd" HorizontalAlignment="Center" >
  18.                 <Polygon.Fill>
  19.                     <RadialGradientBrush>
  20.                         <GradientStop Color="cyan" Offset="0"></GradientStop>
  21.                         <GradientStop Color="blue" Offset="1"></GradientStop>
  22.                     </RadialGradientBrush>
  23.                 </Polygon.Fill>
  24.                 <Polygon.RenderTransform>
  25.                     <TranslateTransform X="{Binding ElementName=sliderX, Path=Value}" Y="{Binding ElementName=sliderY, Path=Value}"/>
  26.                 </Polygon.RenderTransform>
  27.             </Polygon>
  28.         </Canvas>
  29.     </Grid>
  30. </Window>

WPF_13_Trasformazioni_Fig3 

RotateTransform

  1. <Window x:Class="RotateTransform"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="RotateTransform" Height="500" Width="500">
  5.     <Grid>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="Auto" />
  8.             <RowDefinition Height="*" />
  9.         </Grid.RowDefinitions>
  10.         <StackPanel>
  11.             <Slider Name="sliderAngle" Minimum="0" Maximum="360" Value="0" Margin="2"></Slider>
  12.         </StackPanel>
  13.         <Canvas Grid.Row="1" Name="Canvas">
  14.             <Polygon Stroke="black" Canvas.Top="20" Canvas.Left="43"
  15.                  Points="100,100  200,0 400,200 200,400 0,200 100,100 300,100 300,300 100,300"
  16.                  FillRule="EvenOdd" HorizontalAlignment="Center" >
  17.                 <Polygon.Fill>
  18.                     <RadialGradientBrush>
  19.                         <GradientStop Color="cyan" Offset="0"></GradientStop>
  20.                         <GradientStop Color="blue" Offset="1"></GradientStop>
  21.                     </RadialGradientBrush>
  22.                 </Polygon.Fill>
  23.                 <Polygon.RenderTransform>
  24.                     <RotateTransform Angle="{Binding ElementName=sliderAngle, Path=Value}"
  25.                                      CenterX="199.5"
  26.                                      CenterY="199.5"/>
  27.                 </Polygon.RenderTransform>
  28.             </Polygon>
  29.         </Canvas>
  30.     </Grid>
  31. </Window>

WPF_13_Trasformazioni_Fig4

SkewTransform

  1. <Window x:Class="SkewTransform"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="SkewTransform" Height="500" Width="500">
  5.     <Grid>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="Auto" />
  8.             <RowDefinition Height="*" />
  9.         </Grid.RowDefinitions>
  10.         <StackPanel>
  11.             <Slider Name="sliderAngleX" Minimum="0" Maximum="360" Value="0" Margin="2"></Slider>
  12.             <Slider Name="sliderAngleY" Minimum="0" Maximum="360" Value="0" Margin="2"></Slider>
  13.         </StackPanel>
  14.         <Canvas Grid.Row="1" Name="Canvas">
  15.             <Polygon Stroke="black" Canvas.Top="20" Canvas.Left="43"
  16.                  Points="100,100  200,0 400,200 200,400 0,200 100,100 300,100 300,300 100,300"
  17.                  FillRule="EvenOdd" HorizontalAlignment="Center" >
  18.                 <Polygon.Fill>
  19.                     <RadialGradientBrush>
  20.                         <GradientStop Color="cyan" Offset="0"></GradientStop>
  21.                         <GradientStop Color="blue" Offset="1"></GradientStop>
  22.                     </RadialGradientBrush>
  23.                 </Polygon.Fill>
  24.                 <Polygon.RenderTransform>
  25.                     <SkewTransform AngleX="{Binding ElementName=sliderAngleX, Path=Value}"
  26.                                    AngleY="{Binding ElementName=sliderAngleY, Path=Value}"
  27.                                    CenterX="199.5"
  28.                                    CenterY="199.5" />
  29.                 </Polygon.RenderTransform>
  30.             </Polygon>
  31.         </Canvas>
  32.     </Grid>
  33. </Window>

WPF_13_Trasformazioni_Fig5

ScaleTransform

  1. <Window x:Class="ScaleTransform"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="ScaleTransform" Height="500" Width="500">
  5.     <Grid>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="Auto" />
  8.             <RowDefinition Height="*" />
  9.         </Grid.RowDefinitions>
  10.         <StackPanel>
  11.             <Slider Name="sliderScaleX" Minimum="0" Maximum="2" Value="1" Margin="2"></Slider>
  12.             <Slider Name="sliderScaleY" Minimum="0" Maximum="2" Value="1" Margin="2"></Slider>
  13.         </StackPanel>
  14.         <Canvas Grid.Row="1" Name="Canvas">
  15.             <Polygon Stroke="black" Canvas.Top="20" Canvas.Left="43"
  16.                  Points="100,100  200,0 400,200 200,400 0,200 100,100 300,100 300,300 100,300"
  17.                  FillRule="EvenOdd" HorizontalAlignment="Center">
  18.                 <Polygon.Fill>
  19.                     <RadialGradientBrush>
  20.                         <GradientStop Color="cyan" Offset="0"></GradientStop>
  21.                         <GradientStop Color="blue" Offset="1"></GradientStop>
  22.                     </RadialGradientBrush>
  23.                 </Polygon.Fill>
  24.                 <Polygon.RenderTransform>
  25.                     <ScaleTransform ScaleX="{Binding ElementName=sliderScaleX, Path=Value}"
  26.                                     ScaleY="{Binding ElementName=sliderScaleY, Path=Value}"
  27.                                     CenterX="199.5"
  28.                                     CenterY="199.5"/>
  29.                 </Polygon.RenderTransform>
  30.             </Polygon>
  31.         </Canvas>
  32.     </Grid>
  33. </Window>

WPF_13_Trasformazioni_Fig6

MatrixTransform

La matrice di trasformazione è composta da tre righe e tre colonne:

WPF_13_Trasformazioni_Fig7

La matrice unità, cioè con M11=M22=1 e M21=M12=OffsetX=OffsetY=0 indica una trasformazione nulla, ovvero una trasformazione che non modifica l’aspetto dell’elemento.

I componenti della matrice hanno il seguente significato:

· OffsetX e OffsetY consentono di definire una translazione, rispettivamente per l’asse X e Y;

· M11 e M22 definiscono una trasformazione di scala con il valore M11 per le x e M22 per le y;

· M12 e M21 definiscono una trasformazione di skew con il valore M21 per le x e M12 per le y.

Ad esempio la seguente trasformazione esegue uno skew rispetto all’asse x e uno scale rispetto all’asse y:

  1. <MatrixTransform>
  2.     <MatrixTransform.Matrix>
  3.         <Matrix M11="1" M12="0"
  4.                 M21="0.5" M22="1.5"
  5.                 OffsetX="0" OffsetY="0" />
  6.     </MatrixTransform.Matrix>
  7. </MatrixTransform>

WPF_13_Trasformazioni_Fig8


Scarica la versione PDF dell'articolo. Scarica la versione Amazon Kindle dell'articolo.