sábado, 22 de septiembre de 2012

Subreportes de Crystal Reports en VB.NET


Hola people hoy les hablaré sobre los subreportes en Crystal Reports. Un subreporte no es mas que un reporte dentro de otro reporte, esto normalmente lo utilizamos cuando queremos ver información adicional o detalles de la información que estamos manejando en nuestro reporte. No entraremos tanto en detalle de como llenar un reporte ya que eso lo pondré en otro articulo, la idea en la que nos centraremos será en el manejo de subreportes y como “enlazarnos con el reporte”.
Para realizar esto lo que necesitamos hacer es lo siguiente, primero necesitamos crear el reporte que contendrá mis subreporte(s) para ello:
Agregar en elemento Crystal Reports a nuestro proyecto. Para ello nos vamos al menú Project, Add New Item.


En las categorias seleccionamos Reporting.
En esta pantalla seleccionamos nuestro elemento CrystalReports y le ponemos el nombre que gustemos. Presionamos Add y ya tenemos nuestro Elemento de Crystal Reports agregado. Inmediatamente después nos aparecerá un wizard donde nos dirá que seleccionemos que tipo de reporte queremos, en este caso seleccionamos reporte en blanco y damos ok.
Visualizaremos nuestro reporte como se presenta a continuación:
Es importante tener un poco de conocimientos acerca de las distintas secciones que tiene un reporte Crystal Reports ya que cada una de ellas puede ser utilizada según nuestras necesidades. Una vez teniendo nuestro Reporte podemos diseñarlo con los colores y formas que gustemos.
Muy bien, hasta ahora ya tenemos nuestro reporte que contendrá el subreporte. Lo siguiente es realizar los mismos pasos de crear el reporte para crear nuestro subreporte ya que como comentabamos al inicio un subreporte no es mas que un reporte dentro de otro reporte.
Para agregar el subreporte que acabamos de crear a nuestro reporte presionamos botón derecho sobre nuestro reporte, nos vamos a Insert y luego a Subreport y lo acomodamos en la sección que gustemos.

Se abrirá una ventana donde trae 2 pestañas: Subreport y Link. En la pestaña SubReport nos da las opciones de seleccionar un reporte de nuestro proyecto o un reporte ya existente que tengamos en algun directorio fuera de nuestro proyecto.


Cualquiera de las 2 opciones que seleccionemos nos llevará al mismo fin. En la pestaña Link esta una de las cosas interesantes ya que ahi será donde enlazaremos nuestro reporte con nuestro subreporte y para logralo lo único que tenemos que hacer es escoger un campo que tengan en común el reporte y el subreporte por ejemplo un ID de tal forma que esten relacionados como en cualquier consulta a la Base de Datos.


Estos cuantos pasos son todos los necesarios para agregar un subreporte a nuestro reporte. Cabe mencionar que si realizamos una modificación a nuestro subreporte después de haberlo agregar al reporte tenemos que presionar botón derecho sobre el subreporte y dar Re-import Subreport para que se actualice.

Saludos!

Creación de Reportes con Crystal Reports en Visual Studio 2005/2008/2010


Este pequeño tutor de como crear un reporte en Crystal Reports desde Visual Studio 2005/2008, lo hago porque he recibido muchas consultas de como hacerlo de la mejor forma, quizás hiera algunas susceptibilidades, pero espero que entiendan que también hay otras maneras de hacer las cosas.
En primer lugar en este tutor les voy a indicar como crear el reporte de la manera mas larga, pero también, es la mejor manera para tener el control total sobre lo que queremos mostrar en el reporte.
La manera mas fácil de crear un reporte es agregar al proyecto un nuevo ítem de tipo reporte de Crystal Reports, y conectarse  a la base de datos desde el explorador de servidores del Visual Studio, seleccionar las tablas y arrastrarlas sobre el diseñador del reporte.
Si, esta es la manera mas fácil, pero también la que mas problemas nos puede dar al momento de empezar a cambiar campos a mostrar o al tratar de agregar una condición o filtro a los datos que queremos mostrar en el reporte.
La anterior es una buena técnica, siempre y cuando el reporte sea sencillo y detectemos que no tendrá cambios.
A continuación describo la manera en yo creo mis reportes tanto para web como para windows. A muchos les parecerá mas larga pero les aseguro que no tendrán problemas en el futuro pues tienen todo controlado ustedes.
Voy a utilizar un proyecto Windows Forms y una base de datos Sql Server 2008, pero se van a dar cuenta que lo pueden hacer con cualquier tipo de base de datos.
No voy a entrar en detalles del tipo de conexión a la base de datos ni las instrucciones para traer los datos.
A continuación muestro la forma con los datos que vamos a utilizar para nuestro reporte:
image
Bueno la idea de nuestro proyecto es que poder tener un reporte con estos datos, lo primero que vamos a hacer es agregar a nuestro proyecto un objeto dataset, que es el que nos va a servir para poder crear nuestro reporte en Crystal Reports.
image
Clic derecho en el nombre del proyecto, del menú seleccionamos la opción Add, y luego New Item… para que nos aparezca la siguiente pantalla y poder escoger el objeto a adicionar a nuestro proyecto.
image
Escogemos adicionar un objeto dataset que nos servirá como fuente de datos para el reporte y poder crear nuestro reporte como queremos. Le damos un nombre a nuestro dataSet, por lo general yo lo llamo igual que el reporte con el prefijo ds, entonces nuestro dataset se va a llamar dsPersonas.xsd
image
Al darle clic al boton Add nos muestra la ventana de diseño en la cual vamos a agregar un datatable con sus respectivos campos que son los que necesitamos para dibujar el reporte. Al estar aquí, damos clic derecho sobre la superficie para poder agregar el datatable :
image
image
Nos muestra el datatable creado, podemos cambiar el nombre que coloca por defecto, haciendo clic sobre el nombre y se coloca en modo de edicion para poder cambiarlo.
image
Para agregar los diferentes campos de nuestro datatable, seguimos los siguientes paso:
1. Clic derecho en el área de los campos del datatable y los vamos agregando.
image
2. al seleccionar Agregar Columna:
image nos permite colocarle el nombre a la columna, este nombre DEBE ser igual al nombre que vamos a devolver en nuestra consulta SQL a la Base de datos.
3. image En la ventana de propiedades de la columna que estamos agregando, podemos asignar el tipo de campo y su longitud en caso de ser una cadena ( String) y que sea requerido. Mi recomendación es que se apeguen a los mismos tipos de datos que están definidos en la base de datos.
4. En proceso de agregar los campos necesarios para el reporte:
image
Si me preguntan si es se pueden agregar campos que no se van a utilizar en el reporte, la respuesta es SI, porque es posible que ya tengamos la consulta realizada que nos sirve para nuestro  reporte y solo es crearlo a partir de la consulta que  ya existe, y como la consulta nos devuelve datos que no vamos a colocar ene l reporte, de todas formas tenemos que crear esos campos en nuestro datatable.
5. Aqui esta nuestro datatable completo para empezar a generar nuestro reporte:
image
Quizás me pensaran: “es mucho trabajo” pero piensen en esto, este sistema si mas tarde necesitan agregar un nuevo campo es simplemente venir agregar el campo y actualizar la fuente de datos del reporte para tener acceso a ese nuevo campo que acabamos de crear, por el otro método, eso no es tan fácil, es mejor agregar el campo y volver a crear el reporte. Aclaración: “yo, particularmente, no he sabido, o no he logrado como hacerlo cuando lo intente”.
6. Creamos el reporte en crystal reports, nuevamente clic derecho en el nombre del proyecto, Add, New Item..,  en la ventana que aparece, seleccionamos Reporting y escogemos el tipo de reporte Crystal Report:
image
Asignamos un nombre al reporte que se guarda con la extensión .rpt, y clic al botón Add para crear el reporte en nuestro proyecto.
image
Aparece la siguiente pantalla para seleccionar el tipo de reporte a crear, en la parte izquierda señalado en el circulo rojo aparece una nueva barra de herramientas con la cual vamos a trabajar al adicionar los campos al reporte, en la parte derecha, he resaltado en el circulo rojo que se agregan al proyecto de manera automática las referencias necesarias para que funcionen los reporte de Crystal Reports en nuestro proyecto.
De la ventana, seleccionamos la segunda opción, crear un reporte en blanco “As a Blank Report
image
Al darle clic al boton OK de la pantalla anterior nos muestra el reporte en blanco como aparece en la imagen anterior.
La sección de Report Header, colocaremos lo que queremos que aparezca solo en la primera hoja del reporte.
En la sección  Page Header, colocaremos los que queremos se muestre en la cabecera de todas las paginas del reporte, aquí colocaremos los títulos de las columnas, por ejemplo.
En la sección Details, colocaremos el detalle de las columnas del reporte
La sección Report Footer, es la contraparte de la del Page Header, aquí podríamos colocar los números de pagina del reporte, por ejemplo.
La sección Page Footer es la contraparte de Report header.
Ya teniendo claro esto, lo siguiente es seleccionar la fuente de datos de nuestro reporte, aquí es donde entra a jugar el dataset que creamos en pasos anteriores, pues no necesitamos tener la conexión a la base de datos abierta para diseñar nuestro reporte.
image
Damos Clic derecho en el Field Explorer en la entrada Database Field, al aparecer el menú contextual de la imagen seleccionamos Database Expert… para ir a seleccionar nuestra fuente de datos.
image
En esta ventana, expandimos Project Data, luego ADO.NET DataSets, aquí nos van a aparecer todos los dataset que tengamos creados en nuestro proyecto, en nuestro caso solo aparece dsPersonas, que es el que hemos creado en pasos anteriores.
Seleccionamos el datatable  y damos clic en el botón image  para pasar los datos a la parte derecha de la ventana en la cual va a exponer los campos del datable para poder incluirlos en nuestro reporte.
image 
Hacemos clic en el botón OK para empezar a diseñar nuestro reporte. Al hacer esto, ya contamos con los campos del dataset en el Field Explorer:
image
Ahora simplemente es arrastrar los campos al área del reporte y colocarlos de la manera como deseamos se vea el reporte.
image
Seleccionamos la Toolbox (barra de herramientas de crystal) y de allí escogemos el control text object y lo arrastramos a la sección de page header para colocar el titulo del reporte allí, en la imagen están seleccionados en círculos rojos todos los controles mencionados.
image
Al arrastrar un campo del datatable y soltarlo en la sección de detalle de manera automática coloca un control de texto para el titulo del control que acabamos de arrastrar.
image Para corregir el texto del titulo, lo seleccionamos, le damos clic derecho al control y escogemos del menú la opción “Edit Text Object”, lo que nos permite cambiar el texto del titulo.
image
La imagen nos muestra como queda nuestro reporte, no es el alcance de este tutor, indicar como colocar los diferentes atributos de presentación grafica del reporte.
En nuestro formulario windows (web forms) o en nuestro formulario web (web forms) agregamos un control CrystalReportViewwer , el cual nos servirá para mostrar nuestro reporte en pantalla y poder imprimirlo o exportarlo a algún formato como PDF o Excel.
En el boton Imprimir de nuestro formulario, el codigo que voy a colocar para ir a la base de datos, realizar la consulta de los datos, colocarlos en un datatable y este datatable pasarlo a la propiedad datasource del reporte.
A continuacion el codigo del boton imprimir:
Private Sub btnImprimir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImprimir.Click
        Dim oCnn As New OleDbConnection  ‘ Objeto de conexion a la base de datos
        Dim daDatos As New OleDbDataAdapter ‘ Objeto Adaptador para leer datos de la Base de datos
        Dim cmdExec As New OleDbCommand ‘ objeto comando para ejecutar sentencias sql
        Dim dtDatos As New DataTable ‘ datatable para recibir los datos de la base de datos
        Dim sbQuery As New StringBuilder ‘ StringBuilder para armar cadenas
        Try
            oCnn.ConnectionString = "Provider=SQLNCLI10;Server=ralvarado;Database=MiBD;Uid=sa; Pwd=XXX;"
            oCnn.Open()
            cmdExec = oCnn.CreateCommand
            cmdExec.Connection = oCnn
            sbQuery.Append("SELECT Consecutivo  ")
            sbQuery.Append("      ,IdentificacionPersona  ")
            sbQuery.Append("      ,TipoPersona  ")
            sbQuery.Append("      ,Grupo  ")
            sbQuery.Append("      ,PrimerNombre  ")
            sbQuery.Append("      ,PrimerApellido  ")
            sbQuery.Append("      ,SegundoApellido  ")
            sbQuery.Append("      ,Sexo  ")
            sbQuery.Append("      ,Profesion  ")
            sbQuery.Append("      ,Direccion1  ")
            sbQuery.Append("      ,Direccion2  ")
            sbQuery.Append("      ,TelFijo1  ")
            sbQuery.Append("      ,TelFijo2  ")
            sbQuery.Append("      ,TelMovil  ")
            sbQuery.Append("      ,PaginaWeb  ")
            sbQuery.Append("      ,ZonaPostal  ")
            sbQuery.Append("      ,Fax  ")
            sbQuery.Append("      ,Email1  ")
            sbQuery.Append("      ,Email2  ")
            sbQuery.Append("      ,FechaNacimiento  ")
            sbQuery.Append("            FROM Persona   ")
            cmdExec.CommandText = sbQuery.ToString
            daDatos = New OleDbDataAdapter(cmdExec)
            daDatos.Fill(dtDatos)
            Dim CrReport As New CrystalDecisions.CrystalReports.Engine.ReportDocument
            ' Asigno el reporte
            CrReport = New CrystalDecisions.CrystalReports.Engine.ReportDocument()
            CrReport.Load(Application.StartupPath & "\crPersonas.rpt")
            CrReport.SetDataSource(dtDatos)
            CrystalReportViewer1.ReportSource = CrReport
        Catch ex As Exception
            MessageBox.Show("excepcion: " & ex.Message, "Mostrando Reporte")
        End Try
    End Sub
Observen que al llenar los datos en dtDatos, simplemente debo asignarle este objeto al Reporte en su método SetDataSource. Con esto puede ser cualquier base de datos, siempre y cuando los datos correspondan a la estructura del dataset creado como fuente de datos del reporte.
Si en algún momento nuestro reporte cambia que hay que agregarle un nuevo campo, simplemente vamos a nuestro dataset y le agregamos el campo, luego vamos al reporte y lo abrimos y verificamos nuestra fuente de datos para que nuestro nuevo campo aparezca en al lista, luego es simplemente incluirlo en el reporte.
image
Bueno espero haber sido claro en como crear un reporte con Crystal Report y les aseguro que no van a tener problemas al momento de modificaciones en el reporte.

Hasta la próxima!!!!!!.

sábado, 8 de septiembre de 2012

Recorrer todos los nodos de un TreeView

    Private Sub PrintRecursive(ByVal n As TreeNode)
        System.Diagnostics.Debug.WriteLine(n.Text) 'Muestra el texto del nodo en la ventana de inmediato
        MessageBox.Show(n.Text) 'Muestra el mismo mensaje por pantalla

        '*** Es aqui donde añado lo que necesito guardar de cada nodo *** 
        Dim aNode As TreeNode
        'Por cada nodo de la raiz
        For Each aNode In n.Nodes
            PrintRecursive(aNode)
        Next
    End Sub



    'Llame al procedimiento usando los nodos superiores de la vista de árbol.
    Private Sub CallRecursive(ByVal aTreeView As TreeView)
        Dim n As TreeNode
        'Por cada raíz
        For Each n In aTreeView.Nodes
            PrintRecursive(n)
        Next
    End Sub

viernes, 10 de agosto de 2012

Resetear una Columna Identidad (Identity) de SQL Server 2008

En muchos de los Proyectos que he realizado siempre nos hemos encontrado con el Escenario en que para algunas tablas las Claves primarias son Enteras y con la caracteristica de ser una Identity pero el problema surgia en que al eliminar todos los registros de la tabla la columna Identidad guardaba el ultimo valor entero generado y se perdia la secuencia de la misma.

Para los Beginners una columna Identity (Identidad) tiene la caracteristica de tomar valores autogenerados.

Por ejemplo.

Creo esta tabla Alumnos en mi BD SQL Server.

CREATE TABLE Alumnos
(
codigo INT PRIMARY KEY IDENTITY(1,1),
nombre VARCHAR(30)
)

Como veran el campo codigo es una columna Identidad (Identity) que iniciara con valor 1 y se ira incrementando por cada Insert sobre esta tabla en 1.

Los valores dentro de los parentesis pueden ser modificables como por ejemplo quiero que comienze en 100 y se vaya incrementando en 50 entonces quedaria de la siguiente manera

CREATE TABLE Alumnos
(
codigo INT PRIMARY KEY IDENTITY(100,50),
nombre VARCHAR(30)
)

una vez creada la tabla ingresamos 4 registros y consultamos la tabla.

INSERT INTO ALUMNOS (nombre)VALUES('Cristina')
INSERT INTO ALUMNOS (nombre)VALUES('Nicole')
INSERT INTO ALUMNOS (nombre)VALUES('Jhon')
INSERT INTO ALUMNOS (nombre)VALUES('Angel')




como observaran una columna identidad ya no participa de la sentencia insert ya que es un codigo Autogenerado, y como apreciaran el codigo inicia con el valor de 100 y se va incrementando de 50 en 50.

ahora haremos el siguiente escenario. que pasaria si elimino todos los registros de la tabla y inserto un nuevo registro.

DELETE ALUMNOS
go

INSERT INTO ALUMNOS (nombre)VALUES('Royser')

ahora consultamos la tabla nuevamente, y veamos algunas observaciones.



Observamos que una vez despues de eliminar todos los registros de la tabla Alumnos se perdie la secuencia y mas aun de iniciar en 100 como esta en la definicion cuando creamos la tabla.

Bueno para solucionar este problema tenemos que hacer el uso del siguiente comando.

DBCC CHECKIDENT (NOMBRE_TABLA, RESEED, VALOR_IDENTIDAD)
GO

hago un parentisis "(" y quiero entrar a detallar un poco la utilidad de este comando DBCC CHECKIDENT

CHECKIDENT comprueba la identidad actual de la tabla especificada y parte de su funcionalidad es cambiar el valor de la identidad, en pocas palabras modificar manualmente el valor de Identidad Actual de la columna.

la sintaxis es la siguiente:

DBCC CHECKIDENT 
( 
        NOMBRE_TABLA
        [ , { NORESEED | { RESEED [ , NUEVO_VALOR_IDENTIDAD ] } } ]
)

[ WITH NO_INFOMSGS ]


NOMBRE_TABLA: Es el nombre de la tabla del cual se va a ser la verificacion del valor de la columna Identidad.

Esta tabla debe contener una columna Identidad sino esta demas de hacer la comprobacion.

por ejemplo ejecuto lo siguiente:

DBCC CHECKIDENT(ALUMNOS)

Resultado
----------

Checking identity information: current identity value '250', current column value '250'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Como observaran la ionformacion de la verificacion muestra que el valor actual de la identidad es de 250 y el actual valor de la columna es 250. por lo tanto no se ha hecho algun cambio manual para que varie el valor de la columna actual.

hagamos lo siguiente: ejecutar el comando y modificar manualmente el valor de la identidad para que inicie 500 (si deseo que el siguiente registro comienze en 500 deberia iniciarlo en 450)

DBCC CHECKIDENT (ALUMNOS, RESEED, 450)
GO

Tenemos el siguiente mensaje:

Checking identity information: current identity value '250', current column value '450'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Ahora si notamos la diferencia, el actual valor de la columna Identidad es 250 pero si hago un nuevo INSERT tomara el valor actual de la columna identidad que es 450 + 50 el incremento = 500 = Codigo Identidad.

Comprobemos

INSERT INTO ALUMNOS (nombre)VALUES('Royser')

codigo      nombre
----------- ------------------------------
100         Cristina
150         Nicole
200         Jhon
250         Angel
500         Royser

(5 row(s) affected)
NORESEED: Indica que el valor de la identidad en este caso la columna no debe cambiar.

RESEED: Indica que el valor de la identidad en este caso la columna no si debe cambiar.

NUEVO_VALOR_IDENTIDAD: Es el nuevo valor de identidad actual.
WITH NO_INFOMSGS
 : Suprime los mensajes de informacion.

Ahora volviendo al ejercicio propuesto se debera ejecutar lo siguiente:

DBCC CHECKIDENT(ALUMNOS, reseed, 50)

ahora se preguntaran porque iniciamos en 50 y porque no en 100. Es muy simple porque si iniciamos en 100 el primer insert que se haga en la tabla hara que se incremente en 50 osea por consecuencia el primer registro tendra el codigo 100 + 50 = 150.

Es por eso que inicio con 50 para que el primer registro tenga el codigo iniciado en 50 + 50 del incremento = 100 y asi siga la secuencia inicialmente.

Antes de ejecutar el comando DBCC CHECKIDENT Eliminamos nuevamernte todos los registros y luego ejecutamos el comando DBBC CHECKIDENT y luego hacemos un nuevo Insert de los valores Iniciales

DELETE ALUMNOS
GO

DBCC CHECKIDENT (ALUMNOS, RESEED, 50)
GO

INSERT INTO ALUMNOS (nombre)VALUES('Cristina')
INSERT INTO ALUMNOS (nombre)VALUES('Nicole')
INSERT INTO ALUMNOS (nombre)VALUES('Jhon')
INSERT INTO ALUMNOS (nombre)VALUES('Angel')

hacemos un nuevo select a la tabla de alumnos y veamos el siguiente resultado.

jueves, 9 de agosto de 2012

el proceso no puede obtener acceso al archivo porque está siendo utilizado en otro proceso


el proceso no puede obtener acceso al archivo porque está siendo utilizado en otro proceso vb.net
el proceso no puede obtener acceso al archivo porque está siendo utilizado en otro proceso vb.net
La función que adjunta el fichero, lo deja abierto. No se porque, pero es así.
La idea general es crear el fichero en memoria y adjuntar ese fichero en memoria con el nombre que quieras.
Esta clase lo hace:
Imports System.Net.Mail
Imports System.Text
Imports System.Net
Public Class FrmEmail
Public Shared Function SendEMail(ByVal strOrigen As String, ByVal strDestinatario As String, ByVal strAsunto As String, ByVal strMsg As String, ByVal usuario As String, ByVal Clave As String, ByVal smtp As String, ByVal Adjunto As String) As Boolean
Dim msg As New MailMessage()
msg.[To].Add(New MailAddress(strDestinatario))
msg.From = New MailAddress(strOrigen)
msg.Subject = strAsunto
msg.Body = strMsg
‘Adjuntar fichero. No se puede ajuntar el fichero tal cual, pues se queda bloqueado.
Dim contentAsBytes As Byte() = Encoding.UTF8.GetBytes(Adjunto)
Dim memStream As System.IO.MemoryStream = New System.IO.MemoryStream(contentAsBytes)
Dim streamWriter As System.IO.StreamWriter = New System.IO.StreamWriter(memStream)
streamWriter.Flush()
memStream.Position = 0
Dim thisAttachment As Attachment = New Attachment(memStream, vbNull) ‘ “image/jpeg”)
Dim F As Long
Dim FileNameAdjunto As String
F = InStrRev(Adjunto, “\”)
If F = 0 Then
FileNameAdjunto = Adjunto
Else
FileNameAdjunto = Adjunto.Substring(F)
End If
thisAttachment.ContentDisposition.FileName = FileNameAdjunto
msg.Attachments.Add(thisAttachment)
‘msg.Attachments.GetEnumerator()
Dim clienteSmtp As New SmtpClient(smtp)
clienteSmtp.Credentials = New NetworkCredential(usuario, Clave)
Try
clienteSmtp.Send(msg)
Return True
Catch ex As Exception
MsgBox(ex.Message)
Return False
End Try
End Function
End Class