Обработчики изменений значения свойства домена

При изменении OnValueChanging() значения свойства домена в Visual Studio в обработчике свойств домена вызываются методы и OnValueChanged() методы. Чтобы отреагировать на внесенное изменение, можно переопределить эти методы.

Переопределение методов обработчика свойств

Каждое свойство домена вашего доменного языка обрабатывается классом, вложенным в родительский класс домена. Его имя следует формату PropertyNamePropertyHandler. Этот класс обработчика свойств можно проверить в файле Dsl\Generated Code\DomainClasses.cs. В этом классе непосредственно перед изменением значения вызывается метод OnValueChanging(), а сразу после изменения — метод OnValueChanged().

Например, предположим, что у вас есть класс Comment домена с именем строкового доменного свойства и целочисленное свойство с именем TextTextLengthCount. TextLengthCount Чтобы всегда содержать длину Text строки, можно написать следующий код в отдельном файле в проекте Dsl:

// Domain Class "Comment":
public partial class Comment
{
  // Domain Property "Text":
  partial class TextPropertyHandler
  {
    protected override void OnValueChanging(CommentBase element, string oldValue, string newValue)
    {
      base.OnValueChanging(element, oldValue, newValue);

      // To update values outside the Store, write code here.

      // Let the transaction manager handle undo:
      Store store = element.Store;
      if (store.InUndoRedoOrRollback || store.InSerializationTransaction) return;

      // Update values in the Store:
      this.TextLengthCount = newValue.Length;
    }
  }
}

Об обработчиках свойств необходимо помнить следующее.

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

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

  • Вычисляемые и пользовательские свойства доменов хранения не имеют методов OnValueChanged и OnValueChanging.

  • Обработчик изменений нельзя использовать для изменения нового значения. Если это необходимо, например для ограничения значения в определенном диапазоне, определите правило ChangeRule.

  • Обработчик изменений нельзя добавить в свойство, представляющее роль отношения. Вместо этого настройте правила AddRule и DeleteRule в классе отношения. Они запускаются, когда связи создаются или изменяются. Дополнительные сведения см. в разделе "Правила распространения изменений в модели".

Изменения внутри хранилища и за его пределами

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

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

Более того, обновлять значения не нужно и тогда, когда модель загружается из файла.

Изменения в модели следует защищать тестом следующего вида:

if (!store.InUndoRedoOrRollback && !store. InSerializationTransaction)
{
   this.TextLength = ...; // in-store changes
}

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

Отмена изменения

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

if (newValue > 10)
{
   store.TransactionManager.CurrentTransaction.Rollback();
   System.Windows.Forms.MessageBox.Show("Value must be less than 10");
}

Альтернативный метод: вычисляемые свойства

В предыдущем примере показано, как использовать метод OnValueChanged() для распространения значений из одного свойства домена в другое. Каждое свойство имеет свое сохраненное значение.

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

Вместо предыдущего TextLengthCount примера можно задать поле "Тип" для вычисления в определении DSL. Вы предоставили собственный метод Get для этого свойства домена. Метод Get возвращает текущую длину Text строки.

Потенциальный недостаток вычисляемых свойств заключается в том, что выражение оценивается при каждом использовании значения, что может снижать производительность. Также к вычисляемым свойствам не применяются методы OnValueChanging() и OnValueChanged().

Альтернативный метод: изменение правил

Если вы определяете ChangeRule, он выполняется в конце транзакции, в которой изменяется значение свойства. Дополнительные сведения см. в разделе "Правила распространения изменений в модели".

Если в одной транзакции вносятся сразу несколько изменений, метод ChangeRule выполняется после их завершения. Напротив, OnValue... методы выполняются, когда некоторые изменения не были выполнены. В зависимости от целей метод ChangeRule может оказаться более подходящим.

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

Предупреждение

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

using Microsoft.VisualStudio.Modeling;
...
// Change rule on the domain class Comment:
[RuleOn(typeof(Comment), FireTime = TimeToFire.TopLevelCommit)]
class MyCommentTrimRule : ChangeRule
{
  public override void
    ElementPropertyChanged(ElementPropertyChangedEventArgs e)
  {
    base.ElementPropertyChanged(e);
    Comment comment = e.ModelElement as Comment;

    if (comment.Text.StartsWith(" ") || comment.Text.EndsWith(" "))
      comment.Text = comment.Text.Trim();
    // If changed, rule will trigger again.
  }
}

// Register the rule:
public partial class MyDomainModel
{
 protected override Type[] GetCustomDomainModelTypes()
 { return new Type[] { typeof(MyCommentTrimRule) };
 }
}

Пример

Description

Код в приведенном ниже примере переопределяет обработчик свойств домена и уведомляет пользователя об изменении свойства класса домена ExampleElement.

Код

using DslModeling = global::Microsoft.VisualStudio.Modeling;
using DslDesign = global::Microsoft.VisualStudio.Modeling.Design;

namespace msft.FieldChangeSample
{
  public partial class ExampleElement
  {
    internal sealed partial class NamePropertyHandler
    {
      protected override void OnValueChanged(ExampleElement element,
         string oldValue, string newValue)
      {
        if (!this.Store.InUndoRedoOrRollback)
        {
           // make in-store changes here...
        }
        // This part is called even in undo:
        System.Windows.Forms.MessageBox.Show("Value Has Changed");
        base.OnValueChanged(element, oldValue, newValue);
      }
    }
  }
}