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