我正在尝试创建一个显示动画3D模型的wpf应用。我有工作代码在BuildWave中创建模型(我知道这可以像以前一样使用它)。但是,当我将代码移动到wpf窗口的类中的后台工作程序时,我得到错误"调用线程无法访问此对象,因为另一个线程拥有它。"
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = BuildWave();
}
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e)
{
GeometryModel3D model = (GeometryModel3D)e.Result;
mGeometry = model.Clone(); //mGeometry is a private member of the window
if (group.Children.Contains(mGeometry)) //error is on this line
{
group.Children.Remove(mGeometry); //group is a Model3DGroup added in xaml
}
group.Children.Add(mGeometry);
System.Diagnostics.Debug.WriteLine("Added geometry to group");
}
我已经搜索过这个问题的解决方案并发现了一个帖子,其中包含了同一错误(modifying the Jongo Mapper)的问题,建议使用Dispatcher.Invoke()。但是,当我尝试:
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e)
{
GeometryModel3D model = (GeometryModel3D)e.Result;
mGeometry = model.Clone();
group.Dispatcher.Invoke(() =>
{
if (group.Children.Contains(mGeometry))
{
group.Children.Remove(mGeometry);
}
group.Children.Add(mGeometry); //error is now thrown on this line
});
System.Diagnostics.Debug.WriteLine("Added geometry to group");
}
这会抛出错误"不能使用属于与其父Freezable不同的线程的DependencyObject。"再次有一个帖子涵盖类似的问题(The calling thread cannot access this object because a different thread owns it),这表明冻结我在BuildWave中完成的模型:
GeometryModel3D model = new GeometryModel3D(WaveMesh, new DiffuseMaterial(Brushes.YellowGreen));
model.Transform = new Transform3DGroup();
model.Freeze();
return model;
我该怎么做才能解决这个问题?
提前谢谢。
答案 0 :(得分:1)
因为它没有问题,请在你的bgworker中为几何模型准备所有数据(点列表,三角形顶点列表),不要使用gui对象,如Point3DCollection
或{{1或几何。然后,当你准备好它时,在lambda方法中创建所有的几何等等(你可以很乐意将这个创建提取到一个方法以获得更多的可读性并在lambda中调用它),你可以在调度程序上调用它。这应该有用。
答案 1 :(得分:0)
在UI线程中调用类似这样的内容:
public static Model3DCollection GetModel3DCollectionByTemplates(List<GeometryTemplate> geometryTemplates) {
var modelCollection = new Model3DCollection();
foreach (var geometryTemplate in geometryTemplates) {
var positions = geometryTemplate.Positions;
var indicies = geometryTemplate.Indicies;
var normals = geometryTemplate.Normals;
var meshGeometry3D = new MeshGeometry3D {
Positions = new Point3DCollection(positions),
TriangleIndices = new Int32Collection(indicies),
Normals = new Vector3DCollection(normals)
};
var geometry = new GeometryModel3D(meshGeometry3D,
new DiffuseMaterial(new SolidColorBrush(Colors.Aquamarine)));
modelCollection.Add(geometry);
}
// =======================
return modelCollection;
}
但是在Task(TPL)中返回GeometryTemplate的List。 简单的数据包装类:
public class GeometryTemplate {
public List<Point3D> Positions { get; private set; }
public List<Int32> Indicies { get; private set; }
public List<Vector3D> Normals { get; private set; }
public GeometryTemplate(MeshGeometry3D meshGeometry3D) {
SetPositions(meshGeometry3D.Positions);
SetIndicies(meshGeometry3D.TriangleIndices);
SetNormals(meshGeometry3D.Normals);
}
private void SetNormals(Vector3DCollection normals) {
Normals = new List<Vector3D>(normals);
}
private void SetIndicies(Int32Collection triangleIndices) {
Indicies = new List<Int32>(triangleIndices);
}
private void SetPositions(Point3DCollection positions) {
Positions = new List<Point3D>(positions);
}
}
最后一点:
_model3DGroupContainer.Children = model3DCollection;
其中_model3DGroupContainer是Model3DGroup