.gif не анимируется, пока не закончится весь цикл?

Я пытаюсь добавить 300 кнопок в winform во время выполнения с помощью цикла. Это занимает много времени, поэтому я хочу отображать загружаемое изображение .gif во время выполнения цикла. Загрузка.gif просто отображается, но не анимируется до тех пор, пока цикл не завершится. Это почему?

pictureBox1.Load("loading.gif");
pictureBox1.Invalidate();
pictureBox1.Update();

// loop to add buttons
this.SuspendLayout();
for (int i = 0; i < 300; i++)
    // add buttons
this.ResumeLayout();
this.PerformLayout();

person Fish    schedule 09.02.2015    source источник
comment
Если вы закомментируете код, который добавляет кнопки, анимируется ли GIF?   -  person Bijington    schedule 09.02.2015
comment
зачем тебе 300 кнопок? может есть лучшее решение?   -  person JeffRSon    schedule 09.02.2015
comment
@Bijington да, это оживит   -  person Fish    schedule 09.02.2015
comment
@JeffRson представляет собой шахматную доску, поэтому для игры мне нужно около 300 ячеек.   -  person Fish    schedule 09.02.2015
comment
вау, какая большая доска и даже не квадратная.. Я играю только на 64 полях. Рассмотрите возможность перехода на DataGridView!!   -  person TaW    schedule 09.02.2015


Ответы (2)


Цикл блокирует поток пользовательского интерфейса, поэтому pictureBox1 не обновляется. Есть несколько возможностей решить эту проблему:

Уродливый: время от времени используйте Application.DoEvents(); (т.е. не каждый раунд) в цикле создания кнопки.

Или вы можете создавать кнопки из таймера, 10 или 20 каждый раз, пока не получите 300.

Или вы можете использовать заставку на основе потока. Однако важно, чтобы все кнопки создавались потоком пользовательского интерфейса.

Или найдите лучшее решение, которое не требует 300 кнопок.

person JeffRSon    schedule 09.02.2015
comment
Application.DoEvents() действительно работает, большое спасибо - person Fish; 09.02.2015
comment
@Fish: DoEvents() на самом деле никогда не следовало даже предлагать, и это абсолютно худший способ решить проблему. :( - person Peter Duniho; 15.12.2020

События анимации можно обрабатывать вручную. Удивительно, но событие OnFrameChanged все еще срабатывает, что позволяет выполнять анимацию.

public class Form1 : Form {

    Button btn = new Button { Text = "Button", Dock = DockStyle.Top };
    AsyncPictureBox box = new AsyncPictureBox("c:\\temp\\chick_dance.gif") { Dock = DockStyle.Fill };

    public Form1() {
        Controls.Add(box);
        Controls.Add(btn);

        btn.Click += delegate {
            box.AnimateImage = !box.AnimateImage;
            Thread.Sleep(30000);
        };
    }
}

public class AsyncPictureBox : Control {

    Bitmap bitmap = null;
    bool currentlyAnimating = false;
    int frameCount = 0;
    int frame = 0;

    public AsyncPictureBox(String filename) {
        bitmap = new Bitmap(filename);
        this.DoubleBuffered = true;
        frameCount = bitmap.GetFrameCount(System.Drawing.Imaging.FrameDimension.Time);
    }

    public bool AnimateImage {
        get {
            return currentlyAnimating;
        }

        set {
            if (currentlyAnimating == value)
                return;

            currentlyAnimating = value;
            if (value)
                ImageAnimator.Animate(bitmap, OnFrameChanged);
            else
                ImageAnimator.StopAnimate(bitmap, OnFrameChanged);
        }
    }

    // even though the UI thread is busy, this event is still fired
    private void OnFrameChanged(object o, EventArgs e) {
        Graphics g = this.CreateGraphics();
        g.Clear(this.BackColor);
        bitmap.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Time, frame);
        frame = (frame + 1) % frameCount;
        g.DrawImage(bitmap, Point.Empty);
        g.Dispose();
    }

    protected override void Dispose(bool disposing) {
        base.Dispose(disposing);
        if (disposing) {
            if (bitmap != null)
                bitmap.Dispose();
            bitmap = null;
        }
    }
}
person Loathing    schedule 09.02.2015