How to combine Silverlight and the XNA Framework in a Windows Phone app

[This documentation is preliminary and is subject to change.]

July 06, 2012

Applies to: Windows Phone 8 Developer Preview | Windows Phone OS 7.1

This topic provides step-by-step instructions for creating a basic app that combines Silverlight and the XNA Framework. You can find this completed Silverlight/XNA Framework sample in the Code samples for Windows Phone topic. There is also a more elaborate sample called MyLittleTeapot on the same page that demonstrates how to update the XNA Framework content by responding to gestures from the Silverlight input system.

Tip Tip:

Before continuing, read Using the project template that combines Silverlight and XNA in Windows Phone to understand the code created by the project template used in this article.

In the past, you were forced to decide whether to use Silverlight or the XNA Framework to build your Windows Phone app. While some classes could be shared across frameworks, only one framework could be used for visuals. Starting with Windows Phone OS 7.1, you can combine Silverlight and the XNA Framework into a single app by using the new SharedGraphicsDeviceManager and the UIElementRenderer class.

Note Note:

The steps in the following procedure are for Visual Studio 2010 Express for Windows Phone. You may see some minor variations in menu commands or window layouts when you are using the add-in for Visual Studio 2010 Professional or Visual Studio 2010 Ultimate.

This topic contains the following sections.

The first step in creating a Windows Phone Silverlight app is to create a new project.

To create a new project

  1. Make sure you have downloaded and installed the Windows Phone SDK. For more information, see Installing the Windows Phone SDK.

  2. Start Visual Studio 2010 Express for Windows Phone from the Windows Start menu. If the Registration window appears, you can either register or temporarily dismiss the window.

  3. Create a new project by selecting the File | New Project menu command.

  4. The New Project window is displayed. Expand the Visual C# templates, and then select the Silverlight for Windows Phone templates.

  5. Select the Windows Phone Silverlight and XNA Application template. Fill in the project Name with a name of your choice.

    GetStartedNewProjectSilverlightXNA
  6. Click OK. Visual Studio creates a new project and opens MainPage.xaml in the Visual Studio designer window.

    After creating the project, you may see an item in the Warning window that says something similar to: “The project 'SilverlightXNAAppLib' cannot be referenced. The referenced project is targeted to a different framework family (.NETFramework).” You can safely ignore this error. It is simply referring to naming differences between the Silverlight and XNA Framework assemblies.

  7. Make sure Windows Phone Emulator is selected in the target drop-down at the top of Visual Studio.

  8. Press F5 to run the project under Windows Phone Emulator.

  9. In the emulator, press the Change to game page button.

The default project uses the XNA Framework to clear the Windows Phone screen to the CornflowerBlue color. We will:

  • Add code to animate a rectangle on the screen

  • Add Silverlight button controls, creating a color panel, to change the color of the rectangle

  • Add a button to toggle the visibility of the color panel

The XNA Framework will render these controls and the animated rectangle.

Create and add different colored rectangles to the library content for the project.

To create new graphics library content

  1. Right-click on the following graphic and choose Save picture as….

    Red rectangle
  2. In the Save Picture dialog, navigate to the directory where you created your project.

  3. Save the picture as redRect.jpg in the XxxxLibContent directory, where Xxxx is the name of the project you entered in step 5 of the Creating a New Project section earlier in this topic.

  4. Do the same with the following two graphics, saving them as greenRect.jpg and blueRect.jpg, respectively.

    Green rectangle

    Blue rectangle
  5. In Solution Explorer, right-click XxxxLibContent (Content), where Xxxx is the name of the project you entered in step 5 of the Creating a New Project section earlier in this topic.

  6. In the context menu, choose Add > Existing Item….

  7. In the Add Existing Item dialog, select all 3 files by holding down the CTRL key while clicking blueRect.jpg, greenRect.jpg, and redRect.jpg.

  8. Click the Add button to add the graphics files to the project.

In this section, we will load the rectangles as graphics content and animate the currently selected rectangle.

To load and animate the graphics

  1. In Solution Explorer, expand GamePage.xaml by clicking the triangle to its left.

  2. In the code editor, open GamePage.xaml.cs by double-clicking it.

  3. Declare four Texture2D variables at class scope in the GamePage class.

    // The current rectangle
    Texture2D texture;
    
    // A variety of rectangle colors
    Texture2D redTexture;
    Texture2D greenTexture;
    Texture2D blueTexture;
    
  4. Scroll down to the OnNavigatedTo method.

  5. After the TODO: comment, add the following code:

    // If texture is null, we've never loaded our content.
    if (null == texture)
    {
        redTexture = contentManager.Load<Texture2D>("redRect");
        greenTexture = contentManager.Load<Texture2D>("greenRect");
        blueTexture = contentManager.Load<Texture2D>("blueRect");
    
        // Start with the red rectangle.
        texture = redTexture;
    }
    
  6. Declare two Vector2 variables at class scope in the GamePage class.

    // Used to move the rectangle around the screen
    Vector2 spritePosition;
    Vector2 spriteSpeed = new Vector2(100.0f, 100.0f);
    
  7. Replace the contents of the OnUpdate method with the following code.

    // Move the sprite by speed, scaled by elapsed time.
    spritePosition += spriteSpeed * (float)e.ElapsedTime.TotalSeconds;
    
    int MinX = 0;
    int MinY = 0;
    int MaxX = SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width - texture.Width;
    int MaxY = SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Height - texture.Height;
    
    // Check for bounce.
    if (spritePosition.X > MaxX)
    {
        spriteSpeed.X *= -1;
        spritePosition.X = MaxX;
    }
    
    else if (spritePosition.X < MinX)
    {
        spriteSpeed.X *= -1;
        spritePosition.X = MinX;
    }
    
    if (spritePosition.Y > MaxY)
    {
        spriteSpeed.Y *= -1;
        spritePosition.Y = MaxY;
    }
    else if (spritePosition.Y < MinY)
    {
        spriteSpeed.Y *= -1;
        spritePosition.Y = MinY;
    }
    
  8. Replace the contents of the OnDraw method with the following code.

    SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);
    
    // Draw the sprite
    spriteBatch.Begin();
    
    // Draw the rectangle in its new position
    spriteBatch.Draw(texture, spritePosition, Color.White);
    
    spriteBatch.End();
    
  9. Select Windows Phone Emulator as the target and press F5 to run your app. Click the Change to game page button and you should see something very similar to the following image.

    Silverlight XNA application animated rectangle

In this section, we use XAML to create a panel of Silverlight Button controls. The buttons enable the user to change the color of the rectangle. We’ll also add a button to toggle the visibility of the color panel. Using the UIElementRenderer class, these controls are rendered to a Texture2D, which is then painted on the screen in a SpriteBatch operation in the OnDraw method.

To add Silverlight controls

  1. In Solution Explorer, double-click GamePage.xaml to open it in the designer.

  2. Since we will be using XAML, replace the following comment:

    <!--No XAML content as the page is rendered entirely with XNA-->
    

    With the following XAML code.

    <!-- LayoutRoot is the root grid where all page content is placed. -->
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
    
        <!-- Toggle the visibility of the ColorPanel. -->
        <Button Grid.Row="0" x:Name="ColorPanelToggleButton" Click="ColorPanelToggleButton_Click" Margin="1,0,-1,0">Toggle Color Panel</Button>
    
        <!-- Arrange buttons in a horizontal line by using StackPanel. -->
        <StackPanel x:Name="ColorPanel" Grid.Row="2"  Height="100" Orientation="Horizontal" HorizontalAlignment="Center" Visibility="Visible">
            <!-- Buttons to set the rectangle to specific colors -->
            <Button Click="redButton_Click" HorizontalAlignment="Center" Height="75" VerticalAlignment="Center" BorderThickness="3" Background="Red" Width="75" />
            <Button Click="greenButton_Click" HorizontalAlignment="Center" Height="75" VerticalAlignment="Center" BorderThickness="3" Background="Lime" Width="75" />
            <Button Click="blueButton_Click" HorizontalAlignment="Center" Height="75" VerticalAlignment="Center" BorderThickness="3" Background="Blue" Width="75" />
        </StackPanel>
    </Grid>
    

    This XAML code creates a Grid element to contain all the other elements. It first defines the Grid to have three rows. By using the Auto keyword, the top row and the bottom row Height properties are defined by their content. Using the asterisk (*) for the middle row Height property makes that row take up all the remaining space between the other two rows.

    Next, the XAML defines a Button with the Click event handler set to a method called ColorPanelToggleButton_Click.

    The XAML then defines a StackPanel to hold the Button elements that make up our color panel. The StackPanel has the x:Name property set to ColorPanel. This name is used in the C# code to toggle the visibility of this panel.

    The Button elements each have their Background color set and a Click event handler assigned.

    The following figure shows what our app in the designer should look like.

    GetStartedSilverlightXNALayout

Now that we’ve added our controls and assigned names to the Click event handlers, we need to implement the handler methods.

To add event handlers

  1. In the Visual Studio code editor, open or switch to GamePage.xaml.cs.

  2. Scroll down to the end of the file, past the OnDraw method.

  3. Copy and paste the following code immediately after the OnDraw method.

    // Toggle the visibility of the StackPanel named "ColorPanel".
    private void ColorPanelToggleButton_Click(object sender, RoutedEventArgs e)
    {
        if (System.Windows.Visibility.Visible == ColorPanel.Visibility)
        {
            ColorPanel.Visibility = System.Windows.Visibility.Collapsed;
        }
        else
        {
            ColorPanel.Visibility = System.Windows.Visibility.Visible;
        }
    }
    

    This code simply toggles the Visibility property on the StackPanel that we named “ColorPanel” in the XAML code.

  4. After the ControlPanelToggleButton_Click handler, copy and paste the following three Click handlers for the color Button elements that we declared in the XAML.

    // Switch to the red rectangle.
    private void redButton_Click(object sender, RoutedEventArgs e)
    {
        texture = redTexture;
    }
    
    // Switch to the green rectangle.
    private void greenButton_Click(object sender, RoutedEventArgs e)
    {
        texture = greenTexture;
    }
    
    // Switch to the blue rectangle.
    private void blueButton_Click(object sender, RoutedEventArgs e)
    {
        texture = blueTexture;
    }
    

    These event handlers just set the Texture2D object that we use to render the rectangle on the screen, called “texture”, to point to the appropriately colored rectangle, which we already loaded in the OnNavigatedTo method.

Now that we have created the controls and coded the event handlers, all we need to do is render them on the screen.

To render Silverlight controls

  1. In the GamePage.xaml.cs file, declare a UIElementRenderer at class scope level in the GamePage class.

    // For rendering the XAML onto a texture
    UIElementRenderer elementRenderer;
    
  2. In the GamePage class constructor, declare a handler for the LayoutUpdated event.

    // Use the LayoutUpdate event to know when the page layout 
    // has completed so that we can create the UIElementRenderer.
    LayoutUpdated += new EventHandler(GamePage_LayoutUpdated);
    
  3. Implement the GamePage_LayoutUpdated event handler. The this parameter in the call to the UIElementRenderer constructor is referring to the GamePage class, which is partially defined by the XAML code in the GamePage.xaml file. The UIElementRenderer class takes the XAML elements that are derived from UIElement and renders them to a Texture2D object.

    void GamePage_LayoutUpdated(object sender, EventArgs e)
    {
      // Create the UIElementRenderer to draw the XAML page to a texture.
    
      // Check for 0 because when we navigate away the LayoutUpdate event
      // is raised but ActualWidth and ActualHeight will be 0 in that case.
      if ((ActualWidth > 0) && (ActualHeight > 0))
      {
        SharedGraphicsDeviceManager.Current.PreferredBackBufferWidth = (int)ActualWidth;
        SharedGraphicsDeviceManager.Current.PreferredBackBufferHeight = (int)ActualHeight;
      }
    
      if (null == elementRenderer)
      {
        elementRenderer = new UIElementRenderer(this, (int)ActualWidth, (int)ActualHeight);
      }
    }
    
    Note Note:

    You cannot remove the Silverlight UIElement specified in the UIElementRendererconstructor from the visual tree.

  4. Next, use the UIElementRenderer instance to draw the Silverlight controls on the screen. Find the OnDraw method in the GamePage.xaml.cs file. Add the following line of code before the call to spriteBatch.Begin. This is the code that actually renders the XAML into a buffer that can be accessed with the Texture property of the UIElementRenderer.

    // Render the Silverlight controls using the UIElementRenderer.
    elementRenderer.Render();
    
  5. Also in the OnDraw method, add the following line of code between the calls to spriteBatch.Begin and spriteBatch.End.

    // Using the texture from the UIElementRenderer, 
    // draw the Silverlight controls to the screen.
    spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Color.White);
    
  6. Select Windows Phone Emulator as the target and press F5 to run your app. You should see something very similar to the following image.

    GetStartedSilverlightXNARunning
  7. Click the buttons in the color panel at the bottom of the app to switch the color of the animated rectangle.

  8. Click the Toggle Color Panel button at the top of the app to hide and show the color panel.

Show: