2

我有一个OpenFileDialogPictureBox用户控制。为了更好地理解这个问题,我将用几句话解释这个用户控件是如何工作的。用户可以选择要为表单打开的图像。该图像的名称保存在数据库中,并且该图像的文件被复制到默认位置。当数据库中保存了一些图像时,它会在加载带有图片框控件的表单时加载到图片框中。如果用户选择另一个图像并想用新图像保存表单,我有一个方法可以从我的默认位置删除旧图像文件,这就是问题发生的地方。

当我加载图像并尝试保存新图像时,有时(实际上非​​常罕见)我会收到一个错误,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();

                        }

将处理此问题,但有时仍会发生。而且因为不是每次都更重要的是要处理它,因为在某些时候我可能会决定我已经解决了它,但实际上只是幸运一段时间。

4

4 回答 4

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);
    }

当然,如果图像很大,则应避免使用它。并且请注意另一个进程实际上可能对文件有类似的锁定。对此你无能为力。

于 2013-03-07T15:12:26.077 回答
1

像这样的事情的一个主要困难PictureBox是,因为 aPictureBox无法知道它是否是图像的唯一用户,因此它无法知道它是否应该在不再需要该图像时处理该图像。

因此,任何拥有图片框的代码也必须拥有与之相关的图像的所有权。我可以建议这样做三种方法:

  • 创建一个控件,该控件派生自PictureBox该文档本身,并假定其拥有任何图像的所有权。这样的控件可能应该用一种方法替换 image 属性(其语义是,一旦SetImageWithOwnership图像传递给图像被赋予盒子)。PictureOwningBoxDispose

  • 将事件处理程序附加到 aPictureBox以处理盒子被破坏或分配给它的不同图像的情况。

  • 有任何代码会导致PictureBox处理或加载不同的图像,也处理Image分配给它的。

虽然在某些情况下调用GC.Collect并让垃圾收集器处理事情是合适的,但这种方法通常是不合理的。

于 2013-03-07T16:51:33.623 回答
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;
                  }
                }
于 2013-03-07T15:09:29.970 回答
0

我以前遇到过这样的问题,我发现确保资源被释放的一种方法Dispose()是使用GC.Collect(). 我确信有一种更清洁的方法来处理资源处理,但是GC.Collect()运行所需的时间不应妨碍您的程序。

于 2013-03-07T15:10:01.777 回答