Практическое руководство. Расширение конструктора доменного языка
Это можно сделать расширения конструктора, используемые для изменения определения DSL.Введите расширения, то можно сделать, чтобы включить добавление команды меню, добавляя обработчики перетаскивания и дважды щелкнуть жесты и правила, которые активированы, если указанные типы значений или связей.Расширения можно упаковать как расширение интеграции Visual Studio (VSIX) и распределять другим пользователям.
Образец закодируйте и дополнительные сведения об этой функции см. в разделе Visual Studio Визуализация и моделирование веб-сайте пакета SDK (VMSDK).
Настройка решения
Настройте проект, содержащий код расширения и проект VSIX, который экспортирует проект.Решение может содержать другие проекты, которые включены в один и тот же VSIX.
Создание решения расширения конструктор DSL
Создайте новый проект с помощью шаблона проекта библиотеки классов.В диалоговом окне Создать проект щелкните *** Visual C# *** а затем в среднем нажмите кнопку Библиотека классов окна.
Этот проект будет содержать код собственных расширений.
Создайте новый проект с помощью шаблона проекта VSIX.В диалоговом окне Создать проект разверните *** Visual C# *** нажмите кнопку Расширение среды, а затем в среднем окне выберите Проект VSIX.
Выберите Добавить в решение.
Открытые Source.extension.vsixmanifest в редакторе манифеста VSIX.
По содержимому поля, щелкните Добавление содержимого.
В диалоговом окне Добавление содержимого, установите *** Выберите тип содержимого *** к *** компонент MEF *** и набор Проект в проект библиотеки классов.
Щелкните *** Выберите выпуски *** и убедитесь, что *** Visual Studio Ultimate *** проверяется.
Убедитесь, что проект VSIX автозагружаемый проект решения.
В проекте библиотеки классов добавьте ссылки на следующие сборки:
Microsoft.VisualStudio.CoreUtility
Microsoft.VisualStudio.Modeling.Sdk.11.0
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0
Microsoft.VisualStudio.Modeling.Sdk.DslDefinition.11.0
Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0
System.ComponentModel.Composition
System.Drawing
System.Drawing.Design
System.Windows.Forms
Тестирование и развертывание
Тестирование все расширения в этом разделе, построение и запуск решение.Откроется экспериментальный экземпляр Visual Studio.В этом случае откройте решение DSL.Правка схема DslDefinition.Расширения функциональности расширения можно отобразить.
Развертывание расширений к главному Visual Studio и на других компьютерах, выполните следующие действия:
Найдите файл установки VSIX в проекте VSIX в каталоге bin \ * \ *.vsix
Скопируйте этот файл на целевой компьютер, а затем в проводнике windows (или обозревателе файла) дважды щелкните его.
Диспетчер расширений Visual Studio открывает для подтверждения того, что расширение было установленно.
Чтобы удалить модуль, выполните следующие действия:
в Visual Studio, в меню Сервис, нажмите кнопку *** Диспетчер расширений ***.
Выберите расширение и удалите его.
Добавление команда контекстного меню
Чтобы сделать команда контекстного меню отображаться в области конструктора DSL либо в окне обозревателя DSL, создайте класс походя следующее.
Класс должен реализовывать ICommandExtension и должен иметь атрибут DslDefinitionModelCommandExtension.
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.DslDefinition;
using Microsoft.VisualStudio.Modeling.DslDefinition.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.DslDesigner;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
namespace Fabrikam.SimpleDslDesignerExtension
{
/// <summary>
/// Command extending the DslDesigner.
/// </summary>
[DslDefinitionModelCommandExtension]
public class MyDslDesignerCommand : ICommandExtension
{
/// <summary>
/// Selection Context for this command
/// </summary>
[Import]
IVsSelectionContext SelectionContext { get; set; }
/// <summary>
/// Is the command visible and active?
/// This is called when the user right-clicks.
/// </summary>
public void QueryStatus(IMenuCommand command)
{
command.Visible = true;
// Is there any selected DomainClasses in the Dsl explorer?
command.Enabled =
SelectionContext.AtLeastOneSelected<DomainClass>();
// Is there any selected ClassShape on the design surface?
command.Enabled |=
(SelectionContext.GetCurrentSelection<ClassShape>()
.Count() > 0);
}
/// <summary>
/// Executes the command
/// </summary>
/// <param name="command">Command initiating this action</param>
public void Execute(IMenuCommand command)
{
...
}
/// <summary>
/// Label for the command
/// </summary>
public string Text
{
get { return "My Command"; }
}
}
}
Обработка жесты мыши
Код напоминает код команды меню.
[DslDefinitionModelGestureExtension]
class MouseGesturesExtensions : IGestureExtension
{
/// <summary>
/// Double-clicking on a shape representing a Domain model element displays this model element in a dialog box
/// </summary>
/// <param name="targetElement">Shape element on which the user has clicked</param>
/// <param name="diagramPointEventArgs">event args for this double-click</param>
public void OnDoubleClick(ShapeElement targetElement,
DiagramPointEventArgs diagramPointEventArgs)
{
ModelElement modelElement = PresentationElementHelper.
GetDslDefinitionModelElement(targetElement);
if (modelElement != null)
{
MessageBox.Show(string.Format(
"Double clicked on {0}", modelElement.ToString()),
"Model element double-clicked");
}
}
/// <summary>
/// Tells if the DslDesigner can consume the to-be-dropped information
/// </summary>
/// <param name="targetMergeElement">Shape on which we try to drop</param>
/// <param name="diagramDragEventArgs">Drop event</param>
/// <returns><c>true</c> if we can consume the to be dropped data, and <c>false</c> otherwise</returns>
public bool CanDragDrop(ShapeElement targetMergeElement,
DiagramDragEventArgs diagramDragEventArgs)
{
if (diagramDragEventArgs.Data.GetDataPresent(DataFormats.FileDrop))
{
diagramDragEventArgs.Effect = DragDropEffects.Copy;
return true;
}
return false;
}
/// <summary>
/// Processes the drop by displaying the dropped text
/// </summary>
/// <param name="targetMergeElement">Shape on which we dropped</param>
/// <param name="diagramDragEventArgs">Drop event</param>
public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
{
if (diagramDragEventArgs.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] droppedFiles =
diagramDragEventArgs.Data.
GetData(DataFormats.FileDrop) as string[];
MessageBox.Show(string.Format("Dropped text {0}",
string.Join("\r\n", droppedFiles)), "Dropped Text");
}
}
}
Отклик на изменения значений
Этому обработчику модели домена будет работать правильно.Мы обеспечиваем простую модель домена.
using System.Diagnostics;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.DslDefinition;
namespace Fabrikam.SimpleDslDesignerExtension
{
/// <summary>
/// Rule firing when the type of a domain model property is changed. The change is displayed
/// in the debugger (Output window of the Visual Studio instance debugging this extension)
/// </summary>
[RuleOn(typeof(PropertyHasType))]
public class DomainPropertyTypeChangedRule : RolePlayerChangeRule
{
/// <summary>
/// Method called when the Type of a Domain Property
/// is changed by the user in a DslDefinition
/// </summary>
/// <param name="e"></param>
public override void RolePlayerChanged(RolePlayerChangedEventArgs e)
{
// We are only interested in the type
if (e.DomainRole.Id == PropertyHasType.TypeDomainRoleId)
{
PropertyHasType relationship =
e.ElementLink as PropertyHasType;
DomainType newType = e.NewRolePlayer as DomainType;
DomainType oldType = e.OldRolePlayer as DomainType;
DomainProperty property = relationship.Property;
// We write about the Type change in the debugguer
Debug.WriteLine(string.Format("The type of the Domain property '{0}' of domain class '{1}' changed from '{2}' to '{3}'",
property.Name,
property.Class.Name,
oldType.GetFullName(false),
newType.GetFullName(false))
} } } );
В следующем коде реализуется простой моделью.Создайте новый идентификатор GUID, чтобы заменить местозаполнитель.
using System;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.DslDefinition;
namespace Fabrikam.SimpleDslDesignerExtension
{
/// <summary>
/// Simplest possible domain model
/// needed only for extension rules.
/// </summary>
[DomainObjectId(SimpleDomainModelExtension.DomainModelId)]
public class SimpleDomainModelExtension : DomainModel
{
// Id of this domain model extension
// Please replace this with a new GUID:
public const string DomainModelId =
"00000000-0000-0000-0000-000000000000";
/// <summary>
/// Constructor for the domain model extension
/// </summary>
/// <param name="store">Store in which the domain model will be loaded</param>
public SimpleDomainModelExtension(Store store)
: base(store, new Guid(SimpleDomainModelExtension.DomainModelId))
{
}
/// <summary>
/// Rules brought by this domain model extension
/// </summary>
/// <returns></returns>
protected override System.Type[] GetCustomDomainModelTypes()
{
return new Type[] {
typeof(DomainPropertyTypeChangedRule)
};
}
}
/// <summary>
/// Provider for the DomainModelExtension
/// </summary>
[Export(typeof(DomainModelExtensionProvider))] [ProvidesExtensionToDomainModel(typeof(DslDefinitionModelDomainModel))]
public class SimpleDomainModelExtensionProvider
: DomainModelExtensionProvider
{
/// <summary>
/// Extension model type
/// </summary>
public override Type DomainModelType
{
get
{
return typeof(SimpleDomainModelExtension);
}
}
}
}