sábado, enero 10, 2015

Cómo mejorar y extender el diseño en Dynamics NAV?

Recientemente necesitaba incluir un texto largo en una Page y utilizando el control del propio NAV con la opción de multlinea no terminaba de gustarme el resultado:


Entonces se me ocurrió que podía hacer un control Add-in que permitiera visualizar cualquier texto en una Page. Así que busqué información en mi muy a menudo consultado MSDN, aquí tenéis un poco de información sobre la arquitectura, y posteriormente estudié este artículo de MSDN y me atreví a desarrollar mi propio objeto Label con el que poder visualizar texto multilinea en un formato mejor.

Creando un control Add-in para el cliente Windows

Empecé creando un nuevo proyecto en Visual Studio en C# de tipo Biblioteca de clases. Añadí las 2 referencias a las librería de NAV que encontrarás en el directorio donde tengas instalado el cliente NAV:

Microsoft.Dynamics.Framework.UI.Extensibility
Microsoft.Dynamics.Framework.UI.Extensibility.WinForms

Y otras 2 al propio .NET Framework:

System.Windows.Forms
System.Drawing;

Así mismo las referencié en el código de la clase:

using Microsoft.Dynamics.Framework.UI.Extensibility;
using Microsoft.Dynamics.Framework.UI.Extensibility.WinForms;
using System.Windows.Forms;
using System.Drawing;

Y empecé a declarar la clase:

[ControlAddInExport("CEDART.controls.labelWF")]
public class CDRTlabelWF : WinFormsControlAddInBase

La primera línea es importante porque es la que utilizaremos posteriormente para declarar y registrar el Add-in dentro de NAV.

En cuanto a la segunda línea, podía haber utilizado la clase abstracta StringControlAddInBase en lugar de WinFormsControlAddInBase pero posteriormente me di cuenta que necesitaba que mi control admitiera resizing para que si el contenedor cambiaba de tamaño mi control debía adaptarse a este nuevo tamaño y al parecer la clase abstracta StringControlAddInBase no lo admite tal como veremos más adelante.

En este punto debo decir que según todas las pruebas que he efectuado y algunos comentarios que he leído en foros, los controles Add-in no se llevan muy bien con el resizing, con lo que será importante que lo defináis con unas dimensiones ajustadas a vuestro propósito.

Continuamos con el código de creación del control:

Label _label = new Label();
protected override void OnInitialize()
{
    base.OnInitialize();
    this.ApplySize(new DisplaySize(1, 100, 600), new DisplaySize(1, 20, 300));
}

protected override Control CreateControl()
{
    _label.AutoSize = true;
    _label.Click += (sender, args) => { ControlClick(_label, null); };
    _label.ParentChanged += (sender, args) =>
        {
            if (ControlAddInReady != null)
            {
                ControlAddInReady(_label, null);
            }
        };
     return _label;
}

Continuando con el resizing, necesitamos declarar la función onInitialize() para poder indicar los tamaños mínimos, iniciales y máximos que tomará el control en ancho y largo al iniciar y redimensionar la pantalla principal, en nuestro caso la pantalla del cliente NAV. Esto concretamente es lo que no admite la clase abstracta StringControlAddInBase.

Otra cosa importante es que desde C/AL no podemos hacer nada con el control hasta que esté creado, con lo que debemos disponer de un evento que nos informe cuándo nuestro control Add-in está listo y preparado para admitir que utilicemos sus funciones y propiedades. Esto es lo que hace la última parte del código cuando dispara el evento ControlAddinReady.

Este es el código de definición de los eventos:

[ApplicationVisible]
public event EventHandler ControlAddInReady;
[ApplicationVisible]
public event EventHandler ControlClick;

Como puedes ver he definido un evento que se dispara al dispararse el evento Click del control Label.

Continuamos con la definición de métodos y propiedades:

[ApplicationVisible]
public void SetForeColor(bool black, bool white, bool gray)
{
    if (black)
    {
        _label.ForeColor = Color.Black;
    }
    if (white)
    {
        _label.ForeColor = Color.White;
    }
    if (gray)
    {
        _label.ForeColor = Color.DarkGray;
    }
}

[ApplicationVisible]
public void SetBackColor(bool transparent, bool white, bool gray)
{
    if (transparent)
    {
        _label.BackColor = Color.Transparent;
    }
    if (white)
    {
        _label.BackColor = Color.White;
    }
    if (gray)
    {
        _label.BackColor = Color.LightGray;
    }
}

[ApplicationVisible]
public void SetFont(string family, int size, bool bold)
{
    if (family == null)
    {
        family = "Arial";
    }
    if (size == 0)
    {
        size = 9;
    }
    if (bold == true)
    {
        _label.Font = new Font(family, size, FontStyle.Bold);
    }
    if (bold == false)
    {
        _label.Font = new Font(family, size);
    }
}

[ApplicationVisible]
public string Caption
{
    get { return _label.Text; }
    set { _label.Text = value; }
}

En esta parte los límites son vuestra creatividad, podemos hacer tantas cosas con el control como se nos ocurran (o como se deje el propio control). No es olvidéis de poner la etiqueta [ApplicationVisible] antes de la declaración del evento, método o propiedad para que sea visible desde NAV.

Finalmente deberemos firmar el proyecto. Para ello iremos a las propiedades del proyecto y pulsaremos en la opción Firma para marcar la opción Firmar el ensamblado y crear un nuevo archivo de firma, al que le daremos un nombre y desmarcaremos la opción Proteger mi archivo de clave mediante contraseña:


Tan sólo nos queda compilar el control, pero para registrarlo en NAV deberemos conocer su clave pública, con lo que en las propiedades del proyecto accederemos a la opción Eventos de compilación y en la ventana de Línea de comandos del evento posterior a la compilación añadiremos el siguiente comando para que al compilar nos proporcione el ID de la clave pública:

"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\sn.exe" -T "$(TargetPath)"

Hay una parte del directorio que puede cambiar según vuestra versión de Windows o versión de .NET Framework que utilicéis. 

Con lo que finalmente, al compilar deberemos ver en la ventana Resultados algo similar a esto:
 
No la cerréis, vamos a necesitar el Token en seguida.
 
Registrando el control Add-in en el cliente Windows
 
Primero debemos copiar la librería DLL al directorio de Add-ins en NAV, en mi caso al utilizar NAV 2015 utilizaré el directorio:
 
C:\Program Files (x86)\Microsoft Dynamics NAV\80\RoleTailored Client\Add-ins
 
En el que podemos crear un directorio y copiar la librería desde el directorio (el que os indique vuestra ventana de Resultados), en mi caso:
 
C:\Users\Josep\Documents\Visual Studio 2013\Projects\CEDART\CEDARTwf\bin\Debug\CEDARTwf.dll
 
Abrimos NAV y buscamos Complementos de control para crear un nuevo registro en la tabla e informarlo como sigue:
 
El Nombre complemento control ha de ser idéntico al indicado en nuestro proyecto .NET en la definición [ControlAddInExport("CEDART.controls.labelWF")]

El Token de clave pública es el proporcionado al compilar el proyecto en la ventana Resultados o mediante otros métodos tal como se explica aquí.

Diseñar utilizando nuestro control Add-in

En este punto, y si todo ha ido bien, ya estamos en disposición de utilizar nuestro control Add-in para visualizar un texto dentro de una Page. Con lo que voy a utilizar la misma página mostrada al principio para reacondicionarla:

 
Lo que quiero es sustituir los 2 controles de textos actuales por los de nuestro Add-in, para ello voy a crear una línea adicional y lo pondré nombre Label1, después accederé a las propiedades e indicaré, en la propiedad ControlAddIn el Add-in utilizando el Assist (F6):

 
Accederemos al código (F9) y comprobaremos como disponemos de 2 nuevos eventos:
 
 
El primero se disparará cuando el control Add-in esté listo para ser utilizado y el segundo cuando se haga Click en el control. Vamos a poner código en el primero:

CurrPage.Label1.SetFont('', 14, TRUE);
CurrPage.Label1.Caption := 'Ratios de Liquidez';
 
Crearemos una segunda Label e igualmente introduciremos código en el evento ControlAddInReady:

CurrPage.Label2.Caption :=
  'La liquidez es la capacidad potencial que tiene la empresa ' + 
  'para pagar sus obligaciones. La comparación entre la cantidad ' + 
  'de riqueza disponible (activo circulante) y las deudas que ' + 
  'habrá que atender a corto plazo ' +
  '(pasivo circulante) proporciona una medida de esta liquidez.' +
  'Dependerá del grado de realización de los elementos del activo, ' +
  'es decir, si están cerca de su conversión en liquidez (derechos ' + 
  'de cobro que venzan a corto plazo, existencias que se vayan a ' + 
  'vender, etc.), y del grado de exigibilidad del pasivo, ' +
  'es decir, vencimiento de las deudas y necesidad de su devolución.';
 
Borramos los 2 controles anteriores, compilamos y ejecutamos la Page:
 

 
Mucho mejor que la inicial, ¿no os parece?:



Este Add-in al haber sido creado mediante Windows Forms no es ejecutable desde el cliente Web. En un segundo post os mostraré como construir el Add-in para que pueda ser ejecutado tanto en cliente Windows como en cliente Web.

No hay comentarios:

Publicar un comentario