通过List< Polyline>线程之间

本文关键字:线程 之间 Polyline List 通过 | 更新日期: 2023-09-27 18:13:38

我有一个List<Polyline>,我需要在第二个线程中生成,以免失去GUI响应能力。线程完成后,我需要访问GUI线程中的List<Polyline>来显示。这就是我遇到问题的地方。我用匿名方法调用UI线程上的复制逻辑,将折线复制到已经在UI线程上初始化的List<Polyline>中。我得到"调用线程不能访问这个对象,因为不同的线程拥有它。"

我已经尝试克隆和DeepCopy扩展方法从线程列表复制到UI列表,但折线是不可序列化的。

    Class ThreadedExecuter<T> where T : class
    {
        public delegate void CallBackDelegate(T returnValue);
        public delegate T MethodDelegate();
        private CallBackDelegate callback;
        private MethodDelegate method;
        private Thread t;
        public ThreadedExecuter(MethodDelegate method, CallBackDelegate callback)
        {
            this.method = method;
            this.callback = callback;
            t = new Thread(this.Process);
            //XPSDocument requires STA
            t.SetApartmentState(ApartmentState.STA);
        }
        public void Start()
        {
            t.Start();
        }
        private void Process()
        {
            T stuffReturned = method();
            callback(stuffReturned);
        }
    }

    void StartXPStoPolyThread()
    {
        ThreadedExecuter<List<Polyline>> executer = new ThreadedExecuter<List<Polyline>>(GeneratePolyFromXPS, PolyFromXPSComplete);
        executer.Start();
    }
    List<Polyline> GeneratePolyFromXPS()
    {
        string file = @"C:'Users'Company'Desktop'shapes6.xps";
        Company.XPStoPolyline.XPStoPolylineHelper myXPSPoly = new Company.XPStoPolyline.XPStoPolylineHelper(); //init brushes
        List<Polyline> LocalList = myXPSPoly.ReadFileOutputPolylineList(file, CurrentConfig.ImportTolerance);

        return LocalList;
    }
    void PolyFromXPSComplete(List<Polyline> PolylistIn)
    {
        this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, new Action(() =>
        {
                PolylineList.Clear(); //already initialized in UI thread
                PolylineList = new List<Polyline>(PolylistIn.Capacity);
                foreach (Polyline currentPolyline in PolylistIn)
                {
                    Polyline correctedPolyLine = new Polyline();
                    PointCollection myPointCollection = new PointCollection();
                    Point pointToAdd = currentPolyline.Points[0]; //"The calling thread cannot access this object because a different thread owns it."
                    myPointCollection.Add(pointToAdd);
                    for (int i = 1; i < currentPolyline.Points.Count; i++)
                    {
                        ....copy points
                    }
                    correctedPolyLine.Points = myPointCollection;
                    correctedPolyLine.Stroke = currentPolyline.Stroke;
                    correctedPolyLine.StrokeThickness = 1;
                    PolylineList.Add(correctedPolyLine);
                }
                //display for testing
                VectorGridCanvas.Children.Clear();
                foreach (Polyline myPolyLine in PolylineList)
                {
                    VectorGridCanvas.Children.Add(myPolyLine);
                }
        }));           
    }

通过List< Polyline>线程之间

因为Polyline是一个WPF元素类,它被绑定到UI线程。如果你试图从另一个线程访问它的任何属性,它将抛出异常。

请注意,Polyline是一个显示类,而不是一个数据类型。您不应该在后台线程中摆弄WPF控件或其他显示元素。WPF将与您并肩作战。

您最好的选择是使用您自己设计的中间数据类型执行XPS到折线转换计算。除了元素,任何东西都可以。值类型结构可能是合适的。一旦您完成了任何需要后台线程的密集计算工作,就可以输出您的数据并向UI线程发出信号,表明数据已经就绪。然后UI线程可以读取中间数据并根据需要在UI线程上构造折线。

如果你有数以千万计的折线来构建和观察一个令人反感的UI打嗝,你可以把工作分成更小的批次,以防止一次阻塞UI太长时间。

Polyline(和一般的WPF)被绑定到UI线程,没有多少后台线程会改变这一点。

不要以为线程会拯救你。

首先,你真的有一个可证明的UI阻塞问题吗?如果没有,你就完蛋了。不需要线程。

如果你有一个UI阻塞问题,它可以被分解成更小的批次,仍然在UI线程上执行吗?如果是,就完成了。不需要线程。

如果使用后台线程真的是解决问题最有效的方法,那么实现它时不要使用像Polyline这样的WPF类。