Search code examples
wpfmultithreadingasynchronous3dviewport3d

Adding a child to Viewport3D asynchronously gives "This API was accessed with arguments from the wrong context."


When I try to add 3D-content to a Viewport3D, asynchronously, this results in "This API was accessed with arguments from the wrong context." in a TargetInvocationException.

The 3D-content is generated from the data of a 3D-scanning device. The communication&calculations needed for that are done in a separate thread. First, I tried to acces the viewport3D from that thread. I realized this should be done by the GUI-thread, so now I use this code:

        ModelVisual3D model = new ModelVisual3D();
        model.Content = scanline;

        DispatcherOperation dispOp = this.viewport.Dispatcher.BeginInvoke(
            new AddModelDelegate(StartAddModel), model);
    }
    private void StartAddModel(ModelVisual3D model)
    {
        this.viewport.Children.Add(model); 
        //model is not in the context of this current thread. 
        //Throws exception: "This API was accessed with arguments from the wrong context."
    }

    private delegate void AddModelDelegate(ModelVisual3D model);

It seems that the object named "model" is not in the context of the current thread. How can I fix this? Is there a way to get the model to the context of the Dispatcher? Or is this way of doing this just not the way to go here?


Solution

  • This will occur when ever you generate/modify scene objects to add to Viewport, from a different thread then the one Viewport was instantiated on. There is a simple work around. Encapsulate the code that updates Viewport objects into a function. Insert the following snippet and you are done.

    private delegate void MyFunctionDelegate();
    
    void MyFunction()
    {
         if(!Application.Current.Dispatcher.CheckAccess())
         {
             Application.Current.Dispatcher.Invoke(new MyFunctionDelegate(MyFunction));
             return; // Important to leave the culprit thread
         }
         .
         .
         .
         this.Viewport3D.Children.Remove(model);
         MyModifyModel(model);
         this.Viewport3D.Children.Add(model); 
    }