Compartilhar via


Criar uma Linguagem Específica de Domínio baseada no Windows Forms

Você pode usar Windows Forms para exibir o estado de um modelo DSL (linguagem específica do domínio) em vez de usar um diagrama DSL. Este tópico explica como associar um Windows Form a uma DSL usando o SDK de Visualização e Modelagem do Visual Studio.

A seguinte imagem mostra uma interface do usuário do Windows Form e o gerenciador de modelos para uma instância DSL:

DSL instance in Visual Studio

Criar uma DSL do Windows Forms

O modelo DSL Minimal WinForm Designer cria uma DSL mínima que você pode modificar para atender aos seus requisitos.

  1. Crie uma DSL com base no modelo Minimal WinForm Designer.

    Neste passo a passo, os seguintes nomes são considerados:

    • Solução e nome DSL: FarmApp
    • Namespace: Company.FarmApp
  2. Experimente o exemplo inicial que o modelo fornece:

    1. Transformar todos os modelos.

    2. Compilar e executar a amostra (Ctrl+F5).

    3. Na instância experimental do Visual Studio, abra o arquivo Sample no projeto de depuração.

      Observe que ele é exibido em um controle Windows Forms.

      Você também pode ver os elementos do modelo exibidos no Explorer.

      Adicione alguns elementos no formulário ou no Explorer e observe se eles aparecem na outra exibição.

    Na instância principal do Visual Studio, observe os seguintes pontos sobre a solução DSL:

  • DslDefinition.dsl não contém elementos de diagrama. Isso ocorre porque você não usará diagramas DSL para exibir modelos de instância dessa DSL. Em vez disso, você associará um Windows Form ao modelo e os elementos no formulário exibirão o modelo.

  • Além dos projetos Dsl e DslPackage, a solução contém um terceiro projeto chamado UI.UI que contém a definição de um controle do Windows Forms. DslPackage depende de UI e UI depende de Dsl.

  • No projeto DslPackage, UI\DocView.cs contém o código que exibe o controle do Windows Forms definido no projeto UI.

  • O projeto UI contém um exemplo funcional de um controle de formulário associado à DSL. No entanto, ele não funcionará quando você tiver alterado a Definição de DSL. O projeto UI contém:

    • Uma classe do Windows Forms chamada ModelViewControl.

    • Um arquivo chamado DataBinding.cs que contém uma definição parcial adicional de ModelViewControl. Para ver seu conteúdo, no Gerenciador de Soluções, abra o menu de atalho do arquivo e escolha Exibir Código.

Sobre o projeto da interface do usuário

Ao atualizar o arquivo de Definição de DSL para definir sua DSL, você precisará atualizar o controle no projeto UI para exibir sua DSL. Ao contrário dos projetos Dsl e DslPackage, o projeto de amostra UI não é gerado de DslDefinitionl.dsl. Você poderá adicionar arquivos .tt para gerar o código se desejar, embora isso não seja abordado neste passo a passo.

Atualizar a definição de DSL

A imagem a seguir é a definição de DSL usada neste passo a passo.

DSL definition

  1. Abra DslDefinition.dsl no designer DSL.

  2. Excluir ExampleElement

  3. Renomeie a classe de domínio ExampleModel como Farm.

    Forneça propriedades de domínio adicionais nomeadas Size do tipo Int32 e IsOrganic do tipo booliano.

    Observação

    Se você excluir a classe de domínio raiz e criar uma nova raiz, precisará redefinir a propriedade Editor Root Class. No Gerenciador DSL, selecione Editor. Na janela Propriedades, defina Classe Raiz como Farm.

  4. Use a ferramenta Classe de Domínio Nomeada para criar as seguintes classes de domínio:

    • Field – dê a ela uma propriedade de domínio adicional chamada Size.

    • Animal– na janela Propriedades, defina Modificador de Herança como Abstrato.

    Observação

    A ferramenta Classe de Domínio Nomeada e as outras ferramentas mencionadas nesta seção são encontradas na janela de ferramentas da Caixa de Ferramentas. Você pode abrir ou ocultar essa janela com Exibir>Caixa de Ferramentas.

  5. Use a ferramenta Classe de Domínio para criar as seguintes classes:

    • Sheep

    • Goat

  6. Use a ferramenta Herança para fazer Goat e Sheep herdar de Animal.

  7. Use a ferramenta Inserção para inserir Field e Animal em Farm.

  8. Talvez você queira organizar o diagrama. Para reduzir o número de elementos duplicados, use o comando Bring Subtree Here no menu de atalhos dos elementos folha.

  9. Transformar Todos os Modelos na barra de ferramentas do Gerenciador de Soluções.

  10. Compile o projeto DSL.

    Observação

    Nesta fase, os outros projetos não serão compilados sem erros. No entanto, queremos compilar o projeto DSL para que seu assembly esteja disponível para o Assistente da Fonte de Dados.

Atualizar o projeto da interface do usuário

Agora você pode criar um novo controle de usuário que exibirá as informações armazenadas no modelo DSL. A maneira mais fácil de conectar o controle de usuário ao modelo é por meio de associações de dados. O tipo de adaptador de associação de dados chamado ModelingBindingSource foi projetado especificamente para conectar DSLs a interfaces não VMSDK.

Definir seu modelo DSL como uma fonte de dados

  1. No menu Dados, escolha Mostrar Fontes de Dados.

    A janela Fontes de Dados é aberta.

    Escolha Adicionar Nova Fonte de Dados. O Assistente de Configuração de Fonte de Dados é aberto.

  2. Escolha Objeto, Avançar.

    Expanda DSL, Company.FarmApp e selecione Farm, que é a classe raiz do modelo. Escolha Concluir.

    No Gerenciador de Soluções, o projeto da interface do usuário agora contém Properties\DataSources\Farm.datasource

    As propriedades e as relações da classe de modelo aparecem na janela Fontes de Dados.

    Data sources window

Conectar seu modelo a um formulário

  1. No projeto da interface do usuário, exclua todos os arquivos .cs existentes.

  2. Adicione um novo arquivo Controle de Usuário chamado FarmControl ao projeto UI.

  3. Na janela Fontes de Dados, no menu suspenso do Farm, escolha Detalhes.

    Deixe as configurações padrão para as outras propriedades.

  4. Abra FarmControl.cs na exibição de design.

    Arraste Farm da janela Fontes de Dados para FarmControl.

    Um conjunto de controles é exibido, um para cada propriedade. As propriedades de relação não geram controles.

  5. Exclua farmBindingNavigator. Isso também é gerado automaticamente no designer FarmControl, mas não é útil para esse aplicativo.

  6. Usando a caixa de ferramentas, crie duas instâncias de DataGridView e nomeie-as como AnimalGridView e FieldGridView.

    Observação

    Uma etapa alternativa é arrastar os itens Animais e Campos da janela Fontes de Dados para o controle. Essa ação cria automaticamente grades de dados e associações entre a exibição de grade e a fonte de dados. No entanto, essa associação não funciona corretamente para DSLs. Portanto, é melhor criar as grades de dados e as associações manualmente.

  7. Se a Caixa de Ferramentas não contiver a ferramenta ModelingBindingSource, adicione-a. No menu de atalho da guia Dados, selecione Escolher Itens. Na caixa de diálogo Escolher Itens da Caixa de Ferramentas, selecione ModelingBindingSource na guia .NET Framework.

  8. Usando a Caixa de Ferramentas, crie duas instâncias de ModelingBindingSource e nomeie-as como AnimalBinding e FieldBinding.

  9. Defina a propriedade DataSource de cada ModelingBindingSource como farmBindingSource.

    Defina a propriedade DataMember como Animais ou Campos.

  10. Defina as propriedades DataSource de AnimalGridView como AnimalBinding e de FieldGridView como FieldBinding.

  11. Ajuste o layout do controle Farm ao seu gosto.

    O ModelingBindingSource é um adaptador que executa várias funções específicas para DSLs:

  • Ele encapsula atualizações em uma Transação de Repositório VMSDK.

    Por exemplo, quando o usuário exclui uma linha da grade de exibição de dados, uma associação regular resultaria em uma exceção de transação.

  • Ela garante que, quando o usuário seleciona uma linha, a janela Propriedades exibe as propriedades do elemento de modelo correspondente em vez da linha da grade de dados.

    Schema of the DSL binding

    Esquema de links entre fontes de dados e exibições.

Concluir as associações à DSL

  1. Adicione o seguinte código em um arquivo de código separado no projeto de interface do usuário:

    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. No projeto DslPackage, edite DslPackage\DocView.tt para atualizar a seguinte definição de variável:

    string viewControlTypeName = "FarmControl";
    

Testar a DSL

A solução DSL agora pode ser compilada e executada, embora talvez você queira adicionar outras melhorias posteriormente.

  1. Compile e execute a solução.

  2. Na instância experimental do Visual Studio, abra o arquivo de Amostra.

  3. No FarmApp Explorer, abra o menu de atalho no nó raiz Farm e escolha Add New Goat.

    Goat1 aparece no modo de exibição Animals.

    Aviso

    Você deve usar o menu de atalho no nó Farm, não no nó Animals.

  4. Selecione o nó raiz Farm e exiba suas propriedades.

    No modo de exibição de formulário, altere o Name ou Size da fazenda.

    Quando você navega para longe de cada campo no formulário, a propriedade correspondente é alterada na janela Propriedades.

Aprimorar o DSL

Fazer com que as propriedades atualizem imediatamente

  1. Na exibição de design de FarmControl.cs, selecione um campo simples, como Name, Size ou IsOrganic.

  2. Na janela Propriedades, expanda DataBindings e abra (Avançado).

    Na caixa de diálogo Formatação e Associação Avançada, em Modo de Atualização da Fonte de Dados, escolha OnPropertyChanged.

  3. Compile e execute a solução.

    Verifique se, quando você altera o conteúdo do campo, a propriedade correspondente do modelo Farm é alterada imediatamente.

Fornecer botões Adicionar

  1. Na exibição de design de FarmControl.cs, use a caixa de ferramentas para criar um botão no formulário.

    Edite o nome e o texto do botão, por exemplo, para New Sheep.

  2. Abra o código por trás do botão (por exemplo, clicando duas vezes nele).

    Edite da seguinte maneira:

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

    Você também precisará inserir a seguinte diretiva:

    
    using Microsoft.VisualStudio.Modeling;
    
  3. Adicione botões semelhantes para Cabras e Campos.

  4. Compile e execute a solução.

  5. Verifique se o novo botão adiciona um item. O novo item deve aparecer no FarmApp Explorer e na exibição de grade de dados apropriada.

    Você deve ser capaz de editar o nome do elemento na exibição de grade de dados. Você também pode excluir.

    Sample data grid view

Sobre o código para adicionar um elemento

Para os novos botões de elemento, o código alternativo a seguir é um pouco mais simples.

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

No entanto, esse código não define um nome padrão para o novo item. Ele não executa nenhuma mesclagem personalizada que você possa ter definido nas Diretivas de Mesclagem de Elementos da DSL e não executa nenhum código de mesclagem personalizado que possa ter sido definido.

Portanto, recomendamos que você use ElementOperations para criar elementos. Para obter mais informações, confira Personalizar a criação e a movimentação de elementos.