WPF - 我使用BackgroundWorker创建Model3D对象,但是当我想将它添加到XAML中定义的Model3DGroup时,我得到了异常:
不能使用属于与其父Freezable不同的线程的DependencyObject。
这是完整的代码背后:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
GeometryModel3D geometryModel3D = (GeometryModel3D)e.Result;
model3DGroup.Children.Add(geometryModel3D);
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
GeometryModel3D geometryModel3D = new GeometryModel3D();
e.Result = geometryModel3D;
}
}
这就是整个XAML:
<Grid>
<Viewport3D Margin="4,4,4,4" Grid.Row="0" Grid.Column="0">
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup x:Name="model3DGroup">
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
答案 0 :(得分:2)
在RunWorkerCompleted处理程序中,您将GeometryModel3D实例添加到Model3DGroup,这显然是在UI线程以外的线程中创建的,因为BackgroundWorker.DoWork处理程序是在单独的线程中执行的。
简而言之,WPF不允许这样做,因为您可能已经从异常消息中注意到了。必须在同一个线程中创建应用程序中所有DispatcherObject派生对象的所有UI元素,或更准确地说。
概述WPF Threading Model,并参阅BackgroundWorker文档中的备注部分。
编辑:您可以通过同步调用MainWindow类的Dispatcher来创建新的GeometryModel3D实例(未经测试):
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = Dispatcher.Invoke(
(Func<GeometryModel3D>)(() => new GeometryModel3D()));
}
答案 1 :(得分:1)
在我的情况下,我在新的调度程序线程上创建了一个新的WPF窗口。
一切都与最小的WPF项目完美配合,但如果我将相同的代码移植到我们的大型生产WPF代码库中,它就失败了。
问题是有一些继承的对象绑定到错误线程上的某些东西。
我能够在受影响的UserControl中使用它来避免此错误:
public MyUserControl()
{
// Discard all inherited styles.
this.InheritanceBehavior = InheritanceBehavior.SkipAllNow;
this.InitializeComponent();
}
现在我已经有了它,我可以找出哪个样式或附加属性有一个隐藏的绑定到另一个线程,这导致了这个问题。
问题在于某些资源未被冻结。这里引用了违规资源:
ResourceDictionary resources = Application.Current.Resources;
foreach (var resource in resources)
{
// The offending resource (a scrollbar) is listed here.
}
答案 2 :(得分:0)
You can create Model3D geometry in a separate thread. But Freeze it after it is created. The RunWorkerCompleted method can then simply Clone the frozen geometry (although I have failed to get this to work if a Model3D contains a texture).