viernes, febrero 04, 2011

DatagridviewComboBoxColumn: celdas con items irrepetibles por fila

Ahora voy a presentar un datagridview con una columna de tipo DatagridViewComboboxColumn donde cada item seleccionado en la columna tipo combobox no se vuelva a repetir en ninguna otra fila.

Habeces es necesario hacer validaciones de este tipo, por ejemplo si en un datagridview mostramos el nombre de un trabajador donde se le debe de asignar los conceptos de pago ya sea Sueldo Básico, Horas Extras, Movilidad, etc, pero donde cada concepto sea único por fila, es decir que un trabajador no podrá tener 2 importes por concepto de sueldos basicos o 3 importes por concepto de horas extras.

Para empezar creamos la clase personal.vb


Public Class Personal
Private lcod_personal As String
Private lnom_personal As String
Private lcod_concepto As String
Private limp_concepto As Decimal


Public Property cod_personal() As String
Get
Return lcod_personal
End Get
Set(ByVal value As String)
lcod_personal = value
End Set
End Property
Public Property nom_personal() As String
Get
Return lnom_personal
End Get
Set(ByVal value As String)
lnom_personal = value
End Set
End Property
Public Property cod_concepto() As String
Get
Return lcod_concepto
End Get
Set(ByVal value As String)
lcod_concepto = value
End Set
End Property

Public Property imp_concepto() As Decimal
Get
Return limp_concepto
End Get
Set(ByVal value As Decimal)
limp_concepto = value
End Set
End Property


End Class



luego creamos una clase ListPersonal.vb que herede de una lista de personal

Public Class ListPersonal
Inherits List(Of Personal)
Sub New()

End Sub

Sub AddPersonal(ByVal lcod_personal As String, _
ByVal lnom_personal As String, _
ByVal lcod_concepto As String, _
ByVal limp_concepto As Decimal)

Dim lPersonal As New Personal
lPersonal.cod_personal = lcod_personal
lPersonal.nom_personal = lnom_personal
lPersonal.cod_concepto = lcod_concepto
lPersonal.imp_concepto = limp_concepto
Me.Add(lPersonal)
End Sub

End Class


Ahora debemos crear la clase Conceptos.vb

Public Class Conceptos
Private lcod_concepto As String
Private lnom_concepto As String

Public Property cod_concepto() As String
Get
Return lcod_concepto
End Get
Set(ByVal value As String)
lcod_concepto = value
End Set
End Property

Public Property nom_concepto() As String
Get
Return lnom_concepto
End Get
Set(ByVal value As String)
lnom_concepto = value
End Set
End Property
End Class


ademas como el caso anterior creamos la clase ListConcepto.vb que herede de una lista de Conceptos

Public Class ListConcepto
Inherits List(Of Conceptos)

Sub New()
End Sub

Sub AddConcepto(ByVal Codigo As String, ByVal Nombre As String)
Dim lconcepto As New Conceptos
lconcepto.cod_concepto = Codigo
lconcepto.nom_concepto = Nombre
Me.Add(lconcepto)
End Sub

End Class



por ultimo un formulario con un datagridview y dos botones (un boton para eliminar filas y el otro para agregar una nueva fila)


Public Class Form1
Dim lListPersonal As New ListPersonal
Dim lListConcepto As New ListConcepto
Dim lBinding As New BindingSource

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'Creamos la Estructura del datagridview
Dim ColumnCodigo As New DataGridViewTextBoxColumn
ColumnCodigo.Name = "Código"
ColumnCodigo.HeaderText = "Codigo"
ColumnCodigo.DataPropertyName = "cod_personal"
ColumnCodigo.Width = 80
Me.DataGridView1.Columns.Add(ColumnCodigo)

Dim ColumnNombre As New DataGridViewTextBoxColumn
ColumnNombre.Name = "Nombre"
ColumnNombre.HeaderText = "Apellidos y nombre"
ColumnNombre.DataPropertyName = "nom_personal"
ColumnNombre.Width = 200
Me.DataGridView1.Columns.Add(ColumnNombre)

Dim ColumnConcepto As New DataGridViewComboBoxColumn
ColumnConcepto.Name = "Concepto"
ColumnConcepto.HeaderText = "Concepto pago"
ColumnConcepto.DataPropertyName = "cod_concepto"
ColumnConcepto.Width = 140
Me.DataGridView1.Columns.Add(ColumnConcepto)

Dim ColumnImporte As New DataGridViewTextBoxColumn
ColumnImporte.Name = "Concepto"
ColumnImporte.HeaderText = "Importe S/."
ColumnImporte.DataPropertyName = "imp_concepto"
Me.DataGridView1.Columns.Add(ColumnImporte)

Me.DataGridView1.AutoGenerateColumns = False

'Agregamos los conceptos de pago y los asignamos a la columna tipo combobox
lListConcepto.AddConcepto("", "(SELECCIONE)")
lListConcepto.AddConcepto("01", "SUELDO BÁSICO")
lListConcepto.AddConcepto("02", "ASIGNACION FAMILIAR")
lListConcepto.AddConcepto("03", "HORAS EXTRAS")
lListConcepto.AddConcepto("04", "GRATIFICACION")
lListConcepto.AddConcepto("05", "MOVILIDAD")
lListConcepto.AddConcepto("06", "REFRIGERIO")

ColumnConcepto.DataSource = lListConcepto
ColumnConcepto.DisplayMember = "nom_concepto"
ColumnConcepto.ValueMember = "cod_concepto"

'Cargamos algunos trabajadores


lListPersonal.AddPersonal("XY001", "PEREZ RODRIGUEZ, JUAN", "", 0)
lBinding.DataSource = lListPersonal
Me.DataGridView1.DataSource = lBinding

End Sub


Private Sub btnAgregar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAgregar.Click
Dim lInfo As New Personal
lInfo.cod_personal = "XY001"
lInfo.nom_personal = "PEREZ RODRIGUEZ, JUAN"
lInfo.cod_concepto = ""
lInfo.imp_concepto = 0
lBinding.Add(lInfo)

End Sub


Private Sub DataGridView1_CurrentCellChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DataGridView1.CurrentCellChanged
If DataGridView1.CurrentRow Is Nothing Then Exit Sub
If DataGridView1.CurrentRow.Cells("Concepto").Value = String.Empty Then
Me.DataGridView1.CurrentRow.ErrorText = "Debe seleccionar un concepto válido"
Else
Me.DataGridView1.CurrentRow.ErrorText = String.Empty
End If
End Sub

Private Sub DataGridView1_CellBeginEdit(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellCancelEventArgs) Handles DataGridView1.CellBeginEdit
Dim lStrColumn As String = Me.DataGridView1.Columns(e.ColumnIndex).Name

'Solo es váido cuando la columna del datagridview corresponde a conceptos
If lStrColumn = "Concepto" Then


Dim lConceptosAsignados As New List(Of String)
Dim lConceptosNoAsignados As New ListConcepto

'PASO 1
'Obtenemos los conceptos que ya fueron asignados al personal

'Recorremos las filas del datagridview
For Each lInfo As DataGridViewRow In Me.DataGridView1.Rows
'Entraran a la condicion todas las filas excepto la fila que esta
'en edicion
If e.RowIndex <> lInfo.Index Then
'Obtenemos la entidad por fila
Dim lBoundItem As Personal = lInfo.DataBoundItem
If lBoundItem Is Nothing Then
Continue For
End If
'Agregamos a la lista de conceptos asignados
lConceptosAsignados.Add(lBoundItem.cod_concepto)
End If
Next

'PASO 2
'En la Celda del DataGridViewComboboxcolum que esta en edicion
'mostramos aquellos conceptos que aun no han sido asignados

Dim lBoolAsignado As Boolean = False
For Each info As Conceptos In lListConcepto
lBoolAsignado = False
'Verificamos si el concepto ha sido asignado en alguna fila
For Each Value As String In lConceptosAsignados
If info.cod_concepto = Value Then
lBoolAsignado = True
Exit For
End If
Next
'Si el concepto aun no ha sido asignado
If lBoolAsignado = False Then
lConceptosNoAsignados.Add(info)
End If
Next

'A la celda del DatagridViewComboBoxcolumn en edicion indicamos
'que solo se muestren los items que aun no han sido asignados
Dim dgvColumn As New DataGridViewComboBoxCell
dgvColumn.DataSource = lConceptosNoAsignados
dgvColumn.ValueMember = "cod_concepto"
dgvColumn.DisplayMember = "nom_concepto"
Me.DataGridView1.Item(lStrColumn, e.RowIndex) = dgvColumn
End If
End Sub

Private Sub btnEliminar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEliminar.Click
If Not (DataGridView1.CurrentRow Is Nothing) Then
lBinding.RemoveCurrent()
End If
End Sub
End Class


En el evento CellBeginEdit del datagridview es donde se van a filtrar solo aquellos conceptos que aun no han sido seleccionados y se mostraran el la celda en edición.

Puedes descargar el código del ejemplo en la siguiente dirección:
http://cid-ad089621e4982823.office.live.com/self.aspx/Ejemplos%20.Net/DataGridViewComboBoxColumnItems.rar

No hay comentarios.: