3

I have four PictureBoxes (each PictureBox represents one dice) and a Timer that changes every 100ms source pictures (loaded in memory as List<Bitmap> imagesLoadedFromIncludedResources).

enter image description here

Code:

private List<PictureBox> dices = new List<PictureBox>();

private void timer_diceImageChanger_Tick(object sender, EventArgs e)
{
    foreach (PictureBox onePictureBox in dices)
    {
        oneDice.WaitOnLoad = false;
        onePictureBox.Image = //... ;
        oneDice.Refresh();
    }
}  

I need to change all the images at once - at this moment, you can see that the images are changing from left to right with a small delay.

I tried variant with one Thread for each PictureBox (using Control.Invoke method from this answer) - it is visually little better but not perfect.

Community
  • 1
  • 1
illagrenan
  • 6,033
  • 2
  • 54
  • 66

3 Answers3

4

You can try to suspend form's layout logic:

SuspendLayout();
// set images to pictureboxes
ResumeLayout(false);
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
0
Parallel.ForEach
(
    dices,
    new ParallelOptions { MaxDegreeOfParallelism = 4 },
    (dice) =>
    {
        dice.Image = ...;
        dice.WaitOnLoad = false;
        dice.Refresh();
    }
);

The problem is that UI controls can only be accessed from the UI thread. If you want to use this approach, you must create a copy of your PictureBoxes and then replace the UI ones once the operation is done.

Another approach would be creating two PictureBoxes, with the first one just on the top of the other one (hiding the latter)... you change all the images and then, once the processing is complete, you iterate all the ones in the back putting them on the top which would result in a lesser delay.

Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
0

I'd approach this differently - it's been a while since I've played with WinForms stuff, but I'd probably take more control over the rendering of the images.

In this example I've got the images all in one source bitmap stacked vertically, stored as a resource in assembly:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private Timer timer;

        private Bitmap dice;

        private int[] currentValues = new int[6];

        private Random random = new Random();

        public Form1()
        {
            InitializeComponent();
            this.timer = new Timer();
            this.timer.Interval = 500;
            this.timer.Tick += TimerOnTick;

            this.dice = Properties.Resources.Dice;
        }

        private void TimerOnTick(object sender, EventArgs eventArgs)
        {
            for (var i = 0; i < currentValues.Length; i++)
            {
                this.currentValues[i] = this.random.Next(1, 7);
            }

            this.panel1.Invalidate();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (this.timer.Enabled)
            {
                this.timer.Stop();
            }
            else
            {
                this.timer.Start();
            }
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(Color.White);

            if (this.timer.Enabled)
            {
                for (var i = 0; i < currentValues.Length; i++)
                {
                    e.Graphics.DrawImage(this.dice, new Rectangle(i * 70, 0, 60, 60), 0, (currentValues[i] - 1) * 60, 60, 60, GraphicsUnit.Pixel);
                }
            }
        }
    }
}

The source is here if it helps: http://sdrv.ms/Wx2Ets

Mike Goatly
  • 7,380
  • 2
  • 32
  • 33