C#WPF ModelVisual3D创建耗时太长,无法在单独的线程上完成

C#WPF ModelVisual3D创建耗时太长,无法在单独的线程上完成,c#,wpf,multithreading,viewport3d,C#,Wpf,Multithreading,Viewport3d,我有一个WPF项目(VS2010,.NET4.0),我在其中创建了一个相当大的ModelVisual3D对象(从自定义格式STL文件读取,处理信息,创建网格等),这大约需要3-4秒。待创建,再等待2-3秒。执行mainViewport.Children.Add(ModelVisual3D)。 我在自定义类中完成这一切,并调用此方法: class My3DModel { ... public MyModelVisual3D createModelVisual3D(MyTypes

我有一个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;
            }
}
我只想在节目开始时做一次以下

{
        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:我试过线程、
BackgroundWorker
&
Task
类。结果是相似的,如果不是说相同的话


PPS:完整版本将加载30-40秒以上的大型模型。

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

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

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

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

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

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

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

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

很抱歉回答得太晚,但我很久以前就通过以下方式解决了这个问题:

    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);
        }
    }
delegate void myDelegate();
私有无效文件打开按钮\单击(对象发送者,路由目标)
{
尝试
{
线程ViewportLoaderThread=新线程(loadViewportItemsAsync);
ViewportLoaderThread.IsBackground=true;
ViewportLoaderThread.Start();
}
catch(异常错误){UtilsProgram.writeErrorLog(err.ToString());}
}
私有void loadViewportItemsAsync()
{
尝试
{
//尝试浏览文件
如果(!browseForFile())返回;
Invoke(新操作(()=>{myStatusBar.Visibility=System.Windows.Visibility.Visibility;menuItemHelpDemo.IsEnabled=false;}),null);
//加载文件、解压缩、解密、加载STL并创建ModelGroup3D对象
UtilsDen.DenModel=new DenLoader(UtilsDen.Filename,UtilsDen.Certificate,UtilsDen.PrivateKey,this);
//将模型加载到视口异步
myDelegate asyncDel=新的myDelegate(sendModelsToViewportAsync);
this.Dispatcher.BeginInvoke(asyncDel,null);
}
catch(异常错误){MessageBox.Show(UtilsProgram.langDict[“msg18”]);UtilsProgram.writeErrorLog(err.ToString());}
}
私有void sendModelsToViewportAsync()
{
对于(int i=0;i

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

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

    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);
        }
    }
delegate void myDelegate();
私有无效文件打开按钮\单击(对象发送者,路由目标)
{
尝试
{
线程ViewportLoaderThread=新线程(loadViewportItemsAsync);
ViewportLoaderThread.IsBackground=true;
ViewportLoaderThread.Start();
}
catch(异常错误){UtilsProgram.writeErrorLog(err.ToString());}
}
私有void loadViewportItemsAsync()
{
尝试
{
//尝试浏览文件
如果(!browseForFile())返回;
Invoke(新操作(()=>{myStatusBar.Visibility=System.Windows.Visibility.Visibility;menuItemHelpDemo.IsEnabled=false;}),null);
//加载文件、解压缩、解密、加载STL并创建ModelGroup3D对象
UtilsDen.DenModel=new DenLoader(UtilsDen.Filename,UtilsDen.Certificate,UtilsDen.PrivateKey,this);
//将模型加载到视口异步
myDelegate asyncDel=new m