MIGRATION GUIDES How to Migrate from PDFSharp to IronPDF in C# Curtis Chau 發表日期:2026年2月1日 下載 IronPDF NuGet 下載 DLL 下載 Windows 安裝程式 開始免費試用 法學碩士副本 法學碩士副本 將頁面複製為 Markdown 格式,用於 LLMs 在 ChatGPT 中打開 請向 ChatGPT 諮詢此頁面 在雙子座打開 請向 Gemini 詢問此頁面 在 Grok 中打開 向 Grok 詢問此頁面 打開困惑 向 Perplexity 詢問有關此頁面的信息 分享 在 Facebook 上分享 分享到 X(Twitter) 在 LinkedIn 上分享 複製連結 電子郵件文章 從 PDFSharp 遷移到 IronPDF 會將您的 PDF 產生工作流程從基於座標的手動繪圖轉變為現代 HTML/CSS 範本。 本指南提供了一條完整的、循序漸進的遷移路徑,用 Web 技術取代了繁瑣的 GDI+ 式定位,從而大大縮短了開發時間,並透過標準的 HTML/CSS 技能使 PDF 生成變得可維護。 為什麼要從 PDFSharp 遷移到 IronPDF 了解 PDFSharp PDFSharp 是一個知名的底層 PDF 建立庫,允許開發人員透過程式設計方式產生 PDF 文件。 PDFSharp 採用 MIT 授權發布,賦予開發者社群使用和修改的自由。 PDFSharp 主要用作從頭開始繪製和編譯 PDF 的工具,這既有利也有弊,具體取決於專案的性質。 PDFSharp 有時會被誤認為是 HTML 轉 PDF 轉換器,但它不是。 它的唯一用途是專門用於程式化創建PDF文件。 雖然有一個名為 HtmlRenderer.PdfSharp 的插件,旨在提供 HTML 渲染功能,但它僅支援 CSS 2.1,不支援現代 CSS 功能,如 flexbox 和 grid。 座標計算問題 PDFSharp 的 GDI+ 方法意味著您必須: 計算每個元素的精確 X、Y 位置 手動追蹤頁面溢出的內容高度 自行處理換行和文字長度設定 逐單元格繪製表格,並進行邊框計算。 管理具有手動分頁符號的多頁文檔 PDFSharp 的架構需要對使用座標進行定位有深入的了解,這通常會為創建複雜的佈局帶來挑戰。 PDFSharp 與 IronPDF 對比 特徵 PDFSharp IronPDF 執照 麻省理工學院(免費) 商業的 HTML 轉 PDF 支持 不 是的(支援HTML5/CSS3) 現代 CSS 支持 否(僅限 CSS 2.1) 是的(完整 CSS3) 文件創建 基於座標的繪圖 HTML/CSS模板 佈局系統 手動 X、Y 軸定位 CSS Flow/Flexbox/Grid 分頁符 手動計算 自動 + CSS 控制 表格 單獨繪製單元格 HTML<table> 造型 基於程式碼的字體/顏色 CSS樣式表 文件 API 低級(需要座標) 進階(簡化 API) 更新 不頻繁 常規的 IronPDF 在需要將 HTML 文件完整轉換為 PDF 的場景中表現出色。 該 .NET 程式庫支援 HTML5 和 CSS3,確保符合現代 Web 標準。 其原生的 HTML 轉 PDF 功能意味著開發人員可以利用現有的 Web 內容或使用現代 Web 工具設計的範本。 對於計劃在 2025 年和 2026 年採用 .NET 10 和 C# 14 的團隊,IronPDF 提供了一種現代化的方法,該方法消除了坐標計算,同時利用了 Web 開發技能。 開始之前 先決條件 .NET 環境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+ NuGet 存取權限:能夠安裝 NuGet 套件 IronPDF 許可證:請從ironpdf.com取得您的許可證密鑰。 NuGet 套件變更 # Remove PDFSharp dotnet remove package PdfSharp dotnet remove package PdfSharp-wpf dotnet remove package PdfSharp.Charting # Add IronPDF dotnet add package IronPdf # Remove PDFSharp dotnet remove package PdfSharp dotnet remove package PdfSharp-wpf dotnet remove package PdfSharp.Charting # Add IronPDF dotnet add package IronPdf SHELL 許可證配置 // Add at application startup (Program.cs or Startup.cs) IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"; // Add at application startup (Program.cs or Startup.cs) IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"; $vbLabelText $csharpLabel 識別 PDFSharp 使用情況 # Find all PDFSharp usages in your codebase grep -r "PdfSharp\|XGraphics\|XFont\|XBrush\|XPen" --include="*.cs" . # Find all PDFSharp usages in your codebase grep -r "PdfSharp\|XGraphics\|XFont\|XBrush\|XPen" --include="*.cs" . SHELL 完整 API 參考 命名空間變更 // Before: PDFSharp using PdfSharp.Pdf; using PdfSharp.Drawing; using PdfSharp.Pdf.IO; // After: IronPDF using IronPdf; using IronPdf.Editing; // Before: PDFSharp using PdfSharp.Pdf; using PdfSharp.Drawing; using PdfSharp.Pdf.IO; // After: IronPDF using IronPdf; using IronPdf.Editing; $vbLabelText $csharpLabel 核心 API 映射 PDFSharp API IronPDF API 筆記 new PdfDocument() ChromePdfRenderer.RenderHtmlAsPdf() 從 HTML 創建 document.AddPage() 自動的 由 HTML 內容建立的頁面 XGraphics.FromPdfPage() 不需要 使用 HTML 元素 XGraphics.DrawString() HTML<p> ,<h1> , ETC。 使用 CSS 定位 XGraphics.DrawImage() HTML<img>標籤 使用 CSS 定位 XFont CSS font-family 、 font-size 標準 CSS XBrush 、 XPen CSS顏色/邊框 color , background-color document.Save() pdf.SaveAs() 類似功能 PdfReader.Open() PdfDocument.FromFile() 開啟現有PDF 程式碼遷移範例 範例 1:HTML 轉 PDF (PDFSharp 之前): // NuGet: Install-Package PdfSharp using PdfSharp.Pdf; using PdfSharp.Drawing; using System; class Program { static void Main() { // PDFSharp does not have built-in HTML 轉 PDF conversion // You need to manually parse HTML and render content PdfDocument document = new PdfDocument(); PdfPage page = document.AddPage(); XGraphics gfx = XGraphics.FromPdfPage(page); XFont font = new XFont("Arial", 12); // 手動的 text rendering (no HTML support) gfx.DrawString("Hello from PDFSharp", font, XBrushes.Black, new XRect(0, 0, page.Width, page.Height), XStringFormats.TopLeft); document.Save("output.pdf"); } } // NuGet: Install-Package PdfSharp using PdfSharp.Pdf; using PdfSharp.Drawing; using System; class Program { static void Main() { // PDFSharp does not have built-in HTML 轉 PDF conversion // You need to manually parse HTML and render content PdfDocument document = new PdfDocument(); PdfPage page = document.AddPage(); XGraphics gfx = XGraphics.FromPdfPage(page); XFont font = new XFont("Arial", 12); // 手動的 text rendering (no HTML support) gfx.DrawString("Hello from PDFSharp", font, XBrushes.Black, new XRect(0, 0, page.Width, page.Height), XStringFormats.TopLeft); document.Save("output.pdf"); } } $vbLabelText $csharpLabel (IronPDF 之後): // NuGet: Install-Package IronPdf using IronPdf; using System; class Program { static void Main() { // IronPDF has native HTML 轉 PDF rendering var renderer = new ChromePdfRenderer(); string html = "<h1>Hello from IronPDF</h1><p>Easy HTML 轉 PDF conversion</p>"; var pdf = renderer.RenderHtmlAsPdf(html); pdf.SaveAs("output.pdf"); } } // NuGet: Install-Package IronPdf using IronPdf; using System; class Program { static void Main() { // IronPDF has native HTML 轉 PDF rendering var renderer = new ChromePdfRenderer(); string html = "<h1>Hello from IronPDF</h1><p>Easy HTML 轉 PDF conversion</p>"; var pdf = renderer.RenderHtmlAsPdf(html); pdf.SaveAs("output.pdf"); } } $vbLabelText $csharpLabel 這個例子突顯了這兩個函式庫之間最顯著的差異。 PDFSharp 明確指出它"沒有內建的 HTML 到 PDF 轉換功能"—您必須手動建立一個PdfDocument ,新增一個PdfPage ,取得一個XGraphics對象,建立一個XFont ,然後使用DrawString()和XRect座標。 IronPDF 透過ChromePdfRenderer提供原生 HTML 到 PDF 的渲染功能。 RenderHtmlAsPdf()方法接受 HTML 字串,並使用 Chromium 引擎在內部轉換。 IronPDF 可以輕鬆地將 HTML 檔案轉換為 PDF,保留 HTML5 和 CSS3 中定義的所有樣式,無需進行座標計算。 請參閱HTML 轉 PDF 文件以取得完整範例。 範例 2:為現有 PDF 新增文字/浮水印 (PDFSharp 之前): // NuGet: Install-Package PdfSharp using PdfSharp.Pdf; using PdfSharp.Pdf.IO; using PdfSharp.Drawing; using System; class Program { static void Main() { // Open existing PDF PdfDocument document = PdfReader.Open("existing.pdf", PdfDocumentOpenMode.Modify); PdfPage page = document.Pages[0]; // Get graphics object XGraphics gfx = XGraphics.FromPdfPage(page); XFont font = new XFont("Arial", 20, XFontStyle.Bold); // Draw text at specific position gfx.DrawString("Watermark Text", font, XBrushes.Red, new XPoint(200, 400)); document.Save("modified.pdf"); } } // NuGet: Install-Package PdfSharp using PdfSharp.Pdf; using PdfSharp.Pdf.IO; using PdfSharp.Drawing; using System; class Program { static void Main() { // Open existing PDF PdfDocument document = PdfReader.Open("existing.pdf", PdfDocumentOpenMode.Modify); PdfPage page = document.Pages[0]; // Get graphics object XGraphics gfx = XGraphics.FromPdfPage(page); XFont font = new XFont("Arial", 20, XFontStyle.Bold); // Draw text at specific position gfx.DrawString("Watermark Text", font, XBrushes.Red, new XPoint(200, 400)); document.Save("modified.pdf"); } } $vbLabelText $csharpLabel (IronPDF 之後): // NuGet: Install-Package IronPdf using IronPdf; using IronPdf.Editing; using System; class Program { static void Main() { // Open existing PDF var pdf = PdfDocument.FromFile("existing.pdf"); // Add text stamp/watermark var textStamper = new TextStamper() { Text = "Watermark Text", FontSize = 20, Color = IronSoftware.Drawing.Color.Red, VerticalAlignment = VerticalAlignment.Middle, HorizontalAlignment = HorizontalAlignment.Center }; pdf.ApplyStamp(textStamper); pdf.SaveAs("modified.pdf"); } } // NuGet: Install-Package IronPdf using IronPdf; using IronPdf.Editing; using System; class Program { static void Main() { // Open existing PDF var pdf = PdfDocument.FromFile("existing.pdf"); // Add text stamp/watermark var textStamper = new TextStamper() { Text = "Watermark Text", FontSize = 20, Color = IronSoftware.Drawing.Color.Red, VerticalAlignment = VerticalAlignment.Middle, HorizontalAlignment = HorizontalAlignment.Center }; pdf.ApplyStamp(textStamper); pdf.SaveAs("modified.pdf"); } } $vbLabelText $csharpLabel PDFSharp 需要使用PdfReader.Open()指定PdfDocumentOpenMode.Modify開啟 PDF,存取頁面,建立XGraphics對象,建立帶有樣式的XFont ,並使用DrawString()和XPoint指定精確的 X、Y 座標 (200, 400)。 IronPDF 透過PdfDocument.FromFile() 、具有聲明性屬性( Text 、 FontSize 、 Color 、 VerticalAlignment 、 HorizontalAlignment )的TextStamper物件以及ApplyStamp()簡化了這個過程。 無需進行座標計算——只需指定對齊方式,IronPDF 即可處理定位。 請注意, IronPdf.Editing命名空間是實現蓋章功能所必需的。 範例 3:建立帶有圖像的 PDF (PDFSharp 之前): // NuGet: Install-Package PdfSharp using PdfSharp.Pdf; using PdfSharp.Drawing; using System; class Program { static void Main() { // Create new PDF document PdfDocument document = new PdfDocument(); PdfPage page = document.AddPage(); XGraphics gfx = XGraphics.FromPdfPage(page); // Load and draw image XImage image = XImage.FromFile("image.jpg"); // Calculate size to fit page double width = 200; double height = 200; gfx.DrawImage(image, 50, 50, width, height); // Add text XFont font = new XFont("Arial", 16); gfx.DrawString("Image in PDF", font, XBrushes.Black, new XPoint(50, 270)); document.Save("output.pdf"); } } // NuGet: Install-Package PdfSharp using PdfSharp.Pdf; using PdfSharp.Drawing; using System; class Program { static void Main() { // Create new PDF document PdfDocument document = new PdfDocument(); PdfPage page = document.AddPage(); XGraphics gfx = XGraphics.FromPdfPage(page); // Load and draw image XImage image = XImage.FromFile("image.jpg"); // Calculate size to fit page double width = 200; double height = 200; gfx.DrawImage(image, 50, 50, width, height); // Add text XFont font = new XFont("Arial", 16); gfx.DrawString("Image in PDF", font, XBrushes.Black, new XPoint(50, 270)); document.Save("output.pdf"); } } $vbLabelText $csharpLabel (IronPDF 之後): // NuGet: Install-Package IronPdf using IronPdf; using System; class Program { static void Main() { // Create PDF from HTML with image var renderer = new ChromePdfRenderer(); string html = @" <h1>Image in PDF</h1> <img src='image.jpg' style='width:200px; height:200px;' /> <p>Easy image embedding with HTML</p>"; var pdf = renderer.RenderHtmlAsPdf(html); pdf.SaveAs("output.pdf"); // Alternative: Add image to existing PDF var existingPdf = new ChromePdfRenderer().RenderHtmlAsPdf("<h1>Document</h1>"); var imageStamper = new IronPdf.Editing.ImageStamper(new Uri("image.jpg")) { VerticalAlignment = IronPdf.Editing.VerticalAlignment.Top }; existingPdf.ApplyStamp(imageStamper); } } // NuGet: Install-Package IronPdf using IronPdf; using System; class Program { static void Main() { // Create PDF from HTML with image var renderer = new ChromePdfRenderer(); string html = @" <h1>Image in PDF</h1> <img src='image.jpg' style='width:200px; height:200px;' /> <p>Easy image embedding with HTML</p>"; var pdf = renderer.RenderHtmlAsPdf(html); pdf.SaveAs("output.pdf"); // Alternative: Add image to existing PDF var existingPdf = new ChromePdfRenderer().RenderHtmlAsPdf("<h1>Document</h1>"); var imageStamper = new IronPdf.Editing.ImageStamper(new Uri("image.jpg")) { VerticalAlignment = IronPdf.Editing.VerticalAlignment.Top }; existingPdf.ApplyStamp(imageStamper); } } $vbLabelText $csharpLabel PDFSharp 需要建立一個新的PdfDocument ,新增一個PdfPage ,取得XGraphics ,從檔案載入一個XImage ,計算寬度和高度,使用DrawImage()和精確座標 (50, 50, 200, 200),然後單獨使用DrawString()新增文字。 IronPDF 使用標準的 HTML 格式。<img>標籤和 CSS 樣式(style='width:200px; 高度:200px;')。 無需進行座標計算——CSS 會自動處理佈局。 IronPDF 也提供了ImageStamper ,用於在現有 PDF 中新增影像,並具有聲明式對齊屬性。 了解更多信息,請閱讀我們的教程。 關鍵遷移說明 範式轉移:從座標到 HTML/CSS 最顯著的變化是從基於座標的繪圖方式轉向HTML/CSS: // PDFSharp: 手動的 positioning nightmare gfx.DrawString("Invoice", titleFont, XBrushes.Black, new XPoint(50, 50)); gfx.DrawString("Customer: John", bodyFont, XBrushes.Black, new XPoint(50, 80)); // IronPDF: Let CSS handle layout var html = @" <div style='padding: 50px;'> <h1>Invoice</h1> <p>Customer: John</p> </div>"; var pdf = renderer.RenderHtmlAsPdf(html); // PDFSharp: 手動的 positioning nightmare gfx.DrawString("Invoice", titleFont, XBrushes.Black, new XPoint(50, 50)); gfx.DrawString("Customer: John", bodyFont, XBrushes.Black, new XPoint(50, 80)); // IronPDF: Let CSS handle layout var html = @" <div style='padding: 50px;'> <h1>Invoice</h1> <p>Customer: John</p> </div>"; var pdf = renderer.RenderHtmlAsPdf(html); $vbLabelText $csharpLabel 字體遷移 // PDFSharp: XFont objects var titleFont = new XFont("Arial", 24, XFontStyle.Bold); var bodyFont = new XFont("Times New Roman", 12); // IronPDF: CSS font properties var html = @" <style> h1 { font-family: Arial, sans-serif; font-size: 24px; font-weight: bold; } p { font-family: 'Times New Roman', serif; font-size: 12px; } </style>"; // PDFSharp: XFont objects var titleFont = new XFont("Arial", 24, XFontStyle.Bold); var bodyFont = new XFont("Times New Roman", 12); // IronPDF: CSS font properties var html = @" <style> h1 { font-family: Arial, sans-serif; font-size: 24px; font-weight: bold; } p { font-family: 'Times New Roman', serif; font-size: 12px; } </style>"; $vbLabelText $csharpLabel 文件載入變更 // PDFSharp: PdfReader.Open() PdfDocument document = PdfReader.Open("existing.pdf", PdfDocumentOpenMode.Modify); // IronPDF: PdfDocument.FromFile() var pdf = PdfDocument.FromFile("existing.pdf"); // PDFSharp: PdfReader.Open() PdfDocument document = PdfReader.Open("existing.pdf", PdfDocumentOpenMode.Modify); // IronPDF: PdfDocument.FromFile() var pdf = PdfDocument.FromFile("existing.pdf"); $vbLabelText $csharpLabel 儲存方法更改 // PDFSharp: document.Save() document.Save("output.pdf"); // IronPDF: pdf.SaveAs() pdf.SaveAs("output.pdf"); // PDFSharp: document.Save() document.Save("output.pdf"); // IronPDF: pdf.SaveAs() pdf.SaveAs("output.pdf"); $vbLabelText $csharpLabel 頁面存取權限變更 // PDFSharp: document.Pages[0] PdfPage page = document.Pages[0]; // IronPDF: 自動的 page handling or pdf.Pages[0] // Pages are created automatically from HTML content // PDFSharp: document.Pages[0] PdfPage page = document.Pages[0]; // IronPDF: 自動的 page handling or pdf.Pages[0] // Pages are created automatically from HTML content $vbLabelText $csharpLabel 遷移後的新功能 遷移到 IronPDF 後,您將獲得 PDFSharp 無法提供的功能: 原生 HTML 轉 PDF var renderer = new ChromePdfRenderer(); var pdf = renderer.RenderHtmlAsPdf("<h1>Modern Web Content</h1>"); var renderer = new ChromePdfRenderer(); var pdf = renderer.RenderHtmlAsPdf("<h1>Modern Web Content</h1>"); $vbLabelText $csharpLabel PDF檔案的URL var pdf = renderer.RenderUrlAsPdf("https://example.com"); var pdf = renderer.RenderUrlAsPdf("https://example.com"); $vbLabelText $csharpLabel PDF合併 var pdf1 = PdfDocument.FromFile("document1.pdf"); var pdf2 = PdfDocument.FromFile("document2.pdf"); var merged = PdfDocument.Merge(pdf1, pdf2); var pdf1 = PdfDocument.FromFile("document1.pdf"); var pdf2 = PdfDocument.FromFile("document2.pdf"); var merged = PdfDocument.Merge(pdf1, pdf2); $vbLabelText $csharpLabel 帶有 HTML 的浮水印 pdf.ApplyWatermark("<h2 style='color:red;'>CONFIDENTIAL</h2>"); pdf.ApplyWatermark("<h2 style='color:red;'>CONFIDENTIAL</h2>"); $vbLabelText $csharpLabel 功能對比總結 特徵 PDFSharp IronPDF 基於座標的繪圖 ✓ ✗(使用 HTML) HTML 轉 PDF ✗ ✓ CSS3 支持 ✗ ✓ Flexbox/網格佈局 ✗ ✓ 文字印章 XGraphics 手冊 文字印章 圖像印章 手動 XImage 圖像印章 合併PDF 手動的 ✓ PDF檔案的URL ✗ ✓ 現代網頁渲染 ✗ 鉻引擎 自動分頁符 ✗ ✓ 遷移清單 遷移前 清點程式碼庫中所有 PDFSharp 的使用情況 識別正在產生的文件類型(報告、發票、證書) 注意任何自訂圖形或繪圖操作 規劃 IronPDF 許可證密鑰儲存(建議使用環境變數) 先使用 IronPDF 試用許可證進行測試 軟體包變更 刪除PdfSharp NuGet 套件 如果已使用,請移除PdfSharp-wpf NuGet 套件 如果已使用,請移除PdfSharp.Charting NuGet 套件。 安裝IronPdf NuGet 套件: dotnet add package IronPdf 程式碼更改 更新命名空間導入( using PdfSharp.Pdf; → using IronPdf; ) 增加using IronPdf.Editing;以實現蓋章功能 將基於座標的佈局轉換為 HTML/CSS 將XFont替換為 CSS 字型屬性 將XBrush / XPen替換為 CSS 顏色/邊框。 將XGraphics.DrawString()替換為 HTML 文字元素 將XGraphics.DrawImage()替換為 HTML<img>標籤 將PdfReader.Open()替換為PdfDocument.FromFile() 將document.Save()替換為pdf.SaveAs() 將表格繪製程式碼轉換為 HTML 表格 移民後 產生PDF檔案的可視化比較 測試多頁文檔 驗證字體渲染 依需求新增功能(HTML 轉 PDF、合併、浮水印) Curtis Chau 立即與工程團隊聊天 技術撰稿人 Curtis Chau 擁有電腦科學學士學位(卡爾頓大學),專長於前端開發,精通 Node.js、TypeScript、JavaScript 和 React。Curtis 對製作直覺且美觀的使用者介面充滿熱情,他喜歡使用現代化的架構,並製作結構良好且視覺上吸引人的手冊。除了開發之外,Curtis 對物聯網 (IoT) 也有濃厚的興趣,他喜歡探索整合硬體與軟體的創新方式。在空閒時間,他喜歡玩遊戲和建立 Discord bots,將他對技術的熱愛與創意結合。 相關文章 發表日期 2026年2月1日 How to Migrate from ZetPDF to IronPDF in C# Master the migration from ZetPDF to IronPDF with this complete C# guide. Switch from a coordinate-based library to a modern HTML-to-PDF solution. Includes code examples for HTML conversion, merging PDFs, and removing PDFSharp dependencies. 閱讀更多 發表日期 2026年2月1日 How to Migrate from Scryber.Core to IronPDF in C# Master the migration from Scryber.Core to IronPDF with this complete C# guide. Switch from custom XML/HTML parsing to a modern Chromium renderer. Includes code examples for HTML conversion, URL rendering, and replacing proprietary bindings. 閱讀更多 發表日期 2026年2月1日 How to Migrate from XFINIUM.PDF to IronPDF in C# Master the migration from XFINIUM.PDF to IronPDF with this complete C# guide. Switch from manual coordinate-based positioning to declarative HTML/CSS rendering. Includes code examples for replacing graphics primitives and automatic layout. 閱讀更多 How to Migrate from PDFView4NET to IronPDF in C#How to Migrate from PDFreactor to I...
發表日期 2026年2月1日 How to Migrate from ZetPDF to IronPDF in C# Master the migration from ZetPDF to IronPDF with this complete C# guide. Switch from a coordinate-based library to a modern HTML-to-PDF solution. Includes code examples for HTML conversion, merging PDFs, and removing PDFSharp dependencies. 閱讀更多
發表日期 2026年2月1日 How to Migrate from Scryber.Core to IronPDF in C# Master the migration from Scryber.Core to IronPDF with this complete C# guide. Switch from custom XML/HTML parsing to a modern Chromium renderer. Includes code examples for HTML conversion, URL rendering, and replacing proprietary bindings. 閱讀更多
發表日期 2026年2月1日 How to Migrate from XFINIUM.PDF to IronPDF in C# Master the migration from XFINIUM.PDF to IronPDF with this complete C# guide. Switch from manual coordinate-based positioning to declarative HTML/CSS rendering. Includes code examples for replacing graphics primitives and automatic layout. 閱讀更多