本教學課程介紹 Win2D 的一些基本繪圖功能。 您將瞭解如何:
- 把 Win2D 加入 WinUI(C#)應用程式。
- 繪製文字和幾何。
- 套用篩選效果。
- 以動畫顯示您的 Win2D 內容。
- 遵循 Win2D 最佳做法。
請參考「Win2D NuGet」套件
- 建立一個新的 WinUI 應用程式,並新增 Microsoft.Graphics.Win2D Nuget 套件。
將 Win2D CanvasControl 新增至應用程式的 XAML
- 若要使用 Win2D,您需要在某處繪製圖形。 在 XAML 應用程式中,最簡單的方法是在您的 XAML 頁面上新增一個 CanvasControl。
在繼續之前,請先確認專案的架構選項設定為 x86 或 x64,而不是 Any CPU。 Win2D 會在 C++中實作,因此使用 Win2D 的項目必須以特定 CPU 架構為目標。
在 Solution Explorer 中雙擊
MainWindow.xaml,以移動到你的專案。 這會開啟檔案。 為了方便起見,您可以按兩下 [設計工具] 索引標籤中的 [XAML] 按鈕;這會隱藏可視化設計工具,並保留程式代碼檢視的所有空間。新增控制項之前,您必須先告訴 XAML CanvasControl 的定義位置。 要做到這一點,請前往 Window 元素的定義,並加入這個指令:
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"。 您的 XAML 現在看起來應該像這樣:
<Window
...
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
mc:Ignorable="d">
- 現在,將
canvas:CanvasControl作為子元素新增到根 Grid 元素。 為控件指定名稱,例如「canvas」。 您的 XAML 現在看起來應該像這樣:
<Grid>
<canvas:CanvasControl x:Name="canvas"/>
</Grid>
- 接著,為 Draw 事件定義事件處理器。 每當您的應用程式需要繪製或重新繪製其內容時,CanvasControl 就會引發
Draw。 最簡單的方法是讓 Visual Studio 自動完成來協助你。 在 CanvasControl 定義中,開始輸入事件處理程式的新屬性Draw:
<canvas:CanvasControl x:Name="canvas" Draw="canvas_Draw" />
在 Win2D 中繪製您的第一個字
現在,讓我們前往 C# 的後端程式碼。 從Solution Explorer開啟
MainWindow.xaml.cs。C# 檔案頂端有各種命名空間定義。 新增下列命名空間:
using Windows.UI;
using System.Numerics;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
- 接下來,您應該會看到下列由 AutoComplete 插入的空白事件處理程式:
private void canvas_Draw(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender,
Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
{
}
(如果您在上一個步驟中未使用 AutoComplete,請立即新增此程序代碼。
- CanvasDrawEventArgs參數會暴露一個成員,DrawingSession,其類型為 CanvasDrawingSession。 這堂課提供了 Win2D 中大部分基本繪圖功能:它有 CanvasDrawingSession.DrawRectangle、CanvasDrawingSession.DrawImage,以及繪製文字所需的方法 CanvasDrawingSession.DrawText。
將下列程式碼加入 canvas_Draw 方法:
args.DrawingSession.DrawText("Hello, World!", 100, 100, Colors.Black);
第一個自變數 "Hello, World!"是您想要 Win2D 顯示的字串。 兩個 「100」 會告訴 Win2D 將文字向右和向下位移 100 個 DIP(與裝置無關的圖元)。 最後,Colors.Black 定義文字的色彩。
- 現在您已準備好執行您的第一個 Win2D 應用程式。 按 F5 鍵進行編譯和啟動。 您應該會看到一個空白的視窗,上面有黑色的“Hello, world!”。
正確處置 Win2D 資源
- 在繼續繪製其他類型的內容之前,您應該先新增一些程式代碼,以確保您的應用程式避免記憶體流失。 大多數以.NET語言撰寫並使用 Win2D 控制項如 CanvasControl 的 Win2D 應用程式,都需要遵循以下步驟。 嚴格來說,您簡單的 「Hello, world」 應用程式不會受到影響,但這是一般遵循的好作法。
如需詳細資訊,請參閱 避免記憶體流失。
打開
MainWindow.xaml並找到包含你 CanvasControl 的 XAML 元素。 它應是檔案中的第一個元素。新增
Unloaded事件的處理程式。 您的 XAML 看起來應該像這樣:
<Page
...
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
mc:Ignorable="d"
Unloaded="Page_Unloaded">
- 移至
MainWindow.xaml.cs並尋找Page_Unloaded事件處理程式。 新增下列程式碼:
void Page_Unloaded(object sender, RoutedEventArgs e)
{
this.canvas.RemoveFromVisualTree();
this.canvas = null;
}
- 如果您的應用程式包含多個 Win2D 控制件,則您必須針對包含 Win2D 控制件的每個 XAML 頁面重複上述步驟。 您的應用程式目前只有一個 CanvasControl,這樣就足夠了。
繪製一些圖形
- 將 2D 幾何新增至您的應用程式同樣容易。 將下列程式碼新增至
canvas_Draw的最後:
args.DrawingSession.DrawCircle(125, 125, 100, Colors.Green);
args.DrawingSession.DrawLine(0, 0, 50, 200, Colors.Red);
這兩種方法的自變數類似於 DrawText。 圓形是由中心點(125、125)、半徑(100)和色彩(綠色)所定義。 線條是由開頭 (0, 0), 結尾 (50, 200) 和色彩 (紅色) 所定義。
- 現在,按 F5 執行應用程式。 您應該會看到 “Hello, world!” 以及綠色圓圈和紅色線條。
您可能想知道如何控制更進階的繪圖選項,例如線條粗細和虛線,或更複雜的填滿選項,例如使用筆刷。 Win2D 提供所有這些選項和更多選項,並可讓您在想要時輕鬆使用它們。 所有 Draw(...) 方法都提供許多可接受額外參數的重載,例如 CanvasTextFormat(字型族、大小等)以及 CanvasStrokeStyle(破折號、點、端帽等)。 可以隨意探索 API 的範圍,以了解更多關於這些選項的資訊。
動態產生繪圖參數
- 現在,讓我們透過繪製一堆具有隨機色彩的圖形和文字,來新增一些品種。
將下列程式代碼新增至 MainWindow 類別頂端。 這是協助程式功能,可在繪製時產生您將使用的隨機值:
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);
}
- 修改您的
canvas_Draw方法,以使用這些隨機參數來繪製:
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()));
}
讓我們來分析 DrawText 如何變化。
"Hello, World!" 與之前相同。 x 和 y 位移參數已取代為由 產生的單一 RndPosition。 最後,Color.FromArgb 可讓您使用 A、R、G 和 B 值來定義色彩,而不是使用預先定義的色彩。 是指A,也就是Alpha或不透明度層級,於此情況下,您總是會選擇完全不透明(255)。
DrawCircle 和 DrawLine 的運作方式與 DrawText類似。
- 最後,將繪圖程式碼包裝成
forloop。 您最終應該得到下列canvas_Draw程式代碼:
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()));
}
- 再次執行應用程式。 您應該會看到一堆含有隨機位置和大小的文字、線條和圓形。
將影像效果套用至您的內容
影像效果也稱為篩選效果,是套用至像素數據的圖形轉換。 飽和度、色調旋轉和高斯模糊是一些常見的影像效果。 圖片效果可以串聯在一起,產生精緻的視覺效果,且不需多費力氣。
你使用影像效果的方式是提供一個原始影像(你起始的內容),建立像 GaussianBlurEffect 這類效果,設定屬性如 BlurAmount,然後用 DrawImage 繪製效果輸出。
要為文字和形狀套用影像效果,首先需要將內容渲染成 CanvasCommandList。 此物件可作為您效果的輸入。
- 將
canvas_Draw方法變更為以下程式碼:
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()));
}
}
您可以從 CanvasDrawingSession 取得用來繪製的 CanvasDrawEventArgs,一樣,您可以從 CanvasDrawingSession建立 CanvasCommandList。 唯一的差別在於,當您將繪圖繪製到命令清單的繪圖會話(clds)時,您不會直接渲染到 CanvasControl。 相反地,命令清單是中繼物件,可儲存轉譯結果以供日後使用。
您可能已經注意到包裝命令清單繪圖會話的 using 區塊。 繪圖會話會實作 IDisposable,並且必須在完成渲染時釋放(程式區塊 using 會這麼做)。 您從 CanvasDrawingSession 取得的 CanvasDrawEventArgs 會自動為您關閉,但您必須處置您明確建立的任何繪圖會話。
- 最後,將下列程式代碼新增至
GaussianBlurEffect方法的結尾,以定義canvas_Draw:
GaussianBlurEffect blur = new GaussianBlurEffect();
blur.Source = cl;
blur.BlurAmount = 10.0f;
args.DrawingSession.DrawImage(blur);
- 再次執行應用程式。 您應該會看到線條、文字和圓形呈現模糊不清的外觀。
使用 CanvasAnimatedControl 建立應用程式動畫
. Win2D 可以讓您即時更新內容並製作動畫,例如,在每個畫面中變更高斯模糊效果的半徑。 為了做到這一點,你會使用 CanvasAnimatedControl。
CanvasControl 最適合大部分靜態圖形內容 ,只有在需要更新或重新繪製內容時,才會引發 Draw 事件。 如果您持續變更內容,您應該考慮改用 CanvasAnimatedControl。 兩個控件的運作方式非常類似,但 CanvasAnimatedControl 會定期引發 Draw 事件:預設會呼叫每秒 60 次。
- 若要切換至 ,請移至
CanvasAnimatedControlMainPage.xaml,刪除 CanvasControl 行,並將它取代為下列 XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<canvas:CanvasAnimatedControl x:Name="canvas" Draw="canvas_DrawAnimated" CreateResources="canvas_CreateResources"/>
</Grid>
就像使用 CanvasControl 一樣,讓 AutoComplete 為您建立 Draw 事件處理程式。 預設情況下,Visual Studio會將此處理程序命名為 canvas_Draw_1,因為 canvas_Draw 已經存在;這裡我們將方法重新命名為 canvas_AnimatedDraw,以明確表示這是不同的事件。
此外,你還要處理一個新事件,CreateResources。 再次讓 AutoComplete 建立處理程式。
現在您的應用程式將以每秒 60 幀的速度重新繪製,因此您可以一次性建立 Win2D 的視覺資源,並在每幀中重複使用,這樣會更有效率。 建立 CanvasCommandList,並在內容保持靜態時,每秒 60 次將 300 個項目繪製到其中是沒有效率的。
CreateResources 是當 Win2D 判斷您需要重新建立視覺資源時才引發的事件,例如在載入頁面時。
- 切換回
MainPage.xaml.cs。 尋找您的canvas_Draw方法,它應該看起來像這樣:
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);
}
此現有繪製程式代碼中絕大多數不需要與每個框架一起執行:包含文字、線條和圓形的命令清單會與每個框架保持相同,而唯一變更的是模糊半徑。 因此,您可以將此「靜態」程式代碼移至 CreateResources。
首先,剪下(CTRL+X)canvas_Draw 的所有內容,但保留最後一行(args.DrawingSession.DrawImage(blur);)。 您現在可以刪除 canvas_Draw 的其餘部分,因為不再需要:請記得 CanvasAnimatedControl 有自己的不同 Draw 事件。
- 找到自動產生的
canvas_CreateResources方法:
private void canvas_CreateResources(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl sender,
Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
{}
將先前剪下的程式代碼貼到此方法中(CTRL+V)。 接下來,將 GaussianBlurEffect 宣告移至方法主體之外,讓變數成為MainPage類別的成員。 您的程式代碼現在看起來應該如下所示:
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
};
}
- 現在您可以以動畫顯示高斯模糊。 尋找
canvas_DrawAnimated方法,並新增下列程序代碼:
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);
}
這會讀取 CanvasAnimatedDrawEventArgs 提供的總經過時間,並用此計算所需的模糊量;正弦函數隨時間提供了有趣的變化。 最後,GaussianBlurEffect 已完成渲染。
- 執行應用程式以觀看模糊內容在過程中的變化。
恭喜您完成本快速入門教學課程! 希望您已瞭解如何使用 Win2D 來建立豐富的動畫視覺效果場景,只需幾行 C# 和 XAML 程式代碼即可。