定義鎖定原則來建立唯讀區段Defining a Locking Policy to Create Read-Only Segments

Visual Studio 視覺效果和模型 SDK 的永久性 API 可讓程式鎖定部分或所有特定領域語言 (DSL) 模型,讓它可以讀取但不會變更。The Immutability API of the Visual Studio Visualization and Modeling SDK allows a program to lock part or all of a domain-specific language (DSL) model so that it can be read but not changed. 例如,您可以使用這個唯讀選項,讓使用者可以要求同事標注和審核 DSL 模型,但不允許他們變更原始模型。This read-only option could be used, for example, so that a user can ask colleagues to annotate and review a DSL model but can disallow them from changing the original.

此外,作為 DSL 的作者,您可以定義 鎖定原則。In addition, as author of a DSL, you can define a locking policy. 鎖定原則會定義允許、不允許或強制的鎖定。A locking policy defines which locks are permitted, not permitted, or mandatory. 例如,當您發佈 DSL 時,可以鼓勵協力廠商開發人員以新的命令延伸。For example, when you publish a DSL, you can encourage third-party developers to extend it with new commands. 但是,您也可以使用鎖定原則來防止它們變更模型指定部分的唯讀狀態。But you could also use a locking policy to prevent them from altering the read-only status of specified parts of the model.

注意

您可以使用反映來規避鎖定原則。A locking policy can be circumvented by using reflection. 它為協力廠商開發人員提供明確的界限,但不提供強大的安全性。It provides a clear boundary for third-party developers, but does not provide strong security.

如需詳細資訊和範例,請參閱 Visual Studio 視覺效果和模型 SDK 網站。More information and samples are available at the Visual Studio Visualization and Modeling SDK website.

注意

文字模板轉換 元件會自動安裝為 Visual Studio 延伸模組開發 工作負載的一部分。The Text Template Transformation component is automatically installed as part of the Visual Studio extension development workload. 您也可以從 Visual Studio 安裝程式的 [ 個別元件 ] 索引標籤,在 [sdk]、[連結 庫] 和 [架構] 類別下進行安裝。You can also install it from the Individual components tab of Visual Studio Installer, under the SDKs, libraries, and frameworks category. 從 [個別元件] 索引標籤安裝 模型 SDK 元件。Install the Modeling SDK component from the Individual components tab.

設定和取得鎖定Setting and Getting Locks

您可以在存放區、分割區或個別元素上設定鎖定。You can set locks on the store, on a partition, or on an individual element. 例如,此語句可防止刪除模型專案,也會防止變更其屬性:For example, this statement will prevent a model element from being deleted, and will also prevent its properties from being changed:

using Microsoft.VisualStudio.Modeling.Immutability; ...
element.SetLocks(Locks.Delete | Locks.Property);

您可以使用其他鎖定值來防止關聯性、元素建立、資料分割之間的移動,以及重新排序角色中的連結。Other lock values can be used to prevent changes in relationships, element creation, movement between partitions, and re-ordering links in a role.

鎖定適用于使用者動作和程式碼。The locks apply both to user actions and to program code. 如果程式碼嘗試進行變更, InvalidOperationException 將會擲回。If program code attempts to make a change, an InvalidOperationException will be thrown. 復原或重做作業會忽略鎖定。Locks are ignored in an Undo or Redo operation.

您可以使用來探索某個專案是否有指定之集合中的任何鎖定 IsLocked(Locks) ,而且您可以使用來取得專案目前的鎖定集 GetLocks()You can discover whether an element has a any lock in a given set by using IsLocked(Locks) and you can obtain the current set of locks on an element by using GetLocks().

您可以設定不使用交易的鎖定。You can set a lock without using a transaction. 鎖定資料庫不是存放區的一部分。The lock database is not part of the store. 如果您設定鎖定以回應存放區中的值變更,例如在 OnValueChanged 中,您應該允許屬於復原作業一部分的變更。If you set a lock in response to a change of a value in the store, for example in OnValueChanged, you should allow changes that are part of an Undo operation.

這些方法是在命名空間中定義的擴充方法 Microsoft.VisualStudio.Modeling.ImmutabilityThese methods are extension methods that are defined in the Microsoft.VisualStudio.Modeling.Immutability namespace.

分割區和存放區的鎖定Locks on partitions and stores

鎖定也可以套用至分割區和存放區。Locks can also be applied to partitions and the store. 在分割區上設定的鎖定會套用至資料分割中的所有元素。A lock that is set on a partition applies to all the elements in the partition. 因此,下列語句將會防止刪除分割區中的所有元素,而不考慮它們本身的鎖定狀態。Therefore, for example, the following statement will prevent all the elements in a partition from being deleted, irrespective of the states of their own locks. 不過,其他鎖定(例如) Locks.Property 仍然可以在個別元素上設定:Nevertheless, other locks such as Locks.Property could still be set on individual elements:

partition.SetLocks(Locks.Delete);

在存放區上設定的鎖定會套用至其所有專案,不論資料分割上的鎖定設定和元素。A lock that is set on the Store applies to all its elements, irrespective of the settings of that lock on the partitions and the elements.

使用鎖定Using Locks

您可以使用鎖定來執行配置,例如下列範例:You could use locks to implement schemes such as the following examples:

  • 除了表示批註的專案和關聯性之外,不允許對所有元素和關聯性進行變更。Disallow changes to all elements and relationships except those that represent comments. 這可讓使用者在不變更模型的情況下對其加上批註。This allows users to annotate a model without changing it.

  • 不允許變更預設分割區,但允許圖表分割區中的變更。Disallow changes in the default partition, but allow changes in the diagram partition. 使用者可以重新排列圖表,但無法改變基礎模型。The user can rearrange the diagram, but cannot alter the underlying model.

  • 除了在個別資料庫中註冊的使用者群組以外,不允許變更存放區。Disallow changes to the Store except for a group of users who are registered in a separate database. 若為其他使用者,則圖表和模型是唯讀的。For other users, the diagram and model are read-only.

  • 如果圖表的 [布林值] 屬性設定為 true,則不允許對模型進行變更。Disallow changes to the model if a Boolean property of the diagram is set to true. 提供功能表命令來變更該屬性。Provide a menu command to change that property. 這有助於確保使用者不會不小心進行變更。This helps ensure users that they do not make changes accidentally.

  • 不允許新增和刪除特定類別的元素和關聯性,但允許屬性變更。Disallow addition and deletion of elements and relationships of particular classes, but allow property changes. 這會為使用者提供固定的表單,讓他們可以填滿屬性。This provides users with a fixed form in which they can fill the properties.

鎖定值Lock values

您可以在存放區、資料分割或個別的 ModelElement 上設定鎖定。Locks can be set on a Store, Partition, or individual ModelElement. 鎖定是 Flags 列舉:您可以使用 ' | ' 將其值結合。Locks is a Flags enumeration: you can combine its values using '|'.

  • ModelElement 的鎖定一律會包含其分割區的鎖定。Locks of a ModelElement always include the Locks of its Partition.

  • 分割區的鎖定一律會包含存放區的鎖定。Locks of a Partition always include the Locks of the Store.

    您無法在分割區或存放區上設定鎖定,同時停用個別元素的鎖定。You cannot set a lock on a partition or store and at the same time disable the lock on an individual element.

Value 表示 if IsLocked(Value) 為 trueMeaning if IsLocked(Value) is true
None 無限制。No restriction.
屬性Property 無法變更元素的網域屬性。Domain properties of elements cannot be changed. 這並不適用于關聯性中網域類別角色所產生的屬性。This does not apply to properties that are generated by the role of a domain class in a relationship.
Add 無法在分割區或存放區中建立新的元素和連結。New elements and links cannot be created in a partition or store.

不適用於 ModelElementNot applicable to ModelElement.
移動Move 如果 element.IsLocked(Move) 是 true,或是如果為 true,則無法在分割區之間移動元素 targetPartition.IsLocked(Move)Element cannot be moved between partitions if element.IsLocked(Move) is true, or if targetPartition.IsLocked(Move) is true.
刪除Delete 如果這個鎖定是在元素本身上設定,或在刪除所要傳播的任何專案(例如內嵌的元素和圖形)上設定,則無法刪除元素。An element cannot be deleted if this lock is set on the element itself, or on any of the elements to which deletion would propagate, such as embedded elements and shapes.

您可以使用 element.CanDelete() 來探索是否可刪除元素。You can use element.CanDelete() to discover whether an element can be deleted.
排序Reorder 無法變更 roleplayer 的連結順序。The ordering of links at a roleplayer cannot be changed.
RolePlayerRolePlayer 無法變更以此專案為來源的連結集合。The set of links that are sourced at this element cannot be changed. 例如,新的元素不能內嵌在此專案底下。For example, new elements cannot be embedded under this element. 這不會影響此元素為目標的連結。This does not affect links for which this element is the target.

如果這個元素是連結,則不會影響其來源和目標。If this element is a link, its source and target are not affected.
全部All 其他值的位 OR。Bitwise OR of the other values.

鎖定原則Locking Policies

作為 DSL 的作者,您可以定義 鎖定原則As the author of a DSL, you can define a locking policy. 鎖定原則會審核 SetLocks ( # A1 的作業,讓您可以防止設定特定鎖定或強制設定特定鎖定。A locking policy moderates the operation of SetLocks(), so that you can prevent specific locks from being set or mandate that specific locks must be set. 一般而言,您會使用鎖定原則來防止使用者或開發人員不慎 contravening 預期的 DSL 使用方式,就像您可以宣告變數一樣 privateTypically, you would use a locking policy to discourage users or developers from accidentally contravening the intended use of a DSL, in the same manner that you can declare a variable private.

您也可以使用鎖定原則來設定相依于專案類型之所有專案的鎖定。You can also use a locking policy to set locks on all elements dependent on the element's type. 這是因為 SetLocks(Locks.None) 當第一次從檔案建立或還原序列化專案時,一律會呼叫。This is because SetLocks(Locks.None) is always called when an element is first created or deserialized from file.

不過,您無法使用原則來改變其生命週期內的鎖定。However, you cannot use a policy to vary the locks on an element during its life. 若要達成這個效果,您應該使用的呼叫 SetLocks()To achieve that effect, you should use calls to SetLocks().

若要定義鎖定原則,您必須:To define a locking policy, you have to:

  • 建立會實作 ILockingPolicy 的類別。Create a class that implements ILockingPolicy.

  • 將這個類別新增至可透過 DSL DocData 使用的服務。Add this class to the services that are available through the DocData of your DSL.

若要定義鎖定原則To define a locking policy

ILockingPolicy 具有下列定義:ILockingPolicy has the following definition:

public interface ILockingPolicy
{
  Locks RefineLocks(ModelElement element, Locks proposedLocks);
  Locks RefineLocks(Partition partition, Locks proposedLocks);
  Locks RefineLocks(Store store, Locks proposedLocks);
}

當對 SetLocks() 存放區、分割區或 ModelElement 進行呼叫時,會呼叫這些方法。These methods are called when a call is made to SetLocks() on a Store, Partition, or ModelElement. 在每個方法中,您都會提供一組建議的鎖定。In each method, you are provided with a proposed set of locks. 您可以傳回建議的集合,也可以加入和減少鎖定。You can return the proposed set, or you can add and subtract locks.

例如:For example:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Immutability;
namespace Company.YourDsl.DslPackage // Change
{
  public class MyLockingPolicy : ILockingPolicy
  {
    /// <summary>
    /// Moderate SetLocks(this ModelElement target, Locks locks)
    /// </summary>
    /// <param name="element">target</param>
    /// <param name="proposedLocks">locks</param>
    /// <returns></returns>
    public Locks RefineLocks(ModelElement element, Locks proposedLocks)
    {
      // In my policy, users can never delete an element,
      // and other developers cannot easily change that:
      return proposedLocks | Locks.Delete);
    }
    public Locks RefineLocks(Store store, Locks proposedLocks)
    {
      // Only one user can change this model:
      return Environment.UserName == "aUser"
           ? proposedLocks : Locks.All;
    }

若要確定使用者一律可以刪除元素,即使其他程式碼呼叫 SetLocks(Lock.Delete):To make sure that users can always delete elements, even if other code calls SetLocks(Lock.Delete):

return proposedLocks & (Locks.All ^ Locks.Delete);

若不允許在 MyClass 的每個元素的所有屬性中變更:To disallow change in all the properties of every element of MyClass:

return element is MyClass ? (proposedLocks | Locks.Property) : proposedLocks;

讓您的原則可作為服務使用To make your policy available as a service

在您的 DslPackage 專案中加入新檔案,其中包含類似下列範例的程式碼:In your DslPackage project, add a new file that contains code that resembles the following example:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Immutability;
namespace Company.YourDsl.DslPackage // Change
{
  // Override the DocData GetService() for this DSL.
  internal partial class YourDslDocData // Change
  {
    /// <summary>
    /// Custom locking policy cache.
    /// </summary>
    private ILockingPolicy myLockingPolicy = null;

    /// <summary>
    /// Called when a service is requested.
    /// </summary>
    /// <param name="serviceType">Service requested</param>
    /// <returns>Service implementation</returns>
    public override object GetService(System.Type serviceType)
    {
      if (serviceType == typeof(SLockingPolicy)
       || serviceType == typeof(ILockingPolicy))
      {
        if (myLockingPolicy == null)
        {
          myLockingPolicy = new MyLockingPolicy();
        }
        return myLockingPolicy;
      }
      // Request is for some other service.
      return base.GetService(serviceType);
    }
}