Поделиться через


Проверка в доменных языках

Как создатель доменного языка (DSL), можно указать ограничения проверки, чтобы убедиться, что модель, созданная пользователем содержательна.Например, если DSL позволит пользователям создавать фамильное дерев дерево продаж и их предков, то можно написать ограничение, которое гарантирует, что дочерние элементы имеют даты рождения после их родительскиев.

Можно иметь ограничения проверки выполнения, когда модель сохраняется, когда она открыта, и когда пользователь явно запускает Проверить команда меню.Можно также выполнить проверку под элементом управления программы.Например, можно выполнить проверку в ответ на изменение значения свойства или связи.

Проверка особенно важна при написании текстовых шаблонов или другие средства, которые обрабатывают модели пользователей.Проверка гарантирует, что модели выполняют предварительные условия, созданные этими средствами.

Предупреждающее замечаниеВнимание

Можно также разрешить ограничения проверки, который нужно указать в отдельном расширениях в DSL вместе с командами меню расширения и обработчиков жестов.Пользователи могут выбирать для установки эти расширения в дополнение к вашему DSL.Дополнительные сведения см. в разделе Расширение доменного языка с помощью MEF.

Запуск проверка

Когда пользователь изменяет модель, т е экземпляр доменного языка, следующие действия могут выполняться проверка.

  • Щелкните правой кнопкой мыши схему и выберите команду Проверить все.

  • Щелкните правой кнопкой мыши верхний узел в обозревателе проекта и выберите DSL Проверить все

  • Сохраните модель.

  • Открытие модели.

  • Кроме того, можно написать программный код, который выполняется проверка, например, в составе команды меню или в ответ на изменение.

Все ошибки проверки будут отображаться в Список ошибок окна.Пользователь может дважды щелкните сообщение об ошибке, чтобы выбрать элементы модели, причина ошибки.

Определение ограничения проверки

Определении ограничения проверки путем добавления методов проверки к доменным классам или связей вашего DSL.Когда проверка выполняется либо в элементе управления пользователем или программы некоторые или все методами проверки выполняются.Каждый метод применяется к каждому экземпляру класса и могут быть несколько методов проверки в каждом классе.

Отчеты каждого метода проверки всех ошибок, которые он обнаруживает.

ПримечаниеПримечание

Методы проверки отчет ошибок, но не изменяют модель.Если необходимо обработать или запретить некоторые изменения, см. раздел Альтернативы проверке.

Определить ограничение проверки

  1. Включите проверку в Editor\Validation узел:

    1. Откройте программу Dsl\DslDefinition.dsl.

    2. Разверните в обозревателе DSL Редактор узел и выбирает Проверка.

    3. В окне свойства установите Использование свойства true.Наиболее удобно задать все эти свойства.

    4. Нажать Преобразовать все шаблоны на панели инструментов обозревателя решений.

  2. Запишите определения разделяемого класса для одной или нескольких своих доменных классов или доменных ссылок.Создайте эти определения в новом файле кода Dsl этот проект.

  3. Префикс каждый класс с данным атрибутом.

    [ValidationState(ValidationState.Enabled)]
    
    • По умолчанию этот атрибут также включает проверку для производных классов.Если требуется отключить проверку определенного производного класса, то можно воспользоваться ValidationState.Disabled.
  4. Добавьте методы проверки к классам.Каждый метод проверки может иметь любое имя, но имеет один параметр типа ValidationContext.

    Он должен иметь префикс с одним или несколькими ValidationMethod атрибуты:

    [ValidationMethod (ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu ) ]
    

    ValidationCategories определяет, если метод выполнен.

Примеры.

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;

// Allow validation methods in this class:
[ValidationState(ValidationState.Enabled)]
// In this DSL, ParentsHaveChildren is a domain relationship
// from Person to Person:
public partial class ParentsHaveChildren
{
  // Identify the method as a validation method:
  [ValidationMethod
  ( // Specify which events cause the method to be invoked:
    ValidationCategories.Open // On file load.
  | ValidationCategories.Save // On save to file.
  | ValidationCategories.Menu // On user menu command.
  )]
  // This method is applied to each instance of the 
  // type (and its subtypes) in a model: 
  private void ValidateParentBirth(ValidationContext context)   
  {
    // In this DSL, the role names of this relationship
    // are "Child" and "Parent": 
     if (this.Child.BirthYear < this.Parent.BirthYear 
        // Allow user to leave the year unset:
        && this.Child.BirthYear != 0)
      {
        context.LogError(
             // Description:
                       "Child must be born after Parent",
             // Unique code for this error:
                       "FAB001ParentBirthError", 
              // Objects to select when user double-clicks error:
                       this.Child, 
                       this.Parent);
    }
  }

Обратите внимание на следующие моменты о коде:

  • Можно добавлять методы проверки к классам или доменным доменным ссылкам.Код для этих типов Dsl\Generated Code\Domain*.cs.

  • Каждый метод проверки применяется к каждому экземпляру класса и соответствующие подклассы.В случае ссылки доменной каждый экземпляр связь между 2 элементами модели.

  • Методы проверки не применяются в каком-либо определенном порядке, и каждый метод не применяется к экземплярам класса в любом порядке прогнозируемый.

  • Обычно неверная использовать для метода проверки обновить содержимое хранилища, поскольку это вело бы к сбивчивым результатам.Вместо этого метод должен сообщить любую ошибку путем вызова context.LogError" LogWarning OR LogInfo.

  • В вызове LogError можно предоставить список элементов модели или ссылок связи, которые будут выделены, когда пользователь дважды щелкает сообщение об ошибке.

  • Дополнительные сведения о чтении модели в программном коде см. в разделе Перемещение по модели и обновление модели в коде программы.

Следующем примере применяется к модели домена.Связь ParentsHaveChildren имеет дочерний элемент с именем роли, и родительский элемент.

Схема определения DSL — модель семейного дерева

Категории проверки

в ValidationMethod атрибут указывается, когда метод проверки должен быть выполнен.

Категория

Выполнение

Menu

Когда пользователь вызывает команду меню проверить.

Open

При открытии файла модели.

Save

Если файл сохранен.Если ошибки проверки, передают пользователю возможность отмены операции сохранения.

Load

Если файл сохранен.Если ошибки из методов в этой категории, то пользователь предупрежен которому может оказаться невозможным повторное открытие файла.

Используйте эту категорию методов проверки, которые проверяют или дублированных имен для идентификаторов или других условий, которые могут вызвать ошибки загрузки.

Custom

При вызове метода ValidateCustom.Проверки этой категории могут вызываться только из программного кода.

Дополнительные сведения см. в разделе Пользовательские категории проверки.

Если задать методы проверки

Можно достижения такого же эффекта с помощью метода проверки на разном представлении.Например, можно добавить метод к классу, а связи ParentsHaveChildren продаж, и есть его перебора связей:

[ValidationState(ValidationState.Enabled)]
public partial class Person
{[ValidationMethod
 ( ValidationCategories.Open 
 | ValidationCategories.Save
 | ValidationCategories.Menu
 )
]
  private void ValidateParentBirth(ValidationContext context)   
  {
    // Iterate through ParentHasChildren links:
    foreach (Person parent in this.Parents)
    {
        if (this.BirthYear <= parent.BirthYear)
        { ...

Статистическая обработка ограничения проверки. Для применения проверки в прогнозируемом порядке, указать один метод проверки на классе владелец том корневой элемент модели.Этот метод также позволяет выполнять статистическое вычисление отчеты о нескольких ошибок в одно сообщение.

Недостатки, что объединенный метод менее прост для управления и ограничения должны иметь одинаковые ValidationCategories.Мы поэтому рекомендуется разместить каждое ограничение в отдельном методе, если это возможно.

Передача значения в кэше контекста. Параметр контекста имеет словарь, в котором можно установить произвольные значения.Словарь сохраняется в течение всего времени существования выполнения проверки.Указанный метод проверки может, например, содержать число ошибок в контексте, и использовать ее во избежание затопить окно ошибки с повторными сообщениями.Примеры.

List<ParentsHaveChildren> erroneousLinks;
if (!context.TryGetCacheValue("erroneousLinks", out erroneousLinks))
erroneousLinks = new List<ParentsHaveChildren>();
erroneousLinks.Add(this);
context.SetCacheValue("erroneousLinks", erroneousLinks);
if (erroneousLinks.Count < 5) { context.LogError( ... ); }

Проверка количество элементов

Методы проверки для проверки минимальное количество элементов автоматически формируются для DSL.Код записывается в Dsl\Generated Code\MultiplicityValidation.cs.Эти методы принимают в силу при включении проверку в Редактор \ проверка узел в обозревателе DSL.

Если задать число элементов роли доменной ссылки на 1. * или 1..1, но пользователь не создает соединение данного отношения, появится сообщение об ошибке проверки.

Например, если DSL имеет продажу и городок классов и связь PersonLivesInTown с отношением 1..* в роли городка, затем для каждой продажи, не имеющей городок, появится сообщение об ошибке.

Запуск проверка из программного кода

Можно выполнять проверку с помощью или создать ValidationController.Если требуется ошибки отображаются пользователю в окне ошибок используйте ValidationController, вложенно для DocData конкретной схемы.Например, если вы пишете, то команда меню CurrentDocData.ValidationController доступных в классе набора команд:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling.Shell;
...
partial class MyLanguageCommandSet 
{
  private void OnMenuMyContextMenuCommand(object sender, EventArgs e) 
  { 
   ValidationController controller = this.CurrentDocData.ValidationController; 
...

Дополнительные сведения см. в разделе Практическое руководство. Добавление команды в контекстное меню.

Можно также вручную создать отдельный контроллер проверки и управления ошибки.Примеры.

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling.Shell;
...
Store store = ...;
VsValidationController validator = new VsValidationController(s);
// Validate all elements in the Store:
if (!validator.Validate(store, ValidationCategories.Save))
{
  // Deal with errors:
  foreach (ValidationMessage message in validator.ValidationMessages) { ... }
}

Запуск проверки при возникновении изменений

Если необходимо убедиться в том, что пользователь предупрежен немедленно, если модель будет недопустимым, то можно указать событие хранилища, выполняется проверка.Дополнительные сведения о событиях см. в разделе store Обработчики событий распространяют изменения за пределы модели.

В дополнение к коду проверки, добавьте в файл пользовательского кода DslPackage проект и содержимого, аналогичный следующему примеру.Этот код использует ValidationController то вложенно к документу.Этот контроллер отображает ошибки проверки в Visual Studio список ошибок.

using System;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
namespace Company.FamilyTree
{
  partial class FamilyTreeDocData // Change name to your DocData.
  {
    // Register the store event handler: 
    protected override void OnDocumentLoaded()
    {
      base.OnDocumentLoaded();
      DomainClassInfo observedLinkInfo = this.Store.DomainDataDirectory
         .FindDomainClass(typeof(ParentsHaveChildren));
      DomainClassInfo observedClassInfo = this.Store.DomainDataDirectory
         .FindDomainClass(typeof(Person));
      EventManagerDirectory events = this.Store.EventManagerDirectory;
      events.ElementAdded
         .Add(observedLinkInfo, new EventHandler<ElementAddedEventArgs>(ParentLinkAddedHandler));
      events.ElementDeleted.Add(observedLinkInfo, new EventHandler<ElementDeletedEventArgs>(ParentLinkDeletedHandler));
      events.ElementPropertyChanged.Add(observedClassInfo, new EventHandler<ElementPropertyChangedEventArgs>(BirthDateChangedHandler));
    }
    // Handler will be called after transaction that creates a link:
    private void ParentLinkAddedHandler(object sender,
                                ElementAddedEventArgs e)
    {
      this.ValidationController.Validate(e.ModelElement,
           ValidationCategories.Save);
    }
    // Called when a link is deleted:
    private void ParentLinkDeletedHandler(object sender, 
                                ElementDeletedEventArgs e)
    {
      // Don't apply validation to a deleted item! 
      // - Validate store to refresh the error list.
      this.ValidationController.Validate(this.Store,
           ValidationCategories.Save);
    }
    // Called when any property of a Person element changes:
    private void BirthDateChangedHandler(object sender,
                      ElementPropertyChangedEventArgs e)
    {
      Person person = e.ModelElement as Person;
      // Not interested in changes in other properties:
      if (e.DomainProperty.Id != Person.BirthYearDomainPropertyId)
          return;

      // Validate all parent links to and from the person:
      this.ValidationController.Validate(
        ParentsHaveChildren.GetLinksToParents(person)
        .Concat(ParentsHaveChildren.GetLinksToChildren(person))
        , ValidationCategories.Save);
    }
  }
} 

Обработчики, также называются после отката или вернут операции, которые влияют на ссылки или элементы.

Пользовательские категории проверки

В дополнение к стандартным категориям проверки, например, меню и открыто, можно определить собственные категории.Эти категории можно вызвать из программного кода.Пользователь не может вызывать их напрямую.

Обычно для пользовательских категорий указать категорию, которая проверяет, удовлетворяет ли модель предварительные условия указанного инструмента.

Чтобы добавить метод проверки в указанной категории префикс ее с атрибутом like образом:

[ValidationMethod(CustomCategory = "PreconditionsForGeneratePartsList")]
[ValidationMethod(ValidationCategory.Menu)] 
private void TestForCircularLinks(ValidationContext context) 
{...}
ПримечаниеПримечание

Можно префикс метод с столько [ValidationMethod()] атрибуты по мере необходимости.Можно добавить метод и к настраиваемым и стандартным категориям.

Чтобы вызвать пользовательскую проверку.

// Invoke all validation methods in a custom category: 
validationController.ValidateCustom
  (store, // or a list of model elements
   "PreconditionsForGeneratePartsList");

Альтернативы проверке

Ошибки отчета о проверке ограничений, но не изменяют модель.Если вместо этого требуется запретить модель недопустимы, можно использовать другие методы.

Однако эти методы не рекомендуется.Обычно лучше позволить пользователю решить, как исправить недопустимую модель.

Обработка изменений для получения модели на допустимость. Например, если пользователь задает максимально допустимый максимум через свойство можно сбросить свойства к максимальному значению.Для этого укажите правило.Дополнительные сведения см. в разделе Правила распространяют изменения в пределах модели.

Откатите транзакцию при попытке недопустимого изменения. Также можно определить правило для этой цели, но в некоторых случаях можно переопределить обработчик свойства **OnValueChanging ()**или переопределить метод OnDeleted(). Чтобы откатить транзакцию, используйте this.Store.TransactionManager.CurrentTransaction.Rollback(). Дополнительные сведения см. в разделе Обработчики изменений значений свойств доменов.

Предупреждающее замечаниеВнимание

Убедитесь, что пользователь знает, что было изменяется или откаченно изменение.Например, используйте System.Windows.Forms.MessageBox.Show("message").

См. также

Основные понятия

Перемещение по модели и обновление модели в коде программы

Обработчики событий распространяют изменения за пределы модели