结论(前):
会引发错误。
结论前置,希望有赞。
导入:
PictureBox控件是winform的常用控件,使用简单易懂。但是如果面临诸如显示图像采集设备的图像这类不断刷新图像的情况,该控件的行为可能需要进一步的探讨,比如,为PictureBox设置图像后,原图像对象是否可以立即进行释放?本文通过实验证明不能立即释放,控件会持有着图片的引用,并在一定情况下会再次通过引用使用图像。
测试过程:
建立窗体程序,将下面的功能以按钮形式提供出来
- 执行一些能触发刷新图像显示的功能
- 修改SizeMode
- 用pictureBox1.Image本身设置pictureBox1.Image
- 将被设置到控件的图像对象内容进行修改
- 为原图添加了一些横线
- 释放源图像
- 直接调用原图的Dispose()
建立了如图所示的窗体
假设:遇到需要刷新的情况时,控件刷新控件时,采用的不是传入图像的副本,而是传入图像的引用
验证方式:
- 修改源图像的内容,尝试各种方式引发刷新,查看图像是否变化。
- 待图像被显示后,释放源图像对象,尝试使用各种方式引发刷新,查看程序是否报错。
实验1现象:点击"修改源图像"后,不论是点击"做一些事"、点击"img=img"、使窗口最小化再恢复,都会观察到图像发生了变化。
实验2现象:点击"释放源图像"后不会立即报错,如果点击"做一些事"、点击"img=img"或使窗口最小化再恢复,程序都会报错,同时,程序报错的位置不在这些行为的代码本身,而是在窗体循环中抛出错误。即Program.Main()的Application.Run(new Form1())中报错。若项目结构较为复杂,这种错误将难以定位来源。
实验1 图:
实验2 图:
结论:
PictureBox控件使用的是外部图像的引用,并在需要的时候通过引用再访问图像对象。
如果进行了相关图像的释放,将使程序产生难以定位的错误。
此外,结合工作经验推论,如果在不合理的时机修改图像(比如在多线程环境的图像队列中重新为图像设置新的内容),也可能产生错误,winform为了防止图像的多线程读取修改冲突,可能会抛出错误。
附代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace TestForPicBox { public partial class Form1 : Form { Bitmap bmp; public Form1() { InitializeComponent(); bmp = Image.FromFile(@"ImgFolder/tstpic.png") as Bitmap; pictureBox1.Image = bmp; } private void btnDisp_Click(object sender, EventArgs e) { bmp.Dispose(); } private void btnDoSth_Click(object sender, EventArgs e) { PictureBoxSizeMode picMod = pictureBox1.SizeMode; picMod = (PictureBoxSizeMode)(((int)picMod + 1) % 5); pictureBox1.SizeMode = picMod; } int editSite = 0; private void btnEditSource_Click(object sender, EventArgs e) { using (var g = Graphics.FromImage(bmp)) { g.DrawLine(Pens.DeepSkyBlue, new Point(0, editSite * 5), new Point(bmp.Width, editSite * 5)); editSite++; } } private void btnImgSelfSet_Click(object sender, EventArgs e) { pictureBox1.Image = pictureBox1.Image; } } }