我在用户控件中有OpenFileDialog
和PictureBox
。为了更好地理解这个问题,我将用几个词来解释这个用户控件是如何工作的。用户可以选择要为表单打开的图像。此图像的名称保存在DataBase中,图像文件将复制到默认位置。当数据库中保存了一些图像时,当加载带有图片框控件的表单时,它将加载到图片框中。如果用户选择另一个图像并想要使用新图像保存表单,我有一个方法,它会从我的默认位置删除旧图像文件,这就是问题发生的地方。
当我加载图像并尝试保存新图像时,有时(实际上非常罕见)我收到错误The resource is being used by another process..
如果需要,我可以粘贴确切的错误。我认为问题是由图片框及其处理图像的方式引起的。
这是我的代码:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
if (MyImage != null)
{
MyImage.Dispose();
}
selectedFile = openFileDialog1.FileName;
selectedFileName = openFileDialog1.SafeFileName;
MyImage = new Bitmap(openFileDialog1.FileName);
pictureBox1.Image = (Image)MyImage;
int imageWidth = pictureBox1.Image.Width;
int picBoxWidth = pictureBox1.Width;
if (imageWidth != 0 && picBoxWidth > imageWidth)
{
pictureBox1.Width = imageWidth;
}
else
{
pictureBox1.Width = defaultPicBoxWidth;
}
}
catch (Exception ex)
{
logger.Error(ex.ToString());
MessageBox.Show("Error loading image!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
和我的删除方法:
public void DeleteImage(AppConfig imageInfo, string imageName)
{
string imgPath = imageInfo.ConfigValue.ToString();
try
{
File.Delete(imgPath + "\\" + imageName);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
我想:
if (MyImage != null)
{
MyImage.Dispose();
}
将处理此问题,但有时仍会发生。并且因为它不是每次都处理它更为重要因为在某些时候我可能会认为我已经解决了它,但事实上它只是幸运了一段时间。
答案 0 :(得分:2)
MyImage = new Bitmap(openFileDialog1.FileName);
pictureBox1.Image = (Image)MyImage;
是的,该代码会锁定文件。锁由GDI +创建的内存映射文件对象生成,以有效地将文件的像素数据映射到内存中,而不必在页面文件中分配空间。只要图像显示在图片框中而不处理,您将无法删除该文件,锁定会阻止该文件。在删除文件之前,必须先处理图像并将Image属性设置为null。
您可以通过制作图像的内存副本来阻止文件被锁定:
using (var temp = new Bitmap(openFileDialog1.FileName)) {
pictureBox1.Image = new Bitmap(temp);
}
当然,如果图像很大,要避免这种效率。并且要注意另一个进程实际上可能对文件具有类似的锁定。你无能为力。
答案 1 :(得分:1)
像PictureBox
这样的事情的主要困难在于,因为PictureBox
无法知道它是否是图像的唯一用户,因此它无法知道是否应该处理那个图像不再需要它时。
因此,无论拥有图片框的代码还必须拥有与其相关联的图像的所有权。我可以建议采用三种方法:
创建一个派生自PictureBox
的控件,该控件将自身记录为假设所有图像的所有权。这样的控件可能应该用SetImageWithOwnership
方法替换image属性(使用语义,一旦图像传递给PictureOwningBox
,该框将被期望“拥有”它,并将处置它当框是Dispose
d或时,框中会显示不同的图像。
将事件处理程序附加到PictureBox
以处理框被销毁或分配了不同图像的情况。
有任何会导致PictureBox
被处理或加载了不同图片的代码,也会处理已分配给它的Image
。
虽然可能存在调用GC.Collect
并让垃圾收集器处理事情的情况,但这种方法通常是不合理的。
答案 2 :(得分:0)
试试:
using(Bitmap MyImage = new Bitmap(openFileDialog1.FileName))
{
pictureBox1.Image = (Image)MyImage;
int imageWidth = pictureBox1.Image.Width;
int picBoxWidth = pictureBox1.Width;
if (imageWidth != 0 && picBoxWidth > imageWidth)
{
pictureBox1.Width = imageWidth;
}
else
{
pictureBox1.Width = defaultPicBoxWidth;
}
}
答案 3 :(得分:0)
我之前遇到过这样的问题,并且我发现了一种确保资源被释放的方法,即使在Dispose()
之后,它实际上只标记了垃圾收集器要删除的对象,是使用GC.Collect()
。我确信有一种更简洁的方法来处理资源处理,但GC.Collect()
运行所需的时间不应该妨碍您的程序。