Rozszerzanie DSL za pomocą MEF
Możesz exntend języka (DSL) określone dla danej domeny przy użyciu zarządzanych rozszerzeń RAM (MEF).Użytkownik lub inni programiści będą mogli zapisywać rozszerzeń dla modem DSL, bez zmiany definicji DSL i kodu programu.Rozszerzenia takie obejmują polecenia menu, przeciągnij i upuść obsługi i sprawdzania poprawności.Użytkownicy będą mogli zainstalować modem DSL, a następnie Opcjonalnie Zainstaluj rozszerzenia dla niego.
Ponadto po włączeniu MEF w modem DSL, można go łatwiejszy do pisania, niektóre funkcje modem DSL, nawet wtedy, gdy one są wbudowane wraz z modemu DSL.
Aby uzyskać więcej informacji na temat MEF zobacz Oprogramowanie Managed Extensibility Framework (MEF).
Aby włączyć DSL zostać przedłużony przez MEF
Utwórz nowy folder o nazwie MefExtension wewnątrz DslPackage projektu.Dodaj następujące pliki do niego:
Nazwa pliku
Zawartość pliku
CommandExtensionVSCT.tt
Ważne
Ustawianie identyfikatora GUID w tym pliku, być taka sama, jak CommandSetId identyfikator GUID, który jest zdefiniowany w DslPackage\GeneratedCode\Constants.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <# // CmdSet Guid must be defined before master template is included // This Guid must be kept synchronized with the CommandSetId Guid in Constants.tt Guid guidCmdSet = new Guid ("00000000-0000-0000-0000-000000000000"); string menuidCommandsExtensionBaseId="0x4000"; #> <#@ include file="DslPackage\CommandExtensionVSCT.tt" #>
CommandExtensionRegistrar.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="DslPackage\CommandExtensionRegistrar.tt" #>
ValidationExtensionEnablement.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="DslPackage\ValidationExtensionEnablement.tt" #>
ValidationExtensionRegistrar.tt
Możesz dodać ten plik, należy włączyć sprawdzanie poprawności w linii DSL za pomocą co najmniej jeden z przełączników w Editor\Validation w Eksploratorze DSL.
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="DslPackage\ValidationExtensionRegistrar.tt" #>
PackageExtensionEnablement.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="DslPackage\PackageExtensionEnablement.tt" #>
Utwórz nowy folder o nazwie MefExtension wewnątrz Dsl projektu.Dodaj następujące pliki do niego:
Nazwa pliku
Zawartość
DesignerExtensionMetaDataAttribute.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="Dsl\DesignerExtensionMetadataAttribute.tt" #>
GestureExtensionEnablement.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="Dsl\GestureExtensionEnablement.tt" #>
GestureExtensionController.tt
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #> <#@ include file="Dsl\GestureExtensionController.tt" #>
Dodaj następujący wiersz do istniejącego pliku o nazwie DslPackage\Commands.vsct:
<Include href="MefExtension\CommandExtensionVSCT.vsct"/>
Wstaw wiersz po istniejących <Include> dyrektywy.
Otwórz DslDefinition.dsl.
W Eksploratorze DSL, zaznacz Editor\Validation.
W oknie dialogowym właściwości, upewnij się, że co najmniej jedna z właściwości o nazwie używa... is true.
Na pasku narzędziowym panelu Solution Explorer, kliknij Transform wszystkie szablony.
Pliki pomocnicze są wyświetlane pod spodem każdego z plików, które zostały dodane.
Tworzenie i uruchamianie roztwór do sprawdzenia nadal pracuje.
Modem DSL jest obecnie włączona MEF.Polecenia menu, gesty obsługi i ograniczeń sprawdzania poprawności można zapisywać jako rozszerzenia MEF.Rozszerzenia te można pisać w rozwiązaniu DSL, wraz z innymi niestandardowego kodu.Ponadto użytkownik lub inni programiści można pisać osobne Visual Studio rozszerzeń, które rozszerzają modem DSL.
Tworzenie rozszerzenia dla DSL włączone MEF
Jeśli masz dostęp do włączone MEF DSL, utworzonych przez siebie lub innej osoby, można napisać rozszerzeń dla niego.Rozszerzenia można dodać polecenia menu, gesty obsługi lub ograniczeń sprawdzania poprawności.Autorem tych rozszerzeń, użyj Visual Studio roztwór rozszerzenie (VSIX).Rozwiązanie składa się z dwóch części: klasa library project buduje zestaw kod i projekt VSIX, który zestaw pakietów.
Aby utworzyć rozszerzenie DSL VSIX
Utwórz nowy projekt biblioteki klas.W tym celu, w Nowy projekt okno dialogowe Wybierz programu Visual Basic lub Visual C# , a następnie wybierz Biblioteka klas.
W projekcie biblioteki klas Dodaj odwołanie do zestawu DSL.
Ten zestaw ma zwykle nazwę, która kończy się ".DSL.dll".
Jeśli masz dostęp do projektu, DSL, można znaleźć pliku zestawu w kataloguDsl\bin\*
Jeśli masz dostęp do pliku DSL VSIX można znaleźć zgromadzenie, zmieniając rozszerzenie nazwy pliku w pliku VSIX na ".zip".Zdekompresuj plik zip.
Dodaj odwołania do następujących.Zestawy netto:
Microsoft.VisualStudio.Modeling.SDK.11.0.dll
Microsoft.VisualStudio.Modeling.SDK.Diagrams.11.0.dll
Microsoft.VisualStudio.Modeling.SDK.Shell.11.0.dll
System.ComponentModel.Composition.dll
System.Windows.Forms.dll
Tworzenie projektu VSIX w tym samym roztworze.W tym celu, w Nowy projekt okno dialogowe rozwiń języka Visual Basic lub Visual C#, kliknij przycisk rozszerzalności, a następnie wybierz projektu VSIX.
W oknie Solution Explorer, kliknij prawym przyciskiem myszy projekt VSIX, a następnie kliknij przycisk ustawiony jako uruchomienia projektu.
Otwórz nowy projekt, source.extension.vsixmanifest.
Kliknij przycisk dodać zawartość.W oknie dialogowym Ustaw Typu zawartości do MEF składnika, i Projektu źródłowego do swojego projektu biblioteki klas.
Dodaj odwołanie VSIX do linii DSL.
W source.extension.vsixmanifest, kliknij przycisk Dodaj odwołanie
W oknie dialogowym kliknij przycisk Dodać ładunku a następnie zlokalizuj plik VSIX z modemu DSL.Plik VSIX jest zbudowany w roztworze DSL w DslPackage\bin\*.
To pozwala użytkownikom instalować DSL i rozszerzenie sieci, w tym samym czasie.Jeśli użytkownik ma już zainstalowany modem DSL, zostanie zainstalowana tylko na rozszerzenie.
Przegląd i aktualizacja innych pól z source.extension.vsixmanifest.Kliknij przycisk Zaznacz wersje i sprawdź, czy poprawne Visual Studio wersje są ustawione.
Dodaj kod do projektu biblioteki klas.Przykładowych formuł można używać w następnej sekcji, jako przewodnik.
Można dodać dowolną liczbę poleceń, gestu i klasy sprawdzania poprawności.
Aby przetestować rozszerzenia, naciśnij klawisz F5.W wystąpieniu doświadczalnych Visual Studio, Utwórz lub Otwórz przykładowy plik DSL.
Zapisywanie rozszerzeń MEF dla DSLs
Można napisać rozszerzeń w programie project kod montażu oddzielnych roztworu rozszerzenie DSL.Można również użyć MEF w projekcie DslPackage to wygodny sposób pisać poleceń, gesty i sprawdzanie poprawności kodu jako część DSL.
Polecenia menu
Aby napisać polecenie menu, należy zdefiniować klasy, która implementuje ICommandExtension i prefiks klasy z atrybutu, który jest zdefiniowany w linii DSL, o nazwie YourDslCommandExtension.Można napisać więcej niż jednej klasy polecenia menu.
QueryStatus()nazywa się w każdym przypadku, gdy użytkownik kliknie prawym przyciskiem myszy diagram.Powinien sprawdzać bieżące zaznaczenie i ustawić command.Enabled wskazuje, kiedy polecenie jest stosowane.
using System.ComponentModel.Composition;
using System.Linq;
using Company.MyDsl; // My DSL
using Company.MyDsl.ExtensionEnablement; // My DSL
using Microsoft.VisualStudio.Modeling; // Transactions
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; // IVsSelectionContext
using Microsoft.VisualStudio.Modeling.ExtensionEnablement; // ICommandExtension
namespace MyMefExtension
{
// Defined in Dsl\MefExtension\DesignerExtensionMetaDataAttribute.cs:
[MyDslCommandExtension]
public class MyCommandClass : ICommandExtension
{
/// <summary>
/// Provides access to current document and selection.
/// </summary>
[Import]
IVsSelectionContext SelectionContext { get; set; }
/// <summary>
/// Called when the user selects this command.
/// </summary>
/// <param name="command"></param>
public void Execute(IMenuCommand command)
{
// Transaction is required if you want to update elements.
using (Transaction t = SelectionContext.CurrentStore
.TransactionManager.BeginTransaction("fix names"))
{
foreach (ExampleShape shape in SelectionContext.CurrentSelection)
{
ExampleElement element = shape.ModelElement as ExampleElement;
element.Name = element.Name + " !";
}
t.Commit();
}
}
/// <summary>
/// Called when the user right-clicks the diagram.
/// Determines whether the command should appear.
/// This method should set command.Enabled and command.Visible.
/// </summary>
/// <param name="command"></param>
public void QueryStatus(IMenuCommand command)
{
command.Enabled =
command.Visible = (SelectionContext.CurrentSelection.OfType<ExampleShape>().Count() > 0);
}
/// <summary>
/// Called when the user right-clicks the diagram.
/// Determines the text of the command in the menu.
/// </summary>
public string Text
{
get { return "My menu command"; }
}
}
}
Obsługa gestu
Obsługa gestu może zajmować obiektów przeciągnięte na diagramie z dowolnego miejsca, wewnątrz lub na zewnątrz Visual Studio.Poniższy przykład pozwala użytkownikowi na przeciągnij pliki z Eksploratora Windows na diagramie.Tworzy elementy, które zawierają nazwy pliku.
Można napisać procedury obsługi do zajmowania się drags z innych modeli DSL i modeli UML.Aby uzyskać więcej informacji, zobacz Porady: dodawanie obsługi przeciągania i upuszczania.
using System.ComponentModel.Composition;
using System.Linq;
using Company.MyDsl;
using Company.MyDsl.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling; // Transactions
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
namespace MefExtension
{
[MyDslGestureExtension]
class MyGestureExtension : IGestureExtension
{
public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
{
System.Windows.Forms.MessageBox.Show("double click!");
}
/// <summary>
/// Called when the user drags anything over the diagram.
/// Return true if the dragged object can be dropped on the current target.
/// </summary>
/// <param name="targetMergeElement">The shape or diagram that the mouse is currently over</param>
/// <param name="diagramDragEventArgs">Data about the dragged element.</param>
/// <returns></returns>
public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
{
// This handler only allows items to be dropped onto the diagram:
return targetMergeElement is MefDsl2Diagram &&
// And only accepts files dragged from Windows Explorer:
diagramDragEventArgs.Data.GetFormats().Contains("FileNameW");
}
/// <summary>
/// Called when the user drops an item onto the diagram.
/// </summary>
/// <param name="targetDropElement"></param>
/// <param name="diagramDragEventArgs"></param>
public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
{
MefDsl2Diagram diagram = targetDropElement as MefDsl2Diagram;
if (diagram == null) return;
// This handler only accepts files dragged from Windows Explorer:
string[] draggedFileNames = diagramDragEventArgs.Data.GetData("FileNameW") as string[];
if (draggedFileNames == null || draggedFileNames.Length == 0) return;
using (Transaction t = diagram.Store.TransactionManager.BeginTransaction("file names"))
{
// Create an element to represent each file:
foreach (string fileName in draggedFileNames)
{
ExampleElement element = new ExampleElement(diagram.ModelElement.Partition);
element.Name = fileName;
// This method of adding the new element allows the position
// of the shape to be specified:
ElementGroup group = new ElementGroup(element);
diagram.ElementOperations.MergeElementGroupPrototype(
diagram, group.CreatePrototype(), PointD.ToPointF(diagramDragEventArgs.MousePosition));
}
t.Commit();
}
}
}
}
Sprawdzanie poprawności ograniczeń
Metody sprawdzania poprawności są oznaczone przez ValidationExtension atrybut, który jest generowany przez modem DSL, a także przez ValidationMethodAttribute.Metoda może się pojawić w dowolnej klasy, która nie jest oznaczone atrybutem.
Aby uzyskać więcej informacji, zobacz Sprawdzanie poprawności w języku specyficznym dla domeny.
using Company.MyDsl;
using Company.MyDsl.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.Validation;
namespace MefExtension
{
class MyValidationExtension // Can be any class.
{
// SAMPLE VALIDATION METHOD.
// All validation methods have the following attributes.
// Specific to the extended DSL:
[MyDslValidationExtension]
// Determines when validation is applied:
[ValidationMethod(
ValidationCategories.Save
| ValidationCategories.Open
| ValidationCategories.Menu)]
/// <summary>
/// When validation is executed, this method is invoked
/// for every element in the model that is an instance
/// of the second parameter type.
/// </summary>
/// <param name="context">For reporting errors</param>
/// <param name="elementToValidate"></param>
private void ValidateClassNames
(ValidationContext context,
// Type determines to what elements this will be applied:
ExampleElement elementToValidate)
{
// Write code here to test values and links.
if (elementToValidate.Name.IndexOf(' ') >= 0)
{
// Log any unacceptable values:
context.LogError(
// Description:
"Name must not contain spaces"
// Error code unique to this type of error:
, "MyDsl001"
// Element to highlight when user double-clicks error:
, elementToValidate);
} } } }
Zobacz też
Koncepcje
Oprogramowanie Managed Extensibility Framework (MEF)
Porady: dodawanie obsługi przeciągania i upuszczania
Sprawdzanie poprawności w języku specyficznym dla domeny