1

这里有点特殊,因为我使用的是一个名为helix-toolkit的库,但请耐心等待。

问题是我想使用后台工作程序在我的代码中并行创建模型对象。

我知道多线程和处理 UI 元素存在一个大问题,但也许有一种解决方法。

这是我的代码的粗略结构:

我在其中创建 Backgroundwoker 的第一个文件,拆分创建 Geometry3D 对象的工作负载,最后调用SetModelGeometry将几何图形绑定到视口。第二个文件显示了绑定是如何完成的。

主窗口.xaml.cs

  private void Draw_Building()
        {
            _worker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
            _worker.DoWork += Draw_Building_DoWork;
            _worker.ProgressChanged += DrawBuilding_ProgressChanged;
            _worker.RunWorkerCompleted += DrawBuilding_RunWorkerCompleted;
            _worker.RunWorkerAsync(10000);

        }

        private void Draw_Building_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            // returns a list containing Geometry3D objects ( created by meshBuilder.ToMeshGeometry3D() )
            Geometryhandler.Draw_Building(sender, e); 
        }

        private void DrawBuilding_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            StatusProgressBar.Value = e.ProgressPercentage;
            var i = (int)e.UserState;
            var actualComponent = MyBuildingComponents.First(c => c.Id == i);
            LblStatusbarInfo.Text = "Currently meshing element #" + actualComponent.Globalid + " (" +
                                    actualComponent.Objectname + ")";
            StatusProgressbarMsg.Text = "Meshing (" + e.ProgressPercentage + " %)";
        }

        private void DrawBuilding_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            StatusProgressbarMsg.Text = "-";
            StatusProgressBar.Value = 0;
            LblStatusbarInfo.Text = "Meshing completed.";

            Geometry = e.Result as List<MeshIdandGeometry>;

            // creates MeshGeometryModel3D objects and binds them to the viewport using the List of Geometries
            MainViewModel.SetModelGeometry(Geometry);

        }

主视图模型.cs

    public void SetModelGeometry(List<MeshIdandGeometry> geometry)
    {

        MyModelGeometry = new Element3DCollection();

        if (geometry != null)
        {
            foreach (var mygeometry in geometry)
            {

                var s = new MeshGeometryModel3D
                {
                    Geometry = mygeometry.Geometry,
                    Material = mygeometry.Material,
                };
                this.MyModelGeometry.Add(s);

                s.Attach(MyModelViewport.RenderHost);
            }

        }

        this.OnPropertyChanged("MyModelGeometry");
    }

我目前的问题是以下错误消息:

调用线程无法访问此对象,因为不同的线程拥有它。

SetModelGeometry尝试将 附加ModelGeometry到视口时在函数中抛出。

我猜编译器抱怨几何图形是在不同的线程中创建的,他现在无法访问。

在不破坏 DrawBuilding 函数的并行执行的情况下,是否有任何解决方法/解决方案?

编辑:

编辑2:发布了错误的Draw_Building方法版本

中的Draw_Building方法Geometryhandler

    public void Draw_Building(object sender, DoWorkEventArgs e)
    {

        var geometry = new List<MeshIdandGeometry>();

        var standardMaterial = new PhongMaterial()
        {
            AmbientColor = SharpDX.Color.LightGray,
            //DiffuseColor = new Color4(0.35f, 0.35f, 0.35f, 1.0f),
            //DiffuseMap = new BitmapImage(new System.Uri(@"Con_Diffuse_2.jpg", System.UriKind.RelativeOrAbsolute)),
            //NormalMap = new BitmapImage(new System.Uri(@"Con_Normal_2.jpg", System.UriKind.RelativeOrAbsolute)),
        };

        var max = _mainWindow.MyBuildingComponents.Count;
        var i = 1;

        // Loop over building components
        foreach (var component in _mainWindow.MyBuildingComponents)
        {

            //if (i == 5) break;
            var component1 = component;
            var componentTriangles = _mainWindow.MyTriangles.Where(triangle => triangle.ComponentId == component1.Id);

                var meshBuilder = new MeshBuilder(true, true, true);

            // Loop over triangles in building element
            foreach (var triangle in componentTriangles)
            {
                var triangle1 = triangle;

                var p1 = _mainWindow.MyVertices.Find(
                    vt => vt.Id == triangle1.PointId1);
                var p2 = _mainWindow.MyVertices.Find(
                    vt => vt.Id == triangle1.PointId2);
                var p3 = _mainWindow.MyVertices.Find(
                    vt => vt.Id == triangle1.PointId3);
                if (p1 != null && p2 != null && p3 != null)
                {
                    //meshBuilder.AddTriangle(new Vector3((float)p1.X, (float)p1.Y, (float)p1.Z),
                    //    new Vector3((float)p2.X, (float)p2.Y, (float)p2.Z),
                    //    new Vector3((float)p3.X, (float)p3.Y, (float)p3.Z));

                    // coordination are switched to match the coordinate system in SharpDX viewport
                    meshBuilder.AddTriangle(new Vector3(-(float)p1.Y, (float)p1.Z, -(float)p1.X),
                        new Vector3(-(float)p2.Y, (float)p2.Z, -(float)p2.X),
                        new Vector3(-(float)p3.Y, (float)p3.Z, -(float)p3.X));
                }
            }
            var mesh = meshBuilder.ToMeshGeometry3D();

            var meshandtriangle = new MeshIdandGeometry
            {
                Id = component1.Id,
                Geometry = mesh,
                Material = standardMaterial,
            };
            geometry.Add(meshandtriangle);

            i++;
            var progressPercentage = Convert.ToInt32(((double)i / max) * 100);
            var backgroundWorker = sender as BackgroundWorker;
            backgroundWorker?.ReportProgress(progressPercentage, component1.Id);
        }

        e.Result = geometry;

    }
4

1 回答 1

1

非常感谢@egse 找到解决方案。

导致问题的部分代码:

    var standardMaterial = new PhongMaterial()
    {
        AmbientColor = SharpDX.Color.LightGray,
        //DiffuseColor = new Color4(0.35f, 0.35f, 0.35f, 1.0f),
        //DiffuseMap = new BitmapImage(new System.Uri(@"Con_Diffuse_2.jpg", System.UriKind.RelativeOrAbsolute)),
        //NormalMap = new BitmapImage(new System.Uri(@"Con_Normal_2.jpg", System.UriKind.RelativeOrAbsolute)),
    };

基本上,上述代码的问题在于,材质是在后台工作人员范围内创建为局部变量的。当 UI 线程尝试进入材质对象时,这会导致所有权问题。

这个问题的解决方案是确保材质是由 UI 线程创建的(例如,在这种情况下, 的构造函数Geometryhandler

TL;DR:不要在 UI 之外的另一个线程中创建从 DependencyObject 继承的类的实例。

于 2016-11-03T12:16:18.240 回答