1

我有一个 WPF 项目 ( VS2010, .NET4.0),在其中创建了一个相当大的ModelVisual3D对象(从自定义格式STL文件、进程信息、创建网格等读取)这大约需要 3-4 秒。要创建和另外 2-3 秒。做一个mainViewport.Children.Add(ModelVisual3D)。我在自定义类中完成所有这些并调用此方法:

 class My3DModel
{
...
        public MyModelVisual3D createModelVisual3D(MyTypes tType, int tNumber)
            {
                this.myModelVisual3D = new MyModelVisual3D(tType, tNumber);
                for (int i = 0, j = 0; i < this.Triangles.Length; i++)
                {
                    this.mesh.Positions.Add(this.Triangles[i].Vertex1);
                    this.mesh.Positions.Add(this.Triangles[i].Vertex2);
                    this.mesh.Positions.Add(this.Triangles[i].Vertex3);
                    this.mesh.Normals.Add(this.Triangles[i].Normal);
                    this.mesh.Normals.Add(this.Triangles[i].Normal);
                    this.mesh.Normals.Add(this.Triangles[i].Normal);
                    this.mesh.TriangleIndices.Add(j++);
                    this.mesh.TriangleIndices.Add(j++);
                    this.mesh.TriangleIndices.Add(j++);
                }
                this.model3DGroup.Children.Add(new GeometryModel3D(this.mesh, material));
                this.myModelVisual3D.Content = this.model3DGroup;
                return this.myModelVisual3D;
            }
}

返回值也是我创建的自定义类:

class ToothModelVisual3D : ModelVisual3D
{
    //VARIABLES
    private MyTypes myType;
    private int number;

    //OPERATORS
    public MyTypes MyType
    {get { return myType; } set { myType = value; }}

    public int Number
    {get { return number; } set { number = value;}}

    public ToothModelVisual3D() { }

    public ToothModelVisual3D(MyTypes tType, int tNumber) { MyType = tType; Number = tNumber; }
}

我想做的就是在程序开始时执行以下操作:

{
        My3DModel myModel;
        myModel = new My3DModel();
        myModel.readFileBytes("C:\\registered\\" + 1 + ".stl");
        myModel.loadTriangles();
        mainViewport.Children.Add(myModel.createModelVisual3D(MyTypes.Sometype, 1);
}

如果我在主线程上执行此操作,则 UI 会挂起。如果我在工作线程上执行此操作并调用mainViewport.Children.Add(...)它,则表示它无法访问在该工作线程上创建的资源。帮助?!

据我了解,我已经达到了一个地步,即我有两个线程和属于它们每个的资源(mainViewport => UIThread & myModel => WorkerThread)。两个线程都不能直接访问对方的资源,但是在 UIThread 上创建和使用 myModel 会使它挂起......我要做的就是从 UI 获得足够的响应能力,因此用户可以在等待程序加载模型时最小化程序,仅此而已。我怎样才能做到这一点?有没有办法在 UIThread 上完成所有 CPU 繁重的工作,因此不会出现资源冲突,并且有一个工作线程只处理那个时间的 UI?

PS:我已经尝试过使用 ThreadBackgroundWorkerTask<TResult>classes。如果不说同样的话,结果是相似的。

PPS:完整版将加载大量模型,加载时间超过 30-40 秒...

4

3 回答 3

1

我最近在将 XNA 应用程序移植到 WPF 时遇到了同样的问题。在我的情况下,我通过使用后台线程从文件中加载位置、法线和索引来部分解决了这个问题。然后在同一个线程中,使用 GeometryModel3D 和 MeshGeometry3D 为 Model3DGroup 构造一个包含 XAML 的内存流。

然后,在 UI 线程中,一旦内存流可用,就加载模型......

Model3DGroup model = System.Windows.Markup.XamlReader.Load(memoryStream) as Model3DGroup;

仍然存在延迟,但由于文件访问是在后台线程中完成的,因此没有那么严重。

于 2015-02-05T00:00:47.413 回答
0

很抱歉回答迟了,但实际上我很久以前就通过以下方式解决了这个问题:

    delegate void myDelegate();

    private void fileOpenButton_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            Thread ViewportLoaderThread = new Thread(loadViewportItemsAsync);
            ViewportLoaderThread.IsBackground = true;
            ViewportLoaderThread.Start();
        }
        catch (Exception err) { UtilsProgram.writeErrorLog(err.ToString()); }
    }

    private void loadViewportItemsAsync()
    {
        try
        {
            //TRY to browse for a file
            if (!browseForFile()) return;

            Dispatcher.Invoke(new Action(() => { myStatusBar.Visibility = System.Windows.Visibility.Visible; menuItemHelpDemo.IsEnabled = false; }), null);

            //Load file, unpack, decrypt, load STLs and create ModelGroup3D objects
            UtilsDen.DenModel = new DenLoader(UtilsDen.Filename, UtilsDen.Certificate, UtilsDen.PrivateKey, this);

            //Load the models to viewport async
            myDelegate asyncDel = new myDelegate(sendModelsToViewportAsync);
            this.Dispatcher.BeginInvoke(asyncDel, null);
        }
        catch (Exception err) { MessageBox.Show(UtilsProgram.langDict["msg18"]); UtilsProgram.writeErrorLog(err.ToString()); }
    }

    private void sendModelsToViewportAsync()
    {
        for (int i = 0; i < UtilsDen.DenModel.StlFilesCount; i++)
        {
            //Add the models to MAIN VIEWPORT
            ModelVisual3D modelVisual = new ModelVisual3D();
            GeometryModel3D geometryModel = new GeometryModel3D();
            Model3DGroup modelGroup = new Model3DGroup();

            geometryModel = new GeometryModel3D(UtilsDen.DenModel.StlModels[i].MeshGeometry, UtilsDen.Material);

            modelGroup.Children.Add(geometryModel);
            modelVisual.Content = modelGroup;
            mainViewport.Children.Add(toothModelVisual);
        }
    }

关键是使用this.Dispatcher.BeginInvoke(asyncDel, null);它,因为它在主线程上工作,但不会滞后,因为它是异步执行的。

于 2015-02-05T08:28:45.480 回答
0

使用委托似乎仍然会在 UI 上引入延迟,更好的解决方案是在工作线程中创建模型,然后将其冻结。然后,该模型可以由 UI 线程克隆,而不会出现烦人的异常。这适用于需要 25 秒或更长时间才能加载的模型。我发现的唯一问题是,如果模型包含纹理,它就不起作用。

于 2015-05-13T23:08:56.537 回答