后台工作线程 e.结果导致调用线程无法访问错误



我已经阅读了很多与BackgroundWorker 和 DispatcherTimer 相关的 SO 问题,并了解您无法访问主线程以外的任何线程上的 UI 组件。

所以我有每 1/2 秒滴答一次的调度程序计时器。如您所料,我可以更新视图模型类和任何需要直接操作的 UI 元素,并且 UI 响应迅速。但是,我有一个基于UI上的值的计算,运行大约需要3秒。

我尝试只在调度程序计时器线程中进行计算,并锁定/阻止 UI,直到它完成。目前,我在调度程序计时器中有一个检查,然后触发后台工作线程关闭并进行计算。我使用 e.Arguments 来传递我的 3 秒计算过程所需的数据,以及 e.结果 对于我返回的已完成数据。

我已经检查了结果,没有生成任何错误。但是,当我将 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 列表时,我收到此错误:base {System.SystemException} = {"调用线程无法访问此对象,因为其他线程拥有它。

直到我在 DrawUIMap 方法中尝试访问 MyClass.MapGeo 几何列表时,我才真正看到错误。此时,我回到了可以访问UI的DispatcherTimer thread上。

据我所知,就

我访问 UI 组件的地点/时间而言,我已经做了所有正确的事情。虽然我想我在某处做错了什么。

**编辑:这是执行计算的代码的一部分

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

该对象归创建它的 ThreadPool 线程所有。

如果你调用Freeze(),它应该可以被其他线程使用。

最新更新