图片被另一个进程使用(layoutpanel)

picture is used by another process (layoutpanel)

所以我用图像填充浮动布局面板,代码如下:

    private void FillPanel(string sql)
    {
        panel.Controls.Clear();

        SQLiteConnection dbConnect = new SQLiteConnection("Data Source=" + dbFullPath + ";Version=3;");
        dbConnect.Open();

        SQLiteCommand runQuery = new SQLiteCommand(sql, dbConnect);
        SQLiteDataReader reader = runQuery.ExecuteReader();

        while (reader.Read())
        {              
            PictureBox pB = new PictureBox();
            pB.Image = Image.FromFile(reader["imgPath"].ToString());
            pB.Size = new Size(100, 100);
            pB.SizeMode = PictureBoxSizeMode.StretchImage;
            pB.Padding = new Padding();
            pB.Margin = new Padding(5,5,5,5);
            pB.Name = reader["name"].ToString();
            toolTip_Main.SetToolTip(pB, pB.Name);

            pB.DoubleClick += img_DoubleClick;

            panel.Controls.Add(pB);
        }
        dbConnect.Close();

    }

如果我稍后尝试删除源图片,我会收到一条错误消息。

"image.png is used by another process"

要删除图像,我使用以下代码:

     private void Delete()
    {
            foreach (Control x in panel.Controls)
            {
                if (x is PictureBox)
                {
                    PictureBox pb = x as PictureBox;
                    string name = pb.Name;

                    DirectoryInfo pF = new DirectoryInfo(pictureFolder);
                    foreach (FileInfo file in pF.GetFiles())
                    {
                        if(file.Name == name+".png")
                        {
                            pb.InitialImage = null;
                            pb.Dispose();
                            file.Delete();
                            break;
                        }
                    }
                }
            }
     }

如果我没有用图片填充面板,我可以删除它们。 我只是不知道在 'initialimage = null' & .dispose 旁边我还能做些什么来摆脱面板内的图像。

但他们似乎在某个地方出现了鬼影。

对此有什么想法吗?

打开图像时要记住的基本规则如下:

(如果你想知道,Image.FromFile(String filename) 实际上只是 new Bitmap(String filename) 构造函数的包装器。我个人建议不要使用 Image.FromFile,因为它失去了更精确的 Bitmap 返回对象的类型。)


至于你的问题,似乎处理 PictureBox 并没有处理实际图像。这可能可以通过首先显式处理 pb.Image 来解决:

Image img = pb.Image;
// Needs to happen in this order so the UI will never try to paint the disposed image
pb.Image = null;
if (img != null)
    img.Dispose();
file.Delete();
break;

请注意,放置实际图像框可能会导致问题;您应该首先将其从其父控件中删除,这样它就不再显示在 UI 上,否则您的表单将开始抛出 "object disposed" 异常,因为它试图绘制的控件之一无效。


解决锁定问题的另一种方法是从磁盘读取位图,使用 new Bitmap(Image image) 构造函数从中创建一个新位图,然后处理从文件初始化的位图对象。最好的方法是使用 using 指令,如下所示:

using (Bitmap im = new Bitmap(reader["imgPath"].ToString()))
    pB.Image = new Bitmap(im);

通常,您应该始终清理您创建的图像对象。请注意,这实际上是在新的 32bppARGB 图像上绘制图像,从而丢失图像的任何原始格式。尽管在您的情况下我认为这无关紧要,因为它只是为了在 UI 上显示。 (请注意,如果您确实需要一个完整的 1:1 图像数据克隆而没有任何流或文件链接,有一些方法可以做到这一点,但是 they're slightly more advanced。)