Creare una semplice app Win2D
Questa esercitazione presenta alcune delle funzionalità di disegno di base di Win2D. Si apprenderà come:
- Aggiungere Win2D a un progetto Windows XAML C#.
- Disegnare testo e geometria.
- Applicare effetti di filtro.
- Animare il contenuto Win2D.
- Seguire le procedure consigliate di Win2D.
Configurare il computer di sviluppo
Assicurarsi di configurare il computer con tutti gli strumenti necessari:
- Installa Visual Studio
- Includere la piattaforma UWP o Windows SDK (a seconda delle esigenze), 17763+
- Se si usa UWP, assicurarsi di abilitare anche la modalità sviluppatore
Creare un nuovo progetto Win2D
Seguire i passaggi della guida introduttiva "Hello, World!" win2D per creare un nuovo progetto con Win2D e aggiungere un riferimento al pacchetto NuGet Win2D. Puoi usare WinUI 3 (SDK per app di Windows) o la piattaforma universale di Windows (UWP).
Aggiungere un oggetto CanvasControl Win2D al codice XAML dell'app
- Per usare Win2D, è necessario un punto per disegnare la grafica. In un'app XAML, il modo più semplice per eseguire questa operazione consiste nell'aggiungere un CanvasControl alla pagina XAML.
Prima di continuare, assicurarsi che l'opzione Architettura del progetto sia impostata su x86
o x64
e non su Any CPU
. Win2D viene implementato in C++, quindi i progetti che usano Win2D devono essere destinati a un'architettura di CPU specifica.
Passare a
MainPage.xaml
nel progetto facendo doppio clic su di esso in Esplora soluzioni. Verrà aperto il file. Per praticità, puoi fare doppio clic sul pulsante XAML nella scheda Progettazione; in questo modo verrà nascosta la finestra di progettazione visiva e verrà riservato tutto lo spazio per la visualizzazione codice.Prima di aggiungere il controllo, devi prima indicare a XAML dove CanvasControl è definito. A tale scopo, passare alla definizione dell'elemento Page e aggiungere questa direttiva:
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
. Il codice XAML dovrebbe ora essere simile al seguente:
<Page
...
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
mc:Ignorable="d">
- Aggiungere ora un nuovo
canvas:CanvasControl
elemento come elemento figlio all'elemento Grid radice. Assegnare un nome al controllo, ad esempio "canvas". Il codice XAML dovrebbe ora essere simile al seguente:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<canvas:CanvasControl x:Name="canvas"/>
</Grid>
- Definire quindi un gestore eventi per l'evento Draw. CanvasControl genera
Draw
ogni volta che l'app deve disegnare o ridisegnare il contenuto. Il modo più semplice consiste nell'aiutare il completamento automatico di Visual Studio. Nella definizione CanvasControl iniziare a digitare un nuovo attributo per ilDraw
gestore eventi:
<canvas:CanvasControl x:Name="canvas" Draw="canvas_Draw" />
Nota
Dopo aver immesso in Draw="
, Visual Studio dovrebbe visualizzare una finestra in cui viene richiesto di inserire automaticamente la definizione corretta per il gestore eventi. Premere TAB per accettare il gestore eventi predefinito di Visual Studio. Verrà aggiunto automaticamente anche un metodo del gestore eventi formattato correttamente nel code-behind (`MainPage.xaml.cs``). Non preoccuparti se non hai usato il completamento automatico; è possibile aggiungere manualmente il metodo del gestore eventi nel passaggio successivo.
Disegnare il primo testo in Win2D
A questo punto, passare al code-behind C#. Aprire
MainPage.xaml.cs
da Esplora soluzioni.Nella parte superiore del file C# sono presenti varie definizioni di spazio dei nomi. Aggiungere gli spazi dei nomi seguenti:
using Windows.UI;
using System.Numerics;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
- Verrà quindi visualizzato il gestore eventi vuoto seguente che è stato inserito da AutoComplete:
private void canvas_Draw(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender,
Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
{
}
(Se il completamento automatico non è stato usato nel passaggio precedente, aggiungere ora questo codice.)
- Il parametro CanvasDrawEventArgs espone un membro DrawingSession, che corrisponde al tipo CanvasDrawingSession. Questa classe offre la maggior parte delle funzionalità di disegno di base in Win2D: include metodi come CanvasDrawingSession.DrawRectangle, CanvasDrawingSession.DrawImagee il metodo che è necessario per disegnare il testo CanvasDrawingSession.DrawText.
Aggiungere al metodo canvas_Draw
il codice seguente:
args.DrawingSession.DrawText("Hello, World!", 100, 100, Colors.Black);
Il primo argomento, "Hello, World!"
, è la stringa che si vuole visualizzare da Win2D. I due "100" indicano a Win2D di sfalsare questo testo di 100 DIP (pixel indipendenti dal dispositivo) a destra e verso il basso. Infine, Colors.Black
definisce il colore del testo.
- Ora sei pronto per eseguire la tua prima app Win2D. Premere il tasto F5 per compilare e avviare. Dovrebbe essere visualizzata una finestra vuota con "Hello, world!" in nero.
Eliminare correttamente le risorse Win2D
- Prima di continuare a disegnare altri tipi di contenuto, devi prima aggiungere codice per assicurarti che l'app eviti perdite di memoria. La maggior parte delle applicazioni Win2D scritte in un linguaggio .NET e l'uso di un controllo Win2D come CanvasControl devono seguire la procedura seguente. In senso stretto, la semplice app "Hello, world" non è interessata, ma questa è una buona pratica da seguire in generale.
Per altre informazioni, vedere "Evitare perdite di memoria".
Aprire
MainPage.xaml
e trovare l'elemento XAML Page che contiene CanvasControl. Deve essere il primo elemento del file.Aggiungere un gestore per
Unloaded
l'evento. Il codice XAML dovrebbe essere simile al seguente:
<Page
...
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
mc:Ignorable="d"
Unloaded="Page_Unloaded">
- Passare a
MainPage.xaml.cs
e trovare ilPage_Unloaded
gestore eventi. Aggiungere il codice seguente:
void Page_Unloaded(object sender, RoutedEventArgs e)
{
this.canvas.RemoveFromVisualTree();
this.canvas = null;
}
- Se la tua app contiene più controlli Win2D, devi ripetere i passaggi precedenti per ogni pagina XAML che contiene un controllo Win2D. L'app ha attualmente solo un singolo CanvasControl quindi è tutto fatto.
Disegnare alcune forme
- È altrettanto semplice aggiungere geometria 2D all'app. Aggiungere il codice seguente alla fine di
canvas_Draw
:
args.DrawingSession.DrawCircle(125, 125, 100, Colors.Green);
args.DrawingSession.DrawLine(0, 0, 50, 200, Colors.Red);
Gli argomenti di questi due metodi sono simili a DrawText
. Un cerchio è definito da un punto centrale (125, 125), un raggio (100) e un colore (verde). Una linea è definita da un inizio (0, 0), una fine (50, 200) e un colore (rosso).
- Premere F5 per eseguire l'app. Verrà visualizzato "Hello, world!" insieme a un cerchio verde e a una linea rossa.
Ci si potrebbe chiedere come controllare opzioni di disegno più avanzate, ad esempio spessore linea e trattini, o opzioni di riempimento più complesse come l'uso di pennelli. Win2D offre tutte queste opzioni e altro ancora e semplifica l'uso quando vuoi. Tutti i Draw(...)
metodi offrono molti overload che possono accettare parametri aggiuntivi, ad esempio CanvasTextFormat ((famiglia di caratteri, dimensioni e così via) e CanvasStrokeStyle (trattini, punti, endcap e così via). È possibile esplorare l'area API per altre informazioni su queste opzioni.
Generare dinamicamente parametri di disegno
- A questo punto, aggiungiamo un po' di varietà disegnando una serie di forme e testo con colori casuali.
Aggiungere il codice seguente all'inizio della MainPage
classe. Questa è la funzionalità helper per generare valori casuali che verranno usati durante il disegno:
Random rnd = new Random();
private Vector2 RndPosition()
{
double x = rnd.NextDouble() * 500f;
double y = rnd.NextDouble() * 500f;
return new Vector2((float)x, (float)y);
}
private float RndRadius()
{
return (float)rnd.NextDouble() * 150f;
}
private byte RndByte()
{
return (byte)rnd.Next(256);
}
- Modificare il
canvas_Draw
metodo per disegnare usando questi parametri casuali:
private void canvas_Draw(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender,
Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
{
args.DrawingSession.DrawText("Hello, World!", RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
args.DrawingSession.DrawCircle(RndPosition(), RndRadius(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
args.DrawingSession.DrawLine(RndPosition(), RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
}
Di seguito viene descritto come DrawText
è cambiato. "Hello, World!"
rimane uguale a prima. I parametri di offset x e y sono stati sostituiti con un singolo oggetto System.Numerics.Vector2 che è generato da RndPosition
. Infine, invece di usare un colore predefinito, Color.FromArgb
consente di definire un colore usando i valori A, R, G e B. Uno è alfa o il livello di opacità; in questo caso si desidera sempre completamente opaco (255).
DrawCircle
e DrawLine
funzionano in modo analogo a DrawText
.
- Infine, eseguire il wrapping del codice di disegno in un
for
ciclo. Si dovrebbe finire con il codicecanvas_Draw
seguente:
for (int i = 0; i < 100; i++)
{
args.DrawingSession.DrawText("Hello, World!", RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
args.DrawingSession.DrawCircle(RndPosition(), RndRadius(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
args.DrawingSession.DrawLine(RndPosition(), RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
}
- Eseguire nuovamente l'app. Dovrebbe essere visualizzato un intero gruppo di testo, linee e cerchi con posizioni e dimensioni casuali.
Applicare un effetto immagine al contenuto
Gli effetti immagine, noti anche come effetti filtro, sono trasformazioni grafiche applicate ai dati pixel. La saturazione, la rotazione delle tonalità e la sfocatura gaussiana sono alcuni effetti di immagine comuni. Gli effetti immagine possono essere concatenati, producendo un aspetto visivo sofisticato per un lavoro minimo.
Gli effetti immagine vengono usati fornendo un'immagine di origine (il contenuto che si sta iniziando), creando un effetto come GaussianBlurEffect, impostando le proprietà come BlurAmounte quindi disegnando l'output dell'effetto con DrawImage
.
Per applicare un effetto immagine al testo e alle forme, è necessario prima eseguire il rendering del contenuto in CanvasCommandList. Questo oggetto è utilizzabile come input per l'effetto.
- Modificare il
canvas_Draw
metodo per usare il codice seguente:
CanvasCommandList cl = new CanvasCommandList(sender);
using (CanvasDrawingSession clds = cl.CreateDrawingSession())
{
for (int i = 0; i < 100; i++)
{
clds.DrawText("Hello, World!", RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
clds.DrawCircle(RndPosition(), RndRadius(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
clds.DrawLine(RndPosition(), RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
}
}
Proprio come si ottiene un CanvasDrawingSession
oggetto da CanvasDrawEventArgs
cui è possibile disegnare, è possibile creare un oggetto CanvasDrawingSession
da un oggetto CanvasCommandList
. L'unica differenza è che quando si disegna nella sessione di disegno dell'elenco comandi (clds), non si esegue direttamente il rendering in CanvasControl. L'elenco dei comandi è invece un oggetto intermedio che archivia i risultati del rendering per un uso successivo.
È possibile che sia stato notato il using
blocco che esegue il wrapping della sessione di disegno dell'elenco dei comandi. Le sessioni di disegno implementano IDisposable e devono essere eliminate al termine del rendering (il using
blocco esegue questa operazione). L'oggetto CanvasDrawingSession
ottenuto automaticamente CanvasDrawEventArgs
viene chiuso automaticamente, ma è necessario eliminare tutte le sessioni di disegno create in modo esplicito.
- Infine, definire
GaussianBlurEffect
aggiungendo il codice seguente alla fine delcanvas_Draw
metodo:
GaussianBlurEffect blur = new GaussianBlurEffect();
blur.Source = cl;
blur.BlurAmount = 10.0f;
args.DrawingSession.DrawImage(blur);
- Eseguire nuovamente l'app. Dovrebbero essere visualizzate le righe, il testo e i cerchi con un aspetto sfocato.
Animare l'app con CanvasAnimatedControl
. Win2D ti offre la possibilità di aggiornare e animare il contenuto in tempo reale, ad esempio modificando il raggio di sfocatura del blur gaussiano con ogni fotogramma. A tale scopo, si userà CanvasAnimatedControl.
CanvasControl è particolarmente adatto per il contenuto grafico statico, ma genera solo l'evento Draw
quando il contenuto deve essere aggiornato o ridisegnato. Se il contenuto è in continua evoluzione, è consigliabile invece CanvasAnimatedControl
usare. I due controlli funzionano in modo molto simile, tranne CanvasAnimatedControl
raises the Draw
che genera l'evento su base periodica. Per impostazione predefinita, viene chiamato 60 volte al secondo.
- Per passare a
CanvasAnimatedControl
, passare aMainPage.xaml
, eliminare la riga CanvasControl e sostituirla con il codice XAML seguente:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<canvas:CanvasAnimatedControl x:Name="canvas" Draw="canvas_DrawAnimated" CreateResources="canvas_CreateResources"/>
</Grid>
Proprio come con CanvasControl, consenti al completamento automatico di creare Draw
il gestore eventi. Per impostazione predefinita, Visual Studio denomina questo gestore canvas_Draw_1
perché canvas_Draw
esiste già. In questo caso è stato rinominato il metodo canvas_AnimatedDraw
per chiarire che si tratta di un evento diverso.
Inoltre, si gestisce anche un nuovo evento CreateResources. Ancora una volta, consenti al completamento automatico di creare il gestore.
Ora che l'app verrà ridisegnata a 60 fotogrammi al secondo, è più efficiente creare le risorse visive Win2D una volta e riutilizzarle con ogni fotogramma. È inefficiente creare un oggetto CanvasCommandList
e disegnare 300 elementi in esso 60 volte al secondo quando il contenuto rimane statico. CreateResources
è un evento generato solo quando Win2D determina che è necessario ricreare le risorse visive, ad esempio quando la pagina viene caricata.
- Tornare a
MainPage.xaml.cs
. Trovare ilcanvas_Draw
metodo che dovrebbe essere simile al seguente:
private void canvas_Draw(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender,
Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
{
CanvasCommandList cl = new CanvasCommandList(sender);
using (CanvasDrawingSession clds = cl.CreateDrawingSession())
{
for (int i = 0; i < 100; i++)
{
clds.DrawText("Hello, World!", RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
clds.DrawCircle(RndPosition(), RndRadius(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
clds.DrawLine(RndPosition(), RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
}
}
GaussianBlurEffect blur = new GaussianBlurEffect();
blur.Source = cl;
blur.BlurAmount = 10.0f;
args.DrawingSession.DrawImage(blur);
}
La maggior parte di questo codice di disegno esistente non deve essere eseguita con ogni fotogramma: l'elenco di comandi contenente il testo, le righe e i cerchi rimane invariato con ogni fotogramma e l'unica cosa che cambia è il raggio di sfocatura. Pertanto, è possibile spostare questo codice "statico" in CreateResources
.
A tale scopo, tagliare prima (CTRL+X) l'intero contenuto di canvas_Draw
, ad eccezione dell'ultima riga (args.DrawingSession.DrawImage(blur);
). È ora possibile eliminare il resto di canvas_Draw
perché non è più necessario: ricordare che CanvasAnimatedControl
ha un proprio evento Draw
distinto.
- Trovare il metodo generato
canvas_CreateResources
automaticamente:
private void canvas_CreateResources(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl sender,
Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
{}
Incollare (CTRL+V) il codice tagliato in precedenza in questo metodo. Spostare quindi la dichiarazione di GaussianBlurEffect
all'esterno del corpo del metodo in modo che la variabile diventi un membro della classe MainPage. Il codice dovrebbe ora essere simile al seguente:
GaussianBlurEffect blur;
private void canvas_CreateResources(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl sender,
Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
{
CanvasCommandList cl = new CanvasCommandList(sender);
using (CanvasDrawingSession clds = cl.CreateDrawingSession())
{
for (int i = 0; i < 100; i++)
{
clds.DrawText("Hello, World!", RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
clds.DrawCircle(RndPosition(), RndRadius(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
clds.DrawLine(RndPosition(), RndPosition(), Color.FromArgb(255, RndByte(), RndByte(), RndByte()));
}
}
blur = new GaussianBlurEffect()
{
Source = cl,
BlurAmount = 10.0f
};
}
- Ora puoi animare la sfocatura gaussiana. Trovare il
canvas_DrawAnimated
metodo e aggiungere il codice seguente:
private void canvas_DrawAnimated(
Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender,
Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args)
{
float radius = (float)(1 + Math.Sin(args.Timing.TotalTime.TotalSeconds)) * 10f;
blur.BlurAmount = radius;
args.DrawingSession.DrawImage(blur);
}
Questo legge il tempo totale trascorso fornito da CanvasAnimatedDrawEventArgs e lo usa per calcolare la quantità di sfocatura desiderata. La funzione seno fornisce una variazione interessante nel tempo. Infine, viene eseguito GaussianBlurEffect
il rendering dell'oggetto.
- Eseguire l'app per visualizzare la modifica del contenuto sfocato nel tempo.
Congratulazioni per aver completato questa esercitazione introduttival! Speriamo di aver visto come usare Win2D per creare una scena visiva ricca e animata con poche righe di codice C# e XAML.