Navegando e atualizando um modelo de código de programa
Você pode escrever código para criar e excluir elementos modelo, para definir suas propriedades, e para criar e excluir links entre elementos.Todas as alterações devem ser feita dentro de uma transação.Se os elementos são exibidos em um diagrama, o diagrama anterior” corrigido “será automaticamente no final da transação.
Em este tópico
Uma definição de DSL de exemplo
navegando no modelo
Acessando informações de classe
Fazer alterações em uma transação
Criando elementos modelo
Criando links de relação
Excluindo elementos
Excluindo links de relação
Reorganizando links de uma relação
bloqueios
Impressão e pasta
navegando em e atualizando diagramas
Navegar entre elementos e formas
Propriedades de formas e os conectores
DocView e DocData
As formas, os conectores e os diagramas, e suas relações elementos modelo são descritos em um tópico separado.Para obter mais informações, consulte [redirecionar] Como: navegar e atualizar um diagrama..
Uma definição de DSL de exemplo
Essa é a parte principal de DslDefinition.dsl para os exemplos em este tópico:
Esse modelo é uma instância de esse DSL:
referências e namespaces
Para executar o código em este tópico, você deve referenciar:
Microsoft.VisualStudio.Modeling.Sdk.11.0.dll
Seu código usará este namespace:
using Microsoft.VisualStudio.Modeling;
Além de isso, se você estiver escrevendo código em um projeto diferente do que em seu DSL é definido, você deve importar o assembly que é compilado pelo projeto de Dsl.
navegando no modelo
Propriedades
As propriedades de domínio que você define na definição de DSL tornam-se as propriedades que você pode acessar no código de programa:
Person henry = ...;
if (henry.BirthDate < 1500) ...
if (henry.Name.EndsWith("VIII")) ...
Se você desejar definir uma propriedade, você deve fazê-lo dentro de transação:
henry.Name = "Henry VIII";
Se a definição de DSL, Tipo de uma propriedade é Calculado, você não pode defini-la.Para obter mais informações, consulte Propriedades de armazenamento de calculado e personalizadas.
relações
Os relacionamentos de domínio que você define na definição de DSL tornam-se pares de propriedades, em uma classe em cada final da relação.Os nomes das propriedades aparecem no diagrama de DslDefinition como rótulos funções em cada lado da relação.Dependendo da função, multiplicidade do tipo da propriedade é a classe no outro extremo de relação, ou uma coleção da classe.
foreach (Person child in henry.Children) { ... }
FamilyTreeModel ftree = henry.FamilyTreeModel;
as propriedades em extremos opostos de uma relação são sempre recíprocas.Quando um link é criado ou excluído, as propriedades em ambos os elementos é atualizada.A seguinte expressão (usando as extensões de System.Linq) é sempre true para a relação de ParentsHaveChildren no exemplo:
(Person p) => p.Children.All(child => child.Parents.Contains(p))
&& p.Parents.All(parent => parent.Children.Contains(p));
ElementLinks.Um relacionamento é representada por um elemento modelo também chamado um link, que é uma instância do tipo do relacionamento de domínio.Um link sempre tem um elemento de origem e um elemento de destino.O elemento de origem e o elemento alvo podem ser o mesmo.
você pode acessar um link e suas propriedades:
ParentsHaveChildren link = ParentsHaveChildren.GetLink(henry, edward);
// This is now true:
link == null || link.Parent == henry && link.Child == edward
Por padrão, não é permitida mais de uma instância de uma relação vincular todos os pares de elementos modelo.Mas se a definição de DSL, o sinalizador de Allow Duplicates é verdadeiro para o relacionamento em seguida, pode haver mais de um link, e você deve usar GetLinks:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinks(henry, edward)) { ... }
Há também outros métodos para acessar os links.Por exemplo:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinksToChildren(henry)) { ... }
funções ocultos. Se a definição de DSL, A propriedade é gerada é false para uma função específica, então nenhuma propriedade é gerada que corresponde à função.Em o entanto, você ainda pode acessar os links e a travessia links usando os métodos de relação:
foreach (Person p in ParentsHaveChildren.GetChildren(henry)) { ... }
Mais geralmente o exemplo usado é o relacionamento de PresentationViewsSubject , que referencia um elemento modelo a forma que exibe em um diagrama:
PresentationViewsSubject.GetPresentation(henry)[0] as PersonShape
O diretório de elemento
Você pode acessar todos os elementos no armazenamento usando o diretório do elemento:
store.ElementDirectory.AllElements
Há também métodos para localizar elementos, como o seguinte:
store.ElementDirectory.FindElements(Person.DomainClassId);
store.ElementDirectory.GetElement(elementId);
Acessando informações de classe
Você pode obter informações sobre classes, relacionamentos, e outros aspectos da definição de DSL.Por exemplo:
DomainClassInfo personClass = henry.GetDomainClass();
DomainPropertyInfo birthProperty =
personClass.FindDomainProperty("BirthDate")
DomainRelationshipInfo relationship =
link.GetDomainRelationship();
DomainRoleInfo sourceRole = relationship.DomainRole[0];
As classes de ancestral de elementos modelo são:
ModelElement - todos os elementos e relações são ModelElements
ElementLink - todas as relações são ElementLinks
Fazer alterações em uma transação
Sempre que o código de programa altera qualquer coisa no armazenamento, deve fazê-lo dentro de uma transação.Isso se aplica a todos os elementos modelo, a relações, como formas, como diagramas, e suas propriedades.Para obter mais informações, consulte Transaction.
O método mais conveniente de gerenciar uma transação é com uma instrução de using incluída em uma instrução de try...catch :
Store store; ...
try
{
using (Transaction transaction =
store.TransactionManager.BeginTransaction("update model"))
// Outermost transaction must always have a name.
{
// Make several changes in Store:
Person p = new Person(store);
p.FamilyTreeModel = familyTree;
p.Name = "Edward VI";
// end of changes to Store
transaction.Commit(); // Don't forget this!
} // transaction disposed here
}
catch (Exception ex)
{
// If an exception occurs, the Store will be
// rolled back to its previous state.
}
Você pode fazer qualquer número de alterações dentro de uma transação.Você pode abrir novos transações dentro de uma transação.
Para tornar seu permanent as alterações, você deve Commit a transação antes de ser descartado.Se ocorrer uma exceção que não sejam capturadas na transações, o armazenamento será redefinido em seu estado antes de alterações.
Criando elementos modelo
este exemplo adiciona um elemento a um modelo existente:
FamilyTreeModel familyTree = ...; // The root of the model.
using (Transaction t =
familyTree.Store.TransactionManager
.BeginTransaction("update model"))
{
// Create a new model element
// in the same partition as the model root:
Person edward = new Person(familyTree.Partition);
// Set its embedding relationship:
edward.FamilyTreeModel = familyTree;
// same as: familyTree.People.Add(edward);
// Set its properties:
edward.Name = "Edward VII";
t.Commit(); // Don't forget this!
}
Este exemplo ilustra esses pontos essenciais sobre a criação de um elemento:
Crie o novo elemento em uma partição específico de armazenamento.Para elementos e relacionamentos modelo, mas não formas, isso é geralmente o partição padrão.
Torna o destino de uma relação inseridas.Em o DslDefinition de este exemplo, cada pessoa deve ser o destino da relação FamilyTreeHasPeople inseridas.Para obter isso, podemos ou definir a função da propriedade de FamilyTreeModel do objeto da pessoa, ou adicione a pessoa à função de propriedade de pessoas do objeto de FamilyTreeModel.
Definir as propriedades de um novo elemento, especialmente a propriedade para que IsName é verdadeira no DslDefinition.Este sinalizador marca a propriedade que serve para identificar exclusivamente o elemento dentro do proprietário.Em esse caso, a propriedade name tem esse sinalizador.
A definição de DSL de este DSL deve ter sido carregadas no armazenamento.Se você estiver escrevendo uma extensão como um comando de menu, este será normalmente já true.Em outros casos, você pode explicitamente carregar o modelo no armazenamento, ou use ModelBus para carregá-lo.Para obter mais informações, consulte Como: abrir um modelo de arquivo no código de programa.
Quando você cria um elemento de essa maneira, uma forma é criada automaticamente (se DSL tem um diagrama).Aparece em um local automaticamente atribuído, a maneira padrão, cor, e outros recursos.Se você deseja controlar como e onde a forma associado for exibida, consulte criando um elemento e sua forma.
Criando links de relação
Há duas relações definidas na definição de DSL de exemplo.Cada relacionamento define uma função da propriedade na classe em cada final da relação.
Existem três maneiras em que você pode criar uma instância de um relacionamento.Cada um de esses três métodos tem o mesmo efeito:
Defina a propriedade da função de jogador de origem.Por exemplo:
familyTree.People.Add(edward);
edward.Parents.Add(henry);
Defina a propriedade da função de jogador de destino.Por exemplo:
edward.familyTreeModel = familyTree;
A multiplicidade de essa função é 1..1, de forma que é atribuímos o valor.
henry.Children.Add(edward);
A multiplicidade de essa função é 0..*, o que nós adicionados à coleção.
Crie uma instância de relação explicitamente.Por exemplo:
FamilyTreeHasPeople edwardLink = new FamilyTreeHasPeople(familyTreeModel, edward);
ParentsHaveChildren edwardHenryLink = new ParentsHaveChildren(henry, edward);
O método do último é útil se você desejar definir as propriedades da relação próprias.
Quando você cria um elemento de essa maneira, um conector no diagrama é criado automaticamente, mas tem uma maneira padrão, a cor, e outros recursos.Para controlar como o conector associado é criado, consulte criando um elemento e sua forma.
Excluindo elementos
excluir um elemento chamando Delete():
henry.Delete();
Esta operação também excluirá:
Links de relação a e do elemento.Por exemplo, edward.Parents não conterá henry.
Elementos nas funções para que o sinalizador de PropagatesDelete é válido.por exemplo, a forma que exibe o elemento será excluída.
Por padrão, cada relacionamento inseridas tem PropagatesDelete verdadeiro na função de destino.Excluindo henry não exclui familyTree, mas familyTree.Delete() excluiria qualquer Persons.Para obter mais informações, consulte Personalizar o comportamento de exclusão.
Por padrão, PropagatesDelete não é verdadeiro para as funções de relações de referência.
Você pode fazer com que as regras de exclusão omitam se propaga específicas quando você exclui um objeto.Isso é útil se você está substituindo um elemento para outro.Você fornece um GUID de uma ou mais funções para que a exclusão não deve ser propagada.Um GUID pode ser obtido da classe de relação:
henry.Delete(ParentsHaveChildren.SourceDomainRoleId);
(Esse exemplo específico não terá efeito, porque PropagatesDelete é false para as funções da relação ParentsHaveChildren .)
Em alguns casos, a exclusão é impedida pela existência de um bloqueio, no elemento ou um elemento que é excluído. por bolhavocê pode usar element.CanDelete() para verificar se o elemento possa ser excluído.
Excluindo links de relação
Você pode excluir um link de relação remover um elemento de uma função da propriedade:
henry.Children.Remove(edward); // or:
edward.Parents.Remove(henry); // or:
Você também pode excluir o link explicitamente:
edwardHenryLink.Delete();
Todos esses três métodos têm o mesmo efeito.Você só precisará usar um de eles.
Se a função tem a multiplicidade 0..1 ou 1..1, você pode defini-la a null, ou para outro valor:
edward.FamilyTreeModel = null; ou //:
edward.FamilyTreeModel = anotherFamilyTree;
Requisitando novamente links de uma relação
Links de uma relação específico que são originários ou de destino em um elemento do modelo de detalhe têm uma seqüência específica.Aparecem na ordem em que foram adicionados.Por exemplo, essa instrução sempre renderá os filhos na mesma ordem:
foreach (Person child in henry.Children) ...
Você pode alterar a ordem dos links:
ParentsHaveChildren link = GetLink(henry,edward);
ParentsHaveChildren nextLink = GetLink(henry, elizabeth);
DomainRoleInfo role =
link.GetDomainRelationship().DomainRoles[0];
link.MoveBefore(role, nextLink);
bloqueios
Suas alterações podem ser evitadas por um bloqueio.Os bloqueios podem ser definidas em elementos individuais, e em particiona no armazenamento.Se qualquer um dos níveis têm um bloqueio que evitasse o tipo de alteração que você deseja fazer, uma exceção pode ser lançada quando você tentar a.Você pode descobrir se os bloqueios são definidos usando element.GetLocks(), que é um método de extensão que é definido no namespace Microsoft.VisualStudio.Modeling.Immutability.
Para obter mais informações, consulte Definir uma diretiva de bloqueio para criar segmentos de somente leitura.
Impressão e pasta
Você pode copiar os elementos ou grupos de elementos a IDataObject:
Person person = personShape.ModelElement as Person;
Person adopter = adopterShape.ModelElement as Person;
IDataObject data = new DataObject();
personShape.Diagram.ElementOperations
.Copy(data, person.Children.ToList<ModelElement>());
Os elementos são armazenados como um grupo serializada do elemento.
você pode mesclar os elementos de um IDataObject em um modelo:
using (Transaction t = targetDiagram.Store.
TransactionManager.BeginTransaction("paste"))
{
adopterShape.Diagram.ElementOperations.Merge(adopter, data);
}
Merge () pode aceitar PresentationElement ou ModelElement.Se você fornece PresentationElement, você também pode especificar uma posição no diagrama de destino como um terceiro parâmetro.
navegando em e atualizando diagramas
Em DSL, o elemento modelo de domínio, que representa um conceito como a pessoa ou a música, é separado do elemento, de forma que representa o que você vê no diagrama.O elemento do modelo de domínio armazena as propriedades e relacionamentos importantes conceitos.O elemento de forma armazena o tamanho, posição e cor do modo de objeto no diagrama, e o layout de seus elementos.
Elementos de apresentação
Em sua definição de DSL, cada elemento que você especifica cria uma classe que é derivada de uma das seguintes classes padrão.
Tipo de elemento |
classe base |
---|---|
Classe de domínio |
|
relacionamento de domínio |
|
forma |
|
conector |
|
Diagrama |
Um elemento em um diagrama geralmente representa um elemento modelo.Normalmente (mas não sempre), NodeShape representa uma instância da classe de domínio, e BinaryLinkShape representa uma instância do relacionamento de domínio.A relação de PresentationViewsSubject links uma forma de um nó ou de link para o elemento que representa modelo.
Cada forma de um nó ou de link pertence a um diagrama.Uma forma binária de link conecta duas formas do nó.
As formas podem ter formas filho em dois conjuntos.Uma forma em NestedChildShapes definido é limitada a caixa delimitadora de seu pai.Uma forma na lista de RelativeChildShapes pode aparecer fora ou em lugar fora dos limites do pai – por exemplo um rótulo ou uma porta.Um diagrama não tem RelativeChildShapes e nenhum Parent.
Navegar entre elementos e formas
Elementos modelo de domínio e elementos de forma são relacionados a relação de PresentationViewsSubject .
// using Microsoft.VisualStudio.Modeling;
// using Microsoft.VisualStudio.Modeling.Diagrams;
// using System.Linq;
Person henry = ...;
PersonShape henryShape =
PresentationViewsSubject.GetPresentation(henry)
.FirstOrDefault() as PersonShape;
A mesma relação aos conectores são relacionamentos no diagrama:
Descendants link = Descendants.GetLink(henry, edward);
DescendantConnector dc =
PresentationViewsSubject.GetPresentation(link)
.FirstOrDefault() as DescendantConnector;
// dc.FromShape == henryShape && dc.ToShape == edwardShape
Esse relacionamento também ajudam a raiz do modelo ao diagrama a seguir:
FamilyTreeDiagram diagram =
PresentationViewsSubject.GetPresentation(familyTree)
.FirstOrDefault() as FamilyTreeDiagram;
para obter o elemento modelo representado por uma forma, use:
henryShape.ModelElement as Person
diagram.ModelElement as FamilyTreeModel
Navegue em torno do diagrama
Em geral não é aconselhável navegar entre formas e conectores no diagrama.É melhor navegar nas relações no modelo, mover entre as formas e os conectores somente quando for necessário trabalhar na aparência do diagrama.Esses métodos vinculam conectores para desenhar formas em cada final:
personShape.FromRoleLinkShapes, personShape.ToRoleLinkShapes
connector.FromShape, connector.ToShape
muitas formas são composições; são compostos de uma forma pai e de uma ou mais camadas de filhos.As formas que são identificadas em relação a outra forma seria seus filhos.Quando o formulário pai se move, os filhos se movem com ele.
Os filhos relacionados podem aparecer fora da caixa delimitadora de forma pai.Os filhosaninhados estritamente aparecem nos limites do pai.
para obter o conjunto superior de formas em um diagrama, use:
Diagram.NestedChildShapes
As classes de ancestral de formas e de conectores são:
-- ShapeElement
----- NodeShape
------- Diagram
------- YourShape
----- LinkShape
------- BinaryLinkShape
--------- YourConnector
Propriedades de formas e os conectores
Em a maioria dos casos, não é necessário fazer alterações explícitas para desenhar formas.Quando você alterou os elementos modelo, “corrigir anterior” regras atualizar as formas e os conectores.Para obter mais informações, consulte Respondendo a e propagação de alterações.
Em o entanto, é útil fazer algumas alterações explícitas para desenhar formas nas propriedades que são independentes de elementos modelo.Por exemplo, você pode alterar essas propriedades:
Size - determina a altura e largura da forma.
Location - posição relativa à forma ou ao diagrama pai
StyleSet - o conjunto de menus e pincéis usado desenhando a forma ou o conector
Hide - faz a forma invisível
Show - faz a forma visível após Hide()
criando um elemento e sua forma
Quando você cria um elemento e o links na árvore de relações de uma forma automaticamente, inserindo é criada e associada a ela.Isso é feito pelas regras de “fixup” que executam no final da transação.Em o entanto, o formulário será exibido em um local automaticamente- atribuído, e sua forma, a cor e outros recursos terão valores padrão.Para controlar como a forma é criada, você pode usar a função de mesclagem.Você deve primeiro adicionar elementos que você deseja adicionar em um ElementGroup, e mescla no grupo no diagrama.
este método:
Defina o nome, se você tiver atribuído uma propriedade como o nome do elemento.
Notas todas as políticas de mesclagem do elemento que você especifique na definição de DSL.
Este exemplo cria uma forma na posição do mouse, quando o usuário clica duas vezes no diagrama.Em a definição de DSL para esse exemplo, a propriedade de FillColor de ExampleShape foi expostas.
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
partial class MyDiagram
{
public override void OnDoubleClick(DiagramPointEventArgs e)
{
base.OnDoubleClick(e);
using (Transaction t = this.Store.TransactionManager
.BeginTransaction("double click"))
{
ExampleElement element = new ExampleElement(this.Store);
ElementGroup group = new ElementGroup(element);
{ // To use a shape of a default size and color, omit this block.
ExampleShape shape = new ExampleShape(this.Partition);
shape.ModelElement = element;
shape.AbsoluteBounds = new RectangleD(0, 0, 1.5, 1.0);
shape.FillColor = System.Drawing.Color.Azure;
group.Add(shape);
}
this.ElementOperations.MergeElementGroupPrototype(
this,
group.CreatePrototype(),
PointD.ToPointF(e.MousePosition));
t.Commit();
}
}
}
Se você fornecer mais de uma forma, definir suas posições relacionados usando AbsoluteBounds.
Você também pode definir a cor e outras propriedades expostas dos conectores usando esse método.
use transações
As formas, os conectores e os diagramas são subtipos de ModelElement e vivem no armazenamento.Portanto você deve fazer alterações em eles apenas dentro de uma transação.Para obter mais informações, consulte Como: usar transações para atualizar o modelo.
Modo de exibição de documento e dados de documento
Particiona armazenamento de
Quando um modelo é carregado, o diagrama de rastreamento é carregado ao mesmo tempo.Normalmente, o modelo é carregado em Store.DefaultPartition, e o conteúdo do diagrama é carregado em outra partição.Geralmente, o conteúdo de cada partição é carregado e salvo em um arquivo separado.
Consulte também
Referência
Conceitos
Validação em um idioma específico do domínio
Como: usar transações para atualizar o modelo
A integração de modelos usando o Modelbus de Visual Studio
Outros recursos
Gerando código a partir de uma linguagem específica de domínio