Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How To Add An Animated 3D WPF Splash Screen

0.00/5 (No votes)
25 Oct 2010 1  
Explains how to add an animated 3D splash screen to a WinForms application using WPF and XAML

Introduction

This article is based on Visual Studio 2010. The target .NET Framework for the build is 4.0 so your computer should have all the required software to build and run the project.

Microsoft WPF offers 3D content that you can add to desktop applications or browser-based applications. But what to do with 3D content? What is it really useful for? If you are making games or 3D modeling applications, the answer is obvious. But for most people who are building ordinary applications, it's difficult to figure out a place to fit in 3D content.

One use for 3D models might be as a splash screen. This article explains how to add a splash screen to the beginning of a WinForms application. The splash screen fades into view and contains animated 3D content. It then fades out to reveal your application.

It might seem that this is an oddball example that nobody really needs. But it's a way to add some flash and visual interest to an ordinary looking program. And for those who want to get their hands on doing some 3D coding, it's a simple way to start. Also, there are a few basic things the article teaches. It will show how to integrate WPF controls into an ordinary Windows Forms application. It shows how to include XAML code in your application as an embedded resource. And it includes a couple of other simple but useful techniques, like how to get the screen working area and how to accomplish some simple opacity animation using timers.

To begin, open Visual Studio 2010 and start a WinForms project.

Choose "New" and "Project" from the file menu. For the template, choose "Visual C#" under "Windows" in the left hand tree, then choose "Windows Forms Application" from the list on the right, enter your desired project name (SplashScreenInWPF) and location and click OK.

You will need to add some references to your project since you are using WPF controls in a Windows Forms project. Right click on References in your project in the Solution Explorer and add the following references:

  • PresentationCore
  • PresentationFramework
  • System.XAML
  • WindowsBase
  • WindowsFormsIntegration

You will end up with a project that has one form called Form1. Right click on Form1.cs in the Solution Explorer and choose "View Code."

You will need to add some using lines to the top of your source file:

using System.IO;

This is to allow you to use a StreamReader to read XAML from your embedded resource.

using System.Windows.Markup;

This will allow you to work with XAML content.

using System.Windows.Media.Media3D;

This will allow you to include a 3D model in your application.

using System.Windows.Controls;
	using System.Windows.Forms.Integration;

These will allow you to host WPF controls in your Winforms application.

Now open Form1 in the designer, right click on the form to get the form properties page, and make these changes:

Set FormBorderStyle to 'None' because you don't want any borders or bars or menus on your splash screen.

Set ShowInTaskBar to 'False'. You don't want your splash screen to show in the task bar.

Click "Toolbox" on the "View" menu to show the toolbox window. Under the category "All Windows Forms", find a Timer on the toolbox and drag it to the open area of the Form1. This adds a Timer to the form to control your fade in and fade out behavior.

Double click on the open area of the form to add a Load event. The code looks like this:

private void Form1_Load(object sender, EventArgs e)
{
}

Double click on the timer to add a Tick event. The code looks like this:

private void timer1_Tick(object sender, EventArgs e)
{
}

You will need a text file for your project that contains the XAML to describe the 3D content and animations you want in your splash screen. Generating the exact XAML code is beyond the scope of this article, but later in the article I will explain how I created the animated 3D content for this project and tell you where to get some helpful tools for doing that. For now, I have included a file called splashXAML.txt in the files for this article. Copy the file into your project directory and add it to the project. Right click on the project name in the Solution Explorer and choose "Add" then choose "Existing Item", then browse for the splashXAML.txt file and double click to add it to your project.

Right click on the file splashXAML.txt in the Solution Explorer and choose "Properties" to open the properties page for the file. Set the Build Action for the file to "Embedded Resource".

Add a function to the Form1 class that can read in the XAML from your resource. Here is the code you will need:

private string getSplashXAML()
{
    string contents;

    System.IO.Stream stream = this.GetType().Assembly.GetManifestResourceStream
    				("SplashScreenInWPF." + "splashXAML.txt");

    using (StreamReader reader = new StreamReader(stream))
    {
        contents = reader.ReadToEnd();
    }

return contents;
}

Make sure the string for GetManifestResourceStream is constructed correctly. The first part has to exactly match the namespace for your project, followed by a dot. The second part is the exact name of the resource file you added to the project.

You will want to set the size of your splash screen to the screen working area. So add a function to do that. Here is the code you will need:

public static System.Drawing.Rectangle GetScreenWorkingArea()
{
    System.Drawing.Rectangle rs = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
    Point p = new Point(rs.Width / 2, rs.Height / 2);
    rs = System.Windows.Forms.Screen.GetWorkingArea(p);
    return rs;
}

You will need to add some variables to the top of the Form1 class that will control your animation:

int timerInterval = 4;

bool startedApp = false;
bool endedSplash = false;

private double fadeInTime = 500;
private double holdTime = 2000;
private double fadeOutTime = 2500;
private double startAppTime = 800;

double elapsedTicks = 0;

You can change some of the values to control the speed of your fade in and fade out.

You also need some variables for the controls to host your 3D content:

Viewport3D viewport1 = null;
ContentControl contentControl = null;

You will need a function to hide the splash screen after it has done its job. Here is the code for that:

private void hideSplash()
{
    timer1.Stop();

    // free resources by letting the viewport with its models 
    // and animations to get garbage collected
    contentControl.Content = null;
    viewport1 = null;

    TopMost = false;
    Visible = false;
}

This function also eliminates the reference to your ViewPort3D so the garbage collector can free them. This is important because you don't want the meshes and animation timers from your 3D model taking up memory and cycles that your application could be using.

Now it's time to add a form for your application. Form1 is your splash screen. The new form you add will be the actual user interface for your application. Right click on your project name in the Solution Explorer and choose "Add" from the menu, then choose "Windows Form". Call the new form "FormAppWindow.cs" and click the Add button to add it.

Add a parameter to the constructor for FormAppWindow.cs that takes a Form1 as an argument, and use it to set a local variable in your app form. The code will look like this:

namespace SplashScreenInWPF
{
    public partial class FormAppWindow : Form
    {
         Form1 parentForm;

         public FormAppWindow(Form1 ParentForm)
         {
             InitializeComponent();
             parentForm = ParentForm;
         }
    }
}

Open FormAppWindow in the designer and double click on the open area in the form to add a Load event. On the load event, call the static function you added to your splash screen that gets a rectangle for your screen working area, and, use it to set the bounds of your application when it starts. The code now should look like this:

namespace SplashScreenInWPF
{
    public partial class FormAppWindow : Form
    {
        Form1 parentForm;

        public FormAppWindow(Form1 ParentForm)
        {
            InitializeComponent();
            parentForm = ParentForm;
        }

        private void FormAppWindow_Load(object sender, EventArgs e)
        {
            System.Drawing.Rectangle rs = Form1.GetScreenWorkingArea();
            SetBounds(0, 0, rs.Width, rs.Height);
        }
    }
}

You will need to make sure you close parent of the application form which is your splash screen, when you close your application. So right click on the application form to get a property window. Click on the lightning bolt in the properties window and double click on the FormClosing event to add a handler. Then add some code that closes your parent window. The code for the FormAppWindow will now look like this:

namespace SplashScreenInWPF
{
    public partial class FormAppWindow : Form
    {
        Form1 parentForm;

        public FormAppWindow(Form1 ParentForm)
        {
            InitializeComponent();
            parentForm = ParentForm;
        }

        private void FormAppWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            parentForm.Close();
        }

        private void FormAppWindow_Load(object sender, EventArgs e)
        {
            System.Drawing.Rectangle rs = Form1.GetScreenWorkingArea();
            SetBounds(0, 0, rs.Width, rs.Height);
        }
    }
}

You can use the ToolBox to add some other controls to your FormAppWindow, to make it look like it is ready to do some kind of work. It doesn't matter which controls you add, just give it some visual content to look at and play with. I included in my application window a menu strip, and a text box which can display the XAML string that creates the 3D animation for the splash screen. If you build the project included with this article you can see the menu and the controls I added. I won't describe how to add these parts because it's easy to figure out.

Now we are ready to add the code that makes the splash screen do its work. Go back to the Form1.cs file and add this code to the load event. When you are finished, it should look like the code below. You can read the comments in the code below to understand what it is doing. Basically it creates the controls you need to host your 3D content, reads in the XAML from your embedded resource, and uses that to create a ViewPort3D to show your 3D content.

private void Form1_Load(object sender, EventArgs e)
{
    try
    {
        // get the XAML for your 3D content
        string xaml = getSplashXAML();
        
        // set the window to TopMost because it is your splash screen
        TopMost = true;
        
        CenterToScreen();
        
        Visible = true;
        
        // set the opacity to 0 because we are going to fade the splash screen in
        Opacity = 0;
        
        // set the splash screen size to the screen working area
        System.Drawing.Rectangle rs = GetScreenWorkingArea();
        SetBounds(0, 0, rs.Width, rs.Height);
        
        // add an element host control to the form to let it host WPF controls
        ElementHost elementHost = new ElementHost();
        Controls.Add(elementHost);
        
        // set the size of the elementHost
        elementHost.SetBounds(ClientRectangle.Left, ClientRectangle.Top, 
				ClientRectangle.Width, ClientRectangle.Height);
        
        // add a Grid control to host your content and make is a child of the ElementHost
        Grid grid = new Grid();
        
        grid.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
        grid.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
        
        elementHost.Child = grid;
        
        // add a ContentControl to your Grid that will host the 3D content
        contentControl = new ContentControl();
        
        grid.Children.Add(contentControl);
        
        // call the function you added earlier to get the XAML 
        // for your animated 3D content
        string content = getSplashXAML();
        
        // create a stream from the content so XamlReader can use it
        byte[] byteArray = Encoding.ASCII.GetBytes(content);
        MemoryStream stream = new MemoryStream(byteArray);
        
        // use XamlReader to create a Viewport3D object from the XAML code
        object o = XamlReader.Load(stream);
        
        contentControl.Content = o;
        
        // set your viewport to the one you read in from the resource
        if (o is Viewport3D)
        {
            viewport1 = (Viewport3D)o;
        }
        
        // start a timer that will fade in your content while it animates, 
        // then fade it out
        timer1.Interval = timerInterval;
        timer1.Start();
    }
    catch (Exception ex)
    {
        string s = ex.Message;
        MessageBox.Show(s);
    }
}

Now we are almost finished. Just add some code to the Tick event to make the fades happen and to display your application. See the comments in the code below to get a step by step of what it does:

private void timer1_Tick(object sender, EventArgs e)
{
    // increment the elapsed ticks
    elapsedTicks += timerInterval;
    
    if (elapsedTicks < fadeInTime)
    {
        // for a period of time, we are fading the splash in by incrementing its opacity
        double op = 1;
        op *= elapsedTicks;
        op /= fadeInTime;
        Opacity = op;
    }
    else
    {
        // we are finished fading in
        if (elapsedTicks < holdTime)
        {
            // hold splash steady at full opacity for a specified time
            if (Opacity < 1)
            {
                Opacity = 1;
            }
            
            // start the application window when it is time
            // give its constructor this window as a parent
            if (!startedApp)
            {
                if (elapsedTicks >= startAppTime)
                {
                    startedApp = true;
                    
                    FormAppWindow app = new FormAppWindow(this);
                    app.ShowDialog();
                }
            }
        }
        else
        {
            // now we are fading out to reveal the application behind the splash
            Opacity -= ((double)1 / ((fadeOutTime - holdTime) / timerInterval));
            
            if (Opacity <= 0 && !endedSplash)
            {
                // when we are faded out all the way, hide the splash screen
                endedSplash = true;
                
                Visible = false;
                
                hideSplash();
            }
        }
    }
}

When you run your program, if everything was done correctly, you will see the splash screen gradually fade in until you can see the animated 3D model. Objects in the 3D model will be in motion as it fades into view. The camera will also be doing a flyaround until it lands in front of the model. The application main screen will start after the splash is completely opaque, then the splash screen will fade out, revealing the application.

The last question is: how to come up with the XAML code that makes the 3D animation? Even for a simple scene like the one we include here, thousands of 3D coordinates for hundreds of triangles are required. Visual Studio does not include any tools that help you build or animate 3D triangle meshes. Blend is no help either. I have written a program called Calder4D which lets you directly model 3D shapes and animate them, and then produces the XAML code to make them work. The XAML code file included in this article was made with Calder4D, and it is the same XAML that is used for the Calder4D splash screen. You do not need Calder3D to build this example, but it is available as a tool for creating animated 3D models in XAML.

If you want to try out Calder4D and create some of your own animated 3D scenes, here is a link to find out more about it.

A note about XAML files: if you are making your own XAML file to use as content for this article, it must have a valid Viewport3D as its root object because that is the kind of object the XamlReader is expecting to find. Also, you must add these lines as attributes of the Viewport3D object:

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

These are the WPF and XAML Namespace Declarations. You can look at the XAML file included with this project to see exactly where these lines belong in the XAML file.

History

  • 25th October, 2010: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here