Que tal.
Ahora voy a platicar de una dificultad técnica que me encontré cuando tuve que generar un reporte a través de C# y Crystal Reports.
La problemática consistió en que para generar el reporte en CR (para VS 2010), tenía que hacer la conexión a través del asistente del mismo CR, resulta que en tiempo de ejecucion en la pc de desarrollo, trabaja sin problemas, solo le especificaba el usuario y contraseña a través de código, y, wuala, trabajaba suavemente. Sin embargo cuando lo probé en una pc cualquiera, al llegar a la parte del reporte, me solicitaba credenciales para acceder al servidor de bd (Sql Server Express 2008), no pudiendo conectarse ni siquiera con SA.
El asunto aqui es que, por alguna razón que mi pequeño cerebro no dedujo, no se efectuaba la conexión, es entonces que me dediqué a investigar en la maravillosa fuente de información que es la Internet, cómo resolverlo, sin llegar a una solución, pero si a varias estrategias para llegar a la solución.
Aqui la planteo.
Antecedentes,
-Uso clases para la conexión a datos, en cada una de las tablas de la BD.
-Utilizo clases con sus métodos para las consultas e inserciones.
-Crystal reports no usaba estas clases para la conexión a datos (si ya se, soy un buey), utilizaba el asistente.
Acciones.
-Quité la conexión de crystal reports a través del asistente, y usé un reporte en blanco.
-Agregué campos de texto al reporte, para los datos dinámicos, en total fueron 8 para un reporte y 11 para otro, además de los encabezados.
-Eché mano de una nueva consulta sql, con los datos requeridos, para generar un dataset en tiempo de ejecución y mandarlos, también en tiempo de ejecución al reporte, y esto fue lo más divertido, en seguida lo detallo.
Primero que nada tengo un reporte en blanco de CR al cual le agregué las etiquetas a pata y en donde deben ir los datos les puse nombres del tipo "txtdato1, "txtdato2", hasta que cubrí esa parte. Posteriormente, en VS el crear el reporte sólo lo declaras, se tiene que instanciar de alguna forma, o desde alguna forma.
Entonces, al cargar la forma desde donde se llama el reporte en el evento Load, se genera el dataset que se enviará al reporte, (cabe destacar que esto lo hago para un reporte del tipo encabezado, no lleva un detalle, ya se presentará la problemática, pero por ahora solo tengo esto)
private void visor_reporte_Load(object sender, EventArgs e)
{
orden imprimiendo = new orden(); ---> Se instancia la clase donde hago la consulta
DataSet ds = imprimiendo.imprimir(this.Nuo); ->Se ejecuta el metodo de la consulta
DataTable resultado = ds.Tables[0]; --->Se asigna el dataset devuelto a una tabla.
impresion imp = new impresion(); --->Se instancia el reporte lo llame impresion, ingenioso!!
CrystalDecisions.CrystalReports.Engine.TextObject txt1; --->Se debe declarar un objeto de texto de
CrystalDecisions.CrystalReports.Engine.TextObject txt2; --->reporte, medio raro, pero asi debe ser, por
CrystalDecisions.CrystalReports.Engine.TextObject txt3; ----> cada dato del reporte
CrystalDecisions.CrystalReports.Engine.TextObject txt4;
CrystalDecisions.CrystalReports.Engine.TextObject txt5;
CrystalDecisions.CrystalReports.Engine.TextObject txt6;
CrystalDecisions.CrystalReports.Engine.TextObject txt7;
CrystalDecisions.CrystalReports.Engine.TextObject txt8;
CrystalDecisions.CrystalReports.Engine.TextObject txt9;
CrystalDecisions.CrystalReports.Engine.TextObject txt10;
CrystalDecisions.CrystalReports.Engine.TextObject txt11;
---->Se debe de asignar el elemento del reporte al elemento de texto de reporte, pero no sin antes hacer una conversion o "cast" para que pueda aparecer la propiedad text y entonces asignar el resultado del dataset asignado en la tabla "table".
txt1=(CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtor"];
txt2 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtfc"];
txt3 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtfa"];
txt4 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtre"];
txt5 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtte"];
txt6 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtpo"];
txt7 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtpr"];
txt8 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtfac"];
txt9 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtli"];
txt10 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtes"];
txt11 = (CrystalDecisions.CrystalReports.Engine.TextObject)imp.ReportDefinition.ReportObjects["txtne"];
-----> Aqui ya se asigna a la propiedad texto el contenido requerido de la tabla devuelta por la consulta en el método llamado arriba.
txt1.Text = resultado.Rows[0][0].ToString();
txt2.Text = resultado.Rows[0][1].ToString();
txt3.Text = resultado.Rows[0][2].ToString();
txt4.Text = resultado.Rows[0][3].ToString();
txt5.Text = resultado.Rows[0][4].ToString();
txt6.Text = resultado.Rows[0][5].ToString();
txt7.Text = resultado.Rows[0][6].ToString();
txt8.Text = resultado.Rows[0][7].ToString();
txt9.Text = resultado.Rows[0][8].ToString();
txt10.Text = resultado.Rows[0][9].ToString();
txt11.Text = resultado.Rows[0][10].ToString();
impresion.ReportSource = imp; ---> Este "impresion" es el control donde se muestra el reporte en la
---> forma, no es la clase del reporte, es un "crystalreportviewer"
}
Es así como me funcionó el reporte sin necesidad de autenticación por parte de CR, debido a que sólo le paso los datos a través de asignacion directa de un datatable a los elementos del reporte.
Esto hizo más eficiente el tiempo de carga y mostrado del reportito.
Espero le sirva a alguien más.
Nos vemos.