我需要在第二个线程中生成List<Polyline>
,以免丢失GUI响应。线程完成后,我需要访问GUI线程中的List<Polyline>
进行显示。这是我遇到问题的地方。我使用匿名方法在UI线程上调用复制逻辑,将折线复制到已在UI线程上初始化的List<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);
}
}));
}
答案 0 :(得分:1)
因为Polyline是WPF UIElement类,所以它绑定到UI线程。如果您尝试从另一个线程访问其任何属性,它将抛出异常。
请注意,Polyline是显示类,而不是数据类型。你不应该在背景线程中摆弄WPF控件或其他显示元素。 WPF会在每一步都为你而战。
您最好的选择是使用您自己设计的中间数据类型执行XPS到折线转换计算。除了UIElement之外的任何东西都可以。值类型结构可能是合适的。一旦你做了任何密集的计算体操保证后台线程,吐出你的数据并发信号通知UI线程数据是好的。然后,UI线程可以读取中间数据并根据需要在UI线程上构建Polylines 。
如果你有数以千万计的折线构建并观察到令人反感的UI打嗝,你可以将工作分成更小的批次,以防止阻止UI一次太久。
Polyline(和一般的WPF)绑定到UI线程,并且任何数量的后台线程都不会改变它。
不要假设线程会为您节省开支。
首先,您确实有可证明的UI阻止问题吗?如果没有,你就完成了。无需线程。
如果您确实遇到了UI阻止问题,是否可以将其拆分为较小的批次并仍在UI线程上执行?如果是的话,你就完成了。无需线程。
如果使用后台线程确实是解决问题的最有效方法,那么在不使用Polyline等WPF类的情况下实现它。