Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my form NOT lock up?

Tags:

c#

.net

winforms

While reading this answer from another question I was 100% sure that the following code would lock up the UI and not cause any movement.

private void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 5; i++)
    {
        this.Left += 10;
        System.Threading.Thread.Sleep(75);
        this.Left -= 10;
        System.Threading.Thread.Sleep(75);
    }
}

I and several others in the comments said it would not work but the OP insisted that it did and we should try. I ended up making a new Winforms project, adding a button, then putting the above code in the event handler for click and the form did indeed shake.

How is the form moving when the message pump is being blocked by this method, OnPaint should not be able to be called on the form nor any of its child controls, how is this working?

like image 971
Scott Chamberlain Avatar asked Sep 18 '14 18:09

Scott Chamberlain


2 Answers

Aero does this. Windows don't render straight to the video frame buffer anymore, they render to memory. Think "bitmap". The DWM process then composites these bitmaps and blits them to the buffer. This solves a number of window painting artifacts, the most infamous one was probably the "trail" you'd leave behind when moving one window across another. Whatever process owned the bottom window had to catch up and repaint the revealed pixels. That takes time and the unpainted pixels where visible. Also allows for other special effects, like the live thumbnails you can see when you hover over a taskbar button, simply a copy of that bitmap shrunk to fit. And Aero Peek, just a projection of that bitmap. And glass in Vista and Win7. And the special "screen" where Store apps are displayed in Win8. And the visible marks you see when you touch the screen.

And affects this code as well, the window position is now simply a different location where the bitmap is composited. The original bitmap is still intact and doesn't require repainting.

Don't try this on XP or with Aero turned off.

like image 95
Hans Passant Avatar answered Oct 29 '22 16:10

Hans Passant


This is possible because of Coroutines and Fibers.

Although a thread is the smallest sequence of programmed instructions that can be managed independently by the operating system scheduler, coroutines can exist within an application that share a single thread. This means that one routine can stop in its tracks while another executes, and then resume at the point where it left off, all within the same thread.

Evidently there is far more happening under the covers than we would have imagined when we set those seemingly innocuous properties this.Left and this.Right.

And we can see this happening, if we add a little logging to the code example from the question. Also—since I've removed the Thread.Sleep(75) calls in my example below, and added a longer sleep at an earlier point—we can see that it's not those sleeps that bring about the yield to the other function, but the calls to this.Left and this.Right (which, moreover, still shake the form without the sleep):

  protected override void WndProc(ref Message m)
  {
      if (_logWndProc)
          listBox1.Items.Add(string.Format("WndProc on thread {0}", Thread.CurrentThread.ManagedThreadId));

      base.WndProc(ref m);
  }

  private void button1_Click(object sender, EventArgs e)
  {
      listBox1.Items.Clear();
      _logWndProc = true;
      Thread.Sleep(2000);
      listBox1.Items.Add(string.Format("After sleep on thread {0} (see any WndProc logs before this line?!!!)", Thread.CurrentThread.ManagedThreadId));

      for (int i = 0; i < 5; i++)
      {
          listBox1.Items.Add(string.Format("Right {0} on thread {1}", i, Thread.CurrentThread.ManagedThreadId));
          this.Left += 10;
          listBox1.Items.Add(string.Format("Left {0} on thread {1}", i, Thread.CurrentThread.ManagedThreadId));
          this.Left -= 10;
      }

      _logWndProc = false;
  }

  private bool _logWndProc = false;

The log:

enter image description here

like image 40
Reg Edit Avatar answered Oct 29 '22 16:10

Reg Edit