2013-09-26 33 views
1

做我有一個WPF項目(VS2010.NET4.0),其中我創建了一個相當大的ModelVisual3D對象(從自定義格式STL文件,進程信息讀取,創建網,等等)這大約需要3-4秒。被創造並且另外2-3秒。做一個mainViewport.Children.Add(ModelVisual3D)。 我做的這一切都在一個自定義類,並調用這個方法:C#WPF 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:我已經試過主題,BackgroundWorker & Task<TResult>類。如果不這樣說,結果是相似的。

PPS:完整版將加載大量的模型將加載超過30-40秒......

+0

順便說一句我找不到如何實現* async/await *。如果我把它寫在項目中VS說沒有這樣的事情。 – mandarin

回答

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);因爲它工作在主線程,但不滯後它,因爲它是異步執行的。

1

我移植的XNA應用到WPF跨時同樣的問題最近又傳出。 在我的情況下,我通過使用後臺線程從文件加載位置,法線和索引來部分解決此問題。然後在同一個線程中,使用GeometryModel3D和MeshGeometry3D爲Model3DGroup構造包含XAML的內存流。

然後,在UI線程,曾經的記憶流可用,加載模型...

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

還有一個延遲,但作爲文件訪問是在後臺線程中完成的,它是沒有那麼嚴重。

0

使用委託仍然會在UI上引入延遲,更好的解決方案是在工作線程中創建模型,然後將其凍結。然後可以通過UI線程克隆該模型,而不會出現惱人的異常。這適用於需要25秒或更長時間加載的模型。我發現的唯一問題是,如果模型包含紋理,則不起作用。