在 Windows Presentation Foundation (WPF) 與 Silverlight 中,Canvas 是最接近傳統座標式佈局的面板。它透過 Canvas.Left 與 Canvas.Top 附加屬性,精確定位每個子元素。這與 Grid、StackPanel 等基於演算法自動排版的面板形成鮮明對比。
雖然名為「畫布」,容易讓人聯想到繪圖用途,但若僅用於顯示線條、多邊形、路徑等矢量圖形,這些元素本身已包含座標點,並不需要 Canvas 的附加屬性。那麼,為什麼還要使用 Canvas?是否有更好的替代方案?
作者逐漸傾向於使用「單一儲存格 Grid」——即未定義任何行與列的 Grid——來承載矢量圖形。乍看之下,兩者表現相似:圖形元素皆依自身座標點,相對容器左上角定位。但兩者在佈局系統中的行為卻大相徑庭:
若將一組多邊形放入單一儲存格 Grid,Grid 尺寸即反映圖形實際範圍,可視為具體尺寸的普通元素;若放入 Canvas,則圖形會超出佈局邊界,甚至被裁切。因此,整合組合式矢量圖像時,單一儲存格 Grid 的行為通常更符合預期。
Canvas 並非毫無用處。其「不參與佈局」的特性,反而適合「跳出框架」的場景:
本文透過三個實戰範例展示 Canvas 的進階用法:
需在兩個按鈕間繪製連線與橢圓,且隨視窗大小調整而更新。解決方案:在 SimpleUniformGrid 之上覆蓋一個同尺寸的 Canvas,於 LayoutUpdated 事件中,利用 TransformToVisual 取得按鈕相對 Canvas 的中心座標,繪製路徑幾何。Canvas 尺寸為零、不影響佈局,故修改其內容不會觸發遞迴佈局。

互動式三角函數示範:兩個滑桿定義直角三角形兩頂點,半透明三角形須緊貼滑桿拇指。滑桿拇指隱藏於控制樣板內,需以 VisualTreeHelper 遞迴搜尋可見的 Thumb 元素,再透過 TransformToVisual 取得相對 Canvas 座標,驅動多邊形變形。並將三角形 HitTestVisible 設為 false,避免干擾滑鼠輸入。

嘗試在 DataTemplate 內放置 Canvas 以顯示項目外部資訊,但 ScrollViewer 的裁切區域會遮蔽超出範圍的內容。改良方案:在整個頁面覆蓋一個 Canvas,於 LayoutUpdated 時,透過 ItemContainerGenerator.ContainerFromItem 取得項目容器位置,轉換至 Canvas 座標,動態建立/更新 PopOut 元素(繼承自 ContentControl),僅當項目在可視區內才顯示。

WPF 與 Silverlight 的面板機制極大簡化了佈局,但若將其視為「只能放入格子」的強制規定,便失去了靈活性。Canvas 提供了「跳出格子」的參考點,讓開發者能在佈局系統之上、之外,實現自由、動態的視覺效果。善用 Canvas 的零尺寸、不裁切、不參與佈局等特性,能解決許多看似棘手的 UI 需求。
原始碼範例下載:ThinkingOutsideTheGrid