次の方法で共有


Windows フォームに基づくドメイン固有言語を作成する

DSL 図を使用する代わりに Windows フォームを使用して、ドメイン固有言語 (DSL) モデルの状態を表示できます。 このトピックでは、Visual Studio Visualization and Modeling SDK を使用して Windows フォームを DSL にバインドする手順について説明します。

次の図は、ある DSL インスタンスの Windows フォーム UI とモデル エクスプローラーを示しています。

DSL instance in Visual Studio

Windows フォームの DSL を作成する

最小 WinForm デザイナー DSL テンプレートでは、独自の要件に合わせて変更できる最小限の DSL を作成できます。

  1. 最小 WinForm デザイナー テンプレートから DSL を作成します。

    このチュートリアルでは、次の名前を想定しています。

    • ソリューションと DSL の名前: FarmApp
    • 名前空間: Company.FarmApp
  2. テンプレートに用意されている最初の例を試します。

    1. [すべてのテンプレートの変換] を実行します。

    2. サンプルをビルドして実行します (Ctrl+F5 キー)。

    3. Visual Studio の実験用インスタンスで、デバッグ プロジェクト内の Sample ファイルを開きます。

      これが Windows フォーム コントロールに表示されていることを確認してください。

      また、モデルの要素がエクスプローラーに表示されていることも確認できます。

      フォームまたはエクスプローラーのどちらか一方でいくつかの要素を追加し、それらが他方の表示画面に表示されていることを確認します。

    Visual Studio の主要なインスタンスでは、DSL ソリューションに関する次の点にご注意ください。

  • DslDefinition.dsl にはダイアグラム要素が含まれていません。 この DSL のインスタンス モデルの表示には DSL 図を使用しないためです。 代わりに、Windows フォームをモデルにバインドすると、フォーム上の要素にモデルが表示されます。

  • Dsl および DslPackage プロジェクトに加えて、このソリューションには UI. という名前の 3 つ目のプロジェクトも含まれています。UI プロジェクトには、Windows フォーム コントロールの定義が含まれています。 DslPackageUI に依存しており、UIDsl に依存しています。

  • DslPackage プロジェクトの UI\DocView.cs には、UI プロジェクトで定義されている Windows フォーム コントロールを表示するコードが含まれています。

  • UI プロジェクトには、DSL にバインドされたフォーム コントロールの作業用サンプルが含まれています。 ただし、DSL 定義を変更した場合は機能しなくなります。 UI プロジェクト名には以下が含まれています。

    • ModelViewControl という名前の Windows フォーム クラス。

    • ModelViewControl の追加の部分定義を含む、DataBinding.cs という名前のファイル。 その内容を確認するには、ソリューション エクスプローラーで、そのファイルのショートカット メニューを開き、 [コードの表示] を選択します。

UI プロジェクトについて

DSL 定義ファイルを更新して独自の DSL を定義する場合は、その DSL を表示するように UI プロジェクト内のコントロールを更新する必要があります。 DslDslPackage のプロジェクトとは異なり、DslDefinitionl.dsl から UI のサンプル プロジェクトは生成されません。 必要に応じて、.tt ファイルを追加してコードを生成できます (ただし、これについては、このチュートリアルでは説明しません)。

DSL 定義を更新する

次の図は、このチュートリアルで使用する DSL 定義を示しています。

DSL definition

  1. DSL デザイナーで DslDefinition.dsl を開きます。

  2. ExampleElement を削除します

  3. ExampleModel ドメイン クラスの名前を Farm に変更します。

    これに、Size という名前の Int32 型と、IsOrganic という名前の Boolean 型の追加のドメイン プロパティを指定します。

    Note

    ルート ドメイン クラスを削除してから新しいルートを作成する場合は、[エディターのルート クラス] プロパティをリセットする必要があります。 DSL エクスプローラーで、 [エディター] を選択します。 次に、プロパティ ウィンドウで、 [ルート クラス]Farm に設定します。

  4. [名前付きドメイン クラス] ツールを使用して、次のドメイン クラスを作成します。

    • Field - これに Size という名前の追加のドメイン プロパティを指定します。

    • Animal - プロパティ ウィンドウで、 [継承修飾子][抽象] に設定します。

    Note

    このセクションで説明する名前付きドメイン クラス ツールやその他のツールは、[ツールボックス] ツール ウィンドウにあります。 このウィンドウは、[表示]>[ツールボックス] で開いたり非表示にしたりできます。

  5. [ドメイン クラス] ツールを使用して、次のクラスを作成します。

    • Sheep

    • Goat

  6. [継承] ツールを使用して、GoatSheepAnimal から継承させます。

  7. [埋め込み] ツールを使用して、FieldAnimalFarm の下に埋め込みます。

  8. 図を整理することをお勧めします。 重複する要素の数を減らすには、リーフ要素のショートカット メニュー上の [ここにサブツリーを表示] を使用します。

  9. ソリューション エクスプローラーのツールバーで [すべてのテンプレートの変換] を実行します。

  10. Dsl プロジェクトをビルドします。

    注意

    この段階では、他のプロジェクトはエラーのない状態でビルドされません。 ただし、Dsl プロジェクトは、データ ソース ウィザードでそのアセンブリを使用できるようにビルドする必要があります。

UI プロジェクトを更新する

DSL モデルに格納されている情報を表示する新しいユーザー コントロールを作成できるようになりました。 ユーザー コントロールをモデルに接続する最も簡単な方法は、データ バインディングを使用することです。 ModelingBindingSource という名前のデータ バインディング アダプター タイプは、DSL を VMSDK 以外のインターフェイスに接続するように特別に設計されています。

DSL モデルをデータ ソースとして定義する

  1. [データ] メニューの [データ ソースの表示] をクリックします。

    [データ ソース] ウィンドウが開きます。

    [新しいデータ ソースの追加] を選択します。 データ ソース構成ウィザードが開きます。

  2. [オブジェクト][次へ] の順に選択します。

    [Dsl][Company.FarmApp] の順に展開し、モデルのルート クラスである [Farm] を選択します。 [完了] を選択します。

    ソリューション エクスプローラーでは、UI プロジェクトに Properties\DataSources\Farm.datasource が含まれるようになりました

    モデル クラスのプロパティとリレーションシップが [データ ソース] ウィンドウに表示されます。

    Data sources window

モデルをフォームに接続する

  1. UI プロジェクトで、既存の .cs ファイルをすべて削除します。

  2. FarmControl という名前の新しい ユーザー コントロール ファイルを UI プロジェクトに追加します。

  3. [データ ソース] ウィンドウの [Farm] のドロップダウン メニューで、 [詳細] を選択します。

    他のプロパティの既定の設定はそのままにします。

  4. デザイン ビューで FarmControl.cs を開きます。

    [データ ソース] ウィンドウから FarmControl に [Farm] をドラッグします。

    一連のコントロールが、各プロパティに 1 つずつ表示されます。 リレーションシップのプロパティでは、コントロールは生成されません。

  5. [farmBindingNavigator] を削除します。 これは FarmControl デザイナーでも自動的に生成されますが、このアプリケーションには役立ちません。

  6. ツールボックスを使用して、 [DataGridView] のインスタンスを 2 つ作成し、「AnimalGridView」および「FieldGridView」という名前を付けます。

    注意

    代替手順として、[データ ソース] ウィンドウからそのコントロールに [Animals] と [Fields] の各項目をドラッグすることもできます。 このアクションにより、グリッド ビューとデータ ソースの間にデータ グリッドおよびバインディングが自動的に作成されます。 ただし、このバインディングは DSL では正しく機能しません。 そのため、データ グリッドおよびバインディングは手動で作成することをお勧めします。

  7. ツールボックスに [ModelingBindingSource] ツールが含まれていない場合は、それを追加します。 [データ] タブのショートカット メニューで、 [項目の選択] を選択します。 [ツールボックス項目の選択] ダイアログで、 [.NET Framework] タブの [ModelingBindingSource] を選択します。

  8. ツールボックスを使用して、 [ModelingBindingSource] のインスタンスを 2 つ作成し、「AnimalBinding」および「FieldBinding」という名前を付けます。

  9. [ModelingBindingSource][データ ソース] プロパティを [farmBindingSource] に設定します。

    [データ メンバー] プロパティを [Animals] または [Fields] に設定します。

  10. AnimalGridViewFieldGridView[DataSource] プロパティをそれぞれ AnimalBindingFieldBinding に設定します。

  11. Farm コントロールのレイアウトをご自分の好みに合わせて調整します。

    ModelingBindingSource は、DSL に固有のいくつかの機能を実行するアダプターです。

  • VMSDK ストア トランザクション内の更新をラップします。

    たとえば、ユーザーがデータ ビュー グリッドから行を削除すると、通常のバインディングではトランザクション例外が発生します。

  • ユーザーが行を選択するときに、データ グリッド行ではなく、対応するモデル要素のプロパティがプロパティ ウィンドウに表示されるようにします。

    Schema of the DSL binding

    データ ソースとビューの間のリンクのスキーマ。

DSL へのバインドを完了する

  1. UI プロジェクト内の別のコード ファイルに次のコードを追加します。

    using System.ComponentModel;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Modeling.Design;
    
    namespace Company.FarmApp
    {
      partial class FarmControl
      {
        public IContainer Components { get { return components; } }
    
        /// <summary>Binds the WinForms data source to the DSL model.
        /// </summary>
        /// <param name="nodelRoot">The root element of the model.</param>
        public void DataBind(ModelElement modelRoot)
        {
          WinFormsDataBindingHelper.PreInitializeDataSources(this);
          this.farmBindingSource.DataSource = modelRoot;
          WinFormsDataBindingHelper.InitializeDataSources(this);
        }
      }
    }
    
  2. DslPackage プロジェクトで、次の変数定義を更新するように DslPackage\DocView.tt を編集します。

    string viewControlTypeName = "FarmControl";
    

DSL をテストする

DSL ソリューションをビルドして実行できるようになりましたが、後でさらに改善を加えることもできます。

  1. ソリューションをビルドして実行します。

  2. Visual Studio の実験用インスタンスで、Sample ファイルを開きます。

  3. FarmApp エクスプローラーで、 [Farm] ルート ノードのショートカット メニューを開き、 [Add New Goat] を選択します。

    Goat1[Animals] ビューに表示されます。

    警告

    [Animals] ノードではなく、 [Farm] ノードのショートカット メニューを使用する必要があります。

  4. [Farm] ルート ノードを選択し、そのプロパティを表示します。

    フォーム ビューで、Farm の [Name] または [Size] を変更します。

    フォームの各フィールドから移動すると、対応するプロパティがプロパティ ウィンドウ内で変更されます。

DSL を拡張する

プロパティを直ちに更新する

  1. FarmControl.cs のデザイン ビューで、[Name]、[Size]、[IsOrganic] などの単純なフィールドを選択します。

  2. プロパティ ウィンドウで、 [DataBindings] を展開して [(詳細)] を開きます。

    [フォーマットと詳細バインド] ダイアログの [データ ソース更新モード] で、 [OnPropertyChanged] を選択します。

  3. ソリューションをビルドして実行します。

    フィールドの内容を変更すると、Farm モデルの対応するプロパティがすぐに変更されることを確認します。

ボタンの追加機能を提供する

  1. FarmControl.cs のデザイン ビューで、ツールボックスを使用してフォーム上にボタンを作成します。

    そのボタンの名前やテキストを (New Sheep などに) 編集します。

  2. (ボタンをダブルクリックするなどして) ボタンの背後にあるコードを開きます。

    次のように編集します。

    private void NewSheepButton_Click(object sender, EventArgs e)
    {
      using (Transaction t = farm.Store.TransactionManager.BeginTransaction("Add sheep"))
      {
        elementOperations.MergeElementGroup(farm,
          new ElementGroup(new Sheep(farm.Partition)));
        t.Commit();
      }
    }
    
    // The following code is shared with other add buttons:
    private ElementOperations operationsCache = null;
    private ElementOperations elementOperations
    {
      get
      {
        if (operationsCache == null)
        {
          operationsCache = new ElementOperations(farm.Store, farm.Partition);
        }
        return operationsCache;
      }
    }
    private Farm farm
    {
      get { return this.farmBindingSource.DataSource as Farm; }
    }
    

    次のディレクティブを挿入する必要もあります。

    
    using Microsoft.VisualStudio.Modeling;
    
  3. Goats と Fields についても同様のボタンを 追加します。

  4. ソリューションをビルドして実行します。

  5. 新規作成のボタンによって項目が追加されることを確認します。 FarmApp エクスプローラーと適切なデータ グリッド ビューの両方に新しい項目が表示されます。

    データ グリッド ビューでその要素の名前を編集できます。 そこから削除することもできます。

    Sample data grid view

要素を追加するコードについて

新しい要素のボタンについては、次の代替コードの方がややシンプルです。

private void NewSheepButton_Click(object sender, EventArgs e)
{
  using (Transaction t = farm.Store.TransactionManager.BeginTransaction("Add sheep"))
  {
    farm.Animals.Add(new Sheep(farm.Partition)); ;
    t.Commit();
  }
}

ただし、このコードでは、新しい項目の既定の名前は設定されません。 DSL の要素マージ ディレクティブで定義した可能性のあるカスタマイズされたマージは実行されず、定義されている可能性のあるカスタム マージ コードも実行されません。

そのため、ElementOperations を使用して新しい要素を作成することをお勧めします。 詳細については、「要素作成処理および要素移動処理のカスタマイズ」を参照してください。