sábado, 12 de diciembre de 2009

Visual Studio – Referencia Custom Control en los Proyectos

 

El siguiente video tiene por objetivo mostrar los pasos para poder hacer uso de un control desarrollado desde otro proyecto.

En este caso solo se contara con la dll, la cual será incluida a una carpeta dentro de la estructura de la solución y será desde allí que se referenciara tanto desde el proyecto como desde la toolbox del Visual Studio para poder luego ser arrastrada al formulario y tenerla disponible en modo visual.

Este video mostrara los pasos para poder hacer uso de la dll y al mismo tiempo conservarla dentro de la estructura de desarrollo, para que ante una eventual necesidad de mover de carpeta el desarrollo no se pierdan las referencias.


El video se encuentra en formato flash y podrá ser reproducido ejecutando el archivo .html que se encuentra dentro del zip.

 

[Crystal Reports] Usar DataSet Tipado con dos DataTable

 

Introducción 

La finalidad de este articulo es muy puntual e intentara demostrar como hacer uso en un reporte de Crystal un DataSet Tipado que contiene dos DataTable en su interior.

En este caso se necesita listar los contactos de una empresa, pero para ello no solo se debe contar con los datos de los contactos, sino que además se desea enviar en el mismo origen de datos la información de la empresa.

Para esta operación es que se hace uso de un mismo DataSet Tipado, pero este contendrá dos tablas, las cuales serán cargadas de forma independiente, pero todo el conjunto será enviado como DataSource al reporte.

Para la operación se carga del dataset es que se ha creado un método que permite bajo la misma conexión cargar ambas tablas

public static dtoContactosEmpresa GetContactosEmpresa()
{
    dtoContactosEmpresa dtContactosEmpresa = new dtoContactosEmpresa();


    using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
    {

        #region Cargo Datos Empresa

        string sql = @"SELECT IdEmpresa
                          ,RazonSocial
                          ,Telefono
                          ,Direccion
                          ,CUIT
                      FROM Empresas";

        OleDbCommand command = new OleDbCommand(sql, conn);

        OleDbDataAdapter da = new OleDbDataAdapter(command);

        da.Fill(dtContactosEmpresa, "DatosEmpresa");

        #endregion

        #region Cargo Contactos

        sql = @"SELECT Nombre
                  ,Apellido
                  ,FechaNacimiento
                  ,Localidad
                  ,Calle
                  ,Numero
                  ,Mail
              FROM Contacto";


        command = new OleDbCommand(sql, conn);

        da = new OleDbDataAdapter(command);

        da.Fill(dtContactosEmpresa, "Contactos");

        #endregion

    }

    return dtContactosEmpresa;
}

Es importante remarcar como al hacer el Fill() de los datos se especifica el nombre del datatable donde se quiere volcar la información (líneas 22 y 42)

 

[C#]
[VB.NET]

jueves, 10 de diciembre de 2009

[DataGridView] Parte 2 – Edición de celda con form PopUp para la selección de ítem - KeyDown

 

El objetivo del articulo es demostrar como en la edición de la celda se puede lanzar un formulario de búsqueda para la selección de un ítem determinado, y a retorno del mismo completar la información de la fila en edición con la selección del formulario.

Para esta operación se hace uso de propiedades, y clases las cuales permitirán desacoplar ambas grilla, tanto la que originalmente mantiene la lista de productos seleccionados, como la que se despliega y permite la elección de un ítem determinado.

En el formulario cuyo objetico será llevar la lista de ítems elegidos por el usuario se dispone de siguiente código.

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    DataGridViewTextBoxEditingControl dText = (DataGridViewTextBoxEditingControl)e.Control;

    dText.KeyDown -= new KeyEventHandler(dText_KeyDown);
    dText.KeyDown += new KeyEventHandler(dText_KeyDown);
}

void dText_KeyDown(object sender, KeyEventArgs e)
{
    int rowIndex = ((System.Windows.Forms.DataGridViewTextBoxEditingControl)(sender)).EditingControlRowIndex;

    if (e.Alt && e.KeyCode == Keys.D)
    {
        frmSeleccionarProducto form = new frmSeleccionarProducto();

        form.ShowDialog();

        Producto productoSeleccionado = form.ProductSelected;

        DataGridViewRow row = dataGridView1.Rows[rowIndex];
        row.Cells["IdProducto"].Value = productoSeleccionado.IdProducto;
        row.Cells["Descripcion"].Value = productoSeleccionado.Descripcion;
        row.Cells["precio"].Value = productoSeleccionado.Precio;

        dataGridView1.EndEdit();
    }  
}

Como se observa mucha de la funcionalidad tiene que ver con la asignación de los eventos que permitirán capturar la pulsación de la teclas definidas para que se visualice el formulario de PopUp.

En este caso si bien es posible utilizar cualquier tecla, se decidió que la combinación de Alt + D seria la adecuada, pero podría seleccionar la que sea necesario.

Como se observa si se detecta la pulsación de la tecla, se crea una instancia del formulario y se muestra en formulario modal. Al cierre del mismo se captura la propiedad con el ítem elegido y se carga en la grilla.

El formulario que se desplegara tiene un código muy simple en donde simplemente al hacer dobleclick en una de sus filas, la marcara como seleccionada y cerrar el formulario.

private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    DataGridViewRow row = dataGridView1.SelectedRows[0];

    this.ProductSelected = new Producto()
    {
        IdProducto = Convert.ToInt32(row.Cells["IdProducto"].Value),
        Descripcion = Convert.ToString(row.Cells["Descripcion"].Value),
        Precio = Convert.ToDecimal(row.Cells["precio"].Value),
    };

    this.Close();
}
[C#]
[VB.NET]

[DataGridView] Parte 1 – Valor de celda Condicional usando CellFormatting

 

El ejemplo intenta demostrar como una vez que se bindean los datos estos pueden ser acomodados en las celda según cierta condición.

En este ejemplo se toma un origen de datos con tres columnas pero solo dos serán representadas como datos en la grilla, ya que una condición indicara si debe

 

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    DataGridViewColumn currentColumn = dataGridView1.Columns[e.ColumnIndex];

    if (currentColumn.Name == "Fracciona")
    {
        DataGridViewRow currentRow = dataGridView1.Rows[e.RowIndex];
        DataRowView data = currentRow.DataBoundItem as DataRowView;

        if (data == null)
            return;

        if(Convert.ToBoolean(data["fracc"]))
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["FORM_VENT"]);
        else
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["PRESENTACI"]);
    
    }
}

En este caso la lógica principal se encuentra en el evento CellFormatting, pues este será el encargado de realiza la lógica necesaria para decidir que campo de los datos bindeados deben representarse en la celda.

Se podrá visualizar que un campo que si se ha enlazado a la grilla mediante la propiedad DataPropertyName pero el segunda columnas de la grilla no se le ha asignado este valor ya que será por medio de código quien decida que valor mostrar.

Una de las líneas mas importantes es la 7, ya que esta permite recuperar los datos originales que se están bindeando a esa fila en particular, y por lo tanto trabajar con ellos.

Los datos utilizados para el ejemplo son los siguiente

private DataTable GetDataTable()
{
    DataTable dt = new DataTable();

    dt.Columns.Add("fracc", typeof(bool));
    dt.Columns.Add("PRESENTACI");
    dt.Columns.Add("FORM_VENT");


    DataRow row = dt.NewRow();
    row["fracc"] = true;
    row["PRESENTACI"] = "PRESENTACI 1";
    row["FORM_VENT"] = "FORM_VENT 1";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["fracc"] = false;
    row["PRESENTACI"] = "PRESENTACI 2";
    row["FORM_VENT"] = "FORM_VENT 2";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["fracc"] = false;
    row["PRESENTACI"] = "PRESENTACI 3";
    row["FORM_VENT"] = "FORM_VENT 3";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["fracc"] = true;
    row["PRESENTACI"] = "PRESENTACI 4";
    row["FORM_VENT"] = "FORM_VENT 4";
    dt.Rows.Add(row);

    return dt;

}

esto es importante para poder conocer como se accede a la información bideada en la grilla.

Como funcionalidad adicional se permite que el usuario al marcar o desmarcar una celda esta cambie el contenido con respecto al valor que se obtuvo al momento de bindear la fila

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{

    DataGridViewColumn currentColumn = dataGridView1.Columns[e.ColumnIndex];

    if (currentColumn.Name == "Fracciona")
    {
        DataGridViewCheckBoxCell currentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewCheckBoxCell;

        DataGridViewRow currentRow = dataGridView1.Rows[e.RowIndex];
        DataRowView data = currentRow.DataBoundItem as DataRowView;

        if (data == null)
            return;

        if (Convert.ToBoolean(currentCell.Value))
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["FORM_VENT"]);
        else
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["PRESENTACI"]);

        dataGridView1.EndEdit();
    }
}
[C#]
[VB.NET]

martes, 8 de diciembre de 2009

N-Tier Application – Parte 1

 

El objetivo de este articulo es demostrar como una aplicación web puede trabajar en capas, mejorando así la mantención del código, y mejorando el desarrollo.

 

[C#]
 

miércoles, 2 de diciembre de 2009

[ADO.NET] Excel y Linq (Union)

 

Introducción

El objetivo del articulo es demostrar como poder procesar distintos documentos Excel mediante la utilización del provider para Excel de ADO.NET, a su vez las limitaciones de esta tecnología es superada por la potencia de Linq, el cual otorga poder de procesamiento una vez que se tiene la información recuperada de los documentos y se necesita trabajar con los datos.

La idea del ejemplo es poder mostrar una lista de pedidos, informando el numero y cantidad de ítems solicitados. Pero se debe consolidar la lista agrupando y sumando aquellos numero de pedidos se aparezcan en ambos listados.

Lectura de los documentos Excel
DataTable dtExcel1 = new DataTable();
DataTable dtExcel2 = new DataTable();

using (OleDbConnection cnn = new OleDbConnection(ConfigurationManager.ConnectionStrings["Excel1"].ToString()))
{
    string sql = @"SELECT pedido, 
                          cantidad 
                    FROM [Sheet1$]";

    OleDbCommand command = new OleDbCommand(sql, cnn);

    OleDbDataAdapter da = new OleDbDataAdapter(command);

    
    da.Fill(dtExcel1);

}

using (OleDbConnection cnn = new OleDbConnection(ConfigurationManager.ConnectionStrings["Excel2"].ToString()))
{
    string sql = @"SELECT pedido, 
                          cantidad 
                    FROM [Sheet1$]";

    OleDbCommand command = new OleDbCommand(sql, cnn);

    OleDbDataAdapter da = new OleDbDataAdapter(command);


    da.Fill(dtExcel2);

}

Si se analiza el Excel utilizado en le procesamiento se vera que este cuanta con dos columnas pero en el primer registro de cada una se ha escrito el nombre que se asigna a cada una de ellas, estos nombres coinciden con los utilizados en la consulta sql que será ejecutada.

Para este trabajo se hacen uso de dos dataset los cuales contendrán la información proveniente de cada Excel por separado, que en el próximo paso será usada para trabarla y poder adecuarla a la información que se necesita visualizar.

Uso de Linq para unir la información
var query = from item in
                 (from item in dtExcel1.AsEnumerable()
                  select item).Union(from item in dtExcel2.AsEnumerable()
                                     select item)
             group item by Convert.ToInt32(item["pedido"]) into g
             select new
             {
                 Pedido = g.Key,
                 Cantidad = g.Sum(x=>Convert.ToInt32(x["cantidad"]))
             };

La consulta linq realiza varias operaciones para poder adecuar la información proveniente del Excel y que en este punto se encuentra contendida en cada dataset.

El primer paso que realiza es la unión de los dos dataset, o sea la información de los Excel, unificando en un solo grupo de datos los pedidos de ambas listas.

El segundo paso es la realización del Group by, el cual permitirá unir números de pedidos que se encuentren repetidos en ambos listados.

Por ultimo crea un nueva entidad anónima, es por ellos que utiliza el “select new”, en donde define de forma dinámica las propiedades y si contenido.

En este caso solo son dos las propiedades necesarias, el valor Key del objeto que actuó como agrupador y el cual contiene la lista de ítems sin repetir del listado. Y la suma de la cantidad reportada de cada ítem agrupado.

 

[C#]
 

[DataGridView] KeyPress detectar ENTER y búsqueda

 

El objetivo del artículo es demostrar como mediante la edición de una celda se puede detectar la presión de la tecla ENTER, la cual será capturada para realizar una búsqueda con la información ingresada en la celda

Se debe aclarar que las columnas que no se requiere búsqueda deberá asignarse la propiedad readonly para evitar problemas, pues por defecto también entraran en la lógica que controla la pulsación del enter, salvo que se agregue validaciones para que no actué sobre estas celdas.

 

private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
    dataGridView1.BeginEdit(false);
}

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    DataGridViewTextBoxEditingControl dText = (DataGridViewTextBoxEditingControl)e.Control;
    dText.KeyUp -= new KeyEventHandler(text_KeyUp);
    dText.KeyUp += new KeyEventHandler(text_KeyUp);
}

void text_KeyUp(object sender, KeyEventArgs e)
{
    int rowIndex = ((System.Windows.Forms.DataGridViewTextBoxEditingControl)(sender)).EditingControlRowIndex;
    
    if (e.KeyCode == Keys.Enter)
    {
        int valueEntered = Convert.ToInt32(dataGridView1.Rows[rowIndex - 1].Cells["cuenta"].Value);

        dataGridView1.Rows[rowIndex - 1].Cells["descripcion"].Value = this.Search(valueEntered);
    }
}

Como se observa hay varios eventos asociados al DataGridView necesarios para poder controlar la pulsación del enter en las celdas.

Al editar la calda esta asocia el evento una clase de nombre DataGridViewTextBoxEditingControl, la cual representa un TextBox control asociado a una DataGridViewTextBoxCell.

Se vera además que se realiza una operación de búsqueda, en este caso para simplificar el ejemplo se realiza sobre un datatable cargado previamente, para lo cual se ha utilizado LinQ

 

 

private DataTable GetDataTable()
{
    DataTable dt = new DataTable();

    dt.Columns.Add("cuenta");
    dt.Columns.Add("descripcion");
    

    DataRow row = dt.NewRow();
    row["cuenta"] = "1001";
    row["descripcion"] = "cuenta 1001";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["cuenta"] = "1002";
    row["descripcion"] = "cuenta 1002";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["cuenta"] = "1003";
    row["descripcion"] = "cuenta 1003";
    dt.Rows.Add(row);

    return dt;


}

private string Search(int cuenta)
{
    string descripcion = (from item in this.GetDataTable().AsEnumerable()
                         where Convert.ToInt32(item["cuenta"]) == cuenta
                         select item["descripcion"].ToString()).FirstOrDefault<string>();

    return descripcion;
}

[C#]
 

[WinForms] MDI – Formularios modales

 

En un ambiente MDI es sabido que los formulario hijos no podrán ser desplegados mediante el método ShowDialog() para que estos se comportan de forma modal, pero a veces es necesario que este formulario este en primer plano hasta que este completo para después si poder cerrarlo y capturar la información ingresada.

La solución a este problema se logra mediante el uso de una función del  API de Windows

<System.Runtime.InteropServices.DllImport("user32.DLL")> _
Public Shared Function SetParent(ByVal hWndChild As Integer, ByVal hWndNewParent As Integer) As Integer
End Function


Private Sub btnshowmodal_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnshowmodal.Click

    Dim frm As New Form3
    frm.Show()

    SetParent(CInt(frm.Handle), CInt(Me.MdiParent.Handle))

End Sub

Como se vera en ele ejemplo se sigue utilizando el método Show() el cual se usa en un ambiente MDI, solo que ahora se realiza un paso adicional al utilizar la funcionalidad del Sistema Operativo para establecer las relaciones entre ventanas.

[VB.NET] 
 

martes, 1 de diciembre de 2009

C# – DataGridView – Búsqueda con Linq

 

El objetivo de este ejemplo es demostrar como realizar búsquedas utilizando Linq y una control datagridview

Algo que debe remarcarse es que en el control datagridview se debe permitir la selección múltiple de la celdas, o sea la propiedad

MultiSelect = true

Además se debe especificar la propiedad SelectionMode = CellSelect

La búsqueda tiene dos procesos, el primero determina que las filas cumplen con el filtro especiado, y una ves obtenidas las filas se procede a determinar que celdas especificas aplican al filtro para seleccionarlas.

El objetivo final es demostrar la facilidad que se obtiene con linq para poder realizar búsquedas en el control DataGridView.

 

List<DataGridViewRow>  rows = (from item in dataGridView1.Rows.Cast<DataGridViewRow>()
                                        let clave = Convert.ToString(item.Cells["clave"].Value ?? string.Empty)
                                        let modelo = Convert.ToString(item.Cells["modelo"].Value ?? string.Empty)
                                        let descripcion = Convert.ToString(item.Cells["descripcion"].Value ?? string.Empty)
                                where clave.Contains(busqueda) || 
                                       modelo.Contains(busqueda) || 
                                       descripcion.Contains(busqueda)
                                select item).ToList<DataGridViewRow>();

foreach (DataGridViewRow row in rows)
 {
     List<DataGridViewCell> cells = (from item in row.Cells.Cast<DataGridViewCell>() 
                                            let cell = Convert.ToString(item.Value)
                                     where cell.Contains(busqueda)
                                     select item).ToList<DataGridViewCell>();

     foreach (DataGridViewCell item in cells)
     {
         item.Selected = true;
     }
     
 }

Como se observa en el ejemplo la primer consulta linq permite determinar que Rows cumplen la condición de búsqueda, para ello se evalúa cada celda de la fila.

Un punto ha remarcar es que el habilitar la propiedad AllowUserToAddRows genera una fila adicional en la grilla que será tratada en la consulta linq como si fuera una adicional, el problema con esta fila es que produce un valor null cuando se intenta utilizar la propiedad Value de la celda. Es por ello que en la consulta se observara el uso del operador ?? el cual ante un null devuelve una cadena vacía.

Igualmente el punto anterior podrías haberse evitado el uso de ?? ya que al convertir a string con Convert.ToString() evita el problema con el null.

Si la idea era seleccionar las filas que cumplan la condición con el primera consulta linq ya era suficiente, pero si se quiere ir especialmente a las celdas, es necesario dar un paso mas.

Es por ello que la segunda consulta trabaja a nivel de las celdas, tomando cada fila que cumple con la condición y determinado que celdas especifica también lo hace, para luego marcarla como seleccionada.

 

[C#]
[VB.NET]