A custom Column with custom Cells offers some advantages.
All the design logic is confined in one place and it can be selected as a Column template at design time using the DataGridView
designer.
The performace is quite good (tested with 200 animated cells) and I didn't notice any flickering.
The animated Gifs can be Stretched or Zoomed as usual, using the designer settings, by code or manually resizing the Rows/Columns.
However, I can't consider it complete, because I couldn't find out a good way to start all the animations using this custom Column class methods or properties.
EDIT:
Added an Extension method to the DataGridView
(DataGridView.Animate()
).
This allows to hide the invalidating procedure.
After the DataGridView
Data Binding is complete, simply call the extension method:
DataGridView1.DataSource = [DataSource]
DataGridView1.Animate()
The Module containing the Extension method:
Imports System.Runtime.CompilerServices
Module DGVExtesions
<Extension()>
Public Sub Animate(ByVal AnimatedGrid As DataGridView)
Try
For Each row As DataGridViewRow In AnimatedGrid.Rows
For Each cell As DataGridViewCell In row.Cells.OfType(Of AnimatedDGVColumn.AnimatedCell)()
AnimatedGrid.InvalidateCell(cell)
Next
Next
Catch ex As Exception
Trace.WriteLine("Exception: {0}", ex.Message)
End Try
End Sub
End Module
Of course this is still not good enough. Some more research is needed.
This is the custom Animated Column class:
Imports System.ComponentModel
Imports System.Windows.Forms
Public Class AnimatedDGVColumn
Inherits System.Windows.Forms.DataGridViewColumn
Private custCellTemplate As AnimatedCell
Public Sub New()
Me.custCellTemplate = New AnimatedCell
Me.custCellTemplate.ImageLayout = DataGridViewImageCellLayout.Zoom
MyBase.CellTemplate = custCellTemplate
Me.AutoSizeMode = DataGridViewAutoSizeColumnMode.None
Me.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
End Sub
<Description("The ImageLayout in the Cells for this Column"), Category("Appearance")> _
<EditorBrowsable(EditorBrowsableState.Always), Browsable(True)>
Public Property ImageLayout As DataGridViewImageCellLayout
Get
Return Me.custCellTemplate.ImageLayout
End Get
Set(ByVal value As DataGridViewImageCellLayout)
Me.custCellTemplate.ImageLayout = value
End Set
End Property
Public Overloads Property CellTemplate As AnimatedCell
Get
Return Me.custCellTemplate
End Get
Set(value As AnimatedCell)
Me.custCellTemplate = value
MyBase.CellTemplate = value
End Set
End Property
Public Class AnimatedCell
Inherits System.Windows.Forms.DataGridViewImageCell
Private Animation As Image
Private IsAnimating As Boolean
Public Sub New()
Me.Animation = Nothing
Me.IsAnimating = False
End Sub
Public Overloads Property ImageLayout() As DataGridViewImageCellLayout
Get
Return MyBase.ImageLayout
End Get
Set(ByVal value As DataGridViewImageCellLayout)
MyBase.ImageLayout = value
End Set
End Property
Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, elementState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
If (IsDBNull(value)) OrElse (value Is Nothing) Then Return
If Me.Animation Is Nothing Then
Me.Animation = CType(formattedValue, Image)
End If
Animate()
ImageAnimator.UpdateFrames()
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, Nothing, Me.Animation, errorText, cellStyle, advancedBorderStyle, paintParts)
End Sub
Private Sub Animate()
If Me.IsAnimating = True Then Return
If (Me.Animation IsNot Nothing) AndAlso ImageAnimator.CanAnimate(Me.Animation) = True Then
ImageAnimator.Animate(Me.Animation, AddressOf Me.RotateFrame)
Me.IsAnimating = True
End If
End Sub
Private Sub RotateFrame(o As Object, e As EventArgs)
If Me.RowIndex > -1 Then
Me.DataGridView.InvalidateCell(Me)
End If
End Sub
Public Overrides Function Clone() As Object
Dim result As AnimatedCell = New AnimatedCell With {
.IsAnimating = False,
.Animation = Nothing,
.ImageLayout = Me.ImageLayout
}
Return result
End Function
End Class
End Class