2011-11-05 36 views
2

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

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

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); 
       } 

     }));   
    } 

回答

1

由于Polyline是一个WPF UIElement类,它绑定到UI线程。如果您尝试从另一个线程访问其任何属性,它将引发异常。

请注意Polyline是显示类别,不是数据类型。你不应该摆弄WPF控件或其他来自后台线程的显示元素。 WPF将会为您争取每一步。

最好的办法是使用您自己设计的中间数据类型来执行您的XPS以进行折线转换计算。除UIElement之外的任何东西都可以。值类型结构可能是适当的。一旦你完成了任何密集的计算体操操作,都需要一个后台线程,吐出你的数据并向UI线程发出数据很好的信号。然后UI线程可以读取中间数据并根据需要在UI线程上构建多义线

如果您有数以万计的多段线来构建并观察令人反感的UI呃逆,那么您可以将工作分成更小的批次以防止一次阻塞UI太久。

Polyline(和一般的WPF)绑定到UI线程,并且没有任何后台线程会改变它。

不要以为穿线会为您节省。

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

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

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

+0

“您最好的选择是使用您自己设计的中间数据类型来执行XPS到多段线转换计算。”谢谢你,这个伎俩。我创建了我自己的折线课程,并且从那里做了我的体操,在主线程上重建WPF多段线。 – BCCode