共用方式為


了解 DSL 程式碼

網域指定的語言 (DSL) 方案會產生可用來讀取及更新 Visual Studio 中之 DSL 執行個體的應用程式開發介面。 這個應用程式開發介面是以從 DSL 定義產生的程式碼來定義。 本主題說明產生的應用程式開發介面。

範例方案:元件圖表

若要建立本主題中大多數範例的來源方案,請從 [元件模型] 方案範本建立 DSL。 這是您建立新的 DSL 方案時所顯示的其中一個標準範本。

注意事項注意事項

元件圖表 DSL 範本與 UML 元件範本無關,後者可透過 Visual Studio Ultimate 中的 [架構] 功能表來建立。在 [新增專案] 對話方塊中,展開 [其他專案類型\擴充性],然後按一下 [網域指定的語言設計工具]。

如果您對這個方案範本不熟悉,請按 F5 鍵進行實驗。 請特別注意,您可以將通訊埠工具拖曳到元件上來建立通訊埠,也可以連接通訊埠。

元件和相互連接的通訊埠

DSL 方案的結構

Dsl 專案定義 DSL 的應用程式開發介面。 DslPackage 專案定義與 Visual Studio 的整合方式。 您也可以加入自己的專案,這些專案也可以包含從模型產生的程式碼。

程式碼目錄

上述每個專案中的大多數程式碼都是從 Dsl\DslDefinition.dsl 產生而來。 產生的程式碼會在 Generated Code 資料夾中。 若要查看產生的檔案,請按一下產生之 .tt 檔案旁的 [+]

建議您檢查產生的程式碼,以協助您了解 DSL。 若要查看產生的檔案,請展開 [方案總管] 中的 *.tt 檔。

*.tt 檔包含很少的產生程式碼。 相反地,這些檔案使用 <#include> 指示詞來包含共用範本檔案。 您可以在 \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\DSL SDK\DSL Designer\11.0\TextTemplates 中找到共用檔案。

當您將自己的程式碼加入至 DSL 方案時,請將此程式碼加入至 Generated Code 資料夾外部的其他檔案中。 您可能需要建立 Custom Code 資料夾。 (當您將新的程式碼檔案加入至自訂資料夾時,請記得修正初始程式碼基本架構中的命名空間)。

強烈建議您不要直接編輯產生的程式碼,因為當您重建方案時,您的編輯將會遺失。 相反地,若要自訂您的 DSL:

  • 調整 DSL 定義中的許多參數。

  • 以不同的程式碼檔案撰寫部分類別,覆寫產生的類別中所定義或繼承的方法。 在某些情況下,您必須針對 DSL 定義中的類別設定 [產生雙衍生] 選項,才能覆寫產生的方法。

  • 設定 DSL 定義中的選項,使產生的程式碼為您自己的程式碼提供「攔截」。

    例如,如果您設定網域類別的 [有自訂建構函式] 選項,然後建置方案,您會看到錯誤訊息。 當您按兩下其中一個錯誤訊息時,您會看到產生的程式碼中的註解,說明自訂程式碼應提供的項目。

  • 撰寫您自己的文字範本,以產生應用程式特定的程式碼。 您可以使用包含檔案,以共用許多專案通用的範本組件,也可以建立 Visual Studio 專案範本,以設定透過您自己的檔案結構初始化的專案。

在 DSL 中產生的檔案

Dsl 專案中會顯示下列產生的檔案。

檔案名稱

描述

您的 DSLSchema.xsd

包含您的 DSL 執行個體的檔案結構描述。 這個檔案會複製到編譯 (bin) 目錄中。 當您安裝 DSL 時,您可以將這個檔案複製到 \Program Files\Microsoft Visual Studio 11.0\Xml\Schemas,以便驗證模型檔。 如需詳細資訊,請參閱Deploying Domain-Specific Language Solutions

如果透過設定 [DSL 總管] 中的選項來自訂序列化,此結構描述會據以變更。 但是,如果您撰寫自己的序列化程式碼,這個檔案可能不再表示實際的結構描述。 如需詳細資訊,請參閱Customizing File Storage and XML Serialization

ConnectionBuilders.cs

連接產生器是建立關聯性的類別。 它是連接工具的後置程式碼。 這個檔案針對每個連接工具各包含一組類別。 這些類別的名稱衍生自網域關聯性和連接工具的名稱:關聯性Builder 和 連接工具ConnectAction。

(在元件方案範例中,其中一個連接產生器稱為 ConnectionBuilder,這是巧合,因為網域關聯性的名稱剛好是 Connection。)

關聯性會建立於 關聯性Builder.Connect() 方法中。 預設版本驗證來源和目標模型項目是可接受的,然後再具現化關聯性。 例如:

CommentReferencesSubject(sourceAccepted, targetAccepted);

每個產生器類別是由 [DSL 總管] 之 [連接產生器] 區段中的節點所產生。 一個 Connect 方法可建立一組或多組網域類別之間的關聯性。 每組類別是由 Link Connect 指示詞定義,您可以在 [DSL 總管] 中的產生器節點下找到此指示詞。

例如,您可以針對範例 DSL 中的三種關聯性類型,各加入一個連接產生器 Link Connect 指示詞。 這會提供使用者一個連接工具。 具現化的關聯性類型取決於使用者選取的來源和目標項目類型。 若要加入 Link Connect 指示詞,請以滑鼠右鍵按一下 [DSL 總管] 中的產生器。

若要撰寫自訂程式碼,在建立特定類型的網域關聯性時執行,請在產生器節點下選取適當的 Link Connect 指示詞。 在 [屬性] 視窗中,設定 [使用自訂連接]。 重建方案,然後提供程式碼以修正產生的錯誤。

若要撰寫自訂程式碼,在每次使用者使用這個連接工具時執行,請設定連接產生器的 Is Custom 屬性。 您可以提供程式碼,決定是否允許來源項目、是否允許來源和目標的特定組合,以及建立連接時應進行的更新。 例如,您可以僅在連接不會在圖表中建立迴圈時允許連接。 除了單一關聯性連結之外,您還可以具現化來源和目標之間伺服器內部相關項目的更複雜模式。

Connectors.cs

包含連接線類別,此圖表項目通常可用來表示參考關聯性。 每個類別是由 DSL 定義中的一個連接線所產生。 每一個連接線類別衍生自 BinaryLinkShape

若要將色彩和其他一些樣式功能設定為執行階段的變數,請以滑鼠右鍵按一下 DSL 定義圖表上的類別,然後指向 [加入已公開的項目]。

若要將其他樣式功能設定為執行階段的變數,請參閱範例 TextFieldShapeElement

Diagram.cs

包含定義圖表的類別。 該類別衍生自 Diagram

若要將色彩和其他一些樣式功能設定為執行階段的變數,請以滑鼠右鍵按一下 DSL 定義圖表上的類別,然後指向 [加入已公開的項目]。

此外,這個檔案包含 FixupDiagram 規則,會在新項目加入至模型時回應。 這個規則會加入新圖形,並將圖形連結至模型項目。

DirectiveProcessor.cs

這個指示詞處理器可協助您的使用者撰寫文字範本,以讀取您的 DSL 執行個體。 這個指示詞處理器會載入 DSL 的組件 (DLL),並有效地插入命名空間的 using 陳述式。 如此一來,文字範本中的程式碼便能夠使用您在 DSL 中定義的類別和關聯性。

如需詳細資訊,請參閱Generating Code from a Domain-Specific Language建立自訂 T4 文字範本指示詞處理器

DomainClasses.cs

實作您已定義的網域類別,包括抽象類別和模型根類別。 這些類別衍生自 ModelElement

每個網域類別包含:

  • 每個網域屬性的屬性定義和巢狀處理常式類別。 您可以覆寫 OnValueChanging() 和 OnValueChanged()。 如需詳細資訊,請參閱網域屬性值變更處理常式

    在範例 DSL 中,Comment 類別包含 Text 屬性和 TextPropertyHandler 處理常式類別。

  • 這個網域類別參與之關聯性的存取子屬性。 (角色屬性沒有巢狀類別)。

    在範例 DSL 中,Comment 類別具有存取子,可透過內嵌關聯性 ComponentModelHasComments 來存取其父模型。

  • 建構函式。 如果您要覆寫這些建構函式,請設定網域類別上的 [有自訂建構函式]。

  • 項目群組原型 (EGP) 處理常式方法。 如果使用者將另一個項目「合併」(Merge) 或加入至這個類別的執行個體,則需要這些方法。 使用者通常會透過從項目工具或另一個圖形拖曳,或透過貼上作業,來執行這項操作。

    在範例 DSL 中,「輸入通訊埠」或「輸出通訊埠」可合併為一個「元件」。 此外,「元件」和「註解」可合併為模型。 The

    「元件」類別中的 EGP 處理常式方法允許「元件」接受「通訊埠」,但不接受「註解」。 根模型類別中的 EGP 處理常式接受「元件」和「註解」,但不接受「通訊埠」。

DomainModel.cs

表示網域模型的類別。 該類別衍生自 DomainModel

注意事項注意事項

此類別與模型的根類別不同。

Copy Closure 和 Delete Closure 定義複製或刪除某個項目時,應包含的其他項目。 您可以透過設定每一個關聯性兩端角色的 Propagates CopyPropagates Delete 屬性,來控制這個行為。 如果您要動態決定這些值,您可以撰寫程式碼,覆寫 Closure 類別的方法。 如需詳細資訊,請參閱How to: Program Copy and Paste Behavior - redirect

DomainModelResx.resx

這個檔案包含網域類別和屬性的描述、屬性名稱、工具箱標籤、標準錯誤訊息等字串,以及可能向使用者顯示的其他字串; 也包含工具圖示和影像圖形的影像。

這個檔案會繫結至建置的組件中,並提供這些資源的預設值。 您可以建立包含當地語系化版本之資源的附屬組件,將您的 DSL 當地語系化。 在符合當地語系化資源的文化特性中安裝 DSL 時,會使用該版本。 如需詳細資訊,請參閱Deploying Domain-Specific Language Solutions

DomainRelationships.cs

模型中兩個項目之間的每個連結會以網域關聯性類別執行個體表示。 所有關聯性類別衍生自 ElementLink,後者衍生自 ModelElement。 由於這是 ModelElement,關聯性執行個體可具有屬性,並且可以是關聯性的來源或目標。

HelpKeywordHelper.cs

提供使用者按 F1 鍵時所使用的函式。

MultiplicityValidation.cs

在您指定 1..1 或 1..* 之多重性的關聯性角色中,應警告使用者至少需要一個關聯性執行個體。 這個檔案提供實作這些警告的驗證條件約束。 系統不會驗證內嵌父項的 1..1 連結。

針對要執行的這些條件約束,您必須在 [DSL 總管] 的 [編輯器\驗證] 節點中,設定其中一個 [使用...] 選項。 如需詳細資訊,請參閱網域指定的語言中的驗證

PropertiesGrid.cs

這個檔案只有在您已將「自訂類型描述元」連結至網域屬性時,才會包含程式碼。 如需詳細資訊,請參閱Customizing the Properties Window

SerializationHelper.cs

Serializer.cs

每個網域類別、關聯性、圖形、連接線、圖表和模型的序列化程式類別。

這些類別的許多功能可透過 [DSL 總管] 中 [XML 序列化行為] 下的設定來控制。

Shapes.cs

代表 DSL 定義中每一個圖形類別的類別。 這些圖形衍生自 NodeShape。 如需詳細資訊,請參閱Customizing File Storage and XML Serialization

若要在部分類別中以您自己的方法覆寫產生的方法,請針對 DSL 定義中的連接線設定 [產生雙衍生]。 若要將建構函式取代成您自己的程式碼,請設定 [有自訂建構函式]。

若要將色彩和其他一些樣式功能設定為執行階段的變數,請以滑鼠右鍵按一下 DSL 定義圖表上的類別,然後指向 [加入已公開的項目]。

若要將其他樣式功能設定為執行階段的變數,請參閱範例 TextFieldShapeElement

ToolboxHelper.cs

透過將項目群組原型安裝到項目工具中,來設定工具箱。 當使用者執行工具時,會將這些原型的複本與目標項目合併。

您可以覆寫 CreateElementPrototype() 定義工具箱項目,以建立數個物件的群組。 例如,您可以定義項目,來表示內含子元件的物件。 變更程式碼之後,請重設 Visual Studio 的實驗執行個體以清除工具箱快取。

在 DslPackage 專案中產生的檔案

DslPackage 會與 DSL 模型結合為 Visual Studio Shell,以管理視窗、工具箱和功能表命令。 大多數的類別是雙衍生類別,因此您可以覆寫類別的任何方法。

檔案名稱

描述

CommandSet.cs

圖表上顯示的內容功能表命令。 您可以調整這個組合或將命令加入至這個組合。 這個檔案包含命令的程式碼。 功能表上的命令位置是由 Commands.vsct 檔所決定。 如需詳細資訊,請參閱撰寫使用者命令和動作

Constants.cs

GUID。

DocData.cs

您的 DSLDocData 管理將模型載入和儲存至檔案的作業,並建立存放區執行個體。

例如,如果您要在資料庫 (而不是檔案) 中儲存 DSL,您可以覆寫 Load 和 Save 方法。

DocView.cs

您的 DSLDocView 管理顯示圖表的視窗。 例如,您可以在視窗表單內嵌圖表:

將使用者控制項檔案加入至 DslPackage 專案。 加入可顯示圖表的面板。 加入按鈕和其他控制項。 在表單的程式碼檢視中,加入下列程式碼,並依照您的 DSL 調整名稱:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Shell;
namespace Company.EmbedInForm
{
  public partial class UserControl1 : UserControl
  {
    public UserControl1()
    {
      InitializeComponent();
    }
    
    private DiagramDocView docView;
    public UserControl1(DiagramDocView docView, Control content)
      : this()
    {
      this.docView = docView;
      panel1.Controls.Add(content);
    }
    private void button1_Click(object sender, EventArgs e)
    {
      ExampleModel modelRoot = this.docView.CurrentDiagram.ModelElement as ExampleModel;
      foreach (ExampleElement element in modelRoot.Elements)
      {
       listBox1.Items.Add(element.Name);
      }
    }
  }
  internal partial class EmbedInFormDocView
  {
    private ContainerControl container;
    /// <summary>
    /// Return a User Control instead of the DSL window. 
    /// The user control will contain the DSL window.
    /// </summary>
    public override System.Windows.Forms.IWin32Window Window
    {
      get
      {
        if (container == null)
        {
          // Put the normal DSL Window inside our control
          container = new UserControl1(this, (Control)base.Window);
        }
        return container;
      }
    }
  }
}

EditorFactory.cs

具現化 DocData 和 DocView。 這個檔案執行 Visual Studio 在啟動您的 DSL 封裝時用於開啟編輯器的標準介面。 Package.cs 中的 ProvideEditorFactory 屬性會參考這個檔案。

GeneratedVSCT.vsct

尋找功能表上的標準功能表命令,例如圖表內容功能表、[編輯] 功能表等。 命令的程式碼位於 CommandSet.cs 中。 您可以重新配置或修改標準命令,也可以加入自己的命令。 如需詳細資訊,請參閱撰寫使用者命令和動作

ModelExplorer.cs

定義您的 DSL 的模型總管。 這是使用者會在圖表旁看到的模型樹狀檢視。

例如,您可以覆寫 InsertTreeView(),變更模型總管中項目的顯示順序。

如果您需要使模型總管中的選取與圖表選取保持同步,您可以使用下列程式碼:

protected override void OnSelectionChanged(global::System.EventArgs e)
{
base.OnSelectionChanged(e);
// get the selected element
DslModeling::ModelElement selectedElement = 
this.PrimarySelection as DslModeling::ModelElement;
// Select in the model explorer
SelectInModelExplorer<YOURLANGUAGEExplorerToolWindow>(selectedElement);
}
private void SelectInModelExplorer<T>(DslModeling::ModelElement modelElement)
where T : DslShell.ModelExplorerToolWindow
{
DslShell::ModelingPackage package = 
this.GetService(typeof(VSShell.Package)) as DslShell::ModelingPackage;
if (package != null)
{
// find the model explorer window
T explorerWindow = package.GetToolWindow(typeof(T), true) as T;
if (explorerWindow != null)
{
// get the tree container
DslShell.ModelExplorerTreeContainer treeContainer = 
explorerWindow.TreeContainer;
// find the tree node
DslShell.ExplorerTreeNode treeNode = 
treeContainer.FindNodeForElement(modelElement);
// select the node
explorerWindow.TreeContainer.ObjectModelBrowser.SelectedNode = treeNode;
}
}
}

ModelExplorerToolWindow.cs

定義顯示模型總管的視窗。 處理總管中的項目選取。

Package.cs

這個檔案定義 DSL 與 Visual Studio 的整合方式。 封裝類別上的屬性可將 DSL 註冊為具有您的副檔名之檔案的處理常式;定義其工具箱;以及定義如何開啟新視窗。 將第一個 DSL 載入至 Visual Studio 執行個體時,會呼叫 Initialize() 方法一次。

Source.extension.vsixmanifest

若要自訂這個檔案,請編輯 .tt 檔。

警告

如果您編輯 .tt 檔以納入圖示或影像等資源,請確定 VSIX 組建中包含此資源。在 [方案總管] 中選取檔案,並確定 Include in VSIX 屬性為 True。

這個檔案控制如何將 DSL 封裝成 Visual Studio 整合擴充功能 (VSIX)。 如需詳細資訊,請參閱Deploying Domain-Specific Language Solutions

請參閱

概念

如何定義網域指定的語言

Understanding Models, Classes and Relationships

Customizing and Extending a Domain-Specific Language

其他資源

Writing Code to Customise a Domain-Specific Language