Question

I've read through a lot of the SO questions related to BackgroundWorker and DispatcherTimer and understand that you can't access UI components on any thread other than the main thread.

So I have DispatcherTimer that ticks every 1/2 sec. As you would expect I can update the view model class and any UI element that needs direct manipulation and the UI is pretty responsive. However I have a calculation to do based on a value on the UI that takes about 3 secs to run.

I tried just doing the calulation in the DispatcherTimer thread and that locked/blocked the UI until it completed. At present I have a check in the DispatcherTimer that then triggers a BackgroundWorker thread to go off and do the calculation. I use e.Arguments to pass my 3 sec compute process the data it needs and e.Result for the completed data I get back.

I've checked the result and there are no errors generated. However when I cast the e.Result back into my class, the e.Result is not able to evaluate properly. I essentially get a "calling thread cannot access error" when I come to use the class property.

...
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
}

When I set a break in "threadDrawMap_Completed" and evaluate the List of PathGeometry I get this error: base {System.SystemException} = {"The calling thread cannot access this object because a different thread owns it."}

I don't actually see an error until when I'm in the DrawUIMap method and I try and access the MyClass.MapGeo geometry list. At this point tho I'm back on the DispatcherTimer thread, which can access the UI.

As far as I know I've done everything right as far as where/when I access UI components. Although I figure I've done something horribly wrong somewhere.

**Edit: This is part of the code that does the calulation

public static List<PathGeometry> BuildMap(List<PathGeometry> _geoList)
{
    ...
    List<PathGeometry> retGeoList = new List<PathGeometry>();
    retGeoList.Add(geoPath1);        
    retGeoList.Add(geoPath2);
    ...
    return retGeoList;
}
Was it helpful?

Solution

That object is owned by the ThreadPool thread that created it.

If you call Freeze(), it should become usable by other threads.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top