title: Animate Images in DataGridView
body: <p>I wrote the helper class below in order to animate images in a <code>DataGridView</code>, which is not working (images aren't animated).</p>
  
  <p>Before that, I found some sample code on the wen, but they didn't work either.</p>
  
  <p>I want to understand how this works instead of simply shove a piece of code inside my app just because it works. Why does my code not do what it is expected to?</p>
  
  <h1>Edit</h1>
  
  <p>I discovered the reason why it isn't working. The source <code>DataTable</code> itself don't contain images: they are assigned to <code>DataGridView</code>'s Cells elsewhere in the code by its <code>CellFormatting</code> handler method. Since this event also triggers all the time, a fresh image object is always passed, so it keeps always showing the image's frame #1. When I created a new column with native image values stored in it, they animated as desired.</p>
  
  <p><strong>The question now is</strong>: is it possible to animate images that are assigned to the <code>.FormattedValue</code> property inside <code>DataGridView</code>'s <code>CellFormatting</code> event handler method?</p>
  
  <pre><code>Public Class DataGridViewImageAnimator
  
      Private WithEvents MyDataGridView As DataGridView
  
      Public Sub New(dataGridView As DataGridView)
  
          MyDataGridView = dataGridView
  
      End Sub
  
      Private MyAnimatedImages As New Dictionary(Of Point, Image)
  
      Private Sub ImageAnimator_FrameChanged(sender As Object, e As EventArgs)
  
          Dim imageCells = MyDataGridView.Rows.Cast(Of DataGridViewRow).SelectMany(
              Function(dgvr) dgvr.Cells.OfType(Of DataGridViewImageCell))
  
          For Each cell In imageCells
  
              Dim img = TryCast(cell.FormattedValue, Image)
  
              If img IsNot Nothing AndAlso MyAnimatedImages.ContainsValue(img) Then
  
                  MyDataGridView.InvalidateCell(cell)
  
              End If
          Next
  
      End Sub
  
      Private Sub MyDataGridView_CellPainting(
              sender As Object,
              e As DataGridViewCellPaintingEventArgs
              ) Handles MyDataGridView.CellPainting
  
          If e.ColumnIndex &gt;= 0 AndAlso e.RowIndex &gt;= 0 Then
  
              Dim cell = MyDataGridView(e.ColumnIndex, e.RowIndex)
  
              Dim drawPoint = MyDataGridView.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True).Location
  
              Dim pt = New Point(e.ColumnIndex, e.RowIndex)
  
              Dim cellImg = TryCast(cell.FormattedValue, Image)
  
              If MyAnimatedImages.ContainsKey(pt) AndAlso Equals(MyAnimatedImages(pt), cellImg) Then
                  'If image is already registered as animated, and is still in cell
  
                  ImageAnimator.UpdateFrames()
  
                  e.Graphics.DrawImage(cellImg, drawPoint)
  
              Else
  
                  If MyAnimatedImages.ContainsKey(pt) Then
                      'If image registered as animated is no longer in cell
  
                      ImageAnimator.StopAnimate(MyAnimatedImages(pt), AddressOf ImageAnimator_FrameChanged)
  
                      MyAnimatedImages.Remove(pt)
  
                  End If
  
                  If cellImg IsNot Nothing AndAlso ImageAnimator.CanAnimate(cellImg) Then
                      'If cell contains an image not yet registered as animated
  
                      MyAnimatedImages(pt) = cellImg
  
                      ImageAnimator.Animate(MyAnimatedImages(pt), AddressOf ImageAnimator_FrameChanged)
  
                      ImageAnimator.UpdateFrames()
  
                      e.Graphics.DrawImage(cellImg, drawPoint)
  
                  End If
  
              End If
  
          End If
  
      End Sub
  
  End Class
  </code></pre>