2017-02-26 22 views
2

我正在嘗試創建一個顯示動畫3D模型的wpf應用程序。我有工作代碼在BuildWave中創建模型(我知道這是我以前使用過的)。但是,當我將代碼移動到wpf窗口類中的後臺工作器時,出現錯誤「調用線程無法訪問此對象,因爲不同的線程擁有它」。將GeometryModel3D添加到Model3DGroup

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"); 
    } 

這引發錯誤「不能使用屬於不同的線程比其父可凍結爲DependencyObject。」,並再次有一個涵蓋了類似的問題(Cannot use a DependencyObject that belongs to a different thread than its parent Freezable)後,其建議凍結我在BuildWave中完成的模型:

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

     model.Freeze(); 
     return model; 

我應該怎麼做才能解決這個問題?

謝謝你提前。

回答

0

呼叫在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)內返回GeometryTemplate的名單。 簡潔的數據包裝類:

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

1

因爲這沒有問題的作品,在你準備bgworker所有數據(點名單,三角形頂點的列表)爲您的幾何模型,不使用GUI對象,如Point3DCollectionInt32Collection或幾何形狀。然後,當你準備好了,在你的lambda方法中創建所有的幾何形狀(你可以很高興地將這個創建方法提取到一個方法中,以獲得更好的可讀性,並在lambda中調用它),你可以在調度器上調用它。這應該工作。

+0

感謝。我對代碼的順序感到困惑,以及哪些線程可以完成哪些操作..現在排序! –