我在 a 中包含了一个动画 gif DataGridView
,但图像显示为静态的。可能吗?
2 回答
I implemented a DataGridViewImageAnimator class that takes care of the gif images' animations for any DataGridView. Instances of DataGridViewImageAnimator monitor a given DataGridView and animate any gif image displayed in it. You may download the source code from https://docs.google.com/open?id=0B1r6und31C6BQXktM2VQN1Jza2c
You can create an animator in the form that includes a DataGridView as follows:
public partial class YourForm : Form
{
private DataGridViewImageAnimator dataGridImageAnimator;
public YourForm()
{
InitializeComponent();
dataGridImageAnimator = new DataGridViewImageAnimator(dataGridView1);
}
// ...
}
Alternatively, you can use a DataGridView-derived class that already does this in its constructor, as it's shown below for the AnimatedDataGridView class below (code available at https://docs.google.com/open?id=0B1r6und31C6BQnZUaTBjVXA4SkE)
using System.Windows.Forms;
namespace JLR.Utils
{
public class AnimatedDataGridView : DataGridView
{
private DataGridViewImageAnimator _imageAnimator;
public AnimatedDataGridView()
: base()
{
_imageAnimator = new DataGridViewImageAnimator(this);
}
}
}
The entire code for the DataGridViewImageAnimator is shown below:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace JLR.Utils
{
public class DataGridViewImageAnimator
{
private class RowCol
{
public int Column { get; set; }
public int Row { get; set; }
public RowCol(int column, int row)
{
Column = column;
Row = row;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
RowCol other = obj as RowCol;
if (other == null)
return false;
return (other.Column == Column && other.Row == Row);
}
public bool Equals(RowCol other)
{
if (other == null)
return false;
return (other.Column == Column && other.Row == Row);
}
public override int GetHashCode()
{
return Column.GetHashCode() ^ Row.GetHashCode();
}
public static bool operator ==(RowCol a, RowCol b)
{
// If both are null, or both are same instance, return true.
if (object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.Column == b.Column && a.Row == b.Row;
}
public static bool operator !=(RowCol a, RowCol b)
{
return !(a == b);
}
}
private class AnimatedImage
{
private DataGridView DataGridView { get; set; }
private HashSet<RowCol> _cells = new HashSet<RowCol>();
public Image Image { get; set; }
public AnimatedImage(Image image, DataGridView dataGridView)
{
Image = image;
DataGridView = dataGridView;
}
public bool IsUsed { get { return _cells.Count > 0; } }
public void AddCell(RowCol rowCol)
{
Debug.Assert(!_cells.Contains(rowCol));
if (!_cells.Contains(rowCol))
{
_cells.Add(rowCol);
if (_cells.Count == 1)
{
// this is the first cell we are using this image, so start animation
ImageAnimator.Animate(Image, new EventHandler(OnFrameChanged));
}
}
}
public void RemoveCell(RowCol rowCol)
{
Debug.Assert(_cells.Contains(rowCol));
if (_cells.Contains(rowCol))
{
_cells.Remove(rowCol);
if (_cells.Count == 0)
{
// this was the last cell we were using this image, so stop animation
ImageAnimator.StopAnimate(Image, new EventHandler(OnFrameChanged));
}
}
}
private void OnFrameChanged(object o, EventArgs e)
{
// invalidate each cell in which it's being used
RowCol[] rcs = new RowCol[_cells.Count];
_cells.CopyTo(rcs);
foreach (RowCol rc in rcs)
{
DataGridView.InvalidateCell(rc.Column, rc.Row);
}
}
}
private Dictionary<RowCol, Image> _values = new Dictionary<RowCol, Image>();
private Dictionary<Image, AnimatedImage> _animatedImages = new Dictionary<Image, AnimatedImage>();
private DataGridView _dataGridView;
public DataGridViewImageAnimator(DataGridView dataGridView)
{
_dataGridView = dataGridView;
_dataGridView.CellPainting += new DataGridViewCellPaintingEventHandler(OnDatagridCellPainting);
}
void OnDatagridCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
object value = _dataGridView[e.ColumnIndex, e.RowIndex].Value;
CheckValue(e.ColumnIndex, e.RowIndex, value);
ImageAnimator.UpdateFrames();
}
}
private void AddImage(RowCol rowCol, Image image)
{
_values[rowCol] = image;
AnimatedImage animatedImage;
if (!_animatedImages.TryGetValue(image, out animatedImage))
{
animatedImage = new AnimatedImage(image, _dataGridView);
_animatedImages[image] = animatedImage;
}
animatedImage.AddCell(rowCol);
}
private void RemoveImage(RowCol rowCol, Image image)
{
Debug.Assert(_values.ContainsKey(rowCol));
Debug.Assert(_animatedImages.ContainsKey(image));
_values.Remove(rowCol);
AnimatedImage animatedImage;
if (_animatedImages.TryGetValue(image, out animatedImage))
{
animatedImage.RemoveCell(rowCol);
if (!animatedImage.IsUsed)
{
_animatedImages.Remove(image);
}
}
}
private void CheckValue(int columnIndex, int rowIndex, object value)
{
RowCol rowCol = new RowCol(columnIndex, rowIndex);
// is the new value an Image, and can it be animated?
Image newImage = value as Image;
bool newValueIsImage = (newImage != null && ImageAnimator.CanAnimate(newImage));
// is there a previous image value?
Image oldImage;
if (_values.TryGetValue(rowCol, out oldImage))
{
if (newImage == oldImage)
{
// same old image --> nothing else to do
return;
}
RemoveImage(rowCol, oldImage);
}
if (newValueIsImage)
{
AddImage(rowCol, newImage);
}
}
}
}
Regards,
遵循@AseemGautam 的链接唯一答案,该链接指向另一个论坛中发布的相同问题,另一个链接仅答案链接到包含复杂项目的rar 文件,它归结为一个简单的答案。
直接从资源中包含图像不会播放其动画。因此,我们将图像包含在与网格相同形式的 1x1 像素图像中(此 1x1 图像不能隐藏在其他组件后面,否则动画将无法正常工作,希望 gif 文件中的 1 像素是透明的)。然后使用计时器每 60 毫秒(或 gif 动画中的最小帧持续时间)间隔使单元格无效。这很可能会导致图像闪烁,因此通过添加RowPostPaint
绘制 1 像素线的事件将同步单元格绘制。
void frmMain_Load(object sender, EventArgs e) {
DataGridView1.Rows.Clear();
DataGridView1.Rows.Add(PictureBox1.Image);
}
void Timer1_Tick(object sender, EventArgs e) {
if (DataGridView1.Rows.Count > 0) {
DataGridView1.Rows[0].Cells[0].Value = PictureBox1.Image;
DataGridView1.InvalidateCell(0, 0);
}
}
void DataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) {
e.Graphics.DrawLine(new Pen(SystemColors.ActiveBorder), 0, 0, 1, 1);
}