現在の選択項目を表示および制限する

ドメイン固有言語用のコマンドまたはジェスチャ ハンドラーを記述するときに、ユーザーが右クリックした要素を特定できます。 また、一部の図形またはフィールドが選択されないようにすることもできます。 たとえば、ユーザーがアイコン デコレーターをクリックしたときに、それが含まれる図形が代わりに選択されるようにすることができます。 この方法で選択を制限すると、記述する必要のあるハンドラーの数が減ります。 また、それによってユーザーも楽になり、デコレーターを避けることなく、図形内の任意の場所をクリックできるようになります。

コマンド ハンドラーから現在の選択項目にアクセスする

ドメイン固有言語のコマンド セット クラスには、カスタム コマンド用のコマンド ハンドラーが含まれています。 ドメイン固有言語のコマンド セット クラスの派生元である CommandSet クラスにより、現在の選択項目にアクセスするためのいくつかのメンバーが提供されています。

コマンド ハンドラーでは、コマンドに応じて、モデル デザイナー、モデル エクスプローラー、またはアクティブ ウィンドウに選択項目が含まれることが必要になる場合があります。

選択情報にアクセスするには

  1. CommandSet クラスで定義されている次のメンバーを使用して、現在の選択項目にアクセスできます。

    メンバー 説明
    IsAnyDocumentSelectionCompartment メソッド モデル デザイナーで選択されているいずれかの要素がコンパートメント シェイプである場合は、true を返します。それ以外の場合は false を返します。
    IsDiagramSelected メソッド モデル デザイナーでダイアグラムが選択されている場合は、true を返します。それ以外の場合は false を返します。
    IsSingleDocumentSelection メソッド モデル デザイナーで厳密に 1 つの要素が選択されている場合は、true を返します。それ以外の場合は false を返します。
    IsSingleSelection メソッド アクティブ ウィンドウで厳密に 1 つの要素が選択されている場合は、true を返します。それ以外の場合は false を返します。
    CurrentDocumentSelection プロパティ モデル デザイナーで選択されている要素の読み取り専用のコレクションを取得します。
    CurrentSelection プロパティ アクティブ ウィンドウで選択されている要素の読み取り専用のコレクションを取得します。
    SingleDocumentSelection プロパティ モデル デザイナーでの選択のプライマリ要素を取得します。
    SingleSelection プロパティ アクティブ ウィンドウでの選択のプライマリ要素を取得します。
  2. CurrentDocView クラスの CommandSet プロパティを使用すると、 モデル デザイナー ウィンドウを表す DiagramDocView オブジェクトにアクセスでき、さらにモデル デザイナーで選択されている要素にもアクセスできます。

  3. さらに、生成されたコードでは、ドメイン固有言語用のコマンド セット クラスでエクスプローラー ツール ウィンドウ プロパティとエクスプローラー選択プロパティが定義されています。

    • エクスプローラー ツール ウィンドウ プロパティからは、ドメイン固有言語用のエクスプローラー ツール ウィンドウ クラスのインスタンスが返されます。 エクスプローラー ツール ウィンドウ クラスは ModelExplorerToolWindow クラスから派生し、ドメイン固有言語用のモデル エクスプローラーを表します。

    • ExplorerSelection プロパティからは、ドメイン固有言語用のモデル エクスプローラー ウィンドウで選択されている要素が返されます。

アクティブなウィンドウを特定する

IMonitorSelectionService インターフェイスには、シェルの現在の選択状態にアクセスできるメンバーが定義されています。 ドメイン固有言語用のパッケージ クラスまたはコマンド セット クラスの基底クラスで定義されている MonitorSelection プロパティを使用して、それぞれのクラスから IMonitorSelectionService オブジェクトを取得できます。 パッケージ クラスは ModelingPackage クラスから派生し、コマンド セット クラスは CommandSet クラスから派生しています。

アクティブになっているウィンドウの種類をコマンド ハンドラーから特定するには

  1. CommandSet クラスの MonitorSelection プロパティからは、シェルの現在の選択状態にアクセスできる IMonitorSelectionService オブジェクトが返されます。

  2. IMonitorSelectionService インターフェイスの CurrentSelectionContainer プロパティを使用すると、アクティブな選択コンテナーを取得できます。これは、アクティブなウィンドウとは異なる場合があります。

  3. アクティブなウィンドウの種類を特定するには、次のプロパティをドメイン固有言語用のコマンド セット クラスに追加します。

    // using Microsoft.VisualStudio.Modeling.Shell;
    
    // Returns true if the model designer is the active selection container;
    // otherwise, false.
    protected bool IsDesignerActive
    {
        get
        {
            return (this.MonitorSelection.CurrentSelectionContainer
                is DiagramDocView);
        }
    }
    
    // Returns true if the model explorer is the active selection container;
    // otherwise, false.
    protected bool IsExplorerActive
    {
        get
        {
            return (this.MonitorSelection.CurrentSelectionContainer
                is ModelExplorerToolWindow);
        }
    }
    

選択を制約する

選択規則を追加することにより、ユーザーがモデル内の要素を選択したときに選択される要素を制御できます。 たとえば、ユーザーが複数の要素を 1 つの単位として扱うことができるようにするには、選択規則を使用します。

選択規則を作成するには

  1. DSL プロジェクトでカスタム コード ファイルを作成します

  2. DiagramSelectionRules クラスから派生する選択規則クラスを定義します。

  3. 選択条件を適用するには、選択規則クラスの GetCompliantSelection メソッドをオーバーライドします。

  4. ClassDiagram クラスの部分クラス定義を、カスタム コード ファイルに追加します。

    ClassDiagram クラスは、Diagram クラスから派生し、DSL プロジェクトの生成されたコード ファイル (Diagram.cs) で定義されています。

  5. カスタム選択規則を返すように、ClassDiagram クラスの SelectionRules プロパティをオーバーライドします。

    SelectionRules プロパティの既定の実装では、選択を変更しない選択規則オブジェクトが取得されます。

次のコード ファイルでは、最初に選択されていた各ドメイン シェイプのすべてのインスタンスが含まれるように選択範囲を拡張する選択規則が作成されます。

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace CompanyName.ProductName.GroupingDsl
{
    public class CustomSelectionRules : DiagramSelectionRules
    {
        protected Diagram diagram;
        protected IElementDirectory elementDirectory;

        public CustomSelectionRules(Diagram diagram)
        {
            if (diagram == null) throw new ArgumentNullException();

            this.diagram = diagram;
            this.elementDirectory = diagram.Store.ElementDirectory;
        }

        /// <summary>Called by the design surface to allow selection filtering.
        /// </summary>
        /// <param name="currentSelection">[in] The current selection before any
        /// ShapeElements are added or removed.</param>
        /// <param name="proposedItemsToAdd">[in/out] The proposed DiagramItems to
        /// be added to the selection.</param>
        /// <param name="proposedItemsToRemove">[in/out] The proposed DiagramItems
        /// to be removed from the selection.</param>
        /// <param name="primaryItem">[in/out] The proposed DiagramItem to become
        /// the primary DiagramItem of the selection. A null value signifies that
        /// the last DiagramItem in the resultant selection should be assumed as
        /// the primary DiagramItem.</param>
        /// <returns>true if some or all of the selection was accepted; false if
        /// the entire selection proposal was rejected. If false, appropriate
        /// feedback will be given to the user to indicate that the selection was
        /// rejected.</returns>
        public override bool GetCompliantSelection(
            SelectedShapesCollection currentSelection,
            DiagramItemCollection proposedItemsToAdd,
            DiagramItemCollection proposedItemsToRemove,
            DiagramItem primaryItem)
        {
            if (currentSelection.Count == 0 && proposedItemsToAdd.Count == 0) return true;

            HashSet<DomainClassInfo> itemsToAdd = new HashSet<DomainClassInfo>();

            foreach (DiagramItem item in proposedItemsToAdd)
            {
                if (item.Shape != null)
                    itemsToAdd.Add(item.Shape.GetDomainClass());
            }
            proposedItemsToAdd.Clear();
            foreach (DomainClassInfo classInfo in itemsToAdd)
            {
                foreach (ModelElement element
                    in this.elementDirectory.FindElements(classInfo, false))
                {
                    if (element is ShapeElement)
                    {
                        proposedItemsToAdd.Add(
                            new DiagramItem((ShapeElement)element));
                    }
                }
            }

            return true;
        }
    }

    public partial class ClassDiagram
    {
        protected CustomSelectionRules customSelectionRules = null;

        protected bool multipleSelectionMode = true;

        public override DiagramSelectionRules SelectionRules
        {
            get
            {
                if (multipleSelectionMode)
                {
                    if (customSelectionRules == null)
                    {
                        customSelectionRules = new CustomSelectionRules(this);
                    }
                    return customSelectionRules;
                }
                else
                {
                    return base.SelectionRules;
                }
            }
        }
    }
}