Vb.net 在DataGridView中设置图像动画

Vb.net 在DataGridView中设置图像动画,vb.net,animation,datagridview,Vb.net,Animation,Datagridview,我在下面编写了helper类,以便在DataGridView中设置图像动画,但该类不起作用(图像未设置动画) 在此之前,我在wen上找到了一些示例代码,但它们也不起作用 我想了解它是如何工作的,而不是仅仅因为它工作就在我的应用程序中插入一段代码。为什么我的代码没有达到预期的效果 编辑 我发现了它不起作用的原因。源DataTable本身不包含图像:它们通过其CellFormatting处理程序方法分配给代码中其他位置的DataGridView单元格。由于此事件也会一直触发,因此始终会传递一个新图像

我在下面编写了helper类,以便在
DataGridView
中设置图像动画,但该类不起作用(图像未设置动画)

在此之前,我在wen上找到了一些示例代码,但它们也不起作用

我想了解它是如何工作的,而不是仅仅因为它工作就在我的应用程序中插入一段代码。为什么我的代码没有达到预期的效果

编辑 我发现了它不起作用的原因。源
DataTable
本身不包含图像:它们通过其
CellFormatting
处理程序方法分配给代码中其他位置的
DataGridView
单元格。由于此事件也会一直触发,因此始终会传递一个新图像对象,因此它始终显示图像的帧#1。当我用存储在其中的本机图像值创建一个新列时,它们会根据需要设置动画

现在的问题是:是否可以在
DataGridView
CellFormatting
事件处理程序方法中设置分配给
.FormattedValue
属性的图像动画

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 >= 0 AndAlso e.RowIndex >= 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

带有自定义单元格的自定义列提供了一些优势。

所有设计逻辑都限制在一个地方,可以在设计时使用
DataGridView
designer将其选择为列模板。


性能非常好(用200个动画单元格测试),我没有注意到任何闪烁。

可以使用设计器设置,通过编码或手动调整行/列的大小,像往常一样拉伸或缩放动画GIF。

<>但是,我不能认为它是完整的,因为我找不到一个好的方法来启动所有的动画使用这个自定义的列类方法或属性。 编辑:
DataGridView
DataGridView.Animate()
)添加了扩展方法。
这允许隐藏失效过程。
DataGridView
数据绑定完成后,只需调用扩展方法:

DataGridView1.DataSource = [DataSource]
DataGridView1.Animate()
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
包含扩展方法的模块:

DataGridView1.DataSource = [DataSource]
DataGridView1.Animate()
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
导入System.Runtime.CompilerServices
模块dgvextensions
公共子动画(ByVal AnimatedGrid作为DataGridView)
尝试
对于AnimatedGrid.Rows中作为DataGridViewRow的每一行
对于类型为(AnimatedDGVColumn.AnimatedCell的)()的行.Cells.Of中作为DataGridViewCell的每个单元格
AnimatedGrid.InvalidateCell(单元格)
下一个
下一个
特例
WriteLine(“异常:{0}”,例如Message)
结束尝试
端接头
端模块
当然,这还不够好。需要更多的研究。

这是自定义的动画列类:

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
导入System.ComponentModel
导入System.Windows.Forms
公共类动画列
继承System.Windows.Forms.DataGridViewColumn
私有custCellTemplate作为AnimatedCell
公共分新()
Me.custCellTemplate=新的AnimatedCell
Me.custCellTemplate.ImageLayout=DataGridViewImageCellLayout.Zoom
MyBase.CellTemplate=custCellTemplate
Me.AutoSizeMode=DataGridViewAutoSizeColumnMode.None
Me.DefaultCellStyle.Alignment=DataGridViewContentAlignment.MiddleCenter
端接头
_
公共属性ImageLayout作为DataGridViewImageCellLayout
得到
Return Me.custCellTemplate.ImageLayout
结束
设置(ByVal值为DataGridViewImageCellLayout)
Me.custCellTemplate.ImageLayout=值
端集
端属性
Public将属性CellTemplate重载为AnimatedCell
得到
返回给我
结束
设置(值为AnimatedCell)
Me.custCellTemplate=值
MyBase.CellTemplate=值
端集
端属性
公共类动画单元
继承System.Windows.Forms.DataGridViewImageCell
作为图像的私有动画
私有IsAnimating为布尔值
公共分新()
我。动画=什么都没有
Me.IsAnimating=False
端接头
Public将属性ImageLayout()重载为DataGridViewImageCellLayout
得到
返回MyBase.ImageLayout
结束
设置(ByVal值为DataGridViewImageCellLayout)
MyBase.ImageLayout=值
端集
端属性
保护覆盖子漆(图形为图形,剪贴簿为矩形,单元格边框为矩形,行索引为整数,elementState为DataGridViewElementState,值为对象,格式化值为对象,错误文本为字符串,单元格样式为DataGridViewCellStyle,advancedBorderStyle为DataGridViewAdvancedBorderStyle,paintParts为DataGridViewPaintParts)
如果(IsDBNull(value))或(value为Nothing),则返回
如果是我,动画什么都不是
Me.Animation=CType(formattedValue,Image)
如果结束
制作动画()
ImageAnimator.UpdateFlames()
画图(图形、剪贴簿、单元格边框、行索引、元素状态、无、Me.Animation、errorText、单元格样式、高级边框样式、画图部件)
端接头
私有子动画()
如果Me.IsAnimating=True,则返回
如果(Me.Animation不是空的)和ImageAnimator.CanAnimate(Me.Animation)=True,则
ImageAnimator.Animate(Me.Animation,AddressOf Me.RotateFrame)
真的
如果结束
端接头
私有子RotateName(o作为对象,e作为事件参数)
如果Me.RowIndex>-1,则
Me.DataGridView.InvalidateCell(Me)
如果结束
端接头
公共重写函数Clone()作为对象
将结果变暗为AnimatedCell=新的AnimatedCell{
.IsAnimating=False,