2017-04-04 65 views
2

在我的Windows窗體應用程序中,如果其中一個項目被點擊,我必須打開一個具有特定文件夾的新資源管理器窗口。我聽的MouseUp事件(因爲我已經有了一定的命中檢測,我需要點擊座標)現在,如果我通過當使用Process.Start()時,WindowsForm MouseUp觸發兩次()

private void listView1_MouseUp(object sender, MouseEventArgs e) 
    { 
     Process.Start(@"C:\"); 
    } 
它打開資源管理器窗口的兩倍

打開一個新的瀏覽器窗口。它明確地與Process.Start(@"C:\");有關,因爲當我將該行切換到正常的控制檯輸出時,它只執行一次。

是否有某種方法將事件標記爲已處理或僅忽略第二次執行?

+0

嘗試單步執行代碼並查看它是否運行了代碼兩次? –

+0

嗨巴厘島C,只是試過。如果我只有一個Console.WriteLine(e.Button);我得到了兩次輸出。如果我在方法內部設置斷點而不是隻執行一次。也許焦點轉移到新打開的資源管理器窗口,並返回非常快?但這只是猜測。 – MatzeBrei

+0

嗯,奇怪。您是否嘗試過使用MouseClick事件而不是MouseUp,只是一個念頭... –

回答

5

這是一個重入錯誤,與您在代碼中使用DoEvents()時獲得的錯誤類型非常相似。但是這種情況下,這個bug被嵌入到操作系統中。這個問題的助手是資源管理器,它在這個代碼中有一個非常不尋常的激活模式。當您查看Process.Start()的返回值時可以看到的東西是null。 Process.Start()實際上不啓動進程時發生。

您可以通過使用僅第二次命中的條件斷點來查看錯誤。與非託管調試和符號服務器啓用,調用堆棧看起來是這樣的:

WindowsFormsApp1.exe!WindowsFormsApp1.Form1.listView1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) Line 19 C# 
System.Windows.Forms.dll!System.Windows.Forms.Control.OnMouseUp(System.Windows.Forms.MouseEventArgs e) Line 9140 C# 
System.Windows.Forms.dll!System.Windows.Forms.ListView.WndProc(ref System.Windows.Forms.Message m) Line 6298 C# 
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Line 14236 C# 
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) Line 14291 C# 
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) Line 780 C# 
[Native to Managed Transition] 
[email protected]() Unknown 
user32.dll!UserCallWinProcCheckWow() Unknown 
user32.dll!CallWindowProcW() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
user32.dll!UserCallWinProcCheckWow() Unknown 
user32.dll!DispatchMessageWorker() Unknown 
[email protected]() Unknown 
shell32.dll!SHProcessMessagesUntilEventsEx(struct HWND__ *,void * *,unsigned long,unsigned long,unsigned long,unsigned long) Unknown 
shell32.dll!CShellExecute::_RunThreadMaybeWait(bool) Unknown 
shell32.dll!CShellExecute::ExecuteNormal(struct _SHELLEXECUTEINFOW *) Unknown 
shell32.dll!ShellExecuteNormal(struct _SHELLEXECUTEINFOW *) Unknown 
[email protected]() Unknown 
System.ni.dll!71db9903() Unknown 
[Frames below may be incorrect and/or missing, native debugger attempting to walk managed call stack] 
[Managed to Native Transition] 
System.dll!System.Diagnostics.ShellExecuteHelper.ShellExecuteFunction() Unknown 
System.dll!System.Diagnostics.ShellExecuteHelper.ShellExecuteOnSTAThread() Unknown 
System.dll!System.Diagnostics.Process.StartWithShellExecuteEx(System.Diagnostics.ProcessStartInfo startInfo) Unknown 
System.dll!System.Diagnostics.Process.Start() Unknown 
System.dll!System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo startInfo) Unknown 
System.dll!System.Diagnostics.Process.Start(string fileName) Unknown 
WindowsFormsApp1.exe!WindowsFormsApp1.Form1.listView1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) Line 19 C# 

它是SHProcessMessagesUntilEventsEx()功能是惡人,在很長的路要走拼「調用DoEvents」和實現「也許等到」它會導致Winforms應用程序的調度程序循環被重新輸入。再次檢測到MouseUp條件並重新觸發事件處理程序。

你不能修復的操作系統,但解決辦法是普遍的一個事件處理程序,導致重入的問題,你可以清晰地延遲與的BeginInvoke()棘手的代碼,以便它後立即運行事件處理。像這樣:

private void listView1_MouseUp(object sender, MouseEventArgs e) { 
    this.BeginInvoke(new Action(() => { 
     Process.Start(@"C:\"); 
    })); 
} 
+0

謝謝深入講解了很多的偉大和工作的解決方案!代碼現在按預期工作,我學到了一些東西;-) – MatzeBrei