6

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>
4

3 回答 3

2

在您的 RunWorkerCompleted 处理程序中,您将 GeometryModel3D 实例添加到 Model3DGroup,这显然是在 UI 线程以外的线程中创建的,因为 BackgroundWorker.DoWork 处理程序是在单独的线程中执行的。

简而言之,WPF 不允许这样做,您可能已经从异常消息中注意到了这一点。所有 UI 元素,或者更准确地说,应用程序中的所有DispatcherObject派生对象都必须在同一个线程中创建。

获取 WPF线程模型的概述,另请参阅BackgroundWorker文档中的备注部分。

编辑:但是,您可以通过同步调用 MainWindow 类的Dispatcher来创建新的 GeometryModel3D 实例(未经测试):

private void bw_DoWork(object sender, DoWorkEventArgs e)   
{   
    e.Result = Dispatcher.Invoke(
       (Func<GeometryModel3D>)(() => new GeometryModel3D()));
}   
于 2012-07-08T15:24:23.693 回答
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.                
}
于 2016-11-03T17:49:22.797 回答
0

您可以在单独的线程中创建 Model3D 几何。但在创建后将其冻结。然后 RunWorkerCompleted 方法可以简单地克隆冻结的几何体(尽管如果 Model3D 包含纹理,我无法让它工作)。

于 2015-05-12T23:32:34.057 回答