【发布时间】:2018-04-08 12:40:30
【问题描述】:
我编写了下面的帮助程序类,以便为 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
【问题讨论】:
-
您的
ImageAnimator.Animate()好像放错了地方。该方法应该为动画图像调用一次(在绘画事件中)。它主要用于指定OnFrameChanged处理程序。我通常有一个从Paint()事件调用的方法(比如说Animate())。作为第一件事,Animate()方法检查动画是否已经启动(使用 bool 变量检查 a)。如果是,则立即返回。 Check the example in MSDN Docs -
抱歉,我想我不明白我所做的与您的指示有何不同...我将它放在仅在检测到新图像时运行的代码的一部分中...位于
CellPainting事件处理程序中...我真的很抱歉,如果您能澄清一下,我会非常感谢。 -
嗯,我想了想(我现在唯一能做的,手头没有VS),我看到了你的编辑。我认为您对单元格格式行为是正确的。您也不能存储图像,您最终会得到一个无效的图像。我认为您应该创建一个包含 ImageAnimator 逻辑的自定义单元类型(从 ImageCell 派生),并且可能为自定义单元创建一个自定义列。如果在此期间没有人回答您的问题,明天我会试一试。
-
嗨@Jimi。当我通过创建一个图像列来显示而不是格式化一个整数列来做出一个肮脏的解决方法时......我隐藏了整数列并处理了 CellValueChanged 来选择和存储正确的图像。无论如何,我会继续以一种更整洁的方式思考......
-
有了自定义的Column和自定义的Cells,我觉得效果还是挺不错的。没有闪烁,您可以在 DataGridView 设计器中设置 Column 属性,因此您可以将位图设置为 Zoom 或 Stretch 等。只有一件事我不喜欢:单元格是从自定义 Column 提供的 CellTemplate 构建的,但它们不是新的(ed),它们是克隆的。这意味着在显示列后必须使单元格无效。如果你愿意,我会发布这个自定义列类,可能与你想要的足够接近。顺便说一句,我还没有找到任何好的例子。
标签: vb.net winforms animation datagridview