2015-08-27 40 views
1

我試圖實現一種方法,當用戶將鼠標光標放入組件時,將觸發WPF中的UI事件。C#異步調度程序操作無法識別變量,因爲它開始

行爲應該是:

1)鼠標光標進入組件,調用方法mouseEnter

2)在1秒的計時器開始

3)如果光標仍處於組件,觸發事件(在這種情況下,打開擴展器)。

最初,這是使用Thread完成的,但是現在使用Dispatcher異步執行此操作。

當光標進入組件時,名爲mouseInbool設置爲true。 當光標離開組件時,mouseIn設置爲false。

問題是,如果用戶將光標放入組件中,然後在1秒計時器過去之前將其移出組件,則delegate仍然會看到mouseIn爲真,即使我已確認它正在只要光標離開它就設置爲false。

void mouseEnter(object sender, MouseEventArgs e) { 
    mouseIn = true; 
    Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => { 
     Thread.Sleep(1000); 
     if (mouseIn) { 
      exp.IsExpanded = true; 
     } 
    } 
} 

void mouseLeave(object sender, MouseEventArgs e) { 
    mouseIn = false; 
} 

async delegate通常只在啓動點保持外部變量的狀態嗎? 如果是這樣,是否有辦法迫使它重新檢查價值,或失敗了,實現這種行爲的更好方法?

非常感謝。

回答

3

您在使用Thread.Sleep安排在UI線程你Action,然後就可以阻止(雖然你它使用BeginInvoke異步排隊),這一事實讓小機會被調用mouseLeave事件處理程序。

您可以使用Task.Delay根本沒有阻止消息循環的解決方案。這將產生控制權交還給UI消息循環一旦擊中await,並延續將在UI線程調度一旦延時過後:

async void mouseEnter(object sender, MouseEventArgs e) 
{ 
    mouseIn = true; 
    await Task.Delay(1000); 

    if (mouseIn) 
    { 
     exp.IsExpanded = true; 
    } 
} 

void mouseLeave(object sender, MouseEventArgs e) 
{ 
    mouseIn = false; 
} 
+0

感謝Yuval,那正是我需要的! – Alex

+0

這充分說明了爲什麼阻止呼叫是邪惡的。善待你的線索! – kai

2

只有一個mouseIn變量的副本,該委託是看到相同的變量。問題在於mouseLeave事件未被調用,因爲您的代理中有Thread.Sleep(1000)調用。

Dispatcher.BeginInvoke將在UI線程上調用您的操作。然後用Thread.Sleep調用阻塞UI線程1秒鐘。當UI線程正在休眠時,它不響應用戶輸入,因此鼠標移動不會被註冊。而不是Thread.Sleep使用async/awaitTask.Delay它不會阻止UI線程。

+0

謝謝shf301,這相當簡潔地解釋了這個問題。現在看起來如此明顯,但我一直在研究這個問題一段時間,我只是沒有發現原因。 – Alex