程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Visual Studio DSL 入門 12---狀態機設計器的規則(Rule)和驗證(Validation)

Visual Studio DSL 入門 12---狀態機設計器的規則(Rule)和驗證(Validation)

編輯:關於.NET

上一節我們為狀態機設計器添加了一個Rule,主要用來處理當Transition的屬性 Label,Condition,Action,Event之間的任何一個值發生變化時,其余的屬性值也要按照我們 的規則來更新(我們的Label屬性就是一個輔助的屬性,用來更好的顯示和編輯另外三個屬性). 我們可以看到vs.net dsl提供的Rule機制的強大,它主要提供了以下幾個Rule:

AddRule:當ModelElement或者ElementLink添加時觸發

ChangeRule:當一個元素或者關系的屬性發生變化時觸發

DeleteingRule:刪除元素或關系時觸發

DeletedRule:刪除元素或關系後觸發

RolePlayerChangeRule:當域關系的一端發生變化時

RolePlayerPositionChangeRule:對於多重的關系中的角色發生變化

TransactionBeginningRule:事務開始時觸發

TransactionCommitingRule  事務提交時觸發

TransactionRollingBackRule  事務回滾時觸發

另外應該注意的是,AddRule,ChangeRule,DeleteingRule…這些都是在元素添加,更改, 刪除同時觸發,此時還在事務當中,也就是說,我們可以添加自己的規則,根據我們自定義 的條件取消事務或做一些其它的處理。

但是規則是強制性的,也就是說,在一個規則處理裡面,我們如果限制一個屬性值的類型 必須是整型,否則就拋出異常,停止此事務的提交。這屬於Vs.net Dsl提供的硬約束的一種 實現,相反,還有軟約束,那硬約束和軟約束有什麼不同呢?

硬約束就是指從不讓用戶違反的約束,比如我們例子中的四個屬性之間的這種關系,如果 有些個案,就會導致我們的元數據混亂,生成代碼就很麻煩.

軟約束是用戶有時可以違反,有時又不能違反的約束,或者是說,即使用戶違反了,我們 也要保證元數據能夠正常保存,正常提交。比如說我們的狀態機中沒有初始狀態. 

一個優秀的Dsl設計器應該是硬約束和軟約束結合,軟的不行來硬的!  當然,這裡提到 Rule只是硬約束的一種,比如我們還可以重載指定域屬性值屬性處理器內嵌類中的 OnXXXChanged()方法,例如,我們添加一個 partial類ConditionPropertyHandler:

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);
     }
   }

介紹了硬約束後,我們來看一下vs.net  dsl的軟約束的機制:

和硬約束一樣,軟約束也是通過附加的C#類來完成,相比於定義特殊的規則或者是驗證語 言來說,這很方便,有了更大的靈活性。我們來看一下validation機制,這就是vs.net dsl 提供的軟約束,它和rule最明顯的區別就是,rule是被動觸發的,當我們操作元數據,對模 型進行操作時,觸發了我們定義的Rule(規則),而 validation(驗證)一般是主動觸發的,提 供了上下文菜單,我們可以驗證我們整個模型或者是單個元素。

還是以我們的例子來介紹,為了狀態機的合理性,我們需要遵守:

Name屬性的值的有效性

初始狀態不能做為轉移的目標,結束狀態不能做為轉移的開始.

一個狀態機應該有一個初始狀態

下面我們就一步一步添加這些Validation:

1.首先在我們在CustomCode文件夾下面添加Validation文件夾,來存儲我們的驗證.

2.新建一個partial類State,注意命名空間修改為CompanyName.LanguageSm,要保持和原來 生成的State類一致.

3.給類打上ValidationState屬性標記.

[ValidationState(ValidationState.Enabled)]
  public partial class State
  {
  }

4. 我們在partial類中添加自定義的驗證,其實也就是添加驗證方法,在方法上打上 ValidationMehtods標記

[ValidationState(ValidationState.Enabled)]
  public partial class State
  {
    [ValidationMethod(ValidationCategories.Open |  ValidationCategories.Save | ValidationCategories.Menu)]
    private void ValidateAttributeNameAsValidIdentifier(ValidationContext  context)
    {
      CSharpCodeProvider csharp = new 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);
      }
    }
  }

其中ValidationCategories是代表驗證的調用時機, 設計器打開.保存模型文件還是通過 右鍵菜單中的Validate. 參數ValidationContext包含驗證的上下文信息,上面我們用來記錄 錯誤,信息提示等.

同樣的方式我們添加對另外初始狀態的驗證,上面我們提示的信息是寫死在程序裡面的,當 然可以實現從資源裡獲取.

5.我們要驗證整個狀態機只有一個初始狀態怎麼辦,添加StateMachine的partial類,在這 個類裡面添加驗證:

[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);
   }
}

6.不過這還不夠,我們還需要進行一下設置才能讓驗證生效,打開dsl文件,Dsl Explor中的 Editor/Validation結點,設置Validation屬性中的Use Menu,Use Open,Use Save為True:

 

7.重新轉換所有的模板,我們來測試一下我們的驗證,右鍵全部驗證:

回過頭來想一下,我們不允許結束狀態上建立Transition的源,這應該是強制性的吧,既然 這樣,我們為什麼還要在驗證的時候才去驗證,而允許用戶有機會犯這樣的錯誤呢?下面我們就 來實現對這個的控制,使結束狀態為源不能夠建立Transition關系.

8.打開Dsl Explorer,結點Connection Builder/TransitionBuilder/Link Connect Directives/Transition,選中Transition後,打開Dsl Details窗口,我們設置域關系 Transition的對於源角色State使用自定義接受(Custom accept).

9.轉換所有模板,重新編譯解決方案,你會發現有錯誤發生,是提示你必須要實現 TransitionBuilder中的 CanAcceptStateAsSource和 CanAcceptStateAndStateAsSourceAndTarget方法,這是 vs.net dsl設計自定義處理後通用的 處理方法,你必須手動添加相應的方法後才能夠編譯通過. 在我們的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 CanAcceptSource(sourceState);
     }
   }
}

10.再次運行我們的項目,你會發現,當選中Transition在一個結束狀態上拖拽時,你會發 現,顯示圓形的不可用.

代碼下載: http://files.cnblogs.com/lonely7345/LanguageSm4.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved