2010-06-22 65 views
3

我想調用的UI調度員對話:Dispatcher.Invoke塊永遠

class DialogService : IDialogService 
{ 
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher; 

    public bool? Show(IDialogViewModel viewModel) 
    { 
     if (_dispatcher.CheckAccess()) 
     { 
      var dialogWindow = new DialogWindow(); 
      return dialogWindow.Show(viewModel); 
     } 
     else 
     { 
      Func<IDialogViewModel, bool?> func = Show; 
      return (bool?)_dispatcher.Invoke(func, viewModel); 
     } 
    } 
} 

然而,調用Invoke塊不止,Show不會被調用在UI線程上...

使用BeginInvoke是不是一種選擇:我馬上需要的結果,因爲我是從一個遠程對象(使用.NET遠程)

任何想法處理事件?


UPDATE

這是問題的一個更爲完整的描述:

我有使用.NET遠程Windows服務通信的客戶端應用程序。在某些時候,客戶端調用服務來執行操作(這種調用是由用戶操作觸發的,在這種情況下點擊按鈕)。該服務可能需要憑證才能執行該操作:在這種情況下,會引發一個由客戶端處理的CredentialsNeeded事件。客戶端然後顯示一個對話框來提示用戶輸入憑據,並在事件參數中設置適當的屬性。當事件處理程序返回時,服務使用憑證完成操作,並將控制權返回給客戶端。

因此,當我收到事件時,UI線程正在等待操作在服務端完成......我認爲這就是爲什麼Invoke調用沒有處理的原因,但我該如何解決它?我可以創建另一個 UI線程來顯示對話框嗎?在WinForms中,我知道我可以啓動另一個消息泵Application.Run,但我不知道如何在WPF中執行同樣的操作...

回答

1

我最終找到了解決我的問題的方法:我只需要在自己的調度程序上顯示一個新線程的對話框。以下是修改後的代碼:

class DialogService : IDialogService 
{ 
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher; 

    public bool? Show(IDialogViewModel viewModel) 
    { 
     if (_dispatcher.CheckAccess()) 
     { 
      DoShow(viewModel); 
     } 
     else 
     { 
      bool? r = null; 
      Thread thread = new Thread(() => r = DoShow(viewModel)); 
      thread.SetApartmentState(ApartmentState.STA); 
      thread.Start(); 
      thread.Join(); 
      return r; 
     } 
    } 

    private static bool? DoShow(IDialogViewModel viewModel) 
    { 
     var dialogWindow = new DialogWindow(); 
     return dialogWindow.Show(viewModel); 
    } 
} 
+0

'BeginInvoke'或'InvokeAsync'會解決你的問題。多個STA線程可能很臭。順便說一句,你現在可能已經用'thread.Join();' – MickyD 2018-03-08 23:39:14

+0

@MickyD阻塞了你的_worker_線程,正如我在我的問題中提到的那樣,BeginInvoke不是一個選項,因爲我需要同步獲取對話結果。無論如何,這是一個looong前,這種解決方案爲我工作;) – 2018-03-10 09:51:53

4

您是否在此方法調用期間擁有鎖正試圖獲得?這當然可以解釋它。

這是否發生次?這顯然會更容易診斷。

對我來說,我建議去調試器:打破休息,看看線程在做什麼。

最後,我知道你需要結果...但是如果你改爲調用BeginInvoke會發生什麼(並返回一個虛擬值)?它是否調用調度器中的方法?顯然這不是一個長期的解決方案,但它會提供更多的診斷信息。

+0

感謝您的回答。我沒有在代碼的那一部分做任何明確的鎖定,所以我不認爲問題在那裏。是的,它每次都會發生......其實我認爲我開始明白髮生了什麼問題(請參閱我的更新問題),我只是不知道如何解決它... – 2010-06-22 22:26:10

1

在您嘗試使用Invoke時,UI線程是否對其他內容(可能是您的後臺線程)進行阻塞調用?如果是這樣,那麼你的手上就有一個典型的僵局。兩個線程每個都在等待另一個返回。

在Windows窗體中,他們經常在幕後「抽取信息」時做很多事情,當您最不期望的是爲了避免死鎖而多次創建更多問題並且很難找到由於意外重入而出現的錯誤時。

如果你不認爲你的UI線程正在進行阻塞調用,你應該在調試器中運行應用程序,並在死鎖發生時進入調試器。然後查看主線程的線程窗口。雙擊主線程,然後查看「調用堆棧」窗口以查看主線程所在的位置。

你也可以嘗試顯式指定一個DispatcherPriority發送,雖然我不認爲如果存在真正的死鎖就很重要。

+0

感謝您的回答。事實上,我的主線程正在對遠程對象進行阻塞調用,該遠程對象本身正在對客戶端進行阻塞調用...遠程對象正在引發事件以提示用戶輸入憑據。這就是我試圖展示對話的地方。查看我更新的問題以獲取詳細信 – 2010-06-22 22:26:28