Objectivo
|
Marcar la accion realizada en las filas del DataGridView. |
Vista Previa
|
Requisito:
|
- Visual Estudio 2008 o Superior
- SQL Server Express 2005 o superior
|
Para realizar esta practica :
|
- Agregue un projecto tipo WinForm.
- Agregar una conexion a la base de datos con la que quiere interactual.
Cómo: Conectarse a los
datos de una base de datos.
- Arrastre el objecto de datos con la que quiere trabajar desde la ventana Origen de Datos hacia el diseñador de formulario.
Esto generara los objectos(BindingSource, DataSet, TableAdapter, TableAdapterManager
y el BindingNavigator)
necesario para poder realizar las operaciones(CRUD(Create, Read, Update, Delete))
en la grilla con impacto en la base de datos.
- Deshabilito la funcionalidad de eliminacion del control bindingNavigatorDeleteItem
del BindingNavigator.
|
|
- Agregue las imagenes que servirar como marcador para las filas.
|
- Agregamos una columna de tipo DataGridViewImageColumn en la posicion 0 de la
coleccion de columnas de la grilla y seteamos algunas de sus propiedades
|
Codigo C#
|
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace WindowsCS.Formularios
{
public partial class GridMarkedActionForm : Form
{
DataTable table = new DataTable("TB1");
public GridMarkedActionForm()
{
InitializeComponent();
DoColumn("ID", "System.Int32", true, true);
DoColumn("NameAccion", "System.String", false, false);
DoColumn("Image", "System.Byte[]", false, false);
}
#region Metodos de ayuda
private void DoColumn(string name, string type, bool unique, bool isprimary)
{
DataColumn column = new DataColumn(name);
column.DataType = Type.GetType(type);
column.Unique = unique;
table.Columns.Add(column);
if (isprimary)
{
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = table.Columns[name];
table.PrimaryKey = PrimaryKeyColumns;
}
}
public byte[] ConvertImageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return ms.ToArray();
}
public Image ConvertByteArrayToImage(int id)
{
MemoryStream ms = new MemoryStream((byte[])table.Rows.Find(id).ItemArray[2]);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
public Image ConvertByteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
#endregion Metodos de ayuda
#region EventHandler
private void Form4_Load(object sender, EventArgs e)
{
// TODO: esta línea de código carga datos en la tabla 'testDataSet.T1' Puede moverla o quitarla según sea necesario.
this.t1TableAdapter.Fill(this.testDataSet.T1);
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
row.Cells[0].Value = null;
}
}
private void t1BindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
if (table.Rows.Contains(row.Cells[1].Value))
{
if ((table.Rows.Find((int)row.Cells[1].Value).ItemArray[1]).ToString() == "Delete")
{
t1BindingSource.RemoveCurrent();
}
}
}
this.Validate();
this.t1BindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.testDataSet);
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
row.Cells[0].Value = null;
}
table.Clear();
}
private void t1BindingSource_ListChanged(object sender, ListChangedEventArgs e)
{
DataRow row = table.NewRow();
switch (e.ListChangedType.ToString())
{
case "ItemChanged":
row["ID"] = (int)t1DataGridView.CurrentRow.Cells[1].Value;
row["NameAccion"] = "Edit";
row["Image"] = ConvertImageToByteArray((System.Drawing.Image)Resource1.Edit);
table.Rows.Add(row);
t1DataGridView.CurrentRow.Cells[0].Value = (System.Drawing.Image)Resource1.Edit;
break;
case "ItemAdded":
row["ID"] = (int)t1DataGridView.CurrentRow.Cells[1].Value;
row["NameAccion"] = "Add";
row["Image"] = ConvertImageToByteArray((System.Drawing.Image)Resource1.Add);
table.Rows.Add(row);
t1DataGridView.Rows[e.NewIndex].Cells[0].Value = (System.Drawing.Image)Resource1.Add;
break;
// movido al evento clic del boton eliminar, con el objectivo de eliminar esta
// caracteristica del bindingsource e implementarlo de forma manual.
//case "ItemDeleted":
//
// break;
/*
// no implementado
case "ItemMoved":
break;
*/
default:
break;
}
}
private void t1DataGridView_Sorted(object sender, EventArgs e)
{
if (table.Rows.Count > 0)
{
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
if (table.Rows.Contains((Convert.ToInt32(row.Cells[1].Value))))
{
row.Cells[0].Value = ConvertByteArrayToImage((Convert.ToInt32(row.Cells[1].Value)));
}
}
}
}
private void bindingNavigatorDeleteItem_Click_1(object sender, EventArgs e)
{
DataRow row = table.NewRow();
row["ID"] = (int)t1DataGridView.CurrentRow.Cells[1].Value;
row["NameAccion"] = "Delete";
row["Image"] = ConvertImageToByteArray((System.Drawing.Image)Resource1.Delete);
table.Rows.Add(row);
t1DataGridView.CurrentRow.Cells[0].Value = (System.Drawing.Image)Resource1.Delete;
}
#endregion EventHandler
}
}
|
Descripcion:
|
- Creamos una tabla a nivel de clase el cual nos servira como repositorio para almacenar
aqui la acciones realizada en la grilla.
- En el constructor del formulario invocamos el metodo DoColumn() el cual crea una
tabla con el siguiente ezquema:
- Una columna ID de tipo entero el cual servira como PK de la tabla para almacenar
la PK de la grilla
- Una columna de tipo string llamada NameAction el cual almacenara el nombre de la
accion realizada en la grilla , Sus posible valores son: Add, Delete, Update
- Unaa columna llamada imagen que representa graficamente la accion realizada en la
fila de la grilla
public GridMarkedActionForm()
{
InitializeComponent();
DoColumn("ID", "System.Int32", true, true);
DoColumn("NameAccion", "System.String", false, false);
DoColumn("Image", "System.Byte[]", false, false);
}
- El Metodo DoColumn
declara como parameros formales:
- String que represente el nombre de la columna: name.
- String que represente el tipo de dato de la columna: type; Eemplo, "System.String".
- Valor Booleano que especifca la columna como unica dentro de la tabla: unique.
- Valor Booleano para determinar si la columna a crear sera la PK de la tabla: isprimary.
private void DoColumn(string name, string type, bool unique, bool isprimary)
{
DataColumn column = new DataColumn(name);
column.DataType = Type.GetType(type);
column.Unique = unique;
table.Columns.Add(column);
if (isprimary)
{
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = table.Columns[name];
table.PrimaryKey = PrimaryKeyColumns;
}
}
- El Metodo ConvertImageToByteArray() hace la conversion de System.Image a byte[]
para almacenarla en la base de dato
public byte[] ConvertImageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return ms.ToArray();
}
- El Metodo ConvertByteArrayToImage(), recupera el byte[] de la base de dato hace
la conversion a System.Image para asignarselo a la filas de la grilla.
public Image ConvertByteArrayToImage(int id)
{
MemoryStream ms = new MemoryStream((byte[])table.Rows.Find(id).ItemArray[2]);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
- En el Evento Load del formulario nos encargamos de que las filas tenga una imagen
en blanco
private void Form4_Load(object sender, EventArgs e)
{
// TODO: esta línea de código carga datos en la tabla 'testDataSet.T1' Puede moverla o quitarla según sea necesario.
this.t1TableAdapter.Fill(this.testDataSet.T1);
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
row.Cells[0].Value = null;
}
}
- En el Evento Click del BindingNavigatorSaveItem colocamos el siguiente codigo, aqui
es donde implementaremos la accion de eliminacion.:
private void t1BindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
if (table.Rows.Contains(row.Cells[1].Value))
{
if ((table.Rows.Find((int)row.Cells[1].Value).ItemArray[1]).ToString() == "Delete")
{
t1BindingSource.RemoveCurrent();
}
}
}
this.Validate();
this.t1BindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.testDataSet);
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
row.Cells[0].Value = null;
}
table.Clear();
}
El cual se encarga de:
- Procesar cada una de la fila de la grilla para verificar que el valor de la celda
uno(1) el cual corresponde al PK de la grilla este contenido dentro de la tabla
de repositorio; de ser cierto, busco dentro de la coleccion de fila de la tabla
de repositorio la fila que contenga el valor especificado por medio del valor de
la celda uno(1) que coresponde al valor de la PK de la grilla en la fila actual,
descompongo la fila obtenida en cada uno de sus campos o columnas mediante el uso
de
DataRow.ItemArray (Propiedad) obtengo en valor del campo o columna uno(1)
que corresponde al NameAction de la tabla y lo comparo con el NameAction == "Delete",
de ser afirmativo procedemos a eliminar la fila actual de la grilla mediante la
invocacion de
BindingSource.RemoveCurrent (Método)
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
if (table.Rows.Contains(row.Cells[1].Value))
{
if ((table.Rows.Find((int)row.Cells[1].Value).ItemArray[1]).ToString() == "Delete")
{
t1BindingSource.RemoveCurrent();
}
}
}
- Valido los controles modificado
his.Validate();
- Aplica los cambios pendientes al origen de datos subyacente
this.t1BindingSource.EndEdit();
- Envio todos los cambios al Dataset
this.tableAdapterManager.UpdateAll(this.testDataSet);
- Limpioi la imagen de la filas
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
row.Cells[0].Value = null;
}
- Elimino los valores de la tabla
table.Clear();
- En el Evento ListChanged del BindingSource colocamos el siguiente codigo:
private void t1BindingSource_ListChanged(object sender, ListChangedEventArgs e)
{
DataRow row = table.NewRow();
switch (e.ListChangedType.ToString())
{
case "ItemChanged":
row["ID"] = (int)t1DataGridView.CurrentRow.Cells[1].Value;
row["NameAccion"] = "Edit";
row["Image"] = ConvertImageToByteArray((System.Drawing.Image)Resource1.Edit);
table.Rows.Add(row);
t1DataGridView.CurrentRow.Cells[0].Value = (System.Drawing.Image)Resource1.Edit;
break;
case "ItemAdded":
row["ID"] = (int)t1DataGridView.CurrentRow.Cells[1].Value;
row["NameAccion"] = "Add";
row["Image"] = ConvertImageToByteArray((System.Drawing.Image)Resource1.Add);
table.Rows.Add(row);
t1DataGridView.Rows[e.NewIndex].Cells[0].Value = (System.Drawing.Image)Resource1.Add;
break;
// movido al evento clic del boton eliminar, con el objectivo de eliminar esta
// caracteristica del bindingsource e implementarlo de forma manual.
//case "ItemDeleted":
//
// break;
/*
// no implementado
case "ItemMoved":
break;
*/
default:
break;
}
}
En el cual testeamos
ListChangedEventArgs.ListChangedType (Propiedad) para obtener el tipo
de cambio realizado en el control, creamos una nueva filas con el PK de la grilla,
un NameAction == "a la accion corespondiente", su respectiva imagen y la agregamos
a la coleccion de filas de la tabla de repositorio
- En el evento sorted de la grilla nos aseguramo de las imagenes se corespondan no
importando por que columna se ordenen las filas, pero ante confirmamos que nuestra
tabla de repositorio contenga filas esto no garantiza de que si hubo cambio en la
grilla.
private void t1DataGridView_Sorted(object sender, EventArgs e)
{
if (table.Rows.Count > 0)
{
foreach (DataGridViewRow row in t1DataGridView.Rows)
{
if (table.Rows.Contains((Convert.ToInt32(row.Cells[1].Value))))
{
row.Cells[0].Value = ConvertByteArrayToImage((Convert.ToInt32(row.Cells[1].Value)));
}
}
}
}
- En el evento click del control bindingNavigatorDeleteItem del BindingNavigator,
no eliminamos la filas sino mas bien, la marcamos con la imagen de eliminacion,
pero antes creamos una nueva filas con el PK de la grilla, un NameAction == "Delete",
y la imagen corespondiente a la eliminacion y la agregamos a la coleccion de filas
de la tabla de repositorio
private void bindingNavigatorDeleteItem_Click_1(object sender, EventArgs e)
{
DataRow row = table.NewRow();
row["ID"] = (int)t1DataGridView.CurrentRow.Cells[1].Value;
row["NameAccion"] = "Delete";
row["Image"] = ConvertImageToByteArray((System.Drawing.Image)Resource1.Delete);
table.Rows.Add(row);
t1DataGridView.CurrentRow.Cells[0].Value = (System.Drawing.Image)Resource1.Delete;
}
|
- Nos restaria Agregar Menu contextuales a las filas de la grilla para deshacer los
cambios realizado por filas separada
- Agregar al Toolbox los botones para Deshacer y Reahacer
|