上一節已為狀態機設計器加入 Rule (規則),處理 Transition 的 Label、Condition、Action、Event 四個屬性聯動更新。本節深入探討 VS.NET DSL 提供的規則類型,並導入 Validation (驗證) 機制作為軟性約束的補充。
規則屬於硬性約束:在交易 (Transaction) 過程中被動觸發,若條件不符可取消交易、拋出例外,強制阻止不合法操作。
| 規則類型 | 觸發時機 |
|---|---|
| AddRule | ModelElement 或 ElementLink 新增時 |
| ChangeRule | 元素或關聯屬性變更時 |
| DeletingRule | 刪除元素/關聯前 |
| DeletedRule | 刪除元素/關聯後 |
| RolePlayerChangeRule | 領域關聯一端角色變更時 |
| RolePlayerPositionChangeRule | 多重關聯中角色位置變更時 |
| TransactionBeginningRule | 交易開始時 |
| TransactionCommittingRule | 交易認可時 |
| TransactionRollingBackRule | 交易回滾時 |
注意: AddRule、ChangeRule、DeletingRule 等均在交易進行中觸發,此時可攔截並取消交易。
除了規則,也可重寫屬性處理器的 OnValueChanging/OnValueChanged:
internal sealed partial class ConditionPropertyHandler : DomainPropertyValueHandler<Transition, string>
{
protected override void OnValueChanging(Transition element, string oldValue, string newValue)
{
if (!element.Store.InUndoRedoOrRollback)
{
if (!string.IsNullOrEmpty(newValue))
{
element.Label = ComputeSummary(newValue, element.Condition, element.Action);
}
}
base.OnValueChanging(element, oldValue, newValue);
}
}
與規則被動觸發不同,驗證屬於主動觸發:提供右鍵選單、開啟/儲存模型時自動執行,允許使用者暫時違反但給予警告,不阻擋儲存。適用於「最好遵守但不強制」的商業規則。
在 CustomCode 資料夾下新增 Validation 子資料夾存放驗證類別。
[ValidationState(ValidationState.Enabled)]
public partial class State
{
[ValidationMethod(ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu)]
private void ValidateAttributeNameAsValidIdentifier(ValidationContext context)
{
var csharp = new Microsoft.CSharp.CSharpCodeProvider();
if (string.IsNullOrEmpty(this.Name.Trim()))
context.LogError("State 的名稱不能為空", "StateMachine – State - 01", this);
else if (!csharp.IsValidIdentifier(Name))
context.LogError("State 的名稱不合法", "StateMachines – State - 02", this);
}
// 初始/結束狀態不得作為 Transition 來源/目標的驗證同理可加入
}
[ValidationState(ValidationState.Enabled)]
public partial class StateMachine
{
[ValidationMethod(ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu)]
private void ValidateStateMachineHasOneInitialState(ValidationContext context)
{
if (!States.Exists(p => p.Kind == StateKind.Initial))
context.LogError("狀態機至少應該有一個初始狀態", "StateMachine - 01", this);
}
}
開啟 DslDefinition.dsl,在 DSL Explorer 中選取 Editor / Validation,將 Use Menu、Use Open、Use Save 全設為 True。

重新轉換所有範本,建置並啟動實驗專案。右鍵設計介面選擇「全部驗證」:

此規則屬業務邏輯核心,不應允許使用者違反。改用 Connection Builder 自訂接受 機制在拖曳建立連線時直接阻擋。

TransitionBuilder 兩個靜態方法。CustomCode 新增 TransitionBuilder 靜態部分類別:namespace Company.LanguageSm
{
public static partial class TransitionBuilder
{
private static bool CanAcceptStateAsSource(State state)
{
return (state != null) && (state.Kind != StateKind.Final);
}
private static bool CanAcceptStateAndStateAsSourceAndTarget(State sourceState, State targetState)
{
return CanAcceptStateAsSource(sourceState);
}
}
}