英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论