2013-10-09 25 views
1

我已經通讀了許多與BackgroundWorker和DispatcherTimer相關的SO問題,並且瞭解到您無法訪問主線程以外的任何線程上的UI組件。BackgroundWorker e.Result結果在調用線程無法訪問錯誤

所以我有每1/2秒滴答的DispatcherTimer。正如你所期望的,我可以更新視圖模型類和任何需要直接操作的UI元素,並且UI非常靈敏。不過,我有一個計算是基於UI上需要運行大約3秒的值來完成的。

我試着在DispatcherTimer線程中進行調用,並鎖定/阻止UI直到完成。目前我在DispatcherTimer中檢查,然後觸發BackgroundWorker線程關閉並執行計算。我使用e.Arguments將我需要的數據傳遞給我的3秒計算過程,並將e.Result傳遞給我返回的完成數據。

我檢查了結果,沒有產生錯誤。但是,當我將e.Result重新放入我的課程時,e.Result無法正確評估。當我來使用類屬性時,我基本上得到了「調用線程無法訪問錯誤」。

... 
timerBackgroundLoop = new DispatcherTimer(DispatcherPriority.Background); 
timerBackgroundLoop.Interval = TimeSpan.FromMilliseconds(500); 
timerBackgroundLoop.Tick += new EventHandler(Timer_Tick); 
timerBackgroundLoop.Start(); 
... 

private void Timer_Tick(object sender, EventArgs e) 
{ 
    if (MyClass.NeedToRebuildBuildMap) 
    { 
     MyClass.NeedToRebuildBuildMap = false; //stop next timer tick from getting here 
     threadDrawMap = new BackgroundWorker(); 
     threadDrawMap.WorkerReportsProgress = false; 
     threadDrawMap.WorkerSupportsCancellation = false; 
     threadDrawMap.DoWork += new DoWorkEventHandler(threadDrawMap_DoWork); 
     threadDrawMap.RunWorkerCompleted += new RunWorkerCompletedEventHandler(threadDrawMap_Completed); 
     threadDrawMap.RunWorkerAsync(myClass.MapData); 
    } 
    ... 
} 

private void threadDrawMap_DoWork(object sender, DoWorkEventArgs e) 
{ 
    MyClass.MapData _mapData = (MyClass.MapData)e.Argument;       
    e.Result = BuildMap(_mapData); 
} 

private void threadDrawMap_Completed(object sender, RunWorkerCompletedEventArgs e) 
{ 
    MyClass.MapGeo = (List<PathGeometry>)e.Result; 
    DrawUIMap(MyClass.MapGeo); //draws the map on the UI into a grid 
} 

當我設置斷點在「threadDrawMap_Completed」和評估的PathGeometry的名單我得到這個錯誤:{基地System.SystemException} = {「,因爲不同的線程擁有它調用線程不能訪問該對象。 「}

直到當我在DrawUIMap方法中時,我才真正看到錯誤,並嘗試訪問MyClass.MapGeo幾何列表。在這一點上我回到了DispatcherTimer線程,它可以訪問UI。

據我所知,我已經做了一切正確的地方,當我訪問UI組件。儘管我認爲我在某個地方做了一些可怕的錯誤。

**編輯: 這是做的calulation

public static List<PathGeometry> BuildMap(List<PathGeometry> _geoList) 
{ 
    ... 
    List<PathGeometry> retGeoList = new List<PathGeometry>(); 
    retGeoList.Add(geoPath1);   
    retGeoList.Add(geoPath2); 
    ... 
    return retGeoList; 
} 
+0

你在哪裏重置'MyClass.NeedToRebuildBuildMap',我不確定,但在'timer'中使用一個標誌來防止下一個'BackgroundWoker'運行可能不是最好的選擇?可能有一個機會,國旗重置,並在它被設置爲「假」,兩個「計時器滴答作響」.. – Bolu

+0

對不起剛剛看到您的評論。在這種情況下,答案是否定的,我仔細檢查了它只會被稱爲一次,因此移動了布爾旗。實際上,我在代碼的其他地方根據菜單項單擊設置了標誌,只要用戶基本上要求MapRedraw,我就隱藏它並顯示繁忙的指示符,直到地圖重新繪製。它比我在這裏實際聲音更優雅;-) – MikeyTT

回答

0

該任務通過創建它的線程池線程所擁有的部分代碼。

如果您致電Freeze(),它應該可以被其他線程使用。

+0

哪個對象應該被凍結?我看過我的應用程序的其他部分做類似的事情,沒有任何問題,我看不出有什麼區別。我以前從未在任何對象上使用過凍結。我會在此期間進行調查。 – MikeyTT

+0

@MikeyTT:可能是'PathGeometry's。如果您在一個線程上創建對象,然後在不同的線程上使用它,這只是一個問題。 – SLaks

+0

因此,我檢查並重新檢查了其他代碼,並且在其他地方几乎完全沒有發生此問題的代碼。唯一的區別是我以前從未使用過PathGeometry。如果我有一個List 或另一個類的ObservableCollection,我從來沒有遇到過這個問題,即使我稱之爲「new ...();」在上面。看起來像是與PathGeometry相關的東西。無論哪種方式,只要我凍結對象,然後我可以訪問它。我敢肯定,我現在正在處理一個凍結對象,但是,嘿,寶貝步驟。感謝指針... – MikeyTT