Hola!
Al leer el título, probablemente pensaréis que me he equivocado. Geeks no es precisamente un sitio donde se hable de tecnologías asentadas como .NET 1.1, sino más bien se escribe sobre lo último de lo último. Y es cierto 😉
Pero sin embargo, mucha gente sigue trabajando con .NET 1.1. No todo el mundo puede o quiere migrar a 2.0, pese a que las ventajas son muy interesantes, bien sea por temas de presupuesto, porque el cliente no está dispuesto a asumir el coste de una migración (es un gasto al que un gestor de proyecto no tiene por qué verle las suficientes ventajas), etc.
Hace poco una persona me comentó que no podía cambiar el color de fondo de una fila de un DataGrid en .NET 1.1 en función del valor de uno de los campos de cada fila. Como ese tipo de preguntas son de las que más me estimula (leyendo los dos posts anteriores habréis podido comprobar que soy un poco tocapelotas, pero me gusta bastante ayudar si puedo a la gente), pues me apreté los machos y empecé a indagar cómo se podría hacer.
En .NET 2.0 es bastante sencillo, podemos utilizar la propiedad Rows, que nos devuelve una colección de DataGridViewRow. Una vez tenemos el DataGridViewRow, podemos acceder al elemento enlazado a través de la propiedad DataBoundItem, y podemos modificar el estilo de la fila usando la propiedad DefaultCellStyle. Todo encaja.
Lo primero que pensé fué… Bueno, seguro que no es tan complicado… Voy a la colección Rows del DataGrid, y ahí seguro que puedo cambiarle el BackColor. ¡ERROR! ¡No existe una colección Rows! Ni ninguna que defina las filas del DataGrid desde el punto de vista del interfaz de usuario! (¿Quién diseñó el modelo de objetos del DataGrid de la versión 1.1? ¡Es peor aún que el de Syncfusion!)
Después de andar mirando la documentación un buen rato, y ver que sólo se podían modificar estilos y columnas, decidí tirar por la calle de enmedio. La idea es la siguiente:
- Heredar de la clase DataGridTextBoxColumn.
- Sobreescribir el método Paint de la clase.
- Crear un evento en la clase que pida el color a emplear.
Si lo pensáis, estoy haciendo trampas, porque esto implica que todas las columnas del DataGrid tendrán que ser de esta clase que he creado para que la fila completa aparezca coloreada. Además, dejo como responsabilidad al usuario de la columna el decidir si dicha columna deberá ser coloreada o no. (El código del artículo está disponible en el adjunto).
Al final, el código de la columna era el siguiente: (es VB.NET, que era el lenguaje que me habían pedido utilizar 😛 )
Public Class RowColorEventArgs
Inherits EventArgs
Public Sub New(ByVal col As color, _
ByVal currManager As CurrencyManager, _
ByVal rowNum As Integer)
Me.color = col
Me.src = currManager
Me.row = rowNum
End Sub
Private color As color
Private src As CurrencyManager
Private row As Integer
' Color de la fila.
Public Property RowColor() As color
Get
Return color
End Get
Set(ByVal Value As color)
color = Value
End Set
End Property
' Fuente de datos
Public ReadOnly Property Source() As CurrencyManager
Get
Return src
End Get
End Property
' Indice de la fila.
Public ReadOnly Property RowIndex() As Integer
Get
Return row
End Get
End Property
End Class
Public Class DataGridColoredTextBoxColumn
Inherits DataGridTextBoxColumn
Public Event GetForeColor(ByVal sender As Object, _
ByVal e As RowColorEventArgs)
Public Event GetBackColor(ByVal sender As Object, _
ByVal e As RowColorEventArgs)
Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics, _
ByVal bounds As System.Drawing.Rectangle, _
ByVal source As System.Windows.Forms.CurrencyManager, _
ByVal rowNum As Integer, _
ByVal backBrush As System.Drawing.Brush, _
ByVal foreBrush As System.Drawing.Brush, _
ByVal alignToRight As Boolean)
Dim evArgs As RowColorEventArgs
' Guardamos las brochas para su posterior restauración.
Dim oldBackBrush As Brush = backBrush
Dim oldForeBrush As Brush = foreBrush
' Pedimos el color de fondo
evArgs = New RowColorEventArgs(Me.TextBox.BackColor, source, rowNum)
RaiseEvent GetBackColor(Me, evArgs)
' Creamos la brocha de fondo.
backBrush = New SolidBrush(evArgs.RowColor)
' Pedimos el color del texto.
evArgs = New RowColorEventArgs(Me.TextBox.ForeColor, source, rowNum)
RaiseEvent GetForeColor(Me, evArgs)
' Creamos la brocha del texto
foreBrush = New SolidBrush(evArgs.RowColor)
' Pintamos
MyBase.Paint(g, bounds, source, rowNum, _
backBrush, foreBrush, alignToRight)
' Liberamos las brochas! Los recursos de GDI son limitados!
backBrush.Dispose()
foreBrush.Dispose()
' Restauramos las brochas antiguas
backBrush = oldBackBrush
foreBrush = oldForeBrush
End Sub
End Class
La verdad es que no estoy satisfecho con la solución. La cantidad de eventos generados para pintar el DataGrid es enorme. De todas formas, el código para utilizar esta clase, es un poco truculento, y es el que pongo a continuación:
' En Form1.vb...
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim tableStyle As New DataGridTableStyle
tableStyle.MappingName = Me.OrdersDataSet1.Orders.TableName
Me.FillDataSet()
For Each col As DataColumn In Me.OrdersDataSet1.Orders.Columns
Dim gridCol As DataGridColoredTextBoxColumn = _
New DataGridColoredTextBoxColumn
gridCol.MappingName = col.ColumnName
gridCol.HeaderText = col.ColumnName
AddHandler gridCol.GetBackColor, AddressOf Me.GetBackColor
tableStyle.GridColumnStyles.Add(gridCol)
Next
DataGrid1.TableStyles.Add(tableStyle)
DataGrid1.DataSource = Me.OrdersDataSet1.Orders
End Sub
Private Sub GetBackColor(ByVal sender As Object, _
ByVal e As RowColorEventArgs)
Dim data As DataRowView
Dim value As Integer
data = CType(e.Source.List.Item(e.RowIndex), DataRowView)
value = CInt(data("EmployeeID"))
If value = 5 Then
e.RowColor = Color.Red
End If
End Sub
Private Sub FillDataSet()
' ...
End Sub
Estoy seguro de que hay una forma más sencilla de hacerlo. ¿Alguien conoce alguna?