以程序設計方式操作 Visio 檔案格式
瞭解如何在 Visual Studio 2012 中建立解決方案,以讀取 Visio 2013 中的新檔格式套件、選取套件中的元件、變更元件中的數據,以及將新的元件新增至套件。
Visio 檔案格式操作基本資訊
舊版 Visio 已將檔案儲存為專屬二進位檔格式 (.vsd) 或單一檔 Visio XML 繪圖檔格式 (.vdx) 。 Visio 2013 引進以 XML 和 ZIP 封存技術為基礎的新檔格式 (.vsdx) 。 如同舊版 Visio,檔案會儲存在單一容器中。 不過,不同於舊版檔案,新的檔格式可以開啟、讀取、更新、變更及建構,而不需要自動化 Visio 2013 應用程式。 熟悉操作 XML 或使用 System.IO.Packaging 命名空間的開發人員,可以透過程式設計方式快速開始使用新的檔案格式。 曾使用舊版 Visio XML 繪圖格式的開發人員,可以發現該格式的許多結構都以新的檔格式保留。
在本文中,我們將探討如何使用 Microsoft .NET Framework 4.5、C# 或 Visual Basic,以及 Visual Studio 2012,以程式設計方式使用 Visio 2013 檔格式。 您可以瞭解如何開啟 Visio 2013 檔案、選取檔案內的檔元件、變更元件中的數據,以及建立新的檔案元件。
注意事項
本文中的程式代碼範例假設您對System.Xml 中的類別有基本的瞭解 。Linq 和 System.IO.Packaging 命名空間。 本文也假設您了解開放式封裝慣例的概念和術語。 您應該熟悉套件、檔元件或套件元件的概念,以及關聯性。 如需詳細資訊,請參閱 OPC:封裝數據的新標準。 此程式代碼示範如何建立 LINQ (Language-Integrated Query) 查詢來選取 XML。 大部分的程式代碼範例都會使用查詢語法來建置LINQ查詢。 如有必要,您可以使用 LINQ 方法語法,重寫程式代碼中提供的任何 LINQ 查詢。 如需 LINQ 查詢語法和方法語法的詳細資訊,請參閱 LINQ 查詢語法與方法語法 (C#) 表 1 顯示您在完成本文之前應該熟悉的基本主題。
表 1. 操作 Visio 2013 檔案格式的核心概念
文章標題 | 描述 |
---|---|
Visio 檔案格式 (.vsdx) 簡介 |
此高階概觀說明 Visio 2013 檔格式的一些主要功能。 其中討論 OPC (開放式封裝慣例) ,因為這些慣例已套用至 Visio 2013 檔格式。 它也會列出 Visio 2013 檔案格式與先前 Visio XML 繪圖檔格式 (.vdx) 之間的一些差異。 |
OPC:封裝數據的新標準 |
這篇 MSDN Magazine 文章將開放式封裝慣例描述為概念。 |
開放式封裝慣例的基本概念 Office (2007) Open XML 檔格式簡介 |
這兩篇文章討論開放式封裝慣例如何套用至 Microsoft Office 檔案。 其中包含關聯性如何在套件中運作的描述,並包含一些程式碼範例。 |
建立.vsdx檔案和新的Visual Studio解決方案
您必須先建立 Visio 2013 檔案來開啟和操作,才能開始完成本文中的程式。 本文程式代碼範例中使用的繪圖包含單一頁面,其中有兩個連接的圖形,其中一個圖形是來自「基本流程圖」範本的「開始/結束」圖形。
使用下列程式來建立新的 Visio 2013 檔案,以在本文的其餘程式中使用。
在 Visio 2013 中建立新檔案
開啟 Visio 2013.
選擇 [類別]、[流程圖]、[基本流程圖]、[建立],以基本流程圖範本為基礎建立新檔。
從 [ 圖形] 視窗中,將 [開始/結束 ] 圖形拖曳到畫布上。
選取繪圖畫布上的新 [開始/結束] 圖形,然後輸入 'Begin Process'。
從 [ 圖形] 視窗中,將 [處理] 圖形拖曳到畫布上。
選取繪圖畫布上的新 [處理] 圖形,然後輸入「執行一些工作」。
在 [開始/結束] 圖形的快捷方式功能表上,選取 [將 一個連接器新增至頁面],然後在畫布上的 [開始/結束] 和 [處理] 圖形之間繪製連接器,如圖 1 所示。
圖 1: 簡單的 Visio 2013 繪圖
選擇 [檔案]、[另存新檔]、[計算機]、[桌面],將檔案儲存至您的 Desktop,作為.vsdx檔案。
在 [另存新檔] 對話方塊的 [檔名] 方塊中輸入 Visio 套件“,選取 [另存新檔類型] 清單中的 [Visio 繪圖 (*.vsdx) ],然後選擇 [儲存] 按鈕。
關閉檔案,然後關閉 Visio 2013。
提示
有時候,即使檔案發生問題,Visio 還是會成功開啟檔案。 若要確保 Visio 通知您任何檔案問題,您應該在測試在檔案套件層級操作 Visio 檔案的解決方案時啟用檔案開啟警告。 > 若要啟用檔案開啟警告,請在 Visio 2013 中選擇 [檔案]、[ 選項]、[ 進階]。 在 [ 儲存/開啟] 下,選取 [顯示檔案開啟警告]。
這些程式會使用 Windows 控制台應用程式來操作 「Visio Package.vsdx」 檔案。 使用下列程式,在 Visual Studio 2012 中建立和設定新的 Windows 控制台應用程式。
在 Visual Studio 2012 中建立新的解決方案
在 [ 檔案] 功能表上,選擇 [ 新增]、[ 專案]。
在 [ 新增專案] 對話框中,展開 [ Visual C# ] 或 [ Visual Basic],然後選擇 [Windows, 控制台應用程式]。
在 [ 名稱] 方塊中,輸入 'VisioFileAccessor',選取專案的位置,然後選擇 [ 確定] 按鈕。
在 [ 專案] 功能表上,選擇 [ 新增參考]。
在 [ 參考管理員] 對話框的 [ 元件] 下,選擇 [ 架構],然後新增 System.Xml 和 WindowsBase 元件的參考。
在專案的Program.cs或Module1.vb檔案中,在Visual Basic) 中新增下列using指示詞 (Imports 語句:
using System.Xml; using System.Xml.Linq; using System.IO; using System.IO.Packaging; using System.Text;
Imports System.Xml Imports System.Xml.Linq Imports System.IO Imports System.IO.Packaging Imports System.Text
此外,在 Program.cs 或 Module1.vb 檔案中,在 Visual Basic) 中,Program 類別的 Main 方法結尾 (Module1 之前,新增下列程式代碼以停止執行控制台應用程式,直到使用者按下按鍵為止。
// This code stops the execution of the console application // so you can read the output. Console.WriteLine("Press any key to continue ..."); Console.ReadKey();
' This code stops the execution of the console application ' so you can read the output. Console.WriteLine("Press any key to continue ...") Console.ReadKey()
以套件開啟 Visio 2013 檔案
您必須先在包含在 System.IO.Packaging 命名空間內的 Package 物件內開啟檔案,才能操作檔案內的任何數據。 Package 物件代表整個 Visio 檔案。 它會公開可讓您選取檔案套件內個別檔元件的成員。 特別是, Package 類別會公開靜態 Open (String, FileMode, FileAccess) 方法,用來開啟檔案做為封裝。 它也會公開 Close () 方法,以便在您完成封裝之後關閉套件。
提示
最佳做法是 使用 using 區塊在 Package 物件中開啟 Visio 檔案,這樣您就不需要在完成檔案封裝時明確關閉檔案套件。 您也可以在 try/catch/finally 建構的 finally 區塊中明確呼叫 Package.Close 方法。
使用下列程式代碼,使用 FileInfo 物件取得 「Visio Package.vsdx」 檔案的完整路徑、將路徑當做自變數傳遞至 Package.Open 方法,然後將 Package 物件傳回給呼叫端程式代碼。
以套件開啟.vsdx檔案
在 Visual Basic) 的 Program 類別 (或 Module1 中的 Main 方法之後,新增下列程式代碼。
private static Package OpenPackage(string fileName, Environment.SpecialFolder folder) { Package visioPackage = null; // Get a reference to the location // where the Visio file is stored. string directoryPath = System.Environment.GetFolderPath( folder); DirectoryInfo dirInfo = new DirectoryInfo(directoryPath); // Get the Visio file from the location. FileInfo[] fileInfos = dirInfo.GetFiles(fileName); if (fileInfos.Count() > 0) { FileInfo fileInfo = fileInfos[0]; string filePathName = fileInfo.FullName; // Open the Visio file as a package with // read/write file access. visioPackage = Package.Open( filePathName, FileMode.Open, FileAccess.ReadWrite); } // Return the Visio file as a package. return visioPackage; }
Private Function OpenPackage(fileName As String, _ folder As Environment.SpecialFolder) As Package Dim visioPackage As Package = Nothing ' Get a reference to the location ' where the Visio file is stored. Dim directoryPath As String = System.Environment.GetFolderPath( _ folder) Dim dirInfo As DirectoryInfo = New DirectoryInfo(directoryPath) ' Get the Visio file from the location. Dim fileInfos As FileInfo() = dirInfo.GetFiles(fileName) If (fileInfos.Count() > 0) Then Dim fileInfo As FileInfo = fileInfos(0) Dim filePathName As String = fileInfo.FullName ' Open the Visio file as a package ' with read/write access. visioPackage = Package.Open( _ filePathName, FileMode.Open, FileAccess.ReadWrite) End If ' Return the Visio file as a package. Return visioPackage End Function
在 Visual Basic) 中 Program 類別 (或 Module1 的 Main 方法中,新增下列程式代碼。
// Open the Visio file in a Package object. using (Package visioPackage = OpenPackage("Visio Package.vsdx", Environment.SpecialFolder.Desktop)) { }
' Open the Visio file in a Package object. Using visioPackage As Package = OpenPackage("Visio Package.vsdx", _ Environment.SpecialFolder.Desktop) End Using
從封裝中選取和讀取套件元件
當您將 Visio 2013 檔案開啟為套件之後,就可以使用 System.IO.Packaging 命名空間中包含的 PackagePart 類別來存取其中的檔元件。 PackagePart 物件可以個別具現化或做為集合。 Package 類別會公開 GetParts () 方法和 GetPart (Uri) 方法,以將 PackagePart 物件從封裝中取出。 Package.GetParts 方法會傳回 PackagePartCollection 類別的實例,然後您可以像實作 IEnumerator<T> 介面的任何其他集合一樣與其互動。
使用下列程式中的程式代碼,從 Package 取得 PackagePartCollection 對象作為集合、逐一查看集合中的 PackagePart 物件,並將每個 PackagePart 的 URI 和內容類型寫入控制台。
逐一查看封裝中的封裝元件
OpenPackage
在 Visual Basic) 中 Program 類別 (或 Module1 中的 方法之後,新增下列程式代碼。private static void IteratePackageParts(Package filePackage) { // Get all of the package parts contained in the package // and then write the URI and content type of each one to the console. PackagePartCollection packageParts = filePackage.GetParts(); foreach (PackagePart part in packageParts) { Console.WriteLine("Package part URI: {0}", part.Uri); Console.WriteLine("Content type: {0}", part.ContentType.ToString()); } }
Private Sub IteratePackageParts(filePackage As Package) ' Get all of the package parts contained in the package ' and then write the URI and content type of each one to the console. Dim packageParts As PackagePartCollection = filePackage.GetParts() For Each part In packageParts Console.WriteLine("Package part: {0}", part.Uri) Console.WriteLine("Content type: {0}", part.ContentType.ToString()) Next End Sub
將下列程式代碼新增至 Program 類別 Main 方法的 using 區塊內, (Visual Basic 中 Module1 中 Main 方法的 Using 區塊) :
// Write the URI and content type of each package part to the console. IteratePackageParts(visioPackage);
' Write the URI and content type of each package part to the console. IteratePackageParts(visioPackage)
選擇 F5 鍵來偵錯解決方案。 當程式完成執行時,請選擇要結束的任何金鑰。
主控台應用程式會產生類似下列的輸出 (為了簡潔起見,已省略部分輸出) :
Package part URI: /docProps/app.xml
Content type: application/vnd.openxmlformats-officedocument.extended-properties+xml
Package part URI: /docProps/core.xml
Content type: application/vnd.openxmlformats-officedocument.core-properties+xml
Package part URI: /docProps/custom.xml
Content type: application/vnd.openxmlformats-officedocument.custom-properties+xml
Package part URI: /docProps/thumbnail.emv
Content type: image/x-emf
Package part URI: /visio/document.xml
Content type: application/vnd.ms-visio.drawing.main+xml
Package part URI: /visio/_rels/document.xml.rels
Content type: application/vnd.openxmlformats-package.relationships+xml
Package part URI: /_rels/.rels
Content type: application/vnd.openxmlformats-package.relationships+xml
Press any key to continue …
通常,您需要選取一個 PackagePart ,而不需要逐一查看所有套件元件。 您可以使用 Package 或另一個 PackagePart 的關聯性,從 Package 取得 PackagePart 物件。 Visio 2013 檔格式的關聯性是一個離散實體,描述檔元件與檔案套件的關聯性,或兩個檔元件彼此之間的關聯性。 例如,Visio 2013 檔案套件本身與其 Visio Document 元件有關聯性,而 Visio Document 元件與 Windows 元件有關聯性。 這些關聯性會以 PackageRelationship 或 PackageRelationshipCollection 類別的實例表示 。
Package 類別會公開數種方法,以取得其包含為 PackageRelationship 或PackageRelationshipCollection 對象的關聯性。 您可以使用 GetRelationshipsByType (String) 方法來具現化 PackageRelationshipCollection 物件,其中包含單一特定類型的 PackageRelationship 物件。 當然,使用 Package.GetRelationshipsByType 方法需要您已經知道所需的關聯性類型。 關聯性類型是 XML 命名空間格式的字串。 例如,Visio 檔案元件的關聯性類型是 <https://schemas.microsoft.com/visio/2010/relationships/document
>。
一旦您知道 PackagePart 與 Package 或另一個 PackagePart (的關聯性,也就是您有一個 PackageRelationship 物件,該物件會參考您想要) 的 PackagePart ,您可以使用該關聯性來取得該 PackagePart 的 URI。 然後將 URI 傳遞至 Package.GetPart 方法,以傳回 PackagePart。
注意事項
您也可以只使用 Package.GetPart 方法和 PackagePart 的 URI,略過取得封裝元件關聯性的步驟,來取得特定 PackagePart 的參考。 不過,Visio 檔案套件中的某些套件元件可以儲存到套件中預設位置以外的位置。 您不能假設封裝元件一律位於每個檔案的相同 URI。 > 相反地,最佳做法是使用關聯性來存取個別 的 PackagePart 物件。
使用下列程式,從參考元件的套件取得 PackagePart (Visio 檔元件) 。
若要依關聯性選取套件中的特定套件元件
IteratePackageParts
在 Visual Basic) 中 Program 類別 (或 Module1 中的 方法之後,新增下列方法。private static PackagePart GetPackagePart(Package filePackage, string relationship) { // Use the namespace that describes the relationship // to get the relationship. PackageRelationship packageRel = filePackage.GetRelationshipsByType(relationship).FirstOrDefault(); PackagePart part = null; // If the Visio file package contains this type of relationship with // one of its parts, return that part. if (packageRel != null) { // Clean up the URI using a helper class and then get the part. Uri docUri = PackUriHelper.ResolvePartUri( new Uri("/", UriKind.Relative), packageRel.TargetUri); part = filePackage.GetPart(docUri); } return part; }
Private Function GetPackagePart(filePackage As Package, relationship As String) _ As PackagePart ' Use the namespace that describes the relationship ' to get the relationship. Dim packageRel As PackageRelationship = filePackage.GetRelationshipsByType(relationship).FirstOrDefault() Dim part As PackagePart = Nothing ' If the Visio file package contains this type of relationship with ' one of its parts, return that part. If Not IsNothing(packageRel) Then ' Clean up the URI using a helper class and then get the part. Dim docUri = PackUriHelper.ResolvePartUri( _ New Uri("/", UriKind.Relative), packageRel.TargetUri) part = filePackage.GetPart(docUri) End If Return part End Function
將 Program 類別 Main 方法中using 區塊中的程式代碼取代為下列程式代碼 (Visual Basic 中 Module1 中 Main 方法的 Using 區塊) 。
// Get a reference to the Visio Document part contained in the file package. PackagePart documentPart = GetPackagePart(visioPackage, "http://schemas.microsoft.com/visio/2010/relationships/document");
' Get a reference to the Visio Document part contained in the file package. Dim documentPart As PackagePart = GetPackagePart(visioPackage, _ "http://schemas.microsoft.com/visio/2010/relationships/document")
如先前所述,您也可以使用 PackagePart 物件與其他 PackagePart 對象的關聯性來取得 PackagePart 物件。 這很重要,因為對於任何複雜性的 Visio 檔而言,大部分的 PackagePart 物件與 Package 沒有關聯性。 例如,檔案套件中個別的頁面內容元件 (,也就是 /visio/pages/page1.xml) 與頁面索引部分 (有關聯性,也就是 /visio/pages/pages.xml) ,但與檔案套件本身沒有關聯性。 如果您在套件中沒有個別頁面的確切 URI,您可以使用其與頁面索引部分的關聯性來取得其參考。
PackagePart 類別會公開 GetRelationshipsByType (String) 方法,可用來傳回僅包含一種 PackageRelationship 物件類型的 PackageRelationshipCollection 物件。 擁有 PackageRelationshipCollection 之後,您可以從集合中選取所需的 PackageRelationship ,然後參考 PackagePart 物件。
使用下列程式代碼從 Package 取得 PackagePart,方法是使用其關聯性 (從另一個 PackagePart 取得 PackageRelationship 物件) 。
透過特定套件元件與另一個封裝元件的關聯性來選取特定套件元件
GetPackagePart
在 Visual Basic) 的 Program 類別 (或 Module1 中的 方法之後,新增下列多載方法。private static PackagePart GetPackagePart(Package filePackage, PackagePart sourcePart, string relationship) { // This gets only the first PackagePart that shares the relationship // with the PackagePart passed in as an argument. You can modify the code // here to return a different PackageRelationship from the collection. PackageRelationship packageRel = sourcePart.GetRelationshipsByType(relationship).FirstOrDefault(); PackagePart relatedPart = null; if (packageRel != null) { // Use the PackUriHelper class to determine the URI of PackagePart // that has the specified relationship to the PackagePart passed in // as an argument. Uri partUri = PackUriHelper.ResolvePartUri( sourcePart.Uri, packageRel.TargetUri); relatedPart = filePackage.GetPart(partUri); } return relatedPart; }
Private Function GetPackagePart(filePackage As Package, sourcePart As PackagePart, relationship As String) As PackagePart ' This gets only the first PackagePart that shares the relationship ' with the PackagePart passed in as an argument. You can modify the ' code to return a different PackageRelationship from the collection. Dim packageRel As PackageRelationship = sourcePart. _ GetRelationshipsByType(relationship).FirstOrDefault() Dim relatedPart As PackagePart = Nothing If Not IsNothing(packageRel) Then ' Use the PackUriHelper class to determine the URI of the ' PackagePart that has the specified relationship to the ' PackagePart passed in as an argument. Dim partUri As Uri = PackUriHelper.ResolvePartUri( _ sourcePart.Uri, packageRel.TargetUri) relatedPart = filePackage.GetPart(partUri) End If Return relatedPart End Function
將下列程式代碼新增至 Program 類別 Main 方法中的 using 區塊, (Visual Basic) Module1 中 Main 方法的 Using 區塊,位於上一個程式的程式代碼下方。 (請勿刪除您在上一個程式中新增的程式代碼。)
// Get a reference to the collection of pages in the document, // and then to the first page in the document. PackagePart pagesPart = GetPackagePart(visioPackage, documentPart, "http://schemas.microsoft.com/visio/2010/relationships/pages"); PackagePart pagePart = GetPackagePart(visioPackage, pagesPart, "http://schemas.microsoft.com/visio/2010/relationships/page");
' Get a reference to the collection of pages in the document, ' and then to the first page in the document. Dim pagesPart As PackagePart = GetPackagePart(visioPackage, documentPart, _ "http://schemas.microsoft.com/visio/2010/relationships/pages") Dim pagePart As PackagePart = GetPackagePart(visioPackage, pagesPart, _ "http://schemas.microsoft.com/visio/2010/relationships/page")
您必須先使用 XDocument 類別或 XmlDocument 類別,將 XML 檔載入可讓您讀取 XML 的物件,才能變更檔元件中包含的 XML 。 這兩個類別都會公開工作的方法,例如選取 XML 檔中包含的 XML 元素;建立、讀取和寫入屬性;並將新的 XML 元素插入檔案中。
在兩者中, XDocument 類別可讓您使用 LINQ 查詢 XML。 使用 LINQ,您可以建立查詢,輕鬆地從 XML 檔中選取個別元素,而不是逐一查看集合中的所有元素,並測試您需要的專案。 基於這些原因,本文中的下列程式會使用 XDocument 類別和System.Xml 的其他類別 。 使用 XML 的 Linq 命名空間。
使用下列程式,以 XDocument 物件中的 XML 檔開啟 PackagePart。
讀取封裝元件中的 XML
在 Visual Basic) 中 Program 類別 (或 Module1 中方法的最後一個多載
GetPackagePart
之後,新增下列方法。private static XDocument GetXMLFromPart(PackagePart packagePart) { XDocument partXml = null; // Open the packagePart as a stream and then // open the stream in an XDocument object. Stream partStream = packagePart.GetStream(); partXml = XDocument.Load(partStream); return partXml; }
Private Function GetXMLFromPart(packagePart As PackagePart) As XDocument Dim partXml As XDocument = Nothing ' Open the packagePart as a stream and then ' open the stream in an an XDocument object. Dim partStream As Stream = packagePart.GetStream() partXml = XDocument.Load(partStream) Return partXml End Function
將下列程式代碼新增至 Program 類別 Main 方法中的 using 區塊, (Visual Basic) Module1 中 Main 方法的 Using 區塊,位於上一個程式的程式代碼下方。
// Open the XML from the Page Contents part. XDocument pageXML = GetXMLFromPart(pagePart);
' Open the XML from the Page Contents part. Dim pageXML As XDocument = GetXMLFromPart(pagePart)
選取並變更封裝元件中的 XML 數據
將檔案元件載入 XDocument 物件之後,您可以使用 LINQ 來選取 XML 元素,並變更 XML 檔。 您可以變更 XML 資料、新增或移除資料,然後將 XML 檔案儲存回檔案元件。
操作 Visio 檔案格式最常見的工作是選取檔中的特定 XML 元素或元素集合。 System.Xml。Linq 命名空間包含代表 XML 元素的 XElement 類別。 XElement 類別可讓您以細微層級存取 Visio 檔案中包含的數據,從個別的 Shape 元素到 ValidationRule 元素, (作為範例) 。
使用下列程式代碼從包含 [頁面內容] 元件的 XDocument (選取 Shape 元素) 然後選取特定的 Shape 元素。
若要選取封裝元件中的特定專案
GetXMLFromPart
在 Visual Basic) 中 Program 類別 (或 Module1 中的 方法之後,新增下列方法。private static IEnumerable<XElement> GetXElementsByName( XDocument packagePart, string elementType) { // Construct a LINQ query that selects elements by their element type. IEnumerable<XElement> elements = from element in packagePart.Descendants() where element.Name.LocalName == elementType select element; // Return the selected elements to the calling code. return elements.DefaultIfEmpty(null); }
Private Function GetXElementsByName(partXML As XDocument, _ elementType As String) As IEnumerable(Of XElement) ' Construct a LINQ query that selects elements by their element type. Dim elements As IEnumerable(Of XElement) = From element In partXML.Descendants() Where element.Name.LocalName = elementType Select element ' If there aren't any elements of the specified type ' in the document, return Nothing to the calling code. Return elements.DefaultIfEmpty(Nothing) End Function
在上一
GetXElementsByName
個步驟中的 Program 類別 (或 Module1 中的 方法) 之後,新增下列方法。private static XElement GetXElementByAttribute(IEnumerable<XElement> elements, string attributeName, string attributeValue) { // Construct a LINQ query that selects elements from a group // of elements by the value of a specific attribute. IEnumerable<XElement> selectedElements = from el in elements where el.Attribute(attributeName).Value == attributeValue select el; // If there aren't any elements of the specified type // with the specified attribute value in the document, // return null to the calling code. return selectedElements.DefaultIfEmpty(null).FirstOrDefault(); }
Private Function GetXElementByAttribute(elements As IEnumerable(Of XElement), _ attributeName As String, attributeValue As String) As XElement ' Construct a LINQ query that selects elements from a group ' of elements by the value of a specific attribute. Dim selectedElements As IEnumerable(Of XElement) = From el In elements Where el.Attribute(attributeName).Value = attributeValue Select el ' If there aren't any elements of the specified type ' with the specified attribute value in the document, ' return Nothing to the calling code. Return selectedElements.DefaultIfEmpty(Nothing).FirstOrDefault() End Function
將下列程式代碼新增至 Program 類別 Main 方法中的 using 區塊, (Visual Basic) Module1 中 Main 方法的 Using 區塊,位於上一個程式的程式代碼下方。
// Get all of the shapes from the page by getting // all of the Shape elements from the pageXML document. IEnumerable<XElement> shapesXML = GetXElementsByName(pageXML, "Shape"); // Select a Shape element from the shapes on the page by // its name. You can modify this code to select elements // by other attributes and their values. XElement startEndShapeXML = GetXElementByAttribute(shapesXML, "NameU", "Start/End");
' Get all of the shapes from the page by getting ' all of the Shape elements from the pageXML document. Dim shapesXML As IEnumerable(Of XElement) = GetXElementsByName( _ pageXML, "Shape") ' Select a Shape element from the shapes on the page by ' its name. You can modify this code to select elements ' by other attributes and their values. Dim startEndShapeXML As XElement = GetXElementByAttribute( _ shapesXML, "NameU", "Start/End")
取得 XDocument 物件內含之 XElement 對象的參考後,您可以像其他任何 XML 數據一樣操作該物件,藉此變更包含在 Visio 檔案中的數據。 例如,如果圖形在 Visio 中開啟時有文字,對應的 Shape 元素將包含至少一個 Text 元素。 如果您變更該 Text 元素的值,在 Visio 中檢視檔案時,圖形的文字會變更。
將下列程式代碼新增至 Program 類別 Main 方法中的 using 區塊, (Visual Basic 中 Module1 中 Main 方法的 Using 區塊,) 將開始/結束圖形中的文字從 “Begin process” 變更為 “Start process”。
// Query the XML for the shape to get the Text element, and
// return the first Text element node.
IEnumerable<XElement> textElements = from element in startEndShapeXML.Elements()
where element.Name.LocalName == "Text"
select element;
XElement textElement = textElements.ElementAt(0);
// Change the shape text, leaving the <cp> element alone.
textElement.LastNode.ReplaceWith("Start process");
' Query the XML for the shape to get the Text element, and
' return the first Text element node.
Dim textElements As IEnumerable(Of XElement) =
From element In startEndShapeXML.Elements()
Where element.Name.LocalName == "Text"
Select element
Dim textElement As XElement = textElements.ElementAt(0)
' Change the shape text, leaving the <cp> element alone.
textElement.LastNode.ReplaceWith("Start process")
注意
在先前的程式代碼範例中,現有的圖形文字和用來取代它的字串具有相同的字元數。 另請注意,LINQ 查詢會變更傳回項目的最後一個子節點的值 (在此案例中為文字節點) 。 這麼做是為了避免變更 Text 元素子系之 cp 元素的設定。 > 如果您藉由覆寫 Text 元素的所有子系,以程式設計方式改變圖形文字,可能會導致檔案不穩定。 如上述範例所示,文字格式設定是由檔案中 Text 元素下的 cp 元素表示。 格式的定義會儲存在父 Section 元素中。 如果這兩項資訊變得不一致,則檔案的行為可能不如預期。 Visio 會修復許多不一致的情況,但最好確保任何程式設計變更都一致,讓您控制檔案的最終行為。
當您變更檔元件的 XML 時,這些變更只會存在於記憶體中。 若要保存檔案中的變更,您必須將 XML 儲存回檔案元件。
下列程式代碼會使用 XmlWriter 類別和 XmlWriterSettings 類別,將 XML 寫回封裝元件。 雖然您可以使用 Save () 方法將 XML 儲存回元件, 但是 XmlWriter 和 XmlWriterSettings 類別可讓您更精細地控制輸出,包括指定編碼類型。 XDocument 類別會公開 WriteTo (XmlWriter) 方法,該方法會採用 XmlWriter 物件並將 XML 寫回數據流。
使用下列程式,將 XML 從 Visio 頁面儲存回 [頁面內容] 部分。
將變更的 XML 儲存回封裝
在上一
GetXElementByAttribute
個步驟中的 Program 類別 (或 Module1 中的 方法) 之後,新增下列方法。private static void SaveXDocumentToPart(PackagePart packagePart, XDocument partXML) { // Create a new XmlWriterSettings object to // define the characteristics for the XmlWriter XmlWriterSettings partWriterSettings = new XmlWriterSettings(); partWriterSettings.Encoding = Encoding.UTF8; // Create a new XmlWriter and then write the XML // back to the document part. XmlWriter partWriter = XmlWriter.Create(packagePart.GetStream(), partWriterSettings); partXML.WriteTo(partWriter); // Flush and close the XmlWriter. partWriter.Flush(); partWriter.Close(); }
Private Sub SaveXDocumentToPart(packagePart As PackagePart, _ partXML As XDocument) ' Create a new XmlWriterSettings object to ' define the characteristics for the XmlWriter. Dim partWriterSettings As XmlWriterSettings = New XmlWriterSettings() partWriterSettings.Encoding = Encoding.UTF8 ' Create a new XmlWriter and then write the XML ' back to the document part. Dim partWriter As XmlWriter = XmlWriter.Create(packagePart.GetStream()) partXML.WriteTo(partWriter) ' Flush and close the XmlWriter. partWriter.Flush() partWriter.Close() End Sub
將下列程式代碼新增至 Program 類別 Main 方法中的 using 區塊, (Visual Basic) Module1 中 Main 方法的 Using 區塊,位於上一個程式的程式代碼下方。
// Save the XML back to the Page Contents part. SaveXDocumentToPart(pagePart, pageXML);
' Save the XML back to the Page Contents part. SaveXDocumentToPart(pagePart, pageXML)
選擇 F5 鍵來偵錯解決方案。 當程式完成執行時,請選擇要結束的任何金鑰。
在 Visio 2013 中開啟 Visio Package.vsdx 檔案。
開始/結束圖形現在應該包含文字「開始進程」。
重新計算檔案中的數據
檔案中數據的某些變更可能需要 Visio 在開啟檔案時重新計算檔。 Visio 會為圖表提供許多邏輯,特別是針對圖形關聯性 (,也就是當某個圖形相依於另一個) 並連接圖形時。 如果自定義邏輯所依賴的任何數據變更,Visio 就必須將變更傳播至檔案中所有受影響的導出數據。
Visio 2013 檔格式包含幾種技術,可用來重新計算檔案中的數據。 當您決定是否需要重新計算 Visio 檔案及其作法時,必須考慮三種類型的案例:
數據的變更不會影響檔格式中的任何其他值。 您不需要將任何其他指示新增至 Visio,即可重新計算檔。 如先前所示,您通常可以變更圖形的文字,而不需要重新計算檔。
數據的變更僅限於變更 XML 中 ShapeSheet 單元格的值,而且還有其他相依於此數據的 ShapeSheet 值。 在此情況下,您必須使用 XProcessingInstruction 類別) 將 XML 處理指令新增至已變更的 Cell 元素 (。 例如,圖形的 ThemeIndex 單元格會影響圖形中包含的數個其他 ShapeSheet 單元格的值。 例如,如果您將檔案本身內 的 ThemeIndex 單元格變更 (,則N 值為 “ThemeIndex” 的 Cell 元素 ) ,您必須將處理指令新增至 Cell 元素,以便更新相依值。
數據的變更會影響連接器或連接點的位置。 另一種情況是 ShapeSheet 數據有許多變更,而您想要使用一個指令 (重新計算整份檔,而不是為每個變更) 新增個別的處理指示。 在此情況下,您可以指示 Visio 在開啟整份檔時重新計算。 若要這麼做,請將 RecalcDocument 屬性新增至 Visio 套件的 /docProps/custom.xml) (自定義檔案屬性部分。 調整連線圖表中圖形的位置或大小是這類案例的範例。
請記住,從效能的觀點來看,這是成本最高的選項。
使用下列程式將 Cell 元素插入 Shape 元素中,其中相同 Shape 中的其他 Cell 元素必須因為新的值而重新計算。 新的 Cell 元素包含做為子元素的處理指令,以通知 Visio 它需要執行一些本機重新計算。
重新計算單一圖形的值
使用下列程式代碼取代前兩個範例中的程式代碼, (變更圖形的文字,以及在 Program 類別 Main 方法的using區塊中呼叫
SaveXDocumentToPart
) , (Visual Basic 中 Module1 中 Main 方法的 Using 區塊) 。// Insert a new Cell element in the Start/End shape that adds an arbitrary // local ThemeIndex value. This code assumes that the shape does not // already have a local ThemeIndex cell. startEndShapeXML.Add(new XElement("Cell", new XAttribute("N", "ThemeIndex"), new XAttribute("V", "25"), new XProcessingInstruction("NewValue", "V"))); // Save the XML back to the Page Contents part. SaveXDocumentToPart(pagePart, pageXML);
' Insert a new Cell element in the shape that adds an arbitrary local ' ThemeIndex value. This code assumes that the shape does not ' already have a local ThemeIndex cell. startEndShapeXML.Add(New XElement("Cell", _ New XAttribute("N", "ThemeIndex"), New XAttribute("V", "25"), New XProcessingInstruction("NewValue", "V"))) ' Save the XML back to the Page Contents part. SaveXDocumentToPart(pagePart, pageXML)
選擇 F5 鍵來偵錯解決方案。 當程式完成執行時,請選擇要結束的任何金鑰。
在 Visio 2013 中開啟 Visio Package.vsdx 檔案。 開始/結束圖形現在應該有不同的填滿色彩。
圖形的色彩依賴 ThemeIndex 單元格的值,它會決定圖形繼承自哪一個使用中的主題。 在上一個範例中,圖形會設定為繼承自不同的主題 (ThemeIndex 單元格設定為 “25”) 值。 如果您未使用處理指令,則不會重新計算圖形的文字色彩,也受 ThemeIndex 單元格影響。 圖形的填滿色彩會變更為白色,但其文字會保持白色,讓文字無法讀取。 此外,如果沒有處理指令,Visio 可能會在稍後更新圖形,讓檔案處於不穩定的狀態,而圖形的格式設定值可能無法預期地更新。
如果您變更檔案中需要 Visio 重新計算檔 (例如,變更連接圖形的位置,因而強制連接器重新路由) ,則必須將重新計算指令新增至 Visio 檔案。 指令的建立方式是將名稱屬性值為 “RecalcDocument” 的屬性元素新增至 Visio 檔案套件之 [自定義檔案屬性] 部分的 XML。 最佳做法是檢查自定義檔案屬性部分,以確定 “RecalcDocument” 指令尚未在檔案中註冊。
使用下列程式代碼來變更上一個範例中開始/結束圖形之 PinY 單元格的值。 程序代碼會使用其 N 屬性的值,將包含 PinY 單元格數據的 Cell 元素選取為 XElement 物件。 然後,程式代碼會將重新計算指令新增至 Visio 檔案的自定義檔案屬性部分。
注意事項
此程式代碼依賴先前建立的 GetPackagePart
和 SaveXDocumentToPart
方法。
若要在開啟整個檔時重新計算
在上一
SaveXDocumentToPart
個步驟中的 Program 類別 (或 Module1 中的 方法) 之後,新增下列方法。private static void RecalcDocument(Package filePackage) { // Get the Custom File Properties part from the package and // and then extract the XML from it. PackagePart customPart = GetPackagePart(filePackage, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/" + "custom-properties"); XDocument customPartXML = GetXMLFromPart(customPart); // Check to see whether document recalculation has already been // set for this document. If it hasn't, use the integer // value returned by CheckForRecalc as the property ID. int pidValue = CheckForRecalc(customPartXML); if (pidValue > -1) { XElement customPartRoot = customPartXML.Elements().ElementAt(0); // Two XML namespaces are needed to add XML data to this // document. Here, we're using the GetNamespaceOfPrefix and // GetDefaultNamespace methods to get the namespaces that // we need. You can specify the exact strings for the // namespaces, but that is not recommended. XNamespace customVTypesNS = customPartRoot.GetNamespaceOfPrefix("vt"); XNamespace customPropsSchemaNS = customPartRoot.GetDefaultNamespace(); // Construct the XML for the new property in the XDocument.Add method. // This ensures that the XNamespace objects will resolve properly, // apply the correct prefix, and will not default to an empty namespace. customPartRoot.Add( new XElement(customPropsSchemaNS + "property", new XAttribute("pid", pidValue.ToString()), new XAttribute("name", "RecalcDocument"), new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"), new XElement(customVTypesNS + "bool", "true") )); } // Save the Custom Properties package part back to the package. SaveXDocumentToPart(customPart, customPartXML); }
Private Sub RecalcDocument(filePackage As Package) ' Get the Custom File Properties part from the package and ' then extract the XML from it. Dim customPart As PackagePart = GetPackagePart(filePackage, _ "http://schemas.openxmlformats.org/officeDocument/2006/" + _ "relationships/custom-properties") Dim customPartXML As XDocument = GetXMLFromPart(customPart) ' Check to see whether document recalculation has already been ' set for this document. If it hasn't, use the integer ' value returned by CheckForRecalc as the property ID. Dim pidValue As Integer = CheckForRecalc(customPartXML) If (pidValue > 1) Then Dim customPartRoot As XElement = _ customPartXML.Elements().ElementAt(0) ' Two XML namespaces are needed to add XML data to this ' document. Here, we're using the GetNamespaceOfPrefix and ' GetDefaultNamespace methods to get the namespaces that ' we need. You can specify the exact strings for the ' namespaces, but that is not recommended. Dim customVTypesNS As XNamespace = _ customPartRoot.GetNamespaceOfPrefix("vt") Dim customPropsSchemaNS As XNamespace = _ customPartRoot.GetDefaultNamespace() ' Contruct the XML for the new property in the XDocument.Add ' method. This ensures that the XML namespaces resolve ' properly, apply the correct prefix, and do not default to ' an empty namespace. customPartRoot.Add( _ New XElement(customPropsSchemaNS + "property", _ New XAttribute("pid", pidValue.ToString()), _ New XAttribute("name", "RecalcDocument"), _ New XAttribute("fmtid", _ "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"), _ New XElement(customVTypesNS + "bool", "true") _ )) ' Save the Custom Properties package part back to the package. SaveXDocumentToPart(customPart, customPartXML) End If End Sub
在上一
RecalcDocument
個步驟中的 Program 類別 (或 Module1 中的 方法) 之後,新增下列方法。private static int CheckForRecalc(XDocument customPropsXDoc) { // Set the inital pidValue to -1, which is not an allowed value. // The calling code tests to see whether the pidValue is // greater than -1. int pidValue = -1; // Get all of the property elements from the document. IEnumerable<XElement> props = GetXElementsByName( customPropsXDoc, "property"); // Get the RecalcDocument property from the document if it exists already. XElement recalcProp = GetXElementByAttribute(props, "name", "RecalcDocument"); // If there is already a RecalcDocument instruction in the // Custom File Properties part, then we don't need to add another one. // Otherwise, we need to create a unique pid value. if (recalcProp != null) { return pidValue; } else { // Get all of the pid values of the property elements and then // convert the IEnumerable object into an array. IEnumerable<string> propIDs = from prop in props where prop.Name.LocalName == "property" select prop.Attribute("pid").Value; string[] propIDArray = propIDs.ToArray(); // Increment this id value until a unique value is found. // This starts at 2, because 0 and 1 are not valid pid values. int id = 2; while (pidValue == -1) { if (propIDArray.Contains(id.ToString())) { id++; } else { pidValue = id; } } } return pidValue; }
Private Function CheckForRecalc(customPropsXDoc As XDocument) As Integer ' Set the initial pidValue to -1, which is not an allowed value. ' The calling code test to see whether the pidValue is ' greater than -1. Dim pidValue As Integer = -1 ' Get all of the property elements from the document. Dim props As IEnumerable(Of XElement) = GetXElementsByName( _ customPropsXDoc, "property") ' Get the RecalcDocument property from the document if ' it exists already. Dim recalcProp As XElement = GetXElementByAttribute(props, _ "name", "RecalcDocument") ' If there is already a RecalcDocument instruction in the ' Custom File Properties part, then we don't need another one. ' Otherwise, we need to create a unique pid value. If Not IsNothing(recalcProp) Then Return pidValue Else ' Get all of the pid values of the proeprty elements and then ' convert the IEnumerable object into an array. Dim propIDs As IEnumerable(Of String) = _ From prop In props Where prop.Name.LocalName = "property" Select prop.Attribute("pid").Value Dim propIDArray As String() = propIDs.ToArray() ' Increment this id value until a unique value is found. ' This starts at 2, because 0 and 1 are not valid pid values. Dim id As Integer = 2 While (pidValue = -1) If (propIDArray.Contains(id.ToString())) Then id = id + 1 Else pidValue = id End If End While End If Return pidValue End Function
將 Program 類別 Main 方法中using 區塊中先前範例中的程式代碼取代為下列程式代碼, (Visual Basic) 中 Module1 中 Main 方法的 Using 區塊。
// Change the shape's horizontal position on the page // by getting a reference to the Cell element for the PinY // ShapeSheet cell and changing the value of its V attribute. XElement pinYCellXML = GetXElementByAttribute( startEndShapeXML.Elements(), "N", "PinY"); pinYCellXML.SetAttributeValue("V", "2"); // Add instructions to Visio to recalculate the entire document // when it is next opened. RecalcDocument(visioPackage); // Save the XML back to the Page Contents part. SaveXDocumentToPart(pagePart, pageXML);
' Change the shape's horizontal position on the page ' by getting a reference to the Cell element for the PinY ' ShapeSheet cell and changing the value of its V attribute. Dim pinYCellXML As XElement = GetXElementByAttribute( startEndShapeXML.Elements(), "N", "PinY") pinYCellXML.SetAttributeValue("V", "2") ' Add instructions to Visio to recalculate the entire document ' when it is next opened. RecalcDocument(visioPackage) ' Save the XML back to the Page Contents part. SaveXDocumentToPart(pagePart, pageXML)
選擇 F5 鍵來偵錯解決方案。 當程式完成執行時,請選擇要結束的任何金鑰。
在 Visio 2013 中開啟 Visio Package.vsdx 檔案。
開始/結束圖形現在應該距離繪圖的下邊緣 2 英吋。 開始/結束圖形與進程圖形之間的連接器應該已重新路由,以配合版面配置中的變更。 如果 尚未將 RecalcDocument 屬性新增至檔案,則圖形位置會變更,但連接器不會重新路由至圖形的新位置。
將新的套件元件新增至套件
修改檔案套件的最常見案例之一是將新的檔元件新增至套件。 例如,如果您想要藉由將內容新增至套件,將頁面新增至 Visio 繪圖,您需要將頁面內容部分新增至套件。
將新元件新增至套件的程序很簡單:
您可以使用 PackagePart 的數據來建立 XML 檔。 您必須特別注意控管所建立之特定 XML 檔類型之架構的 XML 命名空間。
您會建立新檔案以包含 XML,並將檔案儲存至 封裝中的位置。
您可以在新的 PackagePart 與 Package或其他PackagePart 物件之間建立必要的關聯性。
您會更新任何需要參考新元件的現有元件。 例如,如果您將新的 [頁面內容] 元件 (新頁面) 新增至檔案,您也需要將 [頁面索引] 元件更新 (/visio/pages/pages.xml 檔案) ,以包含新頁面的正確資訊。
使用下列程式在 Visio 檔案中建立新的功能區擴充性部分。 新的功能區擴充性元件會將包含單一按鈕的單一群組新索引標籤新增至功能區。
若要建立新的套件元件
CheckForRecalc
在上一個程式的 Program 類別 (或 Module1 中的 方法) 之後,新增下列方法。private static XDocument CreateCustomUI() { // Add a new Custom User Interface document part to the package. // This code adds a new CUSTOM tab to the ribbon for this // document. The tab has one group that contains one button. XNamespace customUINS = "http://schemas.microsoft.com/office/2006/01/customui"; XDocument customUIXDoc = new XDocument( new XDeclaration("1.0", "utf-8", "true"), new XElement(customUINS + "customUI", new XElement(customUINS + "ribbon", new XElement(customUINS + "tabs", new XElement(customUINS + "tab", new XAttribute("id", "customTab"), new XAttribute("label", "CUSTOM"), new XElement(customUINS + "group", new XAttribute("id", "customGroup"), new XAttribute("label", "Custom Group"), new XElement(customUINS + "button", new XAttribute("id", "customButton"), new XAttribute("label", "Custom Button"), new XAttribute("size", "large"), new XAttribute("imageMso", "HappyFace") ) ) ) ) ) ) ); return customUIXDoc; }
Private Function CreateCustomUI() As XDocument ' Add a new Custom User Interface document part to the package. ' This code adds a new CUSTOM tab to the ribbon for this ' document. The tab has one group that contains one button. Dim customUINS As XNamespace = _ "http://schemas.microsoft.com/office/2006/01/customui" Dim customUIXML = New XDocument( _ New XDeclaration("1.0", "utf-8", "true"), _ New XElement(customUINS + "customUI", _ New XElement(customUINS + "ribbon", New XElement(customUINS + "tabs", New XElement(customUINS + "tab", New XAttribute("id", "customTab"), New XAttribute("label", "CUSTOM"), New XElement(customUINS + "group", New XAttribute("id", "customGroup"), New XAttribute("label", "Custom Group"), New XElement(customUINS + "button", New XAttribute("id", "customButton"), New XAttribute("label", "Custom Button"), New XAttribute("size", "large"), New XAttribute("imageMso", "HappyFace") ) ) ) ) ) ) ) Return customUIXML End Function
在上一
CreateCustomUI
個步驟中的 Program 類別 (或 Module1 中的 方法) 之後,新增下列方法。private static void CreateNewPackagePart(Package filePackage, XDocument partXML, Uri packageLocation, string contentType, string relationship) { // Need to check first to see whether the part exists already. if (!filePackage.PartExists(packageLocation)) { // Create a new blank package part at the specified URI // of the specified content type. PackagePart newPackagePart = filePackage.CreatePart(packageLocation, contentType); // Create a stream from the package part and save the // XML document to the package part. using (Stream partStream = newPackagePart.GetStream(FileMode.Create, FileAccess.ReadWrite)) { partXML.Save(partStream); } } // Add a relationship from the file package to this // package part. You can also create relationships // between an existing package part and a new part. filePackage.CreateRelationship(packageLocation, TargetMode.Internal, relationship); }
Private Sub CreateNewPackagePart(filePackage As Package, _ partXML As XDocument, packageLocation As Uri, contentType As String, _ relationship As String) ' Need to check first to see whether the part exists already. If Not (filePackage.PartExists(packageLocation)) Then ' Create a new blank package part at the specified URI ' of the specified content type. Dim newPart As PackagePart = filePackage.CreatePart(packageLocation, _ contentType) ' Create a stream from the package part and save the ' XML document to the package part. Using partStream As Stream = newPart.GetStream(FileMode.Create, _ FileAccess.ReadWrite) partXML.Save(partStream) End Using ' Add a relationship from the file package to this ' package part. You can also create relationships ' between an existing package part and a new part. filePackage.CreateRelationship(packageLocation, _ TargetMode.Internal, relationship) End If End Sub
將 Program 類別 Main 方法中using 區塊中的所有程式代碼, (Visual Basic) Module1 中 Main 方法的 Using 區塊取代為下列程式代碼。
// Create a new Ribbon Extensibility part and add it to the file. XDocument customUIXML = CreateCustomUI(); CreateNewPackagePart(visioPackage, customUIXML, new Uri("/customUI/customUI1.xml", UriKind.Relative), "application/xml", "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility");
' Create a new Ribbon Extensibility part and add it to the file. Dim customUIXML As XDocument = CreateCustomUI() CreateNewPackagePart(visioPackage, customUIXML, _ New Uri("/customUI/customUI1.xml", UriKind.Relative), _ "application/xml", _ "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility")
選擇 F5 鍵來偵錯解決方案。 當程式完成執行時,請選擇要結束的任何金鑰。
在 Visio 2013 中開啟 Visio Package.vsdx檔案,然後選擇 [自定義] 索引標籤。
在 Visio 2013 中開啟檔案時,自定義功能區看起來就像圖 2。
圖 2: Visio 2013 功能區中的自定義索引標籤
方法所建立的 CreateCustomUI
XML 如下所示。
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
<tab id="customTab" label="CUSTOM">
<group id="customGroup" label="Custom Group">
<button id="customButton" label="Custom Button" size="large"
imageMso="HappyFace" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
致謝
我們想要辨識 Visio MVP Al Edlund 在建立本技術文章中包含的程式碼範例時的貢獻和輸入。 Al 是操作 Visio 檔案格式的辨識專家,包括 Visio XML 繪圖格式 (.vdx) 和新的 Visio 檔格式 (.vsdx) 。 Al 已建立專案,以程序設計方式探索 Visio 檔格式,並在其中公開結構。
如需 Al 使用 Visio 檔格式的詳細資訊,請參閱下列一節中的連結。
另請參閱
由 Al Edlund:
pkgVisio - CodePlex 上的 Visio 2013 XML 操作 (
https://pkgvisio.codeplex.com/documentation
) 專案。pkgVisio_pt1 YouTube 上的影片。
pkgVisio_pt2 YouTube 上的影片。