Interactive Animated 2D Elements in a 3D ItemsControl

EDIT: After posting this entry, I published an article on CodeProject that shows a more robust and complete solution than the one shown here. You can view that article here.

A few posts back I showed how to apply a custom 3D panel to an ItemsControl, so that its items render in a Viewport3D contained in the panel’s adorner layer. In this post, I take that example a step further and show how to make those 2D elements respond to user input while in 3D space. The demo application is a 3D blogroll for members of the WPF Disciples group. It looks like this:

WPF Disciples 3D Blogroll (Screenshot)

(click on the image to see it at full size)

Each item in the list represents a blogger from WPF Disciples who has a bio on the group’s blog. If you click on the person’s name, a Web browser opens to that person’s bio. If you click on the blogger’s picture, it opens a browser to that person’s blog. Click on the buttons below to navigate between bloggers. Holding a navigation button down will continuously scroll through the items.

I tried to use a Viewport2DVisual3D in my original 3D ItemsControl project,so that the user could interact with the list’s items. However, there was a problem. In order to a host a 2D element in a Viewport2DVisual3D it must be parented to it, by setting the Visual property to the 2D element. Since my Panel3D is being used as an ItemsControl’s ItemsPanel, it cannot add or remove child elements. WPF enforces that rule at run time, by throwing an exception after you try to remove an element from the Panel’s Children collection. A child element of an items panel cannot be parented to another element, but Viewport2DVisual3D must be the visual parent of a 2D element in order to host it in 3D space.

The panel has children that it cannot remove but it must somehow render them in 3D space. The solution I originally used was to create a 3D mesh painted with a VisualBrush that references the panel’s child element. That technique prevented the 2D elements from responding to user input, since they were not really in the 3D scene. It just looked like they were in the 3D scene.

After much experimentation and discussion with other WPF Disciples, I finally found a way around this barrier. I figured out a way to dynamically generate a ContentPresenter such that it renders the content exactly how a ContentPresenter generated by the ItemsControl renders it. Here is that magic method:

WPF Disciples 3D Blogroll (CreateContentPresenter)

I had to jump through some hoops to make the ContentPresenter use the correct DataTemplate for its ContentTemplate property. What is even stranger is the fact that if it uses a typed DataTemplate, it must be declared in XAML with the explicit notation for the TypeExtension. For example, you must configure the typed DataTemplate with DataType=”{x:Type TypeName}” instead of the more convenient DataType=”TypeName“. Smells like a bug to me…

Here is the method that creates a Viewport2DVisual3D and calls the method seen above to create a 2D element:

WPF Disciples 3D Blogroll (Build 3D Model)

You can download this project’s source code here: WPF Disciples 3D Blogroll (Source Code) NOTE: Be sure to change the file extension from .DOC to .ZIP and then decompress the file.

6 Responses to Interactive Animated 2D Elements in a 3D ItemsControl

  1. Karl Shifflett says:

    Josh,

    You are the WPF Grand Master. Awesome work!

    Cheers,

    Karl

  2. […] WPF Disciples has a 3D blogroll 2 04 2008 Josh has been at it again. This time he took all of the WPF Disciple member bio’s and turned it into an interactive 3D blogroll! Check it out here. […]

  3. Josh Smith says:

    Thanks Karl! This is so much fun!!!!!

  4. Josh, you have no limits in WPF!!! You rulez!! 🙂

  5. Josh Smith says:

    Thanks Rodrigo! WPF rules! 😀

  6. peteohanlon says:

    Josh – this is awesome, and just the job for something I’m currently working on. Basically, I want to represent an organisation layout, and this would be a really useful choice for displaying the layout. What I’m thinking is have one “layer” which represents the departments, and when one is selected the employees “fly” out in 3D so that the department moves to the back but the employees are rendered on top.