LaVOZs

The World’s Largest Online Community for Developers

'; wpf - Cannot use a DependencyObject that belongs to a different thread than its parent Freezable - LavOzs.Com

WPF - I'm using BackgroundWorker to create a Model3D object, but when I want to add it to a Model3DGroup that is defined in the XAML, I get exception:

Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.

This is the whole code behind:

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

and this is the whole 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>

In your RunWorkerCompleted handler you're adding a GeometryModel3D instance to a Model3DGroup, which was obviously created in a thread other than the UI thread, since the BackgroundWorker.DoWork handler is executed in a separate thread.

In short, WPF does not allow this, as you might have noticed from the exception message. All UI elements, or to be more precise, all DispatcherObject-derived objects in your application must be created in the same thread.

Get an overview of the WPF Threading Model and also see the Remarks section in the BackgroundWorker documentation.

EDIT: you could however create new GeometryModel3D instances by synchronously invoking the Dispatcher of your MainWindow class (without having tested that):

private void bw_DoWork(object sender, DoWorkEventArgs e)   
{   
    e.Result = Dispatcher.Invoke(
       (Func<GeometryModel3D>)(() => new GeometryModel3D()));
}   

In my situation, I was creating a new WPF window on a new dispatcher thread.

Everything worked perfectly with a minimal WPF project, but if I ported this same code into our large production WPF codebase, it failed.

The problem was that there was some inherited object that was binding to something on an incorrect thread.

I was able to avoid this error using this in the affected UserControl:

public MyUserControl()
{
    // Discard all inherited styles.
    this.InheritanceBehavior = InheritanceBehavior.SkipAllNow;

    this.InitializeComponent();
}

Now that I have it working, I can find out which style or attached property has a hidden binding to another thread, which is causing this issue.

Update

The issue is that some resources were not frozen. The offending resource is referenced here:

ResourceDictionary resources = Application.Current.Resources;
foreach (var resource in resources)
{
   // The offending resource (a scrollbar) is listed here.                
}

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).

Related
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
What is the difference between a process and a thread?
WPF multithreaded progress dialog
Databinding issue with stopwatched elapsed
DataContext in Window_Loaded
Cannot use a DependencyObject that belongs to a different thread than its parent Freezable
The calling thread cannot access this object because a different thread owns it
Cannot use a DependencyObject that belongs to a different thread than its parent Freezable - prism