sábado, marzo 05, 2011

Cuando usar ByVal y ByRef en VB.Net

Generalmente se suele usar ByVal en la programación de una función, por ejemplo

Private Sub (ByVal as ,...)

End Sub

pero tambien podemos escribir la función de la siguiente manera:

Private Sub (ByRef as ,...)

End Sub

¿Y cual es la diferencia?

Hay una gran diferencia al momento de usar ByVal y ByRef que se tiene que tener en cuenta a la hora de programar una función, y es que

El paso de argumento tipo ByVal crea una copia de la variable original, por lo que cualquier modificación hecha a dicha variable no afectará a la variable original.

El paso de argumento tipo ByRef hace una referencia de la variable original, por lo que cualquier modificación hecha a dicha variable si afectará a la variable original.

Para entender mejor en el siguiente ejemplo una variable inicializada en 10, cuyo valor se pasa a una función que lo incrementa en 1, debiendo obtener como resultado final 11.


Usando ByVal:


Dim suma As Integer = 10
fIncrementar(suma)



Private Sub fIncrementar(ByVal Value As Integer)
Value = Value + 1
End Sub


Si ejecutamos este ejemplo podremos comprobar que el item con valor 10 no aumenta a 11 porque en la función fIncrementar al usar ByVal creamos una copia de la variabel cuyo valor modificado no solo se aplicara a la variable orginal, el resutado final es que el número sigue siendo 10.



Usando ByRef:


Dim suma As Integer = 10
fIncrementar(suma)



Private Sub fIncrementar(ByRef Value As Integer)
Value = Value + 1
End Sub


Al usar ByRef prodremos comprobar que el valor de la variable suma que en un principio estuvo en 10 ahora aumento a 11, debido a que ByRef hace que la variable original se referencie en el argumento de la función fIncrementar, y cualquier cambio hecho al argumento Value se aplicará inmediatamente a la variable suma.


Otro caso en que es necesario conocer la diferencia entre Byval y ByRef es cuando queremos modificar una colección que esta siendo usado en un foreach, como se sabe no se puede agregar y tampoco eliminar items de una lista que esta siendo usado en un foreach, si se intenta hacer esto el compilador de visual estudio mostrará el siguiente error "Colección modificada; puede que no se ejecute la operación de enumeración.".

para poder realizar cambios a una colección mientras se usa en un foreach hay un truco usando ByRef .

En el siguiente ejemplo elimino un item de la colección cuando esta siendo usado en un foreach, para ello uso ByRef para hacer referencia a la lista que contiene los items, asi cualquier item que elimine en la función se actualizara en la lista original.




Dim lista As New List(Of Integer)

lista.Add(1)
lista.Add(2)
lista.Add(3)

For Each Item As Integer In lista.ToArray
If Item = 3 Then
fRemove(lista, Item)
End If
Next


Private Sub fRemove(ByRef lList As List(Of Integer), ByVal Item As Integer)
lList.Remove(Item)
End Sub


Con este truco podemos eliminar o agregar un item de la lista genérica mientras esta siendo usado en un foreach.

Reutilizar eventos en Csharp

Muchas veces los eventos de cada formulario en una aplicación MDI repiten el mismo código, por ejemplo si queremos que se abra una ventana de ayuda al presionar F1 debemos repetir el mismo código en el evento KeyDown de todos los formularios y programar la llamada a la ventana de ayuda.

Para simplificar estos temas y reutilizar código podemos optar en crear solo una función que llame a la ventana de ayuda y se ejecute cada vez que el usuario presione F1.

El siguiente ejemplo tiene un formulario MDI y dos formularios hijos, donde cada vez que se presione la tecla F1 en los formularios hijos muestre un mensaje, ademas, en la parte inferior del formulario MDI debe mostrar el nombre del formulario hijo actual.

En el formulario MDI programamos la función que abre a los formularios hijos y se asigna los eventos Activated y KeyDown para los resultados que deseamos conseguir.


//Funciones Generales

//Abrir los formularios hijos
private void fOpenWindows(Form value)
{
value.MdiParent = this;
value.Show();
//Para que los eventos de teclado se apliquen a todo el formulario
value.KeyPreview = true;
//Reutilizamos el evento activate en el formulario que vamos a abrir
value.Activated += new System.EventHandler(EvtActivate_Activated);
//Reutilizamos el evento KeyDown en el formulario que vamos a abrir
value.KeyDown += new KeyEventHandler(EvtKeyDown_KeyDown);
this.tslNomFormularioActivo.Text = value.Text;
}

//Mostrar el nombre del formulario activo
private void EvtActivate_Activated(Object sender, EventArgs e)
{
//Mostrar el nombre del formulario Activo en la parte
//inferior del MDI
this.tslNomFormularioActivo.Text = ((Form)sender).Text;
}


//Tecla presionada por el usuario
private void EvtKeyDown_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
//Mostrar un mensaje cuando se presione F1
if (e.KeyCode == Keys.F1)
{
MessageBox.Show("Usted presionó la tecla F1");
}
//Mostrar un mensaje cuando se presione F2
else if (e.KeyCode == Keys.F5)
{
MessageBox.Show("Usted presionó la tecla F5");
}
//Cuando se presione teclas combinadas que usen Ctrl + {tecla}
else if (e.Control == true)
{
//cuando el usuario presiona Ctrl + C mostrar un mensaje
if (e.KeyCode == Keys.C)
{
MessageBox.Show("Usted presionó la combinación de teclas Ctrl + C");
}
//cuando el usuario presiona Ctrl + V mostrar un mensaje
else if (e.KeyCode == Keys.V)
{
MessageBox.Show("Usted presionó la combinación de teclas Ctrl + V");
}

}
}


Código para abrir los dos formularios hijos.


private void form1ToolStripMenuItem_Click(object sender, EventArgs e)
{
Form1 wOpen = new Form1();
fOpenWindows(wOpen);
}

private void form2ToolStripMenuItem_Click(object sender, EventArgs e)
{
Form2 wOpen = new Form2();
fOpenWindows(wOpen);
}


La lógica nos sirve tanto en aplicaciones de escritorio y aplicaciones web. En Asp.Net tambien podemos reutilizar eventos.

Como vemos no se ha programado nada en los dos formularios hijos, logrando de esta manera reducir el código de nuestra aplicación.

sábado, febrero 26, 2011

Encriptar texto en vb.net con SHA512

SHA512 en un encriptador de cifrado irreversible que se encuentra en la libreria System.Security.Cryptography del .net.

Al ser de cifrado irreversible ya no se puede desencriptar. puede tener diferentes usos por ejemplo si queremos validar la contraseña de un usuario poder comparar la contraseña encriptada en la base de datos y la cadena encriptada de una caja de texto.

para usar SHA512 debemos importar las siguientes librerias


Imports System.Security.Cryptography
Imports System.Text


la siguiente funcion recibe la cabena y devuelve la cadena encriptada


Public Function EncriptarPwd(ByVal pwd As String) As String
Dim cifrador As New SHA512Managed
Dim contraseñaOriginal As Byte() = Encoding.ASCII.GetBytes(pwd)
Dim contraseñaCifrada As Byte() = cifrador.ComputeHash(contraseñaOriginal)
Dim textoContraseñaCifrada As String = Convert.ToBase64String(contraseñaCifrada)
Return textoContraseñaCifrada
End Function

Uso de SET NOCOUNT en SQLServer

En SQLServer se usa SET NOCOUNT para devolver o no la cantidad de filas afectadas por alguna sentencia o transacción ejecutada. SET NOCOUNT tiene dos estados:

SET NOCOUNT ON : Inhabilita la cuenta del número de filas afectadas por una instrucción Transact-SQL

SET NOCOUNT OFF: Habilita la cuenta del número de filas afectadas por una instrucción Transact-SQL





Cuando se usa SET NOCOUNT ON se mejora el rendimiento del servidor porque omite la devolución del numero de filas afectadas al cliente o terminal que ha realizado la consulta, pero hay casos en que es necesario obtener el número de registros afectados segun nuestra necesidad, por ello se recomienda analizar muy bien cuando usar SET NOCOUNT ON.

El siguiente ejemplo hace una consulta a la tabla customers de la base de datos Northwind usando los dos estados de SET NOCOUNT, se puede apreciar la diferencia.

Usando SET NOCOUNT ON



----- 1
GO
SET NOCOUNT ON

select * from dbo.customers
where country = 'France'
GO

Resultado:

Usando SET NOCOUNT OFF


---- 2
GO
SET NOCOUNT OFF

select * from dbo.customers
where country = 'France'
GO


Resultado:

viernes, febrero 25, 2011

Reporte con Crystal Report y Linq to Xml

En el post anterior hice un pequeño ejemplo de como guardar los datos de una tabla a un archivo Xml y luego leerlos y mostrarlos en un DataGridView.

Ahora voy a realizar un ejemplo de como mostrar un reporte de los datos contenidos en un archivo XML usando Linq. Para este ejemplo tengo un proyecto de formularios de windows llamado XmlExample, en el cual tengo un formulario diseñado como muestra la imagen.


En el proyecto XmlExample también debo crear la clase Categories.vb el cual se usará para diseñar el reporte.
Public Class Categories
Private _CategoryID As Integer = String.Empty
Private _CategoryName As String = String.Empty
Private _Description As String = String.Empty

Public Property CategoryID() As Integer
Get
Return _CategoryID
End Get
Set(ByVal value As Integer)
_CategoryID = value
End Set
End Property

Public Property CategoryName() As String
Get
Return _CategoryName
End Get
Set(ByVal value As String)
_CategoryName = value
End Set
End Property

Public Property Description() As String
Get
Return _Description
End Get
Set(ByVal value As String)
_Description = value
End Set
End Property
End Class

Agregamos un nuevo proyecto de CrystalReport




El Explorador de soluciones debe quedar asi:


En el Diseñador del reporte Seleccionamos el origen de datos.

Nos Situamos como muestra la imagen (nueva conexión de ADO.NET) y presionamos doble click.

Aparecerá una ventana donde debemos indicar que objeto deseamos usar, en nuestro caso debemos seleccionar la clase categories.vb que esta en el proyecto XmlExample y presionamos finalizar.

En el arbol de la derecha nos aparecera el orgien de datos con el cual procederemos a diseñar nuestro reporte.

En el proyecto XmlExample donde se encuentra el formulario de consulta agregamos la referencia del proyecto de CrystalReport que hemos agregado


En el formulario agregamos un boton para generar el reporte y un crystalreportView. En el boton ingresamos el siguiente código:
Dim lCategoriaXml As XDocument = XDocument.Load(txtUrl.Text)
Dim lCategorias = From lcategoria In lCategoriaXml.Descendants("Categoria") _
Select CategoryID = lcategoria.Element("CategoryID").Value, _
CategoryName = lcategoria.Element("CategoryName").Value, _
Description = lcategoria.Element("Description").Value

Dim crp As New XMLReport.RptCategories
crp.SetDataSource(lCategorias.ToList)
CrystalReportViewer1.ReportSource = crp
TabControl1.SelectedIndex = 1