2010-02-05 58 views
6

我有一個嵌入Geospace地圖的程序。地圖的事件處理在單獨的線程上處理,以保持地圖響應(例如,點擊地圖時觸發的事件)。C#,WPF,需要時自動調用Dispatcher.Invoke?

我遇到的問題是當地圖觸發事件時,我的程序需要更新GUI中的某些內容,並且還要回到地圖中以處理在地圖上放置圖片。

我嘗試在this.dispatcher.Invoke中包裝整個事件處理程序方法,這使我回到主UI線程。這對於更新我的GUI非常適用,但是當我回到地圖中時,我仍然在UI線程上,這可能會導致地圖中出現一些問題。

基本上,爲了使這項工作,我將不得不運行dispatcher.invoke每次我想改變我的gui控制。有沒有一種方法可以自動執行此操作,而無需在dispatcher.invoke中包裝每個調用?我希望這一切都有道理。

繼承人爲我在談論該事件的一些示例代碼..

private void Map_OnMapClicked(object sender, MapClickedEventArgs e) 
    { 
     this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      // Do something to update my gui 
     })); 

     Map.DoSomethingInTheMap(); 

     this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      // Do something to update my gui 
     })); 


     //etc etc etc 
    } 

回答

6

如果你需要保持各個相應的操作在其自身的同步環境,這是不幸的是最好的辦法。每次更新GUI時,都需要使用Dispatcher進行調用。

這裏有一對夫婦的製作更容易些建議:

  1. 嘗試批量的GUI操作。除了需要較少的代碼(通過較少的調用調用),您將獲得更好的性能。每個Dispatcher.Invoke調用都會帶來相當的開銷,因爲它將消息發佈到必須處理的Dispatcher的消息隊列中。

  2. 考慮使用Dispatcher.BeginInvoke來避免阻塞,除非您確實需要等待。

  3. 如果您可以使用.NET 4中的Task Parallel Library(或Rx Framework中的3.5sp1的backport),則可能需要考慮將其重新設置爲使用Task instances synchronized to the GUI thread。通過使用FromCurrentSynchronizationContext創建TaskScheduler,您可以比在Dispatcher Invoke調用中更容易地在GUI上運行任務。這也可以讓你對批量進行一些控制,因爲你可以很容易地安排它們,並根據需要阻止/等待。

2

您可以使用類似PostSharp或儘量壓縮你的UI更新單方法調用,您調用一次,並做了很多。或者甚至是這樣的模式(它是Winforms,但想法是一樣的):

private void UpdateToolStripItemText(ToolStripItem toolStripItem, string text) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new UpdateToolStripItemTextDelegate(UpdateToolStripItemText), new object[] { toolStripItem, text }); 
    } 
    else 
    { 
     if (text != null) 
     { 
      toolStripItem.Text = text; 
     } 
    } 
}