規則によって変更内容がモデル内に反映される
モデリング SDK (VMSDK) の視覚化 1 個の要素から別の要素への変更を反映させるストアの規則を作成できます。 変更がストアのすべての要素に発生すると処理される規則は最も外側のトランザクションをコミットする場合通常スケジュールされます。 要素を追加または削除などのイベントの種類ごとに異なる規則の型があります。 要素は図形または図の種類に規則を追加できます。 多数の組み込み機能は規則で定義されています : たとえば規則はモデルが変更されると図が更新されていることを確認します。 独自の規則を追加するとドメイン固有言語をカスタマイズできます。
ストアの規則はストア内の変更 - モデル要素につまり変更をリレーションシップおよびドメインのシェイプまたはコネクタのプロパティ反映させる場合に特に便利です。 規則はユーザーが元に戻す操作またはやり直しコマンドの起動時に実行されません。 代わりにトランザクション マネージャーがストアのコンテンツが正しい状態に復元されていることを確認します。 ストアの外部のリソースへの変更を反映する場合はストアのイベントを使用します。 詳細については、「イベント ハンドラーによって変更内容がモデル外に反映される」を参照してください。
たとえばユーザー コード (または) 型 ExampleDomainClass新しい要素を作成するたびに別の型の追加の要素がモデルの他の部分に作成されることを指定するとします。 AddRule を書き込みExampleDomainClass に関連付けることができます。 追加の要素を作成する規則のコードを記述します。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
namespace ExampleNamespace
{
// Attribute associates the rule with a domain class:
[RuleOn(typeof(ExampleDomainClass), FireTime=TimeToFire.TopLevelCommit)]
// The rule is a class derived from one of the abstract rules:
class MyAddRule : AddRule
{
// Override the abstract method:
public override void ElementAdded(ElementAddedEventArgs e)
{
base.ElementAdded(e);
ExampleDomainClass element = e.ModelElement;
Store store = element.Store;
// Ignore this call if we're currently loading a model:
if (store.TransactionManager.CurrentTransaction.IsSerializing)
return;
// Code here propagates change as required – for example:
AnotherDomainClass echo = new AnotherDomainClass(element.Partition);
echo.Name = element.Name;
echo.Parent = element.Parent;
}
}
// The rule must be registered:
public partial class ExampleDomainModel
{
protected override Type[] GetCustomDomainModelTypes()
{
List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
types.Add(typeof(MyAddRule));
// If you add more rules, list them here.
return types.ToArray();
}
}
}
注意
規則のコードはストア内の要素のみの状態を変更するか; つまり規則はモデル要素関係図形コネクタダイアグラムまたはプロパティを変更します。ストアの外部のリソースへの変更を反映する場合はストアのイベントを定義します。詳細については、「イベント ハンドラーによって変更内容がモデル外に反映される」を参照してください。
規則を定義するには
RuleOn の属性が付けられたクラスと規則を定義します。 属性はドメイン クラス関係または図の要素の 1 つがと規則を関連付けます。 規則は抽象可能性があるこのクラスのすべてのインスタンスに適用されます。
ドメイン モデルのクラスの GetCustomDomainModelTypes() によって返される設定に追加することで規則を登録します。
規則クラスを抽象クラスの 1 種類の規則から派生しメソッドの実装コードを記述します。
以降のセクションではこれらの手順について詳しく説明します。
ドメイン クラスの規則を定義するには
カスタム コード ファイルでクラスを定義しRuleOnAttribute の属性と前に : 付けます。
[RuleOn(typeof(ExampleElement), // Usual value – but required, because it is not the default: FireTime = TimeToFire.TopLevelCommit)] class MyRule ...
サブジェクトの最初のパラメーターを指定できます。ドメイン クラスドメイン リレーションシップ形状コネクタまたは図になっています。 通常ドメイン クラスとその関係に規則を適用します。
FireTime は通常 TopLevelCommit です。 これはトランザクションのすべての主な変更が行われた後でのみ規則が使用されるようになります。 またインラインで変更後の規則をすぐに実行する ; および (一番外側でない可能性のある実行などの最後の規則を現在のトランザクション LocalCommit。 またキューの順序に影響する規則の優先順位を設定できますがこれは必要な結果を得る信頼できないメソッドです。
サブジェクトように抽象クラス型を指定できます。
規則はサブジェクト クラスのすべてのインスタンスに適用されます。
FireTime の既定値は TimeToFire.TopLevelCommit です。 最も外側のトランザクションをコミットする場合実行される規則が発生します。 代わりに TimeToFire.Inline です。 これによりトリガーのイベントの後に直ちに実行される規則が発生します。
規則を登録するには
ドメイン モデルの GetCustomDomainModelTypes によって返された型のリストに規則クラスを追加します :
public partial class ExampleDomainModel { protected override Type[] GetCustomDomainModelTypes() { List<Type> types = new List<Type>(base.GetCustomDomainModelTypes()); types.Add(typeof(MyAddRule)); // If you add more rules, list them here. return types.ToArray(); } }
ドメイン モデルのクラス名をよく覚えていない場合ファイル Dsl\GeneratedCode\DomainModel.cs 内の " " を参照してください
DSL のプロジェクトのカスタム コード ファイルで次のコードを記述します。
規則のコードを作成するには
次の基本クラスの 1 種類の規則からクラスを派生します :
[基本クラス]
トリガー
要素はリンク図形が追加されます。
新しい要素に加えて新しいリレーションシップを検出するために使用します。
ドメインのプロパティ値を変更します。 メソッドの引数は新旧の値を指定します。
図形のためにこの規則はシェイプに移動する場合は時 AbsoluteBounds の組み込みプロパティの変更がトリガーされます。
多くの場合プロパティの OnValueChanged ハンドラーまたは OnValueChanging をオーバーライドすると便利です。 これらのメソッドは変更直前の後に呼び出されます。 一方規則は通常トランザクションの最後に実行されます。 詳細については、「ドメイン プロパティ値変更ハンドラー」を参照してください。
注意
この規則はリンクを作成または削除されると発生しません。代わりにドメイン リレーションシップの AddRule と DeleteRule を記述します。
要素またはリンクが削除されると発生します。 プロパティ ModelElement.IsDeleting はトランザクションが終了するまでです。
要素またはリンクが削除されたときに実行される。 規則は DeletingRules が他の規則がすべて実行後に実行されます。 ModelElement.IsDeleting は false になりModelElement.IsDeleted は TRUE です。 それ以降に戻す操作を可能にするには要素は実際にはメモリから削除されませんがStore.ElementDirectory から削除されます。
要素は 1 個のストア パーティションから別のページに移動します。
(これは図形のグラフィカルな場所と無関係に注意してください)。
この規則はドメイン リレーションシップにのみ適用されます。 これはリンクの前または後ろに明示的にモデル要素を割り当てるトリガーされます。
要素へのリンクの命令のリンクの MoveBefore または MoveToIndex のメソッドによって変更されると発生します。
トランザクションが作成されたときに実行されます。
トランザクションをコミットしようとするときに実行されます。
トランザクションをロールバックされるときに実行されます。
- 各クラスにはオーバーライドするメソッドがあります。 これを検出するクラスの override を入力します。 このメソッドのパラメーターは変更する要素を指定します。
規則については次の点に注意してください :
トランザクションの変更セットは多数の規則が呼び出される可能性があります。 通常規則は最も外側のトランザクションがコミットされたときに実行されます。 これらは不定の順序で実行されます。
規則は一つのトランザクション内で常に実行されます。 したがって変更を行う場合は新しいトランザクションを作成する必要はありません。
規則はトランザクションをロールバックまたは元に戻す操作またはやり直し操作の実行時に実行されません。 これらの操作は以前の状態に関するすべての内容をリセットします。 したがって規則がストアの外部の任意の状態を変更した場合ストアの内容で非同期で格納されることがあります。 ストアの外部で状態を更新するにはイベントを使用することをお勧めします。 詳細については、「イベント ハンドラーによって変更内容がモデル外に反映される」を参照してください。
の規則はモデルがファイルから読み込まれたときに実行されます。 読み込みまたは保存して進行中であるかどうかを確認するにはstore.TransactionManager.CurrentTransaction.IsSerializing を使用します。
規則のコードが規則のトリガーを作成する場合トランザクションが完了する前に発生のリストの末尾に追加され実行されます。 DeletedRules は他のすべての規則の後に実行されます。 1 種類の規則はトランザクションで実行する場合は各変更を 1 回実行できます。
規則との間で情報を渡すにはTransactionContext に情報を格納できます。 これはトランザクション中に保存されているディクショナリです。 またトランザクションが終了すると破棄されます。 各規則はイベント引数へのアクセスを提供します。 規則が予測可能な順序で実行されないことに注意してください。
他の代替手段を検討してから規則を使用します。 値が変化したときにたとえばプロパティを更新する場合は計算されたプロパティを使用することを検討してください。 図形のサイズや位置を表示しない場合は BoundsRule を使用します。 プロパティ値の変更に応答するにはプロパティに OnValueChanged ハンドラーを追加します。 詳細については、「変更内容への対応および変更内容の反映」を参照してください。
使用例
次の例では2 種類の要素をリンクするドメイン リレーションシップをインスタンス化するときにプロパティが更新されます。 規則はプログラム コードがリンクを作成するとユーザーが図にリンクを作成するまたは場合に発生します。
この例をテストしDSL をタスクのフローのソリューション テンプレートを使用して作成しDsl のプロジェクト ファイルに次のコードを挿入します。 ソリューションをビルドして実行しプロジェクトのデバッグのサンプル ファイルを開きます。 コメントの図形とフロー要素間のコメント リンクを描画します。 コメントのテキストはをに接続した最新の要素を表示するように変更されます。
実際には通常AddRule の DeleteRule を書き込みます。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.VisualStudio.Modeling; namespace Company.TaskRuleExample { [RuleOn(typeof(CommentReferencesSubjects))] public class RoleRule : AddRule { public override void ElementAdded(ElementAddedEventArgs e) { base.ElementAdded(e); CommentReferencesSubjects link = e.ModelElement as CommentReferencesSubjects; Comment comment = link.Comment; FlowElement subject = link.Subject; Transaction current = link.Store.TransactionManager.CurrentTransaction; // Don't want to run when we're just loading from file: if (current.IsSerializing) return; comment.Text = "Flow has " + subject.FlowTo.Count + " outgoing connections"; } } public partial class TaskRuleExampleDomainModel { protected override Type[] GetCustomDomainModelTypes() { List<Type> types = new List<Type>(base.GetCustomDomainModelTypes()); types.Add(typeof(RoleRule)); return types.ToArray(); } } }
参照
概念