Buscar en este blog

miércoles, 20 de mayo de 2015

Crear barra de progreso en Dynamics Ax 2012

Muchas veces tenemos procesos muy tardados que necesitan al menos que el usuario sepa que se están realizando para que no comience a dar clics por todos lados y espere pacientemente a que el proceso termine.

Para esto están las barras de progreso mundialmente conocidas, es algo como lo siguiente:

image

Para hacerlo en nuestro código es muy sencillo, primero necesitamos identificar el inicio de nuestro proceso, por ejemplo, yo tengo un lectura de una base de datos externa que tarda unos cuantos segundos, así que al inicio de todo mi proceso agrego mi progress

public void run()
{
    #Macrolib.AviFiles
    str ruta;
    //ruta = "Data Source = 'C:\\Temp\\RBAsset.sdf'; LCID= 1033; Case Sensitive=true";    

    if (ruta != "" )
    {
        progress = new RunbaseProgress( 1null);
       progress.setCaption( strFmt ("Procesando %1" "base de datos movil"));
       progress.setTotal(TotalDeRegistros);
       progress.setAnimation(#AviTransfer);
       progress.updateInterval( 1 );

        //Llena tabla intermedia
        this.bulkToAx(ruta);       
    }
    else
        warning( "No se ha definido la ruta de la BD ó el dispositivo no esta conectado." );


}

Y en mi proceso mas pesado, que en este caso es dentro del método bulkToAx es donde voy actualizando la barra, algo similiar al siguiente código:
 
//Manda llamar la clase de .Net para leer la BD Sdf del dispositivo movil
public void bulkToAx( str _rutaBd)
{
    System.Data.DataRowCollection       dataRowCollection;
    System.Data.DataRow                 dataRow;
    int                                 i,totalRow;
    GRWActivosFijosSdf                  gRWActivosFijosSdf;

    System.Data.DataTable tablaNet = new System.Data.DataTable();
    GRWBdSdfToAx.GRWBdSdfToAxClass clase = new GRWBdSdfToAx.GRWBdSdfToAxClass();

    tablaNet = clase.ConsultaTodosLosActivos(_rutaBd);

    dataRowCollection       = tablaNet.get_Rows();
    totalRow                = dataRowCollection.get_Count();

    for(i = 0 ; i < totalRow; i ++)
    {
        dataRow = dataRowCollection.get_Item(i);
        
        gRWActivosFijosSdf.clear();
        gRWActivosFijosSdf.CodigoBarras     = dataRow.get_Item( 0 );
        gRWActivosFijosSdf.Descripcion      = dataRow.get_Item( 1 );
        gRWActivosFijosSdf.Serie            = dataRow.get_Item( 2 );        
        gRWActivosFijosSdf.insert();

        progress.setCount(i);
      progress.setText( strFmt ("Cargando registro: %1" ,i));
      progress.update( true );
    }

}

Listo, con esas tres líneas en nuestro proceso mas pesado, la barra va a ir corriendo e informando al usuario que ax sigue trabajando.


Post que podrían interesarte:
Distintos tipos de indicadores de progreso
Consultas en tablas con ValidTimeState en Ax 2012
Multiselect de grid en Ax 2012
Crear lookup en clase dialog



Y por cierto, acuerdate de darle click a algún anuncio si el post te sirvio de algo.

No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma. 


lunes, 18 de mayo de 2015

Cómo leer una base de datos sdf desde Dynamics Ax 2012

Después de buscar un poco, al parecer en esta versión de ax es un poco complejo (por no decir que no se puede) leer una base de datos de un dispositivo móvil, en este caso una SQL Compact Edition o lo que es lo mismo SQL CE.

Así que la opción que aplique fue, crear un proyecto en visual studio, de tipo librería de clases y ahí hacer la conexión, la consulta de datos, la modificación o inserción de nuevos registros a la base de datos móvil, pero dejando toda la lógica en Ax.

Lo primero que debemos hacer es crear nuestro proyecto en visual studio y agregar la referencia de Sql Ce que generalmente se encuentra en la ruta:

C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v4.0\Desktop\System.Data.SqlServerCe.dll

En la clase del proyecto de vs, creamos un método que realice la conexión como el siguiente:
public DataTable ConsultaTodosLosActivos( string rutaBaseSdf)
        {
            var conn = new SqlCeConnection();

            // Leer la ruta del archivo sdf
            //Para la app normal seria: Data Source = |DataDirectory|\RedBeam\Asset Tracking\RBAsset.sdf
            conn.ConnectionString = "Data Source = 'C:\\temp\\RBAsset.sdf'; LCID= 1033; Case Sensitive=true";

            try
            {
                // Abrir base
                conn.Open();
                return LlenaDataTable(conn);
            }
            catch (Exception )
            {
                try
                {
                    //Como la base de datos esta en una versión anterior, se debe usar el método SqlCeEngine.Upgrade()
                    var engine = new SqlCeEngine(conn.ConnectionString);
                    engine.Upgrade(conn.ConnectionString);

                    conn.Open();
                    return LlenaDataTable(conn);
                }
                catch (Exception exInterno)
                {
                    conn.Close();
                    throw new InvalidOperationException(exInterno.Message);
                }
            }
        }

La línea de la ruta de conexión contiene al final:
var engine = new SqlCeEngine(conn.ConnectionString);
engine.Upgrade(conn.ConnectionString);

esto se refiere a que si la base de datos es un poco mas antigua que nuestro vs 2010 le hace un upgrade y nos permite leerla. Algo importante es que los dispositivos móviles, por default manejan las bases de datos en una ruta similar a esta: “Equipo\WindowsCE\\\Program Files\Aplicacion\Asset Tracking” entonces si tu ya tienes la ruta de donde vas a leer tu base de datos esta perfecto, sino puedes usar la anterior por default, claro cambiando el nombre “Aplicacion” por el que publique la aplicación.

Una vez que hicimos la conexión, llenamos un datatable que es el voy a regresar a ax para despues manipular los datos:
private DataTable LlenaDataTable( SqlCeConnection conexionBd)
        {
            var table = new DataTable();
            table.Columns.Add( "CodigoBarras" typeof ( string));
            table.Columns.Add( "Descripcion" typeof ( string));
            table.Columns.Add( "Serie" typeof ( string));
            table.Columns.Add( "Edificio" typeof ( string));
            table.Columns.Add( "ZonaEdificio" typeof ( string));
            table.Columns.Add( "Custodio" typeof ( string));
            table.Columns.Add( "NombreCustodio" typeof ( string));

            try
            {
                //Leer tablas
                using (SqlCeCommand com = new SqlCeCommand ("SELECT * FROM tblAssets INNER JOIN tblCustodians ON tblAssets.CustodianID = tblCustodians.CustodianID", conexionBd))
                {
                    SqlCeDataReader reader = com.ExecuteReader();
                    while (reader.Read())
                    {
                        table.Rows.Add(reader.GetString(0).Trim(), reader.GetString(1).Trim(), reader.GetString(2).Trim(), reader.GetString(3).Trim(), reader.GetString(4).Trim(), reader.GetString(10).Trim(), reader.GetString(12).Trim());
                    }
                }

                conexionBd.Close();
            }
            catch (Exception exInterno)
            {
                conexionBd.Close();
                throw new InvalidOperationException(exInterno.Message);
            }

            return table;

        }

Una vez que se tienen los métodos en .Net, se agrega el proyecto a AOT y se implementa (o se hace deploy, es lo mismo).

En Ax, para invocar la dll recién creada en vs, invocar el método y recibir esta tabla de .Net, haría algo como esto:

///Manda llamar la clase de .Net para leer la BD Sdf del dispositivo movil
public void bulkToAx( str _rutaBd)
{
    System.Data.DataRowCollection       dataRowCollection;
    System.Data.DataRow                 dataRow;
    int                                 i,totalRow;
    GRWActivosFijosSdf                  gRWActivosFijosSdf;

    System.Data.DataTable tablaNet = new System.Data.DataTable();
    GRWBdSdfToAx.GRWBdSdfToAxClass clase = new GRWBdSdfToAx.GRWBdSdfToAxClass();

    tablaNet = clase.ConsultaTodosLosActivos(_rutaBd);

    dataRowCollection       = tablaNet.get_Rows();
    totalRow                = dataRowCollection.get_Count();

    for(i = 0 ; i < totalRow; i ++)
    {
        dataRow = dataRowCollection.get_Item(i);

        //Los datos de .Net vienen: [0] CodigoBarras, [1] Descripcion, [2] Serie, [3] Edificio, [4] ZonaEdificio
        //[5] Custodio, [6] NombreCustodio
        gRWActivosFijosSdf.clear();
        gRWActivosFijosSdf.CodigoBarras     = dataRow.get_Item( 0 );
        gRWActivosFijosSdf.Descripcion      = dataRow.get_Item( 1 );
        gRWActivosFijosSdf.Serie            = dataRow.get_Item( 2 );
        gRWActivosFijosSdf.Edificio         = dataRow.get_Item( 3 );
        gRWActivosFijosSdf.ZonaEdificio     = dataRow.get_Item( 4 );
        gRWActivosFijosSdf.CodigoCustodio   = dataRow.get_Item( 5 );
        gRWActivosFijosSdf.NombreCustodio   = dataRow.get_Item( 6 );
        gRWActivosFijosSdf.insert();        
    }
}

Listo!!! así se lee una tabla de un dispositivo movil y se guarda la información en una tabla de ax.

Tip: Una vez que se implemento el proyecto de vs, en caso de no ver la dll por código (aunque si en el AOT), hay algunas cosas que es posible hacer, por ejemplo borrar los archivos AUC del archivo de cliente que generalmente estan la ruta:
C:\Users\ADMINMDX_DES\AppData\Local\Microsoft\Dynamics Ax


Post que también podrían ser de tu interés:
Capturar errores del infolog mediante código x++
Crear documentos asociados a un registro por código (DocuRef)
Teclas rápidas en Microsoft Dynamics Ax 2012


Y por cierto, acuérdate de darle click a algún anuncio si el post te sirvió de algo.


No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma.