sábado, 21 de diciembre de 2019

Cargar un datagrid de .Net con traducción de valores

Hay veces que tenemos en base de datos almacenados valores codificados y queremos realizar una pantalla que haga el mantenimiento de dicha tabla pero en vez de  mostrar los códigos deseamos mostrar su significado, pero no siempre existe una tabla con los significados para hacer INNER JOIN o no siempre conviene complicarse, es más sencillo hacerlo por código. 

Así por ejemplo tenemos la siguiente pantalla de mantenimiento de una tabla de la base de datos, pero queremos que en el campo Ambito en vez de R ponga Riesgo y en la columna Capa sustituya A por Av y 2 por  Ambos.

Cargar un datagrid de .Net con traducción de valores


La carga de la pantalla de arriba en VB.Net se realiza de la siguiente forma:

En las definiciones, definimos el DataSet, el DataAdapter, el DataRowView y la tabla de la que leeremos de la base de datos, en este caso tbTraducción.

Imports System.IO
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports System.Data.SqlClient

Public Class frmTraduccion
    Dim ds As New DataSet()

    Dim bs As BindingSource = New BindingSource()
    Dim dA As New OleDb.OleDbDataAdapter
    Dim drEdit As DataRowView
    Dim bolRefrescar As Boolean
    Dim bolPrimeraVez As Boolean = True
    Const Tabla = "tbTraduccion"
    Enum Accion
        Alta = 1
        Baja = 2
        Modificacion = 3
    End Enum

    Dim TipoAccion As Accion

En el form_load definimos los botones de alta, Baja y modificación y llamamos a la función principal de traducción.

Private Sub frmTraduccion_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.grdResult.DataSource = bs

        txtColumna.MaxLength = 40
    
        Traduccion()

        Dim ObjetosPermitidos As Dictionary(Of String, String)
        ObjetosPermitidos = ComprobarPermisos(Me.Name)
        btnModificar.Visible = IIf(ObjetosPermitidos.ContainsKey("btnModificar"), True, False)
        btnBaja.Visible = IIf(ObjetosPermitidos.ContainsKey("btnBaja"), True, False)
        btnAlta.Visible = IIf(ObjetosPermitidos.ContainsKey("btnAlta"), True, False)
    End Sub

En la función Traducción  cargamos y traducimos la tabla.
Definimos algunos objetos que necesitaremos.

Dim tb As DataTable
Dim srSQL As StreamReader
Dim strConsulta As String
Dim cmdbuilder As OleDbCommandBuilder

 tb = New DataTable

Rellenamos la tabla tal cual aparece en la primera imagen de arriba.

strStartupPath = My.Application.Info.DirectoryPath
srSQL = New System.IO.StreamReader(strStartupPath & "\CargarTraducción.sql")
strConsulta = srSQL.ReadToEnd
cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
dA.SelectCommand = cmdPD
cmdbuilder = New OleDbCommandBuilder(dA)
dA.Fill(ds, "traduccion")

Donde"\CargarTraducción.sql" es un archivo .SQL agregado al proyecto que contiene la select para rellenar la tabla. La select es de este estilo.

SELECT  COD,  AMBITO, CAPA, AUD_USUARIO, AUD_FECHA  FROM tbTraduccion

Volviendo al código inicial de la función Traduccion, definimos las funciones automáticas de update, delete e insert y asignamos los valores de la tabla a los campos de texto o combos para edición.

dA.UpdateCommand = cmdbuilder.GetUpdateCommand()
dA.DeleteCommand = cmdbuilder.GetDeleteCommand()
dA.InsertCommand = cmdbuilder.GetInsertCommand()

bs.DataSource = ds.Tables(Tabla)

 Me.txtColumna.DataBindings.Add(New Binding("Text", bs, "COD"))
 Me.CboAmbito.DataBindings.Add(New Binding("Text", bs, "AMBITO"))
 Me.CboCapa.DataBindings.Add(New Binding("Text", bs, "CAPA"))
 Me.txtUsuAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_USUARIO"))
 Me.txtFechaAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_FECHA")) 

Terminamos la función poniendo las cabeceras de las columnas y estableciendo el ancho que ocuparán en la grid.

     grdResult.Columns(0).MinimumWidth = 100
        grdResult.Columns(1).MinimumWidth = 100
        grdResult.Columns(2).MinimumWidth = 30
        grdResult.Columns(3).MinimumWidth = 100
        grdResult.Columns(4).MinimumWidth = 100

        grdResult.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill

        grdResult.Columns(0).HeaderText = "Cod"
        grdResult.Columns(1).HeaderText = "Ambito"
        grdResult.Columns(2).HeaderText = "Capa"
        grdResult.Columns(3).HeaderText = "Usuario Auditoria"
        grdResult.Columns(4).HeaderText = "Fecha Auditoria"
        grdResult.Refresh()

El código para el botón alta será de este estilo.

Private Sub btnAlta_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAlta.Click
        TipoAccion = Accion.Alta

        grbDetalle.Enabled = True
        grbBuscar.Enabled = False
        drEdit = bs.AddNew()
        bs.MoveLast()
        txtUsuAuditoria.Text = Environment.UserName
        txtFechaAuditoria.Text = Now
        grdResult.Refresh()
 End Sub

El código para la baja será

Private Sub btnBaja_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBaja.Click
        Dim drv As DataRowView
        Dim b As Integer
        TipoAccion = Accion.Baja
     

            If MsgBox("¿Esta usted seguro que desea borrar este registro?", MsgBoxStyle.YesNo + MsgBoxStyle.Question, "Confirmación de Baja") = MsgBoxResult.Yes Then
                drv = bs.Current
                b = grdResult.CurrentRow.Index
                drv.Delete()
            End If
            dA.Update(ds, Tabla)
            grbDetalle.Enabled = False
            grdResult.Refresh()
End Sub

Y el código de la modificación

Private Sub btnModificar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnModificar.Click
        TipoAccion = Accion.Modificacion
        grbDetalle.Enabled = True
        grbBuscar.Enabled = False
        txtUsuAuditoria.Text = Environment.UserName
        txtFechaAuditoria.Text = Now
End Sub

Nos falta el código del botón aceptar

Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAceptar.Click
        Dim drv As DataRowView
    
            drv = bs.Current

            bs.EndEdit()
            dA.Update(ds, Tabla)

            grbBuscar.Enabled = True
            grbDetalle.Enabled = False

            grdResult.Refresh()
            Traduccion() 'refresca los cambios
            bolRefrescar = False
End Sub

Y finalmente el botón cancelar

 Private Sub btnCancelar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancelar.Click
        bs.CancelEdit()
        If bolRefrescar Then
            Recargar()
        End If
        grbDetalle.Enabled = False
        grbBuscar.Enabled = True
    End Sub

Con esto ya tenemos el proceso completo del mantenimiento de una tabla, en una pantalla como la mostrada arriba, pero si queremos traducir los códigos por algo más legible que podamos leer, como en la pantalla mostrada a continuación.

Cargar un datagrid de .Net con traducción de valores

Podemos hacer lo siguiente:

En la función traducir, debajo de la carga de la tabla añadimos columnas nueva de la grid de forma manual indicando la traducción.

strStartupPath = My.Application.Info.DirectoryPath
srSQL = New System.IO.StreamReader(strStartupPath & "\CargarTraduccion.sql")
strConsulta = srSQL.ReadToEnd
cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
dA.SelectCommand = cmdPD
cmdbuilder = New OleDbCommandBuilder(dA)
dA.Fill(ds, "Traduccion")

        'Columnas calculadas, Traduce los valores simples en textos
        Dim colAmbito As DataColumn = New DataColumn
        With colAmbito
            .DataType = System.Type.GetType("System.String")
            .ColumnName = "Ambito_traducido"
   'traduce tres valores posibles, E como España, R como Riesgo y cualquier otro como Otro
            .Expression = "IIF(AMBITO='E', 'España', IIF(XTI_AMBITO='R', 'Riesgo','Otro'))"
        End With
        Dim colCapa As DataColumn = New DataColumn
        With colCapa
            .DataType = System.Type.GetType("System.String")
            .ColumnName = "Capa_traducido"
 'traduce tres valores posibles, A como Av, P como Piso y cualquier otro como Ambos
            .Expression = "IIF(CAPA='A', 'Av', IIF(XTI_CAPA='P', 'Piso','Ambos'))"
        End With
        ds.Tables("Traduccion").Columns.Add(colAmbito)
        ds.Tables("Traduccion").Columns.Add(colCapa)

        If Not bolPrimeraVez Then
            Exit Sub
        End If

        bolPrimeraVez = False

        dA.UpdateCommand = cmdbuilder.GetUpdateCommand()
        dA.DeleteCommand = cmdbuilder.GetDeleteCommand()
        dA.InsertCommand = cmdbuilder.GetInsertCommand()

sustituimos también la carga de las combos con los nuevo campos.

Me.txtColumna.DataBindings.Add(New Binding("Text", bs, "COD"))
 Me.CboAmbito.DataBindings.Add(New Binding("Text", bs, "Ambito"))
 Me.CboCapa.DataBindings.Add(New Binding("Text", bs, "Capa"))
 Me.txtUsuAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_USUARIO"))
 Me.txtFechaAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_FECHA"))

Finalmente hacemos invisibles las columnas no traducidas.

grdResult.Columns(1).Visible = False
grdResult.Columns(2).Visible = False

en el botón aceptar hay que introducir una pequeña función que nos traduzca los valores de los combos a los códigos para que en base de datos se grabe correctamente (los combos están cargados con el texto predefinido, no con los códigos)

drv = bs.Current
Traduce(drv) 'traduce las descripciones a códigos
bs.EndEdit()
dA.Update(ds, Tabla)

Y la función traduce será de este estilo

'traduce las descripciones a sus códigos para grabarlos en BBDD
 'Si es DataSet es true si es DataRowView es false

 Private Sub Traduce(ByVal ValoresGrid As Object)
        If CboAmbito.Text = "Otros" Then
            ValoresGrid.Item(1) = "O"
        End If
        If CboAmbito.Text = "España" Then
            ValoresGrid.Item(1) = "E"
        End If
        If CboAmbito.Text = "Riesgo" Then
            ValoresGrid.Item(1) = "R"
        End If

        If CboCapa.Text = "Av" Then
            ValoresGrid.Item(2) = "A"
        End If
        If CboCapa.Text = "Piso" Then
            ValoresGrid.Item(2) = "P"
        End If
        If CboCapa.Text = "Ambos" Then
            ValoresGrid.Item(2) = "2"
        End If
    End Sub

Otra forma de traducir valores sería esta.

Dim oIdioma As DataColumn = New DataColumn
oIdioma.DataType = System.Type.GetType("System.String")
oIdioma.ColumnName = "Idioma"
 oIdioma.Expression = "IIF(XTI_IDIOMA='E','Inglés','España')"

 ds.Tables(Tabla).Columns.Add(oIdioma)

Iría justo encima de estas instrucciones:

dA.UpdateCommand = cmdbuilder.GetUpdateCommand()
        dA.DeleteCommand = cmdbuilder.GetDeleteCommand()
        dA.InsertCommand = cmdbuilder.GetInsertCommand()

El programa completo sería este:

Imports System.IO
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports System.Data.SqlClient

Public Class frmTraduccion
    Dim ds As New DataSet()

    Dim bs As BindingSource = New BindingSource()
    Dim dA As New OleDb.OleDbDataAdapter
    Dim drEdit As DataRowView
    Dim bolRefrescar As Boolean
    Dim bolPrimeraVez As Boolean = True
    Const Tabla = "Traduccion"
    Enum Accion
        Alta = 1
        Baja = 2
        Modificacion = 3
    End Enum

    Dim TipoAccion As Accion

    Private Sub frmTraduccion_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.grdResult.DataSource = bs

        txtColumna.MaxLength = 40
        traduccion()

        Dim ObjetosPermitidos As Dictionary(Of String, String)
        ObjetosPermitidos = ComprobarPermisos(Me.Name)
        btnModificar.Visible = IIf(ObjetosPermitidos.ContainsKey("btnModificar"), True, False)
        btnBaja.Visible = IIf(ObjetosPermitidos.ContainsKey("btnBaja"), True, False)
        btnAlta.Visible = IIf(ObjetosPermitidos.ContainsKey("btnAlta"), True, False)
    End Sub

    Sub Traduccion()

        Dim tb As DataTable
        Dim srSQL As StreamReader
        Dim strConsulta As String
        Dim cmdbuilder As OleDbCommandBuilder

        tb = New DataTable

        'Repeticion si no es la primera vez es que se ha llamado desde el mantenimiento y antes de cargarse debe borrarse la grid
        If Not bolPrimeraVez Then
            ds.Tables("Traduccion").Clear()
        End If
       
        strStartupPath = My.Application.Info.DirectoryPath
        srSQL = New System.IO.StreamReader(strStartupPath & "\CargarTraduccion.sql")
        strConsulta = srSQL.ReadToEnd
        cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
        dA.SelectCommand = cmdPD
        cmdbuilder = New OleDbCommandBuilder(dA)
        dA.Fill(ds, "Traduccion")

        'Columnas calculadas, Traduce los valores simples en textos
        Dim colAmbito As DataColumn = New DataColumn
        With colAmbito
            .DataType = System.Type.GetType("System.String")
            .ColumnName = "Ambito_traducido"
            .Expression = "IIF(AMBITO='E', 'España', IIF(AMBITO='R', 'Riesgo','Otro'))"
        End With
        Dim colCapa As DataColumn = New DataColumn
        With colCapa
            .DataType = System.Type.GetType("System.String")
            .ColumnName = "Capa_traducida"
            .Expression = "IIF(CAPA='A', 'Av', IIF(CAPA='P', 'Piso','Ambos'))"
        End With
        ds.Tables("Traduccion").Columns.Add(colAmbito)
        ds.Tables("Traduccion").Columns.Add(colCapa)

        If Not bolPrimeraVez Then
            Exit Sub
        End If

        bolPrimeraVez = False

        dA.UpdateCommand = cmdbuilder.GetUpdateCommand()
        dA.DeleteCommand = cmdbuilder.GetDeleteCommand()
        dA.InsertCommand = cmdbuilder.GetInsertCommand()

        bs.DataSource = ds.Tables(Tabla)

        Me.txtColumna.DataBindings.Add(New Binding("Text", bs, "COD"))
        Me.CboAmbito.DataBindings.Add(New Binding("Text", bs, "Ambito"))
        Me.CboCapa.DataBindings.Add(New Binding("Text", bs, "Capa"))
        Me.txtUsuAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_USUARIO"))
        Me.txtFechaAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_FECHA"))

        grdResult.Columns(1).Visible = False
        grdResult.Columns(2).Visible = False

        grdResult.Columns(0).MinimumWidth = 100
        grdResult.Columns(1).MinimumWidth = 100
        grdResult.Columns(2).MinimumWidth = 30
        grdResult.Columns(3).MinimumWidth = 100
        grdResult.Columns(4).MinimumWidth = 100

        grdResult.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill

        grdResult.Columns(0).HeaderText = "Modelo"
        grdResult.Columns(1).HeaderText = "Ambito"
        grdResult.Columns(2).HeaderText = "Capa"
        grdResult.Columns(3).HeaderText = "Usuario Auditoria"
        grdResult.Columns(4).HeaderText = "Fecha Auditoria"
        grdResult.Refresh()

    End Sub


    Function BuscarCodigoRelacion() As Integer
        Stop
    End Function


    Private Sub grdResult_RowEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles grdResult.RowEnter

    End Sub


    Private Sub btnAlta_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAlta.Click
        TipoAccion = Accion.Alta

        grbDetalle.Enabled = True
        grbBuscar.Enabled = False
        drEdit = bs.AddNew()
        bs.MoveLast()
        txtUsuAuditoria.Text = Environment.UserName
        txtFechaAuditoria.Text = Now
        grdResult.Refresh()
    End Sub

    Private Sub btnBaja_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBaja.Click
        Dim drv As DataRowView
        Dim b As Integer
        TipoAccion = Accion.Baja
      

            If MsgBox("¿Esta usted seguro que desea borrar este registro?", MsgBoxStyle.YesNo + MsgBoxStyle.Question, "Confirmación de Baja") = MsgBoxResult.Yes Then
                drv = bs.Current
                b = grdResult.CurrentRow.Index
                drv.Delete()
            End If
            dA.Update(ds, Tabla)
            grbDetalle.Enabled = False
            grdResult.Refresh()
    End Sub

    Private Sub btnModificar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnModificar.Click
        TipoAccion = Accion.Modificacion
        grbDetalle.Enabled = True
        grbBuscar.Enabled = False
        txtUsuAuditoria.Text = Environment.UserName
        txtFechaAuditoria.Text = Now
    End Sub

    Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAceptar.Click
        Dim drv As DataRowView
            drv = bs.Current
            Traduce(drv) 'traduce las descripciones a códigos
            bs.EndEdit()
            dA.Update(ds, Tabla)

            grbBuscar.Enabled = True
            grbDetalle.Enabled = False

            grdResult.Refresh()
            UUAAGeografia() 'refresca los cambios
            bolRefrescar = False
    End Sub

    'traduce las descripciones a sus códigos para grabarlos en BBDD
    'Si es DataSet es true si es DataRowView es false

    Private Sub Traduce(ByVal ValoresGrid As Object)
        If CboAmbito.Text = "Otro" Then
            ValoresGrid.Item(1) = "O"
        End If
        If CboAmbito.Text = "España" Then
            ValoresGrid.Item(1) = "E"
        End If
        If CboAmbito.Text = "Riesgo" Then
            ValoresGrid.Item(1) = "R"
        End If

        If CboCapa.Text = "Av" Then
            ValoresGrid.Item(2) = "A"
        End If
        If CboCapa.Text = "Piso" Then
            ValoresGrid.Item(2) = "P"
        End If
        If CboCapa.Text = "Ambos" Then
            ValoresGrid.Item(2) = "2"
        End If
    End Sub

    Private Sub btnCancelar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancelar.Click
        bs.CancelEdit()
        If bolRefrescar Then
            Recargar()
        End If
        grbDetalle.Enabled = False
        grbBuscar.Enabled = True
    End Sub

    Sub Recargar()
        bolRefrescar = False
        ds.Tables(1).Clear()
        ds.Tables(0).Clear()
        Traduccion()
        grdResult.Refresh()
    End Sub

    Private Sub txtColumna_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtColumna.TextChanged
        txtColumna.MaxLength = 8
    End Sub

    Private Sub CboCapa_TextChanged(sender As Object, e As EventArgs) Handles CboCapa.TextChanged
        CboCapa.MaxLength = 1
    End Sub
    Private Sub CboAmbito_TextChanged(sender As Object, e As EventArgs) Handles CboAmbito.TextChanged
        CboAmbito.MaxLength = 1
    End Sub
End Class



No hay comentarios:

Publicar un comentario