2013-10-12 58 views
0

我正在使用Visual Studio 2012來創建一個包含擴展Windows窗體TreeView窗體的類的.dll。我的自定義TreeView被稱爲FolderTreeView。在它的內部,我添加了一些我需要的私有字段,主要是包含DriveInfo和關聯的FileSystemWatcher的Tuple列表。.net自定義窗體甚至處理程序從不同線程調用並崩潰VS

 

foreach (var drive in DriveInfo.GetDrives()) 
      { 
       if (drive.IsReady == true) 
       { 
        FileSystemWatcher watcher = new FileSystemWatcher(drive.RootDirectory.FullName); 
        //_drives is List of Tuples 
        _drives.Add(new Tuple&ltDriveInfo, FileSystemWatcher>(drive, watcher)); 
        watcher.NotifyFilter = NotifyFilters.DirectoryName; 
        watcher.IncludeSubdirectories = true; 
        watcher.Created += new FileSystemEventHandler(FileSystemWatcher_OnCreated); 
        watcher.Changed += new FileSystemEventHandler(FileSystemWatcher_OnChange); 
        watcher.Deleted += new FileSystemEventHandler(FileSystemWatcher_OnDelete); 
        watcher.Renamed += new RenamedEventHandler(FileSystemWatcher_OnRename); 
        watcher.EnableRaisingEvents = true; 

        Nodes.Add(drive.RootDirectory.Name); 

       } 
      } 

此代碼會導致兩個問題,我懷疑這兩個問題都是偶處理程序。第一個問題是FileSystemWatcher的事件從另一個線程被調用,所以它會拋出異常,因爲不應允許其他線程訪問Windows窗體。

第二個問題是,如果我爲FileSystemWatcher設置了重命名事件處理程序的代碼沒有被註釋掉,並且我在Windows資源管理器中更改了文件夾名稱,Visual Studio崩潰了,我不知道爲什麼。我好像很可能是由重命名事件處理程序引起的。

我想首先解決線程問題,因爲可能會修復崩潰,除非有另外的原因可能發生。此外,處理所有Filesystem的東西和在不同類中構建節點會更好嗎,只需從該類中獲取一個節點並將其提供給常規TreeView?

編輯:我相信它與線程有關。當它崩潰時,我可以在Visual Studio的另一個實例中進行調試,並且在斷點處獲取空引用異常。這讓我有理由相信事件正在另一個線程中觸發,所以我的斷點沒有被它認爲應該在的線程觸發?

+0

這是正常的,這些事件在線程池線程上引發。導入,因爲需要快速處理事件以避免緩衝區溢出。當您在每個驅動器上聆聽每一個可能的文件更改時,您都會*需要這樣做。非常不明智的是,你甚至無法調用Control.BeginInvoke()來避免異常。 ConcurrentQueue是最低要求。 –

+0

@HansPassant爲TreeView中的每個展開的節點構造一個新的FileSystemWatcher並將IncludeSubDirectories設置爲false並僅監視可見節點會更好嗎?另外,我只監視目錄,如果這有助於緩衝大問題? – contrapsych

回答

1

在你的事件處理程序,如果你要處理的Windows窗體控件,你將需要檢查Form/Control.InvokeRequired,請參閱:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx

如果這是真的,那麼你是從不同的線程比叫UI線程。在這種情況下使用Form/Control.Invoke有事件排隊的UI線程上,請參閱:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invoke.aspx

參見:http://msdn.microsoft.com/en-us/library/ms171728(v=vs.85).aspx

0

InvokeRequired似乎運作良好,但我最近發現的另一種方式。 FileSystemWatcher有一個名爲SynchronizingObject的屬性。如果這被設置爲FolderTreeView,或者this,因爲它位於繼承該表單的類中,問題似乎也解決了。