为什么我的表格没有锁定?

时间:2014-09-18 18:28:13

标签: c# .net winforms

在从另一个问题中阅读this answer时,我100%确定以下代码会锁定用户界面并且不会导致任何移动。

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);
    }
}

我和评论中的其他几位人士表示不会有效,但OP坚持认为它确实如此,我们应该尝试。我最终创建了一个新的Winforms项目,添加了一个按钮,然后将上面的代码放在事件处理程序中进行单击,表单确实发生了变化。

当此方法阻止消息泵时表单是如何移动的,OnPaint不应该在表单上调用,也不能在其任何子控件上调用,这是如何工作的?

2 个答案:

答案 0 :(得分:10)

Aero做到这一点。 Windows不再直接渲染到视频帧缓冲区,它们渲染到内存中。想想“位图”。然后DWM过程合成这些位图并将它们blits到缓冲区。这解决了许多窗口绘画文物,最臭名昭着的可能就是当你将一个窗口移到另一个窗口时留下的“痕迹”。无论底层窗口拥有什么进程都必须赶上并重新绘制显示的像素。这需要时间和未上漆的像素可见。还允许其他特殊效果,例如当您将鼠标悬停在任务栏按钮上时可以看到的实时缩略图,只需缩小该位图的副本即可。和Aero Peek,只是该位图的投影。和Vista和Win7中的玻璃。以及在Win8中显示商店应用程序的特殊“屏幕”。以及触摸屏幕时看到的可见标记。

并且影响此代码,窗口位置现在只是位图合成的不同位置。原始位图仍然完好无损,不需要重新绘制。

请勿在XP上或关闭Aero时尝试此操作。

答案 1 :(得分:1)

这可能是因为CoroutinesFibers

虽然线程是可由操作系统调度程序独立管理的最小程序指令序列,但协同程序可以存在于共享单个线程的应用程序中。这意味着一个例程可以在另一个例程执行时停止在其轨道中,然后在它停止的位置恢复,所有这些都在同一个线程内。

显然,当我们设置那些看似无害的属性this.Leftthis.Right时,幕后发生的事情远比我们想象的要多。

如果我们在问题的代码示例中添加一点日志记录,我们就可以看到这种情况发生了。另外 - 因为我已经删除了下面示例中的Thread.Sleep(75)次来电,并且在较早的时候添加了更长时间的睡眠 - 我们可以看到,这不是那些带来收益的睡眠其他功能,但是对this.Leftthis.Right的调用(此外,在没有睡眠的情况下仍会摇晃形式):

  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;

日志:

enter image description here