原文鏈接:http://microsoft.github.io/Win2D/html/QuickStart.htm
快速入門
這是 Win2D 的快速入門教程,將會介紹 Win2D 中的基本功能。你將會在此教程中學到:
• 添加 Win2D 到 C# XAML 項目
• 繪制文本和幾何圖形
• 應用濾鏡效果
• 對 Win2D 內容進行動畫效果
• 根據 Win2D 進行最佳實現
安裝 Visual Studio
• 如果你還沒有安裝受支持的 Visual Studio 版本,請按照該步驟:快速開始。
創建一個帶有 Win2D 的新項目
1、運行 Visual Studio 並創建新項目:文件→新建→項目。
2、如果你的目標是 Windows 10,選擇:已安裝→模板→Visual C#→Windows→通用→空白應用(通用 Windows)。
如果你的目標是 Windows 8.1 且使用 Visual Studio 2015,選擇:已安裝→模板→Visual C#→Windows 8→通用→空白應用(通用 Windows 8.1)。
如果你的目標是 Windows 8.1 且使用 Visual Studio 2013,選擇:已安裝→模板→Visual C#→Windows 8.1→空白應用。
3、輸入項目名稱,選擇項目存放路徑,然后點擊確定按鈕創建。
4、Win2D 目前是發布為一個 nuget 包,你需要安裝它才能夠使用。這里有兩個包,一個是 Windows 10 的,另一個是 Windows 8.1 的。選擇:工具→Nuget 包管理器→管理解決方案的 Nuget 程序包。
5、搜索 Win2D,然后選擇對應的包。
如果目標是 Windows 10,選擇 Win2D.uwp。
如果目標是 Windows 8.1,選擇 Win2D.win81。
最后,點擊安裝。
添加 Win2D 的 CanvasControl 到你的 App 的 Xaml 文件中
1、要使用 Win2D,你需要一個地方來繪制你的圖形。在 Xaml App 中,最簡單的方法就是添加一個 CanvasControl 到你的 Xaml 頁面。
在這之前,請先確保你的項目的解決方案平台是 x86 或者 x64,而不是 Any CPU。因為 Win2D 是基於 C++ 實現的,因此使用到 Win2D 的項目都必須指定解決方案平台。
2、在解決方案資源管理器中雙擊 MainPage.xaml 來打開這個頁面。
3、在使用 CanvasControl 之前,你必須得告訴 Xaml,這個控件是哪里定義的。在頁面定義中,添加以下這句:
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
然后你的 Xaml 應該是這樣的:
<Page ... xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml" mc:Ignorable="d">
4、現在,添加 canvas:CanvasControl 到 Grid 元素中,並且給它一個名字,這里我們就叫“canvas”。現在你的 Xaml 應該就變成這樣了:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <canvas:CanvasControl x:Name="canvas"/> </Grid>
5、接下來,定義 Draw 事件。CnavasControl 將會在需要繪制或者重繪的時候調用 Draw 事件。
<canvas:CanvasControl x:Name="canvas" Draw="canvas_Draw" />
使用 Win2D 繪制你的第一條文本
1、在解決方案資源管理器中打開 MainPage.xaml.cs。
2、在 C# 文件頂部添加以下命名空間引用:
using Windows.UI; using System.Numerics; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Effects;
3、確保添加了 canvas_Draw 方法:
private void canvas_Draw( Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) {}
4、CanvasDrawEventArgs 參數中有一個叫做 DrawingSession 的成員,並且類型是CanvasDrawingSession。這個類型提供了 Win2D 中絕大部分的繪制功能。它有一堆名字叫 CanvasDrawingSession.DrawXXX 的方法,例如 CanvasDrawingSession.DrawRectangle,CanvasDrawingSession.DrawImage 和我們現在需要用的 CanvasDrawingSession.DrawText。
添加這行代碼到 canvas_Draw 方法中:
args.DrawingSession.DrawText("Hello, World!", 100, 100, Colors.Black);
第一個參數 "Hello, World!" 是你想 Win2D 顯示的字符串。接下來兩個 100 是指,在 100 DIPs 下,距離容器左邊和頂部的距離。最后一個參數是這個文本顯示的顏色。
5、現在可以運行你的 App 了。按 F5 編譯並運行。你應該可以看見一個空白的窗口上顯示着黑色的 Hello, World! 了。
正確釋放 Win2D 所使用的資源
1、在你打算繼續繪制其它內容之前,你應該先加入一些代碼來避免內存泄漏。絕大部分使用 .Net 語言編寫的 Win2D 程序和使用了 Win2D 中的控件(例如 CanvasControl)都需要添加以下步驟。嚴格來說,像上面那個 Hello World 不會產生影響,但是,遵循常規是一個好習慣。
關於內存泄漏的更多信息,可以點擊此鏈接:http://microsoft.github.io/Win2D/html/RefCycles.htm
2、打開 MainPage.xaml 並找到包含你那個 CanvasControl 的 Page 元素。
3、在 Page 元素中訂閱 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">
4、轉到 MainPage.xaml.cs 文件,並在 Page_Unloaded 添加以下代碼:
void Page_Unloaded(object sender, RoutedEventArgs e) { this.canvas.RemoveFromVisualTree(); this.canvas = null; }
5、如果你的 App 包含多個 Win2D 控件,那么你需要對每一個 Win2D 控件重復上面步驟。因為現在你的 App 就只有這么一個 CanvasControl,所以現在這樣子就已經完成內存釋放了。
繪制一些圖形
1、在你的 App 中添加一些 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)的紅色直線。
2、按 F5 編譯並運行,你應該會看見 Hello,World! 附近有一個綠色邊的圓和紅色的線。
你可能想知道如何使用更高級的繪制方式,例如控制線的粗細、樣式,或者使用刷子來填充圖案這些更加復雜的操作。Win2D 提供了所有的選項來方便你去實現你所想的功能。所有 DrawXXX 方法都提供了多個重載來接受額外的參數,例如 CanvasTextFormat(字體、文字大小等等)類型的參數和 CanvasStrokeStyle(點、線的開始結束等等)類型的參數。
你可以通過查看 API 來了解這些參數。
動態生成繪制參數
1、現在,我們添加一點變化來繪制隨機顏色的圖形和文字。
添加以下代碼到 MainPage.xaml.cs 中。這會幫助你在繪制的時候產生隨機的值。
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); }
2、修改 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 生成的 Vector2 對象。最后,使用 Color.FromArgb 方法並傳遞 A,R,G,B 來定義一個顏色。A 是 Alpha 通道的值,也就是顏色的不透明度。在這個例子中我們始終使用完全不透明,也就是 255。
DrawCircle 和 DrawLine 的操作類似於 DrawText,這里就不詳細說明了。
3、最后,用個循環將它包起來。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())); }
4、再次運行程序,你應該會看見一大堆隨機位置、隨機大小的文字、線條和圓圈。
對內容應用圖像效果
1、圖像效果,也稱濾鏡效果,是像素級別的圖形變換。飽和度、色相模糊和高斯模糊是一些常見的圖像效果。圖像效果可以串聯在一起應用,這樣就可以以最小的代價來實現復雜的視覺效果。
你可以通過提供一幅源圖像(你的初始內容),創建一個特效(例如 GaussianBlurEffect)並設置其屬性(例如 BlurAmount),然后調用 DrawImage 方法來繪制出特效處理過的圖像。
如果你要對文字和圖形應用圖像效果,你需要先將內容呈現到一個 CanvasCommandList 對象中。這個對象可作為效果的輸入。
2、修改 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())); } }
就像你如何從 CanvasDrawEventArgs 對象中獲得一個 CanvasDrawingSession 一樣,你從 CanvasCommandList 中也能得到一個 CanvasDrawingSession 對象。唯一的區別是,你只是將繪圖命令添加到繪圖任務當中,而不是直接渲染到 CanvasControl 上面。反過來說,命令列表是一個存放了渲染命令的中間對象,供給以后實際渲染時使用。
你也許會注意我們使用了 using 來封裝繪圖命令。DrawingSession 是一個實現了 IDisposable 接口的對象,並且必須在已經完成繪制的時候釋放掉。注意:從 CanvasDrawEventArgs 獲取的 CanvasDrawingSession 會自動釋放,並不需要你手動去釋放它。但是,你自己創建的 CanvasDrawingSession 必須要自己手動釋放。
3、最后,定義 GaussianBlurEffect 並添加下面代碼到 canvas_Draw 方法的最后。
GaussianBlurEffect blur = new GaussianBlurEffect(); blur.Source = cl; blur.BlurAmount = 10.0f; args.DrawingSession.DrawImage(blur);
這段代碼創建了一個高斯模糊,並設置源為剛剛繪制的 CanvasCommandList 對象,設置模糊半徑為 10,最后交由原始的 DrawingSession 來渲染輸出。
4、再次運行程序,你會看見你的直線、文字、圓圈都帶有模糊效果了。
使用 CanvasAnimatedControl 來使你的 App 充滿動畫
1、Win2D 允許你在運行時實時更新內容或者應用動畫效果。舉個例子,每一幀改變高斯模糊的半徑。要實現這個功能,你需要使用 CanvasAnimatedControl。
CanvasControl 適用於靜態內容,它僅僅在需要更新或者重繪的時候觸發 Draw 事件。如果你的內容是不斷變化的,那么你應該使用 CanvasAnimatedControl。這兩個控件的使用上相當類似,除了 CanvasAnimatedControl 會定期觸發 Draw 事件。在一般情況下,每秒會觸發 60 次 Draw 事件。
2、現在我們開始轉為使用 CanvasAnimatedControl,轉到 MainPage.xaml,刪除之前的代碼,並修改成這樣:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <canvas:CanvasAnimatedControl x:Name="canvas" Draw="canvas_DrawAnimated" CreateResources="canvas_CreateResources"/> </Grid>
類似於 CanvasControl,訂閱上 Draw 事件(方法名為 canvas_DrawAnimated)。另外,你也應該訂閱一個名字叫做 CreateResources 的事件。
現在,你的程序將會以每秒 60 幀的方式進行渲染。對於那些只需創建一次,能每幀復用的資源,我們應該盡可以將它優化,不要在每一幀都創建一次。CreateResources 事件僅當 Win2D 認為需要重新創建資源的時候才會觸發,例如在頁面加載的時候。
3、回到 MainPage.xaml.cs,你之前的代碼應該是這樣的:
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 將除了最后一行(args.DrawingSession.DrawImage(blur);)以外的代碼剪切掉。然后可以刪除掉 canvas_Draw 這個方法了,因為 CanvasAnimatedControl 將使用 canvas_AnimatedDraw 方法。
4、找到 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 }; }
5、現在,你可以動畫化高斯模糊了,找到 canvas_AnimatedDraw 方法,然后加入下面的代碼:
private void canvas_AnimatedDraw( 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 來呈現。
6、運行程序,你會看到隨着時間變化,內容的模糊程度也在變化。
恭喜你完成了這個快速入門教程!希望你已經知道如何通過短短幾行代碼來創造一個豐富生動的視圖。
PS:本文是渣譯,不喜勿噴;如有幫助,請點推薦。謝謝!