我的代码仅在插入随机 MsgBox 时有效

My code only works when I insert a random MsgBox

我在尝试获取表单中 TableLayoutPanel 的屏幕截图时遇到了一个非常奇怪的问题。

我有这段代码(取自另一个问题 (How to get a screenshot, only for a picturebox);代码由用户 "Chase Rocker" 提供):

    Dim s As Size = TableLayoutPanel1.Size
    Dim memoryImage = New Bitmap(s.Width, s.Height)
    Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
    Dim ScreenPos As Point = Me.TableLayoutPanel1.PointToScreen(New Point(0, 0))
    memoryGraphics.CopyFromScreen(ScreenPos.X, ScreenPos.Y, 0, 0, s)
    Form3.PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
    Form3.PictureBox1.BringToFront()
    Form3.PictureBox1.Image = memoryImage

现在,我的问题来了。这段代码给了我一张空白图片。它显然截取了屏幕截图,但我只能看到白色。现在,我试图查看大小是否正确,所以我在搞乱 MsgBox。我将这一行添加到代码中:

    MsgBox("Random Message")

得到

    Dim s As Size = TableLayoutPanel1.Size
    MsgBox("Random Message")
    Dim memoryImage = New Bitmap(s.Width, s.Height)
    Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
    Dim ScreenPos As Point = Me.TableLayoutPanel1.PointToScreen(New Point(0, 0))
    memoryGraphics.CopyFromScreen(ScreenPos.X, ScreenPos.Y, 0, 0, s)
    Form3.PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
    Form3.PictureBox1.BringToFront()
    Form3.PictureBox1.Image = memoryImage

由于某种我不知道的原因,屏幕截图现在可以使用了。我不再看到白色,而是 TableLayoutPanel 的实际屏幕截图。对我来说,代码只适用于 MsgBox 是很奇怪的。也许我错过了什么。有谁知道为什么会这样?谢谢!

如果您尝试让 TableLayoutPanel 将其自身绘制到位图上呢?这可以使用 Control.DrawToBitmap() 方法来完成。

Dim s As Size = TableLayoutPanel1.Size
Dim memoryImage As New Bitmap(s.Width, s.Height)

TableLayoutPanel1.DrawToBitmap(memoryImage, New Rectangle(New Point(0, 0), s))
Form3.PictureBox1.Image = memoryImage

如果 TableLayoutPanel 填充发生在您抓取图像的同一事件处理程序中,则 Windows 没有为添加到 TableLayoutPanel 的元素绘制 UI。只有当你从事件处理程序中退出时,winforms 引擎才有机会绘制所有内容。

添加 MessageBox 会改变一切,因为调用 Show(一种模式调用会中断您的代码并将控制权交还给 window)允许 Winform 引擎绘制挂起的更新并且您的代码可以正常工作。

您可以添加一个Timer控件,将执行ScreenShoot的代码放在Timer事件中。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
   ......
   ' code that fills the TableLayoutPanel
   ......

   Dim tim1 = new System.Windows.Forms.Timer()
   tim1.Interval = 1
   AddHandler tim1.Tick, AddressOf tim1Ticked
   tim1.Start()
End Sub
Private Sub tim1Ticked(sender As Object, e As EventArgs)

    ......
    ' Code that execute the screenshoot.
    ......

    Dim t = DirectCast(sender, System.Windows.Forms.Timer)
    t.Stop()
End Sub