Panoramica delle trasformazioni

Scopri come usare le trasformazioni nell'API di Windows Runtime modificando i sistemi di coordinate relative di elementi nell'interfaccia utente. Può essere usato per regolare l'aspetto di singoli elementi XAML, ad esempio ridimensionamento, rotazione o trasformazione della posizione nello spazio x-y.

Che cos'è una trasformazione?

Un oggetto transform definisce come eseguire il mapping dei punti, ovvero trasformare i punti, da uno spazio di coordinate a un altro spazio di coordinate. Quando una trasformazione viene applicata a un elemento dell'interfaccia utente, modifica il rendering dell'elemento dell'interfaccia utente sullo schermo come parte dell'interfaccia utente.

Si pensi alle trasformazioni in quattro ampie classificazioni: traslazione, rotazione, ridimensionamento e asimmetria (o taglio). Ai fini dell'uso delle API grafiche per modificare l'aspetto degli elementi dell'interfaccia utente, in genere è più semplice creare trasformazioni che definiscono una sola operazione alla volta. Windows Runtime definisce quindi una classe discreta per ognuna di queste classificazioni di trasformazione:

Di questi, è probabile che si usi TranslateTransform e ScaleTransform più spesso per gli scenari dell'interfaccia utente.

Le trasformazioni possono essere combinate e, a tale scopo, in Windows Runtime sono disponibili due classi: CompositeTransform e TransformGroup. In compositeTransform le trasformazioni vengono applicate in questo ordine: scala, asimmetria, rotazione, traslazione. Usare TransformGroup anziché CompositeTransform se si desidera applicare le trasformazioni in un ordine diverso. Per altre info, vedi CompositeTransform.

Trasformazioni e layout

Nel layout XAML le trasformazioni vengono applicate dopo il completamento del passaggio di layout, quindi sono stati presi calcoli dello spazio disponibile e altre decisioni relative al layout prima dell'applicazione delle trasformazioni. Poiché il layout arriva per primo, a volte si ottengono risultati imprevisti se si trasformano elementi in una cella Grid o in un contenitore di layout simile che alloca spazio durante il layout. L'elemento trasformato può apparire troncato o nascosto perché sta tentando di disegnare in un'area che non ha calcolato le dimensioni post-trasformazione durante la divisione dello spazio all'interno del contenitore padre. Potrebbe essere necessario sperimentare i risultati della trasformazione e regolare alcune impostazioni. Ad esempio, invece di basarsi sul layout adattivo e sul ridimensionamento delle stelle, potrebbe essere necessario modificare le proprietà center o dichiarare misurazioni pixel fisse per lo spazio di layout per assicurarsi che lo spazio padre allochi spazio sufficiente.

Nota di migrazione: In Windows Presentation Foundation (WPF) era presente una proprietà LayoutTransform per l'applicazione delle trasformazioni prima del calcolo del layout. Tuttavia, XAML di Windows Runtime non supporta una proprietà LayoutTransform . (Microsoft Silverlight non disponeva di questa proprietà.)

In alternativa, nel toolkit della Community Windows è disponibile la proprietà LayoutTransformControl che applica le trasformazioni di matrice a qualsiasi elemento FrameworkElement dell'applicazione.

Applicazione di una trasformazione a un elemento dell'interfaccia utente

Quando si applica una trasformazione a un oggetto, in genere si imposta la proprietà UIElement.RenderTransform. L'impostazione di questa proprietà non modifica letteralmente il pixel dell'oggetto in base al pixel. La proprietà applica realmente la trasformazione all'interno dello spazio di coordinate locale in cui tale oggetto esiste. La logica di rendering e l'operazione (post-layout) eseguono quindi il rendering degli spazi di coordinate combinati, rendendo l'aspetto dell'oggetto modificato e potenzialmente anche la relativa posizione di layout (se è stato applicato TranslateTransform).

Per impostazione predefinita, ogni trasformazione è allineata al centro in corrispondenza dell'origine del sistema di coordinate locali dell'oggetto di destinazione: è (0,0). L'unica eccezione è un translateTransform, che non ha proprietà di centro da impostare perché l'effetto di traduzione è lo stesso indipendentemente dalla posizione in cui è centrato. Le altre trasformazioni hanno tuttavia proprietà che impostano i valori CenterX e CenterY .

Ogni volta che usi le trasformazioni con UIElement.RenderTransform, ricorda che esiste un'altra proprietà in UIElement che influisce sul comportamento della trasformazione: RenderTransformOrigin. Ciò che RenderTransformOrigin dichiara è se l'intera trasformazione deve essere applicata al punto predefinito (0,0) di un elemento o a un altro punto di origine all'interno dello spazio di coordinate relativo di tale elemento. Per gli elementi tipici, (0,0) posiziona la trasformazione nell'angolo superiore sinistro. A seconda dell'effetto desiderato, è possibile scegliere di modificare RenderTransformOrigin invece di modificare i valori CenterX e CenterY nelle trasformazioni. Si noti che se si applicano entrambi i valori RenderTransformOrigin e CenterX / CenterY, i risultati possono risultare piuttosto confusi, soprattutto se si anima uno dei valori.

A scopo di hit testing, un oggetto a cui viene applicata una trasformazione continua a rispondere all'input in modo previsto coerente con l'aspetto visivo nello spazio x-y. Ad esempio, se hai usato TranslateTransform per spostare un rettangolo 400 pixel in un secondo momento nell'interfaccia utente, il rettangolo risponde agli eventi PointerPressed quando l'utente preme il punto in cui viene visualizzato visivamente il rettangolo. Non si otterranno eventi false se l'utente preme l'area in cui si trovava Il rettangolo prima di essere tradotto. Per eventuali considerazioni sugli indici z che influiscono sui hit testing, l'applicazione di una trasformazione non fa alcuna differenza; L'indice z che regola l'elemento che gestisce gli eventi di input per un punto nello spazio x-y viene comunque valutato usando l'ordine figlio dichiarato in un contenitore. Questo ordine è in genere uguale all'ordine in cui dichiari gli elementi in XAML, anche se per gli elementi figlio di un oggetto Canvas puoi modificare l'ordine applicando la proprietà associata Canvas.ZIndex agli elementi figlio.

Altre proprietà delle trasformazioni

  • Brush.Transform, Brush.RelativeTransform: influenzano il modo in cui un oggetto Brush usa lo spazio di coordinate nell'area in cui viene applicato un oggetto Brush per impostare proprietà di visualizzazione come primi piani e sfondi. Queste trasformazioni non sono rilevanti per i pennelli più comuni (che in genere impostano colori a tinta unita con SolidColorBrush), ma possono essere occasionalmente utili quando si disegnano aree con ImageBrush o LinearGradientBrush.
  • Geometry.Transform: puoi usare questa proprietà per applicare una trasformazione a una geometria prima dell'uso della geometria per un valore della proprietà Path.Data.

Animazione di una trasformazione

Gli oggetti Transform possono essere animati. Per aggiungere un'animazione a Transform, applicare un'animazione di un tipo compatibile alla proprietà cui si desidera aggiungere un'animazione. Questo significa in genere che usi oggetti DoubleAnimation o DoubleAnimationUsingKeyFrames per definire l'animazione, perché tutte le proprietà della trasformazione sono di tipo Double. Le animazioni che influiscono su una trasformazione usata per un valore UIElement.RenderTransform non vengono considerate animazioni dipendenti, anche se hanno una durata diversa da zero. Per altre info sulle animazioni dipendenti, vedi Animazioni con storyboard.

Se si animano le proprietà per produrre un effetto simile a una trasformazione in termini di aspetto visivo netto, ad esempio animando Width e Height di un FrameworkElement anziché applicando un TranslateTransform, tali animazioni vengono quasi sempre considerate come animazioni dipendenti. Dovrai abilitare le animazioni e potrebbero verificarsi problemi significativi di prestazioni con l'animazione, soprattutto se stai provando a supportare l'interazione dell'utente mentre l'oggetto è animato. Per questo motivo è preferibile usare una trasformazione e animarla anziché animare qualsiasi altra proprietà in cui l'animazione verrebbe considerata come un'animazione dipendente.

Per impostare come destinazione la trasformazione, deve essere presente un Transform esistente come valore per RenderTransform. In genere si inserisce un elemento per il tipo di trasformazione appropriato nel codice XAML iniziale, a volte senza proprietà impostate su tale trasformazione.

In genere si usa una tecnica di destinazione indiretta per applicare animazioni alle proprietà di una trasformazione. Per altre info sulla sintassi di destinazione indiretta, vedi Animazioni con storyboard e sintassi property-path.

Gli stili predefiniti per i controlli talvolta definiscono le animazioni delle trasformazioni come parte del comportamento dello stato di visualizzazione. Ad esempio, gli stati di visualizzazione per ProgressRing usano valori RotateTransform animati per "ruotare" i punti nell'anello.

Ecco un semplice esempio di come animare una trasformazione. In questo caso, anima l'angolo di un oggetto RotateTransform per ruotare un rettangolo attorno al centro visivo. In questo esempio viene assegnato il nome RotateTransform in modo che non sia necessaria la destinazione dell'animazione indiretta, ma in alternativa è possibile lasciare senza nome la trasformazione, denominare l'elemento a cui viene applicata la trasformazione e usare la destinazione indiretta, (UIElement.RenderTransform).(RotateTransform.Angle)ad esempio .

<StackPanel Margin="15">
  <StackPanel.Resources>
    <Storyboard x:Name="myStoryboard">
      <DoubleAnimation
       Storyboard.TargetName="myTransform"
       Storyboard.TargetProperty="Angle"
       From="0" To="360" Duration="0:0:5" 
       RepeatBehavior="Forever" />
    </Storyboard>
  </StackPanel.Resources>
  <Rectangle Width="50" Height="50" Fill="RoyalBlue"
   PointerPressed="StartAnimation">
    <Rectangle.RenderTransform>
      <RotateTransform x:Name="myTransform" Angle="45" CenterX="25" CenterY="25" />
    </Rectangle.RenderTransform>
  </Rectangle>
</StackPanel>
void StartAnimation (object sender, RoutedEventArgs e) {
    myStoryboard.Begin();
}

Uso di frame di coordinate di riferimento in fase di esecuzione

La classe UIElement dispone di un metodo denominato TransformToVisual che può generare una classe Transform per la correlazione tra i frame di coordinate di riferimento per due elementi dell'interfaccia utente. Puoi usarlo per confrontare un elemento con il frame di coordinate predefinito dell'app di riferimento se passi l'oggetto visivo radice come primo parametro. Ciò può essere utile se è stato acquisito un evento di input da un elemento diverso o se si sta tentando di stimare il comportamento del layout senza richiedere effettivamente un passaggio di layout.

I dati dell'evento ottenuti dagli eventi puntatore forniscono l'accesso a un metodo GetCurrentPoint , in cui è possibile specificare un parametro relativeTo per modificare il frame di coordinate del riferimento a un elemento specifico anziché all'impostazione predefinita dell'app. Questo approccio applica semplicemente una trasformazione di traslazione internamente e trasforma i dati delle coordinate x-y quando crea l'oggetto PointerPoint restituito.

Descrizione matematica di una trasformazione

Una trasformazione può essere descritta in termini di matrice di trasformazione. Una matrice 3×3 viene usata per descrivere le trasformazioni in un piano x-y bidimensionale. Le matrici di trasformazione affine possono essere moltiplicate per formare un numero qualsiasi di trasformazioni lineari, ad esempio rotazione e asimmetria (shear), seguite dalla traduzione. La colonna finale di una matrice di trasformazione affine è uguale a (0, 0, 1), quindi è necessario specificare solo i membri delle prime due colonne nella descrizione matematica.

La descrizione matematica di una trasformazione può essere utile se si ha un background matematico o una familiarità con le tecniche di programmazione grafica che usano anche matrici per descrivere le trasformazioni dello spazio delle coordinate. Esiste una classe derivata da Transform che permette di esprimere una trasformazione direttamente con la relativa matrice 3x3, ovvero: MatrixTransform. MatrixTransform ha una proprietà Matrix, che contiene una struttura con sei proprietà: M11, M12, M21, M22, OffsetX and OffsetY. Ogni proprietà Matrix usa un valore Double e corrisponde ai sei valori pertinenti (colonne 1 e 2) di una matrice di trasformazione affine.

Colonna 1 Colonna 2 Colonna 3
M11 M12 0
M21 M22 0
OffsetX OffsetY 1

Qualsiasi trasformazione che è possibile descrivere con un oggetto TranslateTransform, ScaleTransform, RotateTransform o SkewTransform può essere descritto equamente da un oggetto MatrixTransform con un valore Matrix. Ma in genere si usa TranslateTransform e gli altri perché le proprietà di tali classi di trasformazione sono più facili da concettualizzare rispetto all'impostazione dei componenti vettoriali in una matrice. È anche più facile animare le proprietà discrete delle trasformazioni; Una matrice è in realtà una struttura e non un DependencyObject, quindi non può supportare singoli valori animati.

Alcuni strumenti di progettazione XAML che consentono di applicare operazioni di trasformazione serializzeranno i risultati come MatrixTransform. In questo caso potrebbe essere preferibile usare di nuovo lo stesso strumento di progettazione per modificare l'effetto di trasformazione e serializzare di nuovo il codice XAML, invece di tentare di modificare i valori matrix direttamente nel codice XAML.

Trasformazioni 3D

In Windows 10 XAML ha introdotto una nuova proprietà, UIElement.Transform3D, che può essere usata per creare effetti 3D con l'interfaccia utente. A tale scopo, usare PerspectiveTransform3D per aggiungere una prospettiva 3D condivisa o una "fotocamera" alla scena e quindi usare CompositeTransform3D per trasformare un elemento nello spazio 3D, come si usa CompositeTransform. Per informazioni su come implementare trasformazioni 3D, vedere UIElement.Transform3D.

Per effetti 3D più semplici che si applicano solo a un singolo oggetto, è possibile usare la proprietà UIElement.Projection. L'uso di PlaneProjection come valore per questa proprietà equivale all'applicazione di una trasformazione prospettica fissa e di una o più trasformazioni 3D all'elemento. Questo tipo di trasformazione viene descritto in modo più dettagliato negli effetti di prospettiva 3D per l'interfaccia utente XAML.