Mostrando entradas con la etiqueta DataGridViewButtonColumn. Mostrar todas las entradas
Mostrando entradas con la etiqueta DataGridViewButtonColumn. Mostrar todas las entradas

Deshabilitar columna tipo DataGridViewButtonColumn en DataGridView

Problema: Tengo una columna tipo botón en mi grid, pero por validaciones, necesito que en una fila específica, el botón esté deshabilitado y que no funcione.
Solución: Microsoft da una versión general del problema y su solución es bastante limitada, así que he decidido unificar los pedazos que he encontrado en la web.

La parte de Microsoft que utilizo, es la siguiente, sin importar cómo lo voy a utilizar después. Este código sirve para crear un nuevo tipo de botón "deshabilitado", que no viene originalmente en el grid.

Solo es de copiar y pegar, yo lo tengo al final de todo mi código. Más adelante explico como utilizarlo.

#Region "Columna Botón Deshabilitada"
    Public Class DataGridViewDisableButtonColumn
        Inherits DataGridViewButtonColumn

        Public Sub New()
            Me.CellTemplate = New DataGridViewDisableButtonCell()
        End Sub
    End Class

    Public Class DataGridViewDisableButtonCell
        Inherits DataGridViewButtonCell

        Private enabledValue As Boolean
        Public Property Enabled() As Boolean
            Get
                Return enabledValue
            End Get
            Set(ByVal value As Boolean)
                enabledValue = value
            End Set
        End Property

        ' Override the Clone method so that the Enabled property is copied.
        Public Overrides Function Clone() As Object
            Dim Cell As DataGridViewDisableButtonCell = _
                CType(MyBase.Clone(), DataGridViewDisableButtonCell)
            Cell.Enabled = Me.Enabled
            Return Cell
        End Function

        ' By default, enable the button cell.
        Public Sub New()
            Me.enabledValue = True
        End Sub

        Protected Overrides Sub Paint(ByVal graphics As Graphics, _
            ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, _
            ByVal rowIndex As Integer, _
            ByVal elementState As DataGridViewElementStates, _
            ByVal value As Object, ByVal formattedValue As Object, _
            ByVal errorText As String, _
            ByVal cellStyle As DataGridViewCellStyle, _
            ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _
            ByVal paintParts As DataGridViewPaintParts)

            ' The button cell is disabled, so paint the border, 
            ' background, and disabled button for the cell.
            If Not Me.enabledValue Then

                ' Draw the background of the cell, if specified.
                If (paintParts And DataGridViewPaintParts.Background) = _
                    DataGridViewPaintParts.Background Then

                    Dim cellBackground As New SolidBrush(cellStyle.BackColor)
                    graphics.FillRectangle(cellBackground, cellBounds)
                    cellBackground.Dispose()
                End If

                ' Draw the cell borders, if specified.
                If (paintParts And DataGridViewPaintParts.Border) = _
                    DataGridViewPaintParts.Border Then

                    PaintBorder(graphics, clipBounds, cellBounds, cellStyle, _
                        advancedBorderStyle)
                End If

                ' Calculate the area in which to draw the button.
                Dim buttonArea As Rectangle = cellBounds
                Dim buttonAdjustment As Rectangle = _
                    Me.BorderWidths(advancedBorderStyle)
                buttonArea.X += buttonAdjustment.X
                buttonArea.Y += buttonAdjustment.Y
                buttonArea.Height -= buttonAdjustment.Height
                buttonArea.Width -= buttonAdjustment.Width

                ' Draw the disabled button.               
                ButtonRenderer.DrawButton(graphics, buttonArea, _
                    PushButtonState.Disabled)

                ' Draw the disabled button text.
                If TypeOf Me.FormattedValue Is String Then
                    TextRenderer.DrawText(graphics, CStr(Me.FormattedValue), _
                        Me.DataGridView.Font, buttonArea, SystemColors.GrayText)
                End If

            Else
                ' The button cell is enabled, so let the base class
                ' handle the painting.
                MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, _
                    elementState, value, formattedValue, errorText, _
                    cellStyle, advancedBorderStyle, paintParts)
            End If
        End Sub

    End Class
#End Region

Bien, ahora a utilizarlo. Como yo ya tengo mi grid diseñado, debo cambiar mi columna botón original, por el nuevo tipo de botón.

Nota: Recordar que es un nuevo tipo de columna, y se lo debe de cambiar, como si cambiáramos del tipo botón al tipo check.

Primero debemos eliminar la columna botón actual y luego crear la nueva columna con los valores deseados en el sitio específico, todo cuando carga la aplicación.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Elimino la columna botón que ya tengo actualmente
        DataGridView1.Columns.Remove("boton")
        'Creo el nuevo tipo de botón
        Dim column As New DataGridViewDisableButtonColumn()
        'Defino las propiedades del botón
        With column
            .Name = "boton"
            .HeaderText = "Dar Click"
            .AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
        End With
        'Inserto la nueva columna en el sitio especificado
        DataGridView1.Columns.Insert(1, column) 'Está en la segunda fila
End Sub

Ahora la manera de utilizarlo:

Por ejemplo, cuando cargo los datos al grid, deseo que en ciertos registros no se habilite el botón, por lo que lo realizo de esta manera.

Private Sub Actualizar_Boton()
        For Each row As DataGridViewRow In DataGridView1.Rows
                If Not row.Cells("columna1").Value is DBNull.Value Then 'Si el campo NO es nulo
                        'Se deshabilita la columna Botón
                        Dim buttonCell As DataGridViewDisableButtonCell = CType(DataGridView1.Rows(row.Index).Cells("boton"), DataGridViewDisableButtonCell)
                        buttonCell.Enabled = False
                End If
        Next
End Sub

Con esto el botón pasa a verse como si estuviera deshabilitado, pero OJO, aún pueden hacer click en el.
Pero esto se puede resolver añadiendo una validación adicional a la programación que se hace al dar click en el botón.

Private Sub DataGridView1_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
        'Columna Botón
        If DataGridView1.Columns(e.ColumnIndex).Name = "boton" Then
                Dim buttonCell As DataGridViewDisableButtonCell = CType(DataGridView1.Rows(e.RowIndex).Cells("boton"), DataGridViewDisableButtonCell)
                If buttonCell.Enabled = False Then Exit Sub 'Si está deshabilitado no hace nada
                'Aquí el resto de mi código
                'Lo que pasa cuando se da click en el botón
        End If
End Sub

Mover fila en el DataGridView arriba y abajo con botón DataGridViewButtonColumn

Problema: Tengo un grid con dos columnas tipo botón, un botón indica subir una fila y el otro botón indica bajar una fila. Debo mover las filas de arriba hacia abajo dependiendo del clic en su respectivo botón.
Solución: Después de buscar por un buen rato en el Internet, no encontré una forma directa, así que tuve que realizar mi propia opción.

Nota: Mi DataGridView está enlazado a un BindingSource el cual está enlazado a un DataTable (que enredo), lo que significa que los datos iniciales (los que se presentan en el grid) son fueron llenados originariamente en el DataTable, por lo que debo modificar directamente el DataTable.

La acción de mover no es otra cosa que eliminar la fila actual e insertarla una posición arriba o abajo de la que se encontraba originariamente.

'Debo obtener la acción clic de la columna botón
Private Sub DataGridView1_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
       'Sirve para obtener el índice de la fila a mover
        Dim indice As Integer
       'Se crea una nueva fila a partir de la DataTable que está enlazada al grid
        Dim dr As DataRow = DataTable.NewRow()
        'Obtiene la posición actual de la fila a moverse
        indice = DataGridView1.CurrentRow.Index
        'Pregunto si se dio clic en la columna botón arriba
        If DataGridView1.Columns(e.ColumnIndex).Name = "arriba" Then
                'Se encuentra en la parte superior del grid
                If indice = 0 Then
                        Exit Sub
                End If
                'Se deben de insertar los datos en la fila, campo x campo
                dr(0) = DataGridView1.Rows(indice).Cells("campo0").Value
                dr(1) = DataGridView1.Rows(indice).Cells("campo1").Value
                'Primero se elimina la fila actual
                DataTable.Rows.RemoveAt(indice)
                'Después se inserta la fila copiada una posición arriba
                DataTable.Rows.InsertAt(dr, indice - 1)
                'Posiciona el foco en la posición actual
                DataTable.CurrentCell = DataTable.Rows(indice - 1).Cells(0)
        End If
        'Se repiten los mismos pasos para la columna botón abajo
        'Solo que se cambia el signo
        'Click en la columna botón abajo
        If DataGridView1.Columns(e.ColumnIndex).Name = "abajo" Then
                'Se encuentra en la parte inferior del grid
                If indice = DataGridView1.Rows.Count - 1 Then
                        Exit Sub
                End If
                'Se deben de insertar los datos en la fila, campo x campo
                dr(0) = DataGridView1.Rows(indice).Cells("campo0").Value
                dr(1) = DataGridView1.Rows(indice).Cells("campo1").Value
                'Primero se elimina la fila actual
                DataTable.Rows.RemoveAt(indice)
                'Después se inserta la fila copiada una posición abajo
                DataTable.Rows.InsertAt(dr, indice + 1)
                'Posiciona el foco en la posición actual
                DataTable.CurrentCell = DataTable.Rows(indice + 1).Cells(0)
        End If
End Sub

No se necesita actualizar el BindingSource o el DataGridView, si están enlazados al DataTable, puesto que se hace automáticamente.

Crear una columna de botón DataGridViewButtonColumn con imagen

Gracias a esta página encontré una forma para agregar una imagen a una columna botón de un DataGridView

Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

El link indicado está en C#, así que lo cambié a VB.Net

Private Sub DataGridView1_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) _
Handles DataGridView1.CellPainting
        If e.ColumnIndex >= 0 AndAlso DataGridView1.Columns(e.ColumnIndex).Name = "icono" _
        AndAlso e.RowIndex >= 0 Then
                e.Paint(e.CellBounds, DataGridViewPaintParts.All)
                Dim celBoton As DataGridViewButtonCell = _
                TryCast(DataGridView1.Rows(e.RowIndex).Cells("icono"), DataGridViewButtonCell)
                Dim icoAtomico As New Icon(Environment.CurrentDirectory + "\icono.ico")
                e.Graphics.DrawIcon(icoAtomico, e.CellBounds.Left + 3, e.CellBounds.Top + 3)
                DataGridView1.Rows(e.RowIndex).Height = icoAtomico.Height + 10
                DataGridView1.Columns(e.ColumnIndex).Width = icoAtomico.Width + 10
                e.Handled = True
        End If
End Sub

Nota: El icono tiene que estar en la ruta que se encuentra el ejecutable.