我有一个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)的地步。两个线程都不能直接访问对方的资源,但是在myModel上创建和使用UIThread会使其挂起.我所要做的就是从UI中获得足够的响应能力,这样用户就可以在等待它加载模型时最小化程序,仅此而已。我怎么能这么做?有没有一种方法可以在UIThread上完成所有的CPU繁重工作,这样就不会出现资源冲突,并且有一个只在那时处理UI的工作线程?
PS:我尝试过线程、BackgroundWorker和Task<TResult>类。如果不是这样的话,结果是相似的。
PPS:完整的版本将装载大量的型号,装载时间超过30-40秒.
发布于 2015-02-05 08:28:45
很久以前,我就设法解决了这个问题,但很久以前,我用以下方法解决了这个问题,对此我很抱歉:
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-05 00:00:47
最近,我在将XNA应用程序移植到WPF时遇到了同样的问题。在我的例子中,我通过使用后台线程从文件中加载位置、法线和索引来部分解决这个问题。然后,在同一个线程中,用Model3DGroup和MeshGeometry3D构造一个包含XAML的内存流。
然后,在UI线程中,一旦内存流可用,就加载模型.
Model3DGroup model = System.Windows.Markup.XamlReader.Load(memoryStream) as Model3DGroup;仍然存在延迟,但是由于文件访问是在后台线程中完成的,所以没有那么严重。
发布于 2015-05-13 23:08:56
使用委托仍然会在UI上引入延迟,更好的解决方案是在工作线程中创建模型,然后冻结它。然后,该模型可以由UI线程进行克隆,而不会出现恼人的异常。这适用于我的模型,需要25秒或更多的加载。我发现的唯一问题是,如果模型包含纹理,它就不能工作。
https://stackoverflow.com/questions/19026017
复制相似问题