domingo, 29 de septiembre de 2013

contextMenuStrip y DataGridView

Hola a todos:
Aquí mostrare como usar un control contextMenuStrip para:
  1. Copiar el valor de una celda de un control DataGridView al ClipBoard
  2. Copiar el contenido de una Fila de un control DataGridView al ClipBoard
  3. Eliminar un Row del control DataGridView:
Para lograr esto:
1. Cree un proyecto de tipo WindowsForms
2. Agregue un control DataGridView y agregue tres columnas
addColumn
3. Establezca FullRowSelect a la propiedad SelectionMode del control DataGridView.
4. Agregue un control contextMenuStrip y agréguele tres items nuevos con el nombre: copyCellValue, copyRowValue y deleteRow

contextMenuStrip
Bien, ahora sobre el Formulario Form1 haga doble click sobre la barra de titulo, esto generar el evento Load del formulario, una vez echo esto copie y pegue estas líneas para cargar datos al control DataGridView:
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.Rows.Add("Fila uno columna uno", "Fila uno columna dos", "Fila uno columna tres");
dataGridView1.Rows.Add("Fila dos columna uno", "Fila dos columna dos", "Fila dos columna tres");
dataGridView1.Rows.Add("Fila tres columna uno", "Fila tres columna dos", "Fila tres columna tres");
dataGridView1.Rows.Add("Fila cuatro columna uno", "Fila cuatro columna dos", "Fila cuatro columna tres");
}

Ahora, genere el evento CellMouseClick del control DataGridView y pegue el código siguiente (solo lo que este dentro del evento):
//Variable que contendrá el valor de la celda donde se realice el click derecho con el Mouse
private string _cellValue = String.Empty;
private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
//Preguntamos si el boton pulsado del Mouse es el Derecho
//si no lo es no salimos sin hacer nada mas
if (e.Button != MouseButtons.Right) return;

if (e.ColumnIndex < 0 || e.RowIndex < 0)
return;

//enviamos el valor de la celda a la variable _cellValue
_cellValue = dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString();

//Definimos el lugar donde aparecera el scontextMenuStrip
contextMenuStrip1.Show(MousePosition);
}

Después de echo lo anterior, genere el evento ItemClicked del control contextMenuStrip, dentro pegue las siguientes líneas (solo lo que este dentro de evento):

private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
//Preguntamos por el nombre del item pulsado
switch (e.ClickedItem.Name)
{
case "copyCellValue":
//
//Copiamos el valor de la variable _cellValue al ClipBoard
//
Clipboard.SetText(_cellValue);
break;

case "copyRowValue":
//
//Copiamos el valor de toda la Fila selccionada al ClipBoard
//
DataObject dataObj = dataGridView1.GetClipboardContent();
if (dataObj != null)
Clipboard.SetDataObject(dataObj);
break;

case "deleteRow":
//
//Identificamos la Fila actualmente seleccionada
//
DataGridViewRow row = dataGridView1.CurrentRow;
//
//Preguntamos si el valor de Row es diferente de null, esto para evitar posibles
//excepciones de referencias Nulas
//
if (row != null) dataGridView1.Rows.Remove(row);

break;
}

Ahora genere el proyecto y ejecútelo presionando la tecla de función F5 deberá de tener un formulario como el siguiente:

run
Lamentablemente no puedo subir una imagen con el Menú Contextual desplegado porque al pulsar las teclas de Windows este desaparece, pero si hizo todo bien el Menú estará funcionando de maravilla.

Saludos desde Monterrey, Nuevo León México!

Ejemplo C#
Ejemplo Vb.Net

Nota: El proyecto fue desarrollado en Vs2010 el Framework 4.0

Llenar DataGridView con datos de TextBox’s usando Datasource o el método Add()

Hola a todos:

En este artículo le mostraré dos maneras diferentes de como llenar un control DataGridView que son:
  1. Enlazando a un origen de datos mediante la propiedad DataSource del control a una lista Genérica de propiedades  (la cual iremos llenando con los datos contenidos en los controles TextBox).
  2. Usando el método Add, tomando los datos de los controles TextBox.

Después de leer el articulo usted tendrá toda la libertad de decidir cual usar para llenar su control DataGridView.

Empecemos creando un proyecto del tipo WindowsForms, agregando un control GroupBox al cual le agregaremos controles textBox, dos radioButton, un Botón,  un control DataGridView, un control contextMenuStrip y un control ErrorProvider, dejando un diseño como el siguiente:

Articulos

Al DataGridView agréguele 5 columnas y llámelas de la siguiente manera:

columnNumero, columnUpc, columnDescripcion, columnMarca y columnPrecio

Cambie el nombre del Formulario a Artículos, para ello despliegue el Explorador de soluciones y seleccione el Form1, haga Click derecho con el Mouse y seleccione Cambiar Nombre, a continuación ingrese el nombre de Form.

Agregue una clase al proyecto y llámela EArticulo, esta clase contendrá las propiedades o campos, propios del articulo y serán usadas para transportar la información contenida en ellas, la clase quedara de la siguiente manera:

using System;
namespace LlenarDataGridView_CSharp
{
public class EArticulo
{
public int Numero { get; set; }
public string Upc { get; set; }
public string Descripcion { get; set; }
public string Marca { get; set; }
public Decimal Precio { get; set; }
}
}

Recuerde que las propiedades autoimplementadas requieren del uso de FrameWork 4.0 en adelante.  


Bien, ya que tenemos la clase de utilidades y la clase de Entidades vayamos a trabajar sobre la clase Articulos, para ello Despliegue el Explorador de soluciones, ubique y seleccione el formulario Articulos y presione la tecla de funciones F7.

Procedamos a crear los métodos y funciones que usaremos en el Formulario Artículos.

Sumar el valor de una columna

Para poder sumar el valor de una columna de un control DataGridView puede utilizar los métodos de extensión de Linq de esta manera:

private void Sum()
{
    txttotal.Text = Convert.ToString(dgvArticulos.Rows.Cast<DataGridViewRow>().Sum(x => Convert.ToDecimal(x.Cells["columnPrecio"].Value)));
}

Espacio de nombres requerido?

using System.Linq;

O bien

Recorriendo todos los Rows del control en un ciclo foreach() e ir sumando el valor de la columna deseada de manera manual, de esta manera:
private void SumOpcion2()
{
decimal total = 0;
if(dgvArticulos.Rows.Count > 0)
{
foreach(DataGridViewRow row in dgvArticulos.Rows)
{
total += Convert.ToDecimal(row.Cells["columnPrecio"].Value);
}
}

txttotal.Text = Convert.ToString(total);
}


Sea cual sea la opción que elija recuerde que ambos realizan un recorrido de filas, solo que si usa Linq ese recorrido se hace internamente, es decir, usted no necesita escribir mas de una línea de código para hacer el foreach porque de ello se encarga Linq.

Ahora procedamos a llenar el control DataGridView


Primero usaremos la opción 1: Usaremos el DataSource del control DataGridView para mostrar el contenido de una lista genérica de propiedades.

private void UsingDataSource(int articleNumber)
{
//
//Preguntamos si el valor contenido en el parametro articleNumber
//ya exise dentro de la lista y para ello usaremos Linq y un metodo de Extension
//
// Any() devuelve un valor boleano, asi que si el numero de articulo se encuentra
//en la lista devolvera True de lo contrario el valor devuelto sera igual a False
bool exists = _articulo.Any(x => x.Numero.Equals(articleNumber));

//
//Preguntamos por el valor de la variable exists y por el valor de la variable privada _working
//
if ((exists) & (_working.Equals("Add")))
{
// buscamos el valor usando el metodo de la clase Utilidades
// recuerde que la función requiere de 3 parametros que son:
//Nombre del control DataGridView donde hara la busqueda
//Valor a buscar y
// el Indice de la columna donde se realizara la busqueda, recuerde que el indice de
//las columnas es en base Cero.
//
//Usar este Método unicamente es para ubicar el Row que lo contiene.
Utilities.FindValue(dgvArticulos, articleNumber, 0);

MessageBox.Show(
String.Format("El Artículo Número : '{0}' ya se encuentra en la Lista", articleNumber),
"¡Atención!", MessageBoxButtons.OK, MessageBoxIcon.Information);

return;
}

//Si el valor de la variable privada _working es igual a "Edit" entonces procedemso a editar
//los item's relacionados al Numero de articulo
if (_working.Equals("Edit"))
{
Utilities.FindValue(dgvArticulos, articleNumber, 0);

foreach (EArticulo article in _articulo.Where(x => x.Numero == articleNumber))
{
article.Numero = articleNumber;
article.Upc = txtupc.Text;
article.Descripcion = txtdescripcion.Text.Trim();
article.Marca = txtmarca.Text.Trim();
article.Precio = Convert.ToDecimal(txtprecio.Text);
}

Mapping(_articulo);

Clear();

return;
}

//Si el valor de la variable privada _working es igual a "Add" entonces,
//procedemos a ingresar el nuevo item a la lista generica de propiedades
if (!exists & _working.Equals("Add"))
{
EArticulo item = new EArticulo
{
Numero = articleNumber,
Upc = txtupc.Text,
Descripcion = txtdescripcion.Text.Trim(),
Marca = txtmarca.Text.Trim(),
Precio = Convert.ToDecimal(txtprecio.Text),
};

_articulo.Add(item);
Mapping(_articulo);

//Nos movemos hasta el ultimo registros ingresado
Utilities.DataGridViewRowPosition(dgvArticulos);
Clear();
}
}

Ahora mostremos la manera de llenar al control DataGridView usando el método Add() de la propiedad Rows():
private void UsingAdd(int articleNumber)
{
//Usamos la funcion FindValue de la clase Utilidades, recuerde que esta funcion es del tipo
//boolean y devuelve un True si el valor fue encontrado y False si esto no es asi.
//para ellos debemos de satisfacer los parametros que conforman la firma de la funcion, estos
//parametros son:
//Nombre del control DataGridView donde se realizara la busqueda
//Valor a ser buscado y
//El indice de la columna del control DataGridView, recuerde que el indice es en base cero.
if (Utilities.FindValue(dgvArticulos, articleNumber, 0) & (_working.Equals("Add")))
{
MessageBox.Show(
String.Format("El Artículo Número : '{0}' ya se encuentra en la Lista", articleNumber),
"¡Atención!", MessageBoxButtons.OK, MessageBoxIcon.Information);

return;
}

//Si el valor de la variable privada _working es igual a "Edit" entonces procedemso a editar
//los item's relacionados al Numero de articulo
if (_working.Equals("Edit"))
{
DataGridViewRow row = dgvArticulos.CurrentRow;
if (row != null)
{
row.Cells["columnNumero"].Value = txtnumero.Text;
row.Cells["columnUpc"].Value = txtupc.Text.Trim();
row.Cells["columnDescripcion"].Value = txtdescripcion.Text.Trim();
row.Cells["columnMarca"].Value = txtmarca.Text.Trim();
row.Cells["columnPrecio"].Value = txtprecio.Text;

Clear();
}
}

//Si el valor de la variable privada _working es igual a "Add" entonces,
//procedemos a ingresar un nuevo row al control DataGridView
if (_working.Equals("Add"))
{
dgvArticulos.Rows.Add(txtnumero.Text, txtupc.Text, txtdescripcion.Text.Trim(), txtmarca.Text.Trim(), txtprecio.Text);

//Nos movemos hasta el ultimo registros ingresado
Utilities.DataGridViewRowPosition(dgvArticulos);

Clear();
}

Sum();
}

Esos son los dos métodos que utilizaremos para cargar el control dependiendo del estado de los controles Radiobutton’s agregados previamente y que para usarlos necesitamos preguntar por ellos de la siguiente manera:
private void AddArticle()
{
try
{
if (!Validate()) return;

int articleNumber = Convert.ToInt32(txtnumero.Text);

if (rbtndatasource.Checked)
{
UsingDataSource(articleNumber);
}
else
{
UsingAdd(articleNumber);
}
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Error: {0}", ex.Message), "Error inesperado", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}

Acabamos de crear otro método que dentro utiliza los métodos creados anteriormente dependiendo del estado del los radioButton y para usar este método podemos usar el evento Click del botón o el evento KeyDown del ultimo control TextBox:
//usando el evento Click del boton
private void btnagregar_Click(object sender, EventArgs e)
{
AddArticle();
}
//usando el evento KeyDown del control txtPrecio
private void txtprecio_KeyDown(object sender, KeyEventArgs e)
{
//Preguntamos por la tecla pulsada
if (e.KeyData == Keys.Enter)
{
AddArticle();
}
}

Eliminar un Row utilizando la tecla Delete

Para ellos crearemos dos Métodos:
/// <summary>
///
Método utilizado para eliminar un item de la lista Generica/// </summary>
/// <param name="row">
Representa la fila actual del control DataGridView(la fila seleccionada)</param>
private void UsingDataSourceDelete(DataGridViewRow row)
{
if (row != null & _articulo.Count > 0)
_articulo.Remove(_articulo.First(x => x.Numero.Equals(Convert.ToInt32(row.Cells["columnNumero"].Value))));

Mapping(_articulo);
}

/// <summary>
///
Método utilizado para eliminar una fial del control DataGridView cuando no se encuentra enlazado/// a ninguna fuente de datos externa/// </summary>
/// <param name="row">
Representa la fila actual del control DataGridView(la fila seleccionada)</param>
private void UsingAddDelete(DataGridViewRow row)
{
if (row != null)
dgvArticulos.Rows.Remove(row);

Sum();
}

Para eliminar la fila actual usaremos el evento KeyDown del control DataGridView:
private void dgvArticulos_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyData == Keys.Delete)
{
DataGridViewRow row = dgvArticulos.CurrentRow;

if (rbtndatasource.Checked)
{
UsingDataSourceDelete(row);
}
else
UsingAddDelete(row);
}
}
Existen métodos y funciones que no fueron mostrados en el articulo esto para no hacerlo demasiado extenso pero lo mas importante fue mostrado, mas abajo podrán encontrar el link de descarga del proyecto completo.

Saludos desde Monterrey, Nuevo León México!

Ejemplo C#
Ejemplo Vb.Net
Nota: El proyecto fue desarrollado en Vs2010  Framework 4.0