3 de junio de 2017

MemberData y los editores de propiedades de usuario

Artículo original: MemberData and Custom Property Editors
Autor: Doug Hennig
Traducido por: Ana María Bisbé York


Un par de peticiones frecuentes de los desarrolladores VFP eran la posibilidad de contar con letras mayúsculas en las propiedades y métodos de usuario en la ventana Propiedades y en IntelliSense, y la posibilidad de personalizar la ventana Propiedades. Microsoft ha escuchado estas peticiones: VFP 9 ofrece ambas posibilidades, más la capacidad de crear un editor de propiedades propio, con una nueva característica llamada MemberData. Lo explica Doug Henning.

Algo que me ha molestado de VFP desde sus inicios es que las propiedades y métodos de usuario eran forzados a minúsculas en archivos VCX o SCX. Esto hace que aparezcan al final de la ventana Propiedades en lugar de intercaladas con las propiedades, eventos y métodos nativos (referidos como PEMs o miembros). Significa además que IntelliSense no muestra los nombres de los miembros con mayúsculas en las letras significativas, entonces, siempre terminaba corrigiendo el nombre que IntelliSense insertaba por mi. Deseaba además que existiera una vía para limitar la ventana Propiedades de forma tal que mostrara justamente aquellos PEMs que me interesaran, no los cientos que yo nunca utilizo.

VFP 9 ha respondido a mis plegarias. Esta nueva versión proporciona una vía para especificar metadato de las clases miembros. Este metadato, referido como MemberData, contiene atributos tales como el tipo de letra (mayúscula / minúscula) utilizado para mostrar el miembro (el nombre aún se guarda físicamente en minúsculas en el archivo VCX o SCX) y si se muestra o no un miembro en la nueva ficha Favoritos (Favorites) de la ventana Propiedades (Properties).

MemberData se implementa agregando una nueva propiedad llamada _MemberData a una clase y rellenándola con XML de forma tal que contenga el metadato para los miembros de la clase. La propiedad _MemberData no se agrega a la clase automáticamente, ni se llena el XML, es necesario hacer ambas cosas por si mismo (luego, en este artículo, les diré cómo hacerlo).

MemberData

He aquí un esquema XSD para MemberData:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="VFPData">
<xs:complexType>
<xs:sequence>
<xs:element name="memberdata">
<xs:complexType>
<xs:attribute name="name" type="xs:string"
use="required" />
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="display" type="xs:string"/>
<xs:attribute name="favorites" type="xs:boolean"/>
<xs:attribute name="override" type="xs:boolean"/>
<xs:attribute name="script" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Bien, ahora lo digo en español. La Tabla 1 muestra los atributos que estructuran el metadata de un miembro.

AtributoDescripción
nameNombre del miembro.
typeTipo de miembro: "property", "event" o "method".
displayTexto que se utiliza como nombre del miembro en la ventana Propiedades y en IntelliSense.
favorites"True" si el miembro debe aparecer en la ficha Favoritos de la ventana Propiedades o "False" en caso contrario.
override"True" para ignorar el metadata de la clase padre o "False" para heredarlo de la clase padre.
scriptCódigo para ejecutar cuando se selecciona el botón de edición de la propiedad para este miembro en la ventana Propiedades.

Tabla 1. Los atributos del MemberData contienen el metadata para un miembro.

He aquí algunas anotaciones sobre estos elementos:

  • Debido a que es un XML, los nombres de los elementos y atributos son sensibles a las diferencias entre mayúsculas y minúsculas (case-sensitive). Con la excepción del atributo script, el contenido de los atributos también son case-sensitive. El nombre y tipo de los atributos debe estar en minúsculas. "True" y "False" deben ser especificados con letra inicial mayúscula en los atributos favorites y override.
  • El atributo display no puede ser diferente del nombre de los miembros, excepto en tipo de letra (mayúscula / minúscula). Por ejemplo, mientras se acepta "MiPropiedad" para el atributo display del miembro mipropiedad, "CualquierOtraCosa" no lo es.
  • Puede modificar MemberData en subclases sin tener que reproducir la cadena XML entera, los atributos no especificados toman sus valores de la clase padre. Sin embargo, si el atributo override es "True," para los atributos no especificados se utiliza el comportamiento predeterminado. Por ejemplo, suponga que tiene una clase con un metadato especificando un atributo display igual a MiPropiedad. Si el atributo display de la subclase está omitido, heredará de la clase padre. Sin embargo si el atributo override es "True," la propiedad se mostrará como "mipropiedad" en la ventana Propiedades porque el atributo display no hereda de la clase padre y no ha sido especificado en esta clase.
  • Si el atributo script está especificado para un miembro, se verá el botón de edición de la propiedad en la ventana Propiedades al seleccionar el miembro. Al hacer Clic en ese botón se ejecuta el código especificado en el atributo script, utilizando EXECSCRIPT().
  • Si el XML no es válido, no se recibe un mensaje de error; pero tampoco se verán los efectos de MemberData.

He aquí un ejemplo que indica que la propiedad mycustomproperty debe mostrarse como MyCustomProperty y debe aparecer en la ficha Favoritos de la ventana Propiedades, y VFP debe llamar a MyCustomPropertyEditor.PRG cuando se haga clic en el botón de edición de la propiedad en la ventana Propiedades.

<?xml version = "1.0" encoding="Windows-1252"
standalone="yes"?>
<VFPData>
<memberdata
name="mycustomproperty"
type="property"
display="MyCustomProperty"
favorites="True"
override="False"
script="DO MyCustomPropertyEditor.PRG"/>
</VFPData>


Figura 1


Figura 2


Figura 3

La Figura 1 muestra cómo aparece esta propiedad en la ventana Propiedades. Observe que aparece como MyCustomProperty, se encuentra en el lugar adecuado en orden alfabético en lugar de al final de la ventana Propiedades, y un botón de edición de propiedad aparece a la derecha del cuadro de texto del valor. En la Figura 2 puede ver que esta propiedad es una de las pocas mostrada en la ficha Favoritos. La Figura 3 muestra cómo aparece la propiedad en IntelliSense.

MemberData Global

Es fantástico tener una clase MemberData específica; pero sería un obstáculo si tiene que especificar el mismo metadato para las mismas propiedades en todas las clases. Por ejemplo, si agrega la propiedad MyCustomProperty a varias clases, deseará utilizar el mismo metadato para cada clase. Afortunadamente el equipo MS VFP ha pensado en esto.

Para crear un MemberData a nivel global (quiere decir, para todas las clases que tienen este miembro), agregue un registro a la tabla IntelliSense que especifique el MemberData. (La tabla IntelliSense, especificada en la variable de sistema _FOXCODE, de forma predeterminada se llama FOXCODE.DBF y se encuentra en el directorio, que es devuelto por la función HOME(7)).

Establezca el campo TYPE igual a "E" (un valor nuevo en VFP 9 que denota un registro MemberData), coloque el nombre de los miembros en ABBREV (no es importante tener en cuenta mayúsculas y minúsculas), y ponga el MemberData en TIP. Si la propiedad _MemberData para un objeto contiene metadato para un miembro que tiene también un metadato global, la _MemberData sobrescribirá la global.

He aquí un ejemplo que crea un MemberData global para MyCustomProperty al agregar al FOXCODE un registro con la información correcta:
 

local lcXML
* Crear el MemberData.
text to lcXML noshow
<?xml version="1.0" encoding="Windows-1252"
standalone="yes"?>
<VFPData>
<memberdata
name="mycustomproperty"
type="property"
display="MyCustomProperty"
favorites="True"
override="False"
script="do MyCustomPropertyEditor.PRG"/>
</VFPData>
endtext
* Crear ahora un registro en FOXCODE que proporcione el
* MemberData para MyCustomProperty.
use (_foxcode) again shared alias FOXCODE
insert into FOXCODE (TYPE, ABBREV, TIP) values ('E', ;
'MyCustomProperty', lcXML)
use

Haga una prueba: Ejecute el código anterior (GlobalMemberData.PRG en el archivo Descargar) y luego escriba lo siguiente en la ventana Comandos:

create class x of x as custom

Cree una propiedad llamada MyCustomProperty y obseve que aun cuando no existe la propiedad _MemberData para esta clase, MyCustomProperty se muestra con las letras correctas y en la ficha Favoritos.

MemberData no se aplica solamente a las propiedades y métodos de usuario. Por ejemplo, debido a que las propiedades Caption y Name son las que cambio con más frecuencia en formularios, etiquetas, casillas de verificación y otros objetos con estas propiedades, voy a crear un metadato global para agregar estas propiedades a la ficha Favoritos de tal forma que no tenga que saltar por la ventana Propiedades para encontrarlas. Esto me brinda un pequeño empujón de productividad para cada objeto durante toda la vida del proyecto, lo que sumado, puede ser un ahorro de tiempo considerable.

Editores de propiedades (Property editors)

Igual que un generador, un editor de propiedad puede facilitar la entrada del valor de la propiedad. Por ejemplo, la nueva propiedad Anchor define cómo reacciona un control cuando el contenedor es redimensionado (por ejemplo, puede ser redimensionado o movido). Sin embargo, el valor de Anchor es una suma de valores numéricos, por ejemplo 12 (8, anclado a la derecha + 4, anclado al borde inferior). Esto no es muy intuitivo, así que un editor de propiedad puede ayudar mucho en la productividad.

Aunque puede especificar múltiples líneas de código en el atributo script del metadato, normalmente tiene más sentido llamar a un PRF o un formulario. Para un MemberData global, puede especificar además que desea ejecutar un registro script en FOXCODE utilizando lo siguiente como atributo de script:

do (_CODESENSE) with 'RunPropertyEditor', '', 'SomeValue'

SomeValue es el valor que desea pasar al script. Ponga "{ScriptName}" en CMD, donde ScriptName es el nombre del script. Para crear un registro script, agregue un registro a FOXCODE con "S" en TYPE, el nombre del script en ABBREV, "{}" en CMD, y el código a ejecutar en DATA. Utilizar un registro script tiene la ventaja de que es más compacto que un editor de propiedad separado (ya que el código está contenido en FOXCODE) y no son necesarias ningunas rutas.

Al igual que un generador, un editor de propiedad es responsable de obtener una referencia al objeto que será modificado y de escribir a la propiedad del objeto. De hecho, puede pensar que un editor de propiedad como un subconjunto de un generador (el que es usualmente un editor para múltiples propiedades de un objeto), con requerimientos y características de arquitectura similares.

Llegar hasta allá desde aquí

Ahora que sabe como trabaja MemberData, puede utilizarlo agregando una propiedad _MemberData a cada objeto y rellenando luego el XML adecuado de esta propiedad. ¿No parece que esto vaya a reducir su productividad en lugar de aumentarla? Afortunadamente, hay dos cosas que podemos hacer para decirle a VFP que cree automáticamente una propiedad _MemberData para cada clase y genere automáticamente el XML que necesitamos.

La clave para esta primera tarea es agregar un registro a la tabla IntelliSense que se ejecuta cada vez que abra la clase en el diseñador de clases o en un formulario en el Diseñador de formularios. Esto provoca que cuando la ventana Propiedades muestra las PEMs para un objeto, VFP busca en la tabla IntelliSense un registro con TYPE igual a "E" y ABBREV igual a "_GetMemberData". Si encuentra este tipo de registro, ejecutará el código que aparece en el campo memo DATA. Entonces, podemos agregar un registro a FOXCODE que cree una propiedad _MemberData en todas las clases o formularios que no la tengan ya. He aquí un código para hacerlo:

local lcCode
* Crear el código que se desea inserter en FOXCODE.
text to lcCode noshow
lparameters toFoxcode
local laObjects[1], ;
loObject
if aselobj(laObjects) = 0 and aselobj(laObjects, 1) = 0
return ''
endif aselobj(laObjects) = 0 ...
loObject = laObjects[1]
if vartype(loObject) = 'O' and ;
not pemstatus(loObject, '_memberdata', 5)
loObject.AddProperty('_memberdata', '')
endif vartype(loObject) <> = 'O' ...
return ''
endtext
* Crear ahora un registro en FOXCODE que se ejecute
* siempre que se abra una clase en el Diseñador de clases.
use (_foxcode) again shared alias FOXCODE
locate for TYPE = 'E' and ABBREV = '_GetMemberData'
if not found()
insert into FOXCODE (TYPE, ABBREV, DATA) values ('E', ;
'_GetMemberData', lcCode)
endif not found()
use

Este código verifica si el registro _GetMemberData ya existe o no. Al momento de escribir este artículo, Microsoft no ha decidido si este registro va a formar parte, o no, del conjunto estándar de registros en FOXCODE.

El código insertado al campo memo DATA utiliza ASELOBJ() para obtener una referencia a una clase o formulario que será editado, verifica la existencia de _MemberData con PEMSTATUS(), y agrega la propiedad utilizando AddProperty si no ha sido encontrada.

Para ver cómo funciona, ejecute el código (UpdateFoxCode.PRG en el archivo Descargar), y luego escriba lo siguiente en la ventana Comandos:

create class x of x as custom

En la ventana Propiedades verá que VFP automáticamente creó una propiedad _MemberData para esta clase.
Ahora tenemos una propiedad _MemberData para cada cosa que abramos en el Diseñador de clases o Diseñador de formularios, ¿Cómo pudiéramos abordar la segunda tarea: generar el XML desde el metadato?

El editor de la propiedad _MemberData

Esta tarea es muy sencilla de cumplir debido a que VFP 9 incluye una nueva herramienta llamada Editor de MemberData (MemberData Editor) (vea Figura 4). Esta herramienta permite especificar visualmente los atributos para PEMs en un objeto. Entonces se encarga de generar el XML adecuado para la propiedad _MemberData.

Existen varias formas de invocar al Editor de MemberData:

  • El Editor MemberData puede ser registrado globalmente como editor de propiedad para la propiedad _MemberData ejecutando simplemente (DO HOME() + 'MemberDataEditor.APP'). Después de hacer esto, puede seleccionar la propiedad _MemberData en la ventana Propiedades y hacer Clic en el botón editor de propiedad para llamar al Editor de MemberData.
  • Los menús Formularios y Clases tienen una nueva opción “Editor de MemberData” ("MemberData Editor") que invoca al editor.
  • Puede invocar al Editor de MemberData mediante programación con DO HOME() + 'MemberDataEditor.APP'. Si es seleccionado un objeto en el Diseñador de clases o Diseñador de Formularios, se abrirá el editor.
  • Si desea simplemente agregar un PEM a la ficha Favoritos de la ventana Propiedades, haga Clic derecho en la PEM y seleccione la nueva opción “Agregar a Favoritos” ("Add to Favorites"). Esta opción llama en silencio al Editor de MemberData, el que actualiza el XML en _MemberData sin mostrar ninguna interfaz de usuario. Observe que no hay ninguna opción “Quitar de Favoritos” ("Remove from Favorites"); para lograrlo, es necesario utilizar la interfaz del Editor de MemberData Editor.

Para probar esto, cree o modifique una clase en el Diseñador de clases. Agregue algunas propiedades y métodos de usuario, y seleccione luego " Editor de MemberData " desde el menú Clase. Modifique los atributos de MemberData de las propiedades de usuario para que muestren las letras en mayúsculas, y coloque algunas en la ficha favoritos. Haga clic en el botón Aceptar (OK) y observe que los nuevos miembros aparecen ahora en la forma que desea en la ventana Favoritos.

Resumen

MemberData es una gran mejora de productividad en VFP 9 debido a que nos permite especificar cómo deben ser mostrados los miembros en la ventana Propiedades y en IntelliSense, haciendo más fácil encontrar (y ahorrarse la edición si permite a IntelliSense que inserte sus nombres en el código). Además, como los generadores, los editores de propiedades pueden facilitar, la asignación del valor adecuado a la propiedad. Espero que veamos muchos editores de propiedades con VFP 9, y muchos otros se irán creando por emprendedores desarrolladores de VFP.

Descarga

Archivo de descarga: memberdata.zip

No hay comentarios. :

Publicar un comentario