2013-03-07 78 views
1

我在用戶控件有一個OpenFileDialogPictureBox。爲了更好地理解這個問題,我會用幾句話來解釋這個用戶控件是如何工作的。用戶可以選擇要爲表單打開的圖像。該圖像的名稱保存在數據庫中,圖像的文件被複制到默認位置。當數據庫中保存了一些圖像時,當帶有圖片框控件的表單被加載時,它將被加載到圖片框中。如果用戶選擇另一個圖像並希望用新圖像保存表單,我有一種方法可以從我的默認位置刪除舊圖像文件,這就是問題發生的地方。.NET PictureBox的 - 如何確保資源被釋放

當我加載圖像,並嘗試保存新的,有時(事實上非常罕見),我得到一個錯誤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(); 

         } 

會處理這個問題,但還是有時會發生。而且因爲不是每次都要處理它,因爲在某些時候我可能會認爲我已經解決了這個問題,但實際上只是在一段時間內幸運的。

回答

1
MyImage = new Bitmap(openFileDialog1.FileName); 
    pictureBox1.Image = (Image)MyImage; 

是的,該代碼將鎖定文件。該鎖由GDI +創建的內存映射文件對象生成,可將文件的像素數據有效映射到內存中,而無需在分頁文件中分配空間。只要圖像顯示在圖片框中而不處理,您將無法刪除文件,鎖可以防止該情況發生。在刪除文件之前,您必須處理圖像並將圖像屬性設置爲空。

您可以防止文件通過使圖像的內存副本被鎖:

using (var temp = new Bitmap(openFileDialog1.FileName)) { 
     pictureBox1.Image = new Bitmap(temp); 
    } 

這是效率不高,當然,如果圖像是大要避免。並且要小心另一個進程實際上可能對該文件具有類似的鎖定。你無能爲力。

+0

謝謝,我很驚訝,這個問題沒有標準的解決方案。這似乎是許多人使用'PictureBox'的問題。 – Leron 2013-03-07 15:24:23

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; 
        } 
       } 
+0

事實上,我改變了我的代碼,因爲它是我從OP你提出什麼。看起來'use()'也允許這種行爲。實際上,從我讀過的內容中我明白,在使用()時,編譯過程中的'tyr-catch-finally'模塊被讀取爲'finally'子句中調用Dispose',這對我來說不是這樣的(!MYIMAGE = NULL):從多不同'如果 { MyImage.Dispose(); }' – Leron 2013-03-07 15:14:13

0

我以前有問題就是這樣,而且我發現,以確保資源被釋放,即使Dispose()之後,這真的只是標誌着對象的一種方式由垃圾收集器清除,通過使用GC.Collect()。我確信有一個更清潔的方式來處理資源處置,但運行GC.Collect()所需的時間不應妨礙您的計劃。

1

PictureBox這樣的一個主要困難是,因爲PictureBox無法知道它是否是圖像的唯一用戶,因此無法知道當它不再需要時是否應該處理該圖像它。

因此,無論代碼擁有圖片框還必須取得與其相關的圖像的所有權。有三種方法,我可以建議這樣做:

  • 創建一個從PictureBox哪些文件本身假設給它的任何圖像的所有權派生的控件。這樣的控制或許應該替換爲SetImageWithOwnership方法圖像屬性(與曾經的圖像傳遞給PictureOwningBox語義,盒子將有望「擁有」它,並且將其丟棄既可以當盒子Dispose d或當給框賦予不同的圖像時)。

  • 將事件處理程序附加到PictureBox以處理方框,其中方框被銷燬或爲其分配不同的圖像。

  • 有無這將導致PictureBox爲設置或具有不同的圖像加載,還配置已被分配給它的Image任何代碼。

雖然可能有情況下,這將是適當的調用GC.Collect,讓垃圾收集照顧的東西,這樣的做法是不合理的一般。