【问题标题】:Adding GeometryModel3D to Model3DGroup将 GeometryModel3D 添加到 Model3DGroup
【发布时间】:2017-02-26 13:03:38
【问题描述】:

我正在尝试创建一个显示动画 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");
    }

我已经搜索了这个问题的解决方案,并找到了一个包含相同错误 (The calling thread cannot access this object because a different thread owns it) 的帖子,该帖子建议使用 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。”,并且再次有一篇涉及类似问题的帖子 (Cannot use a DependencyObject that belongs to a different thread than its parent Freezable) 建议冻结我在其中完成的模型构建波:

        GeometryModel3D model = new GeometryModel3D(WaveMesh, new DiffuseMaterial(Brushes.YellowGreen));
        model.Transform = new Transform3DGroup();

        model.Freeze();
        return model;

我应该怎么做才能解决这个问题?

提前谢谢你。

【问题讨论】:

    标签: c# wpf 3d


    【解决方案1】:

    因为它没有问题,请在您的 bgworker 中为您的几何模型准备所有数据(点列表,三角形顶点列表),并且不要使用 gui 对象,例如 Point3DCollection 或 Int32Collection 或几何.然后,当您准备好使用它时,在您的 lambda 方法中创建所有几何图形等(您可以很高兴地将这个创建提取到一个方法中以获得更高的可读性并在 lambda 中调用它),您可以在调度程序上调用它。这应该可以。

    【讨论】:

    • 谢谢。我对代码的顺序感到困惑,以及可以在哪些线程中进行哪些操作..现在排序!
    【解决方案2】:

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

    但在任务 (TPL) 中返回几何模板列表。 以及简单的数据包装类:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-23
      相关资源
      最近更新 更多