
Buenas,
cuando los escenarios de trabajo sobre los que se apoyan nuestros DSLs necesitan interactuar con elementos externos, seguramente deberemos enfrentarnos a la tarea de crear elementos dinámicamente dentro de nuestros diagramas. Esta tarea, es mucho más simple de lo que parece a simple vista, pero lamentablemente no hay mucha información al respecto.
Este post muestra un pequeño ejemplo de utilización que me ha costado varias noches de cervecitas e insomnio, y seguramente después de leerlo verán que como dijo Tito Einstein «Cada día sabemos más y entendemos menos»
Tutorial
Sobre la base de ejemplos anteriores, en especial sobre el post en el que mostraba cómo agregar un menú personalizado, crearemos un nuevo menú para duplicar los elementos del tipo User dentro de nuestro diagrama. Este tipo de comportamiento, sumado con los clásicos menúes Cut/Copy/Paste/Duplicate, suele ser muy común de fácil implementación en diagramas creados con las Domain Specific Language Tools.
Una vez creado el menú Duplicate, y aplicado el filtro para que solo aparezca en los elementos del tipo UserElement, nuestro diagrama quedaría como la siguiente imagen:
A continuación debemos implementar la lógica para nuestro menú Duplicate, el siguiente fragmento de código es un ejemplo de una opción para lograrlo. Entre las líneas 11 y 19, validamos el elemento seleccionado y a partir de la línea 22 creamos un nuevo elemento con los datos del elemento seleccionado. El único cambio significativo es que al nombre del UserElement, le agregaremos el prefijo "Copy of " (línea 29).
1 /// <summary>
2 /// Called when [duplicate menu click].
3 /// </summary>
4 /// <param name="sender">The sender.</param>
5 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
6 internal void OnDuplicateMenuClick(object sender, EventArgs e)
7 {
8 // valida la seleccion
9 if (this.CurrentSelection.Count > 0)
10 {
11 // get selected object, cast to UserShape and validate
12 object selectedObject = null;
13 IEnumerator enumCS = this.CurrentSelection.GetEnumerator();
14 while (enumCS.MoveNext())
15 {
16 selectedObject = enumCS.Current;
17 }
18 UserShape selectedUserShape = selectedObject as UserShape;
19 if (selectedUserShape == null) return;
20
21 // All updates must be done inside a transaction
22 using (Transaction t = selectedUserShape.Store.TransactionManager.BeginTransaction())
23 {
24 UserElement selectedUserElement = (UserElement)selectedUserShape.ModelElement;
25
26 // create new User Element
27 UserElement us = new UserElement(selectedUserShape.Store, null);
28 us.EMail = "bcapuano@gmail.com";
29 us.Name = "Copy of " + selectedUserElement.Name;
30
31 // add them to the tree
32 ExampleModel em = (ExampleModel)this.CurrentDocData.RootElement;
33 us.ExampleModel = em;
34
35 // commit changes
36 t.Commit();
37 }
38 }
39 }
Un detalle interesante a remarcar, es que TODOS los cambios que realicemos sobre elementos de un diagrama DSL deben ser realizados dentro de una transacción del tipo Microsoft.VisualStudio.Modeling.Transaction. Este punto es muy importante, ya que cada vez que creemos un nuevo elemento, que modifiquemos una propiedad de un elemento, etc. SIEMPRE necesitamos realizarlo dentro de una transacción.
Conclusión
Una vez compilado y con el proyecto de prueba en marcha, podremos ver que el menú Duplicate crea un nuevo elemento del tipo USerElement y lo agrega al diagrama. Con un poco más de código, podremos agregar funcionalidades extras cómo por ejemplo, setear la posición del nuevo elemento a agregar, agregar además los links que posee el elemento "copiado", etc.
Descarga: http://geeks.ms/files/folders/elbruno/entry66774.aspx
Saludos @ <Fight vs Expression Blend>
El Bruno
Crossposting from
ElBruno.com