Picturebox在将MetaFile分配给图像时抛出“参数无效”的错误。

huangapple go评论57阅读模式
英文:

Picturebox throws "Argument is not valid" when assigning a MetaFile to an image

问题

.Net 4.7.2. Winforms.

渲染一个充满文本和图形的复杂页面。我使用了一个位图(Bitmap)。然后,通过调整PictureBox的大小并将PictureBox放置到一个可滚动的面板中,将其显示在预览窗口中。

对于Bitmap,这个方法完美运行,但当然会占用2GB的内存。所以现在我尝试转向MetaFile以节省内存,并希望能够创建可伸缩的东西。然而,当我这样做时,预览代码会在Width.GET上爆发“参数无效”的异常。这发生在预览窗口的ShowDialog上。
我已经确认Metafile没有被意外释放。它仍然存在并作为按引用传递到预览窗口中的参数。

以下是代码:

' 在按钮事件处理程序中创建文件
Dim gr As Graphics = Me.CreateGraphics()
Dim hdc As IntPtr = gr.GetHdc()
' [剪切不相关的代码]
Try
' [剪切不相关的代码]
' [pagewidth和pageheight是纸张大小(以英寸为单位)*选择的DPI = 像素]
_pedWMF = New Metafile(hdc,
New Rectangle(0, 0, pageWidth, pageHeight),
MetafileFrameUnit.Pixel)
_PedigreeCanvas = Graphics.FromImage(_pedWMF)
_PedigreeCanvas.PageUnit = GraphicsUnit.Pixel

' [剪切不相关的代码]
' 在此调用中渲染文本和图像
RenderPedigree(PedigreeCanvas)
' [剪切不相关的代码]
' 调用预览窗口以显示对话框。

以下是预览中的代码...

Private Sub LayoutPreviewImage()
_iPageWidth = Convert.ToInt32(Me.DeviceDpi * (Convert.ToDouble(_drvPaperSize("PS_WIDTH")) / 100))
_iPageHeight = Convert.ToInt32(Me.DeviceDpi * (Convert.ToDouble(_drvPaperSize("PS_HEIGHT")) / 100))
SuspendLayout()
Dim p As New PictureBox()
p.Name = "pbPreview"
p.Width = _iPageWidth
p.Height = _iPageHeight
'*** _wmfPreview变量已经正确初始化为上面创建的Metafile。
If _wmfPreview IsNot Nothing Then p.Image = _wmfPreview
p.SizeMode = PictureBoxSizeMode.Zoom
pPagePreview.Controls.Add(p)
pPagePreview.Location = New Point(0, 0)
pPagePreview.Width = _iPageWidth + Convert.ToInt32(Math.Round(DeviceDpi * 0.5))
pPagePreview.Height = _iPageHeight + Convert.ToInt32(Math.Round(DeviceDpi * 0.5))
p.Left = Convert.ToInt32(Math.Round(DeviceDpi * 0.25))
p.Top = Convert.ToInt32(Math.Round(DeviceDpi * 0.25))
p.BackColor = Color.White
ResumeLayout()
End Sub

然后,当我调用showDialog()时,就会出现异常。

如果我在调试器中查看,MetaFile会抛出宽度和高度以及许多其他属性的异常。我知道我编写了一些严重错误的代码,但我无法弄清楚是什么。我过去使用Delphi很容易做到这一点。我漏掉了什么,请帮我找出。

谢谢任何帮助。

英文:

.Net 4.7.2. Winforms.

Rendering a complex page full of text and graphics. I used a Bitmap. I then show it in a preview window by sizing a PictureBox and placing the picturebox into a panel that scrolls.

It works perfectly to a Bitmap, except of course for the 2GB of RAM it takes. So now I'm trying to go to a MetaFile to save RAM and hopefully make something scalable. However when I do this the preview code blows up with "Parameter is not valid" on Width.GET. This happens on ShowDialog for the Preview window.
I verified that the Metafile was not accidentally disposed. It's still there and passed into the preview window as a byref parameter.

Here is the code:

    ' In the button event handler to create the file
    Dim gr As Graphics = Me.CreateGraphics()
    Dim hdc As IntPtr = gr.GetHdc()
    ' [snip irrelevant code]
    Try
        ' [snip irrelevant code]
        ' [pagewidth and pageheight are paper size in inches * DPI chosen = pixels]
        _pedWMF = New Metafile(hdc, 
                               New Rectangle(0, 0, pageWidth, pageHeight), 
                               MetafileFrameUnit.Pixel)
        _PedigreeCanvas = Graphics.FromImage(_pedWMF)
        _PedigreeCanvas.PageUnit = GraphicsUnit.Pixel

    ' [snip irrelevant code]
    ' Text and images rendered in this call
    RenderPedigree(PedigreeCanvas)
    ' [snip irrelevant code]
    ' Call to preview window to show dialog.

Here is the code in the Preview...

Private Sub LayoutPreviewImage()
    _iPageWidth = Convert.ToInt32(Me.DeviceDpi * (Convert.ToDouble(_drvPaperSize("PS_WIDTH")) / 100))
    _iPageHeight = Convert.ToInt32(Me.DeviceDpi * (Convert.ToDouble(_drvPaperSize("PS_HEIGHT")) / 100))
    SuspendLayout()
    Dim p As New PictureBox()
    p.Name = "pbPreview"
    p.Width = _iPageWidth
    p.Height = _iPageHeight
    '*** The _wmfPreview variable is properly initialized with the Metafile created above.
    If _wmfPreview IsNot Nothing Then p.Image = _wmfPreview
    p.SizeMode = PictureBoxSizeMode.Zoom
    pPagePreview.Controls.Add(p)
    pPagePreview.Location = New Point(0, 0)
    pPagePreview.Width = _iPageWidth + Convert.ToInt32(Math.Round(DeviceDpi * 0.5))
    pPagePreview.Height = _iPageHeight + Convert.ToInt32(Math.Round(DeviceDpi * 0.5))
    p.Left = Convert.ToInt32(Math.Round(DeviceDpi * 0.25))
    p.Top = Convert.ToInt32(Math.Round(DeviceDpi * 0.25))
    p.BackColor = Color.White
    ResumeLayout()
End Sub

Then when I showDialog(), I get the exception.

If I look in the debugger, the MetaFile throws exceptions for width and height and numerous other properties. I know I have something woefully improperly coded, but I cannot figure out what. I used to easily do this with Delphi back in the day. I am missing something; please help me to find it.

Thanks for any help.

答案1

得分: 0

好的,找到答案了。并非在MS文档中,而是在另一个Stack Overflow的答案中。

每当你完成对Graphics对象的操作来绘制到Metafile中,然后你需要Flush和/或Dispose该Graphics对象,以将这些更改提交到MetaFile中。像这样:

        RenderPedigree(PedigreeCanvas, PedigreeCanvas)
        PedigreeCanvas.Flush()
        PedigreeCanvas.Dispose()
        PedigreeCanvas = Nothing

这样就可以了。

英文:

OK, the answer was found. Not in the MS Documentation but in a different Stack Overflow answer.

Whenever you finish working on a Graphics object to draw into a Metafile, you then need to Flush and or Dispose the Graphics object to commit those changes into the MetaFile. Like so:

        RenderPedigree(PedigreeCanvas, PedigreeCanvas)
        PedigreeCanvas.Flush()
        PedigreeCanvas.Dispose()
        PedigreeCanvas = Nothing

That will do the trick.

huangapple
  • 本文由 发表于 2023年6月22日 05:44:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76527354.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定