2015-12-16 34 views
4

我有兩個項目的解決方案。 在一個庫項目中,我添加了一個公共靜態布爾變量,並將其設置爲true。 然後在Windows窗體項目中,我使用了該標誌。 在Windows窗體項目設計師我添加了一個定時器設置它的間隔爲1000.爲什麼有時在計時器滴答事件中它連續兩次調用該方法?

我在構造函數中啓動計時器。 然後在計時器滴答即使我做:

private void timer1_Tick(object sender, EventArgs e) 
{ 
    if (SDKHandler.Saved == true) 
    { 
     timer1.Stop(); 
     DisplayLastTakenPhoto(); 
     TakePhotoButton.Enabled = true; 
     SDKHandler.Saved = false; 
     timer1.Start(); 
    } 
} 

而且DisplayLastTakenPhoto()方法

private void DisplayLastTakenPhoto() 
{ 
    string mypath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "RemotePhoto"); 
    var directory = new DirectoryInfo(mypath); 
    var myFile = directory.EnumerateFiles() 
     .Where(f => f.Extension.Equals(".jpg", StringComparison.CurrentCultureIgnoreCase) || f.Extension.Equals("raw", StringComparison.CurrentCultureIgnoreCase)) 
     .OrderByDescending(f => f.LastWriteTime) 
     .First(); 

    if (WaitForFile(myFile.FullName) == true) LiveViewPicBox.Load(myFile.FullName); 
} 

而且WaitForFile方法

bool WaitForFile(string fullPath) 
{ 
    int numTries = 0; 
    while (true) 
    { 
     ++numTries; 
     try 
     { 
      using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None, 100)) 
      { 
       fs.ReadByte(); 
       break; 
      } 
     } 
     catch (Exception ex) 
     { 
      if (numTries > 10) 
      { 
       return false; 
      } 
      System.Threading.Thread.Sleep(500); 
     } 
    } 
    return true; 
} 

Somtimes不是所有的時間,但在某些情況下,當它調用DisplayLastTakenPhoto()方法時;連續兩次。即使我先停下了計時器,我正在做timer1.Stop();但仍然在某些情況下,我看到了兩次調用的方法。

第二次,它使程序掛起/凍結有時甚至1-3秒。

+0

它是什麼樣的計時器?它看起來像一個表格計時器? – Equalsk

+0

Equalsk它是。這是Windows窗體計時器,我把它從設計器的工具箱中拖出來。 –

+0

在它上面放置一個斷點,看看它爲什麼被調用兩次。 – Ben

回答

2

你看到的是完全正常的。那一秒鐘快完成真的,尤其是你調試的時候。然後你的代碼會嘗試再次加載相同的圖像文件。除此之外,您的WaitForFile()將失敗,並將您的UI掛起五秒鐘。由於文件被鎖定,PictureBox.Load()會對圖像文件進行鎖定。由Image類使用的內存映射文件生成,這是一種非常有效的方法,可以使頁面文件中的圖像像素數據保持不變。但相當臭名昭着的生產難以診斷的圖像文件操作失敗:)

你需要改善你的代碼,不要試圖加載同一個文件兩次。只需使用存儲最後使用路徑的變量即可完成。並保持超時更適度,5秒是相當長的時間來掛用戶界面,最多一秒是合理的。另外請注意,你根本不需要超時。由於計時器確保您在一秒鐘後再次嘗試。

文件鎖定很容易避免順便說一句,位圖(圖像)構造函數可以完成該作業,它會進行深層複製並允許您處理源圖像。但不是在這種情況下解決問題的正確方法。

您可以通過使用FileSystemWatcher而不是使用定時器輪詢來進一步改進它。然而,您將再次遇到完全相同的鎖定問題,該文件在FSW事件觸發的時刻非常少見,因爲無論寫入文件的過程是否尚未關閉。這一切都可以解決,只要你知道這可能發生。

+0

漢斯我還沒有解決它,但我試圖。你的意思是什麼5秒超時?在我的代碼中,我使用了5秒的超時時間?謝謝。 –

+1

您的WaitForFile()方法調用Thread.Sleep(500)十次。不要這樣做。只是不要循環,這是沒有必要的。 –

+0

Hans ok我完全刪除了循環。也刪除不使用睡眠(500),我還添加了一個檢查,所以它不會加載相同的文件兩次。有時當我使用一個斷點時,我會在計時器滴答事件中看到它調用方法DisplayLastTakenPhoto();現在連續兩次,所以現在有時程序會暫停1-2秒,而不是像以前那樣。我還應該做什麼? –

2

檢查備註和注意事項MSDN documentation。很可能這會導致您觀察到的行爲:

調用在通過調用Stop禁用定時器後啓動將導致定時器重新啓動中斷的間隔。如果您的計時器設置爲5000毫秒間隔,並且在3000毫秒左右的時間內調用停止,則調用開始將導致計時器等待5000毫秒,然後引發滴答事件。

在Windows窗體應用程序中的任何Timer上調用Stop可能會導致應用程序中其他Timer組件的消息立即被處理,因爲所有Timer組件都在主應用程序線程上運行。如果您有兩個Timer組件,一個設置爲700毫秒,一個設置爲500毫秒,並且您在第一個Timer上調用Stop,則應用程序可能會首先收到第二個組件的事件回調。

當應用程序暫時凍結以檢查究竟發生了什麼時,您也可以在調試器中暫停。

+0

你能解釋爲什麼這可能導致行爲?據我瞭解,第1段不會導致這被稱爲兩次,但只是增加下一個事件的等待時間。 第二段聽起來有關,但要求有多個計時器,但OP沒有提及。 – steinar

相關問題