Day #25: Silverlight Outside The Browser (Part 3 of 3)

If you’re wondering, I am certainly not writing these on the day they publish. These were written many, many days prior, and are only being published over the holidays. I’m spending my time celebrating with my family, exchanging gifts, and catching up on some sleep. Have a happy holiday season everyone.

Detecting A Network Connection

Today is the final part of a three part series on “Out of Browser”, which is a part of a larger series, the 31 Days of Silverlight.

We continued yesterday with a simple Silverlight project that had Out of Browser enabled, and was capable of installation and detected its state. You can download that out of browser application here. We’ll be adding to that project today.

Our next step is to determine whether a user has a network connection while running our application.

1. Checking the network connection

We have to add an additional namespace in order to work with our network connection, so let’s start there. Add this using statement to the top of your MainPage.xaml.cs file:

using System.Net.NetworkInformation;

Once we’ve added that, we can use the NetworkInterface API. Since we know we’re going to need to extract this code into its own method, let’s just do that out of the gate. I am creating a function that has an if statement checking another boolean value, this time to determine if there is a network connection. If there is, my network status image is green, and if not, the image is red. Here’s the entire method:

        private void CheckNetworkStatus()
{
if (NetworkInterface.GetIsNetworkAvailable())
{
networkimage.Source = new BitmapImage(new Uri("network_on.png", UriKind.Relative));
}
else
{
networkimage.Source = new BitmapImage(new Uri("network_off.png", UriKind.Relative));
}
}

2. Setting up an event handler for changes

Because our network status can change while we’re running the application, we need to make sure that we’ve subscribed to the NetworkAddressChanged event. This way, our application will always be aware of the current network status. Here’s my event handler code:

NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);

Hooking everything up

Now, we’ve got an CheckNetworkStatus() method, but it’s not being called yet. I’m actually going to call it from two places: once when our apoplication loads, and the other in the event handler method. Here’s what our final code looks like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Net.NetworkInformation;

namespace SilverlightOutOfBrowser
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
outofbrowserimage.MouseLeftButtonUp += new MouseButtonEventHandler(installBigBangTheory);
}

void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
CheckNetworkStatus();
}

void installBigBangTheory(object sender, MouseButtonEventArgs e)
{
if (Application.Current.InstallState == InstallState.NotInstalled)
{
Application.Current.Install();
}
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
checkOOB();
CheckNetworkStatus();
}

private void CheckNetworkStatus()
{
if (NetworkInterface.GetIsNetworkAvailable())
{
networkimage.Source = new BitmapImage(new Uri("network_on.png", UriKind.Relative));
}
else
{
networkimage.Source = new BitmapImage(new Uri("network_off.png", UriKind.Relative));
}
}

private void checkOOB()
{
if (Application.Current.IsRunningOutOfBrowser)
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_on.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Big Bang Theory is installed on your machine.");
}
else
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_off.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Install Big Bang Theory");
}
}
}
}

Summary

For many applications, network status may seem like something you don’t need. But if you’re talking to web services, data, etc., you absolutely need to know that those things are not available. In general, I’d recommend setting up a local data cache, and synchronizing that in the background, so that you can pass the data back and forth with the confidence that you won’t lose it if the user loses their connection. But that’s an article for another time.

Launch this completed Silverlight Out of Browser application.

You can download the final source code for this Out of Browser Silverlight project here.

Day #24: Silverlight Outside The Browser (Part 2 of 3)

Detecting Whether A User Is In Or Out Of Browser

Today is the second part of a three part series on “Out of Browser”, which is a part of a larger series, the 31 Days of Silverlight.

We started yesterday with a simple Silverlight project that had Out of Browser enabled. You can download that out of browser application here. We’ll be adding to that project today.

In our next step, we’re going to need to know when the application is running in an out of browser state vs. a traditional in-browser state. With some simple event handlers, we can make this happen. We can also change our application to accommodate these changes.

1. Setting up a Loaded event handler

The first thing we need to do is tell our application to call an initial method when it loads. To do this, I added a simple event handler in my MainPage() method.

        public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}

This also creates the event handler method for us, and I’m going to add a simple if/then/else statement to determine our browser state.

2. Detecting the browser state

In our new event handler method, I’ve created an if statement that just checks the boolean value of Application.Current.IsRunningOutOfBrowser. In each case, I change the image to either red or green, and adjust the tooltip to read the appropraite text for the state. Here’s what the method looks like:

        void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (Application.Current.IsRunningOutOfBrowser)
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_on.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Uninstall Big Bang Theory");
}
else
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_off.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Install Big Bang Theory");
}
}

Because I might want to call this functionality at other times than when the application loads, I’m going to refactor this code a little. If you haven’t used this functionality of Visual Studio 2008 before, I highly recommend it.

3. Refactoring our code

Highlight the code you want to move to its own method, and right click on it. Like this:

It will prompt you to give this code a new method name. I called my method CheckOOB, since that’s what it will do.

So here’s what my entire code-behind file looks like now:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

namespace SilverlightOutOfBrowser
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
checkOOB();
}

private void checkOOB()
{
if (Application.Current.IsRunningOutOfBrowser)
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_on.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Uninstall Big Bang Theory");
}
else
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_off.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Install Big Bang Theory");
}
}
}
}

The next thing I want to do it make it so that the image I am using to show status is also a button for the user to click. I don’t want them to have to discover the right-click menu to install, instead, I want to make it an obvious choice. Let’s do that next.

4. Creating an Install button

We will need an event handler on the image, so let’s start there:

outofbrowserimage.MouseLeftButtonUp += new MouseButtonEventHandler(outofbrowserimage_MouseLeftButtonUp);

In the subsequent method, we can simply call the Application.Current.Install() method. We need to wrap this statement in a check to make sure that the application has not already been installed. Where this becomes the biggest issue is when the user has installed your application, but is back at the website version of your app. If they click the Install button again, your application will throw an error, because it’s already been installed. Here’s the code:

void installBigBangTheory(object sender, MouseButtonEventArgs e)
{
if (Application.Current.InstallState == InstallState.NotInstalled)
{
Application.Current.Install();
}
}

An important thing to note about this Install() function is that it MUST be called by a user-instantiated action. This means that you can’t just call it when the application loads, or in the background. It has to have a code pathway that resulted from a user action.

Also, regarding uninstalling…there’s no way to do it via code. To uninstall, your user will have to right-click on the application, or go to their control panel to uninstall it. I’m hoping that we can provide a more user-friendly solution to this in future versions of Silverlight, but for SL3, this is the way it is.

Summary

This is actually a pretty simple process. Check a boolean value, and act accordingly. But, as we learned from the Spiderman movies, “with great power comes great responsibility.” Make sure that you’re providing clear instructions for your users regarding how to install and uninstall your application. Installing, as a word, is frightening to many users and most every systems administrator.

To see this application running, and to install it, click here.

If you’d like to download this code for this project, you can get my Out of Browser Detection solution here.

Day #23: Silverlight Outside The Browser (Part 1 of 3)

Enabling Out Of Browser in Your Silverlight App

For the next three days in the 31 Days of Silverlight, we’re going to cover some of the intricacies of getting a Silverlight application to run outside the user’s browser. This is a relatively simple change to your app, but it also introduces new challenges, like the need to detect which mode the user is in, and whether they have network connectivity or not. The next two articles will cover these topics specifically.

Today, we’re going to show you how to get out-of-browser working. So let’s get started.

To make this a little easier, I have created a sample project for you to start with. Inside, you’ll find a simple application that has a video player, and two images. The first image indicates whether there is network connectivity, and the other is to allow the user to “Install” the application to their machine.

But before we deal with any of that, we need to get our application “enabled” for the out of browser experience. By default, Silverlight 3 applications are not enabled.

1. Go to your Silverlight project properties

Opening the properties of your Silverlight project will give you the choice to “Enable running the application out of the browser, in addition to some new configuration choices. We’ll get to those in a second. Here’s what the screens look like:

2. Customize Your Settings

Once you’ve enabled Out of Browser for your Silverlight application, you get a new button to customize the settings for your installation. It includes things like titles, descriptions, and icons of different sizes for the shortcuts on your user’s machines. Here’s my completed Settings screen:

In case you’re curious, these settings are saved in a new XML file in your project. Look for OutOfBrowserSettings.xml in your Silverlight project’s Properties folder. Here’s what my settings file looks like:

<OutOfBrowserSettings ShortName="Big Bang Theory" EnableGPUAcceleration="False" ShowInstallMenuItem="True">
<
OutOfBrowserSettings.Blurb>This application will play the theme song for the CBS television show Big Bang Theory in a video found on YouTube. You can also find the video here: http://www.youtube.com/watch?v=lhTSfOZUNLo</OutOfBrowserSettings.Blurb>
<
OutOfBrowserSettings.WindowSettings>
<
WindowSettings Title="Big Bang Theory" Height="480" Width="640" />
</
OutOfBrowserSettings.WindowSettings>
<
OutOfBrowserSettings.Icons>
<
Icon Size="16,16">globe_16.png</Icon>
<
Icon Size="32,32">globe_32.png</Icon>
<
Icon Size="48,48">globe_48.png</Icon>
<
Icon Size="128,128">globe_128.png</Icon>
</
OutOfBrowserSettings.Icons>
</
OutOfBrowserSettings>

3. Installing the Application

I’ve chosen not to embed my application below (you can launch it here), because it has audio, and I don’t want to have that playing while you’re reading this post. If you right click on the application, you should have a second choice: Installing the application. If you choose this, it will save your application down to the local sandbox on your machine, and also gives you some choices for where to install it. When you’re done, it will also launch the local version for you as well. At that point, you can close your browser, and the application still works.

Here is a screenshot of the installation dialog (with my custom icon):

And here is a screenshot of the application running in the out-of-browser window.

Summary

You can see that this is a pretty simple process to enable Out of Browser functionality for your Silverlight application. In the next two days, we’re going to work on adding to this application, detecting whether the user has installed it or not, and then whether or not they have a network connection. Yes, Virginia, your Silverlight application can now run in a disconnected mode. See you tomorrow!

If you’d like to download this starter application, you can get my Out of Browser solution here.

Day #22: Using The Farseer Physics Engine in Silverlight

Today we’re going to venture into something you may never have played with before: a physics engine. This is article #22 in my series 31 Days of Silverlight. We are going to take a look at the Farseer Physics Engine for Silverlight.

What IS a physics engine?

Specifically, this is a 2-dimensional physics engine. What that means is that we can create elements that are smart enough to bounce off of each other, react to “gravity”, and other things that we might expect to see in the real world. There’s even properties like friction that we can apply to our XAML elements.

How do we get started?

The first thing you’ll want to do is download the actual Farseer engine from CodePlex. I provided a link to the project home page in the opening paragraph, but if you want a link to the specific version we’ll be using for this demo, you can also download the Farseer Engine 2.1.1 Silverlight here.

We’re going to grab another open source project, a Physics Helper. While the Farseer engine is incredibly useful, it could really use an additional layer of abstraction, and this Physics Helper does exactly that.

In order to make this incredibly simple, however, I’m providing a link to download the 3 DLLs we will need to add to our project. Download the Farseer and Physics Helper DLLs here.

1. Start a new Silverlight project.

Create a new Silverlight project. I named mine SilverlightPhysicsPyramid. You can name yours whatever you like.

2. Add some references to the DLLs.

Since you’ve already downloaded the three DLLs we will need, store them in a safe place, and add references to them in your project. Go ahead. I’ll wait. Once you’ve got that done, you’ll also want to add a reference to the System.Windows.Interactivity assembly as well. This is found in the “.NET” tab of the Add Reference dialog box.

3. Open your MainPage.xaml file.

For an application using these physics DLLs, we will always want to use a <Canvas> tag. So change the <Grid> tag to a <Canvas>. Don’t forget to change the closing tag as well. Next, I’ve created some XAML that we will use, so copy and paste this XAML into your <Canvas> tag. Here’s what the contents of your XAML file should look like:

<UserControl x:Class="SilverlightPhysicsPyramid.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<
Canvas x:Name="LayoutRoot" Background="Black">
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="215" Canvas.Top="433"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="245" Canvas.Top="433"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="433"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="433"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="335" Canvas.Top="433"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="365" Canvas.Top="433"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="230" Canvas.Top="403"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="283"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="313"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="313"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="320" Canvas.Top="343"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="343"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="260" Canvas.Top="343"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="335" Canvas.Top="373"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="373"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="373"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="245" Canvas.Top="373"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="350" Canvas.Top="403"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="320" Canvas.Top="403"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="403"/>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="260" Canvas.Top="403"/>
<
Rectangle Fill="White" StrokeThickness="2" Height="29" Width="640" Canvas.Left="0" Canvas.Top="475"/>
<
Ellipse Fill="Red" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Top="173" Canvas.Left="255"/>
</
Canvas>
</
UserControl>

If you run your project at this point, you should see a black background, and a pyramid of squares over a white platform with a red ball above them. Here’s a screenshot:

4. Adding those XML namespace entries

So, we added our DLLs as references, but because we’re going to do this work in our XAML file, we need to make sure that we have referenced the ones we’re using directly at the top of our file. We need to add the Spritehand.PhysicsBehaviors assembly, as well as System.Windows.Interactivity. If you’ve never used these statements before, just think of them like “using” statements in C#. Your <UserControl> tag should now look like this:

<UserControl x:Class="SilverlightPhysicsPyramid.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:pb="clr-namespace:Spritehand.PhysicsBehaviors;assembly=Spritehand.PhysicsBehaviors"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

I gave them nicknames of “i” and “pb” respectively, but you can call them whatever works for you. They’re just going to be shortcuts for adding our physics behaviors to our XAML elements.

5. Adding our PhysicsControllerBehavior

The first thing we need to do is define our PhysicsController. In most cases, this will be your primary <Canvas>, but you can really make any XAML container your PhysicsController. To do this in XAML, we going to add a Behaviors node to our &ltCanvas> and then specify the physics behavior we want to use. It looks like this:

<Canvas x:Name="LayoutRoot" Background="Black">
<
i:Interaction.Behaviors>
<
pb:PhysicsControllerBehavior MousePickEnabled="True"/>
</
i:Interaction.Behaviors>

You can see that I have added the PhysicsControllerBehavior to our <Canvas>. I also enabled the MousePickEnabled property, which will allow us to pick up and move any of our XAML elements that are specified as PhysicsObjects. Let’s do that next.

6. Creating PhysicsObjects

Much like we did with the PhysicsController, we are going to add a behavior to elements of our XAML document. The first two we’re going to start with are the <Ellipse> and the white rectangular platform at the bottom. For each of these, we’ll have to expand the tags to not be self-closing, but they’ll have to have both opening and closing tags. As an example, here’s what the <Ellipse> should look like now:

        <Ellipse Fill="Red" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Top="173" Canvas.Left="255">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Ellipse>

Our <Rectangle> platform will have the same thing done to it, but we are going to add one property: IsStatic. This defines the platform as an object that will participate in the physics engine, but doesn’t have any gravity affecting it. By default, each element that is a PhysicsObject will automatically have gravity, mass, etc. Here’s what our platform looks like:

        <Rectangle Fill="White" StrokeThickness="2" Height="29" Width="640" Canvas.Left="0" Canvas.Top="475">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior IsStatic="True"/>
</
i:Interaction.Behaviors>
</
Rectangle>

If you run your project now, you should see the red ball fall behind the pyramid of blocks, and “land” on the platform. Also, because we used the MousePickEnabled property on our PhysicsController, you can click on the ball and drag it around the screen, throwing it in the air, rolling it along the platform, etc. Have some fun with it! Please note that the “pyramid” of blocks don’t interact with the ball AT ALL. This is because they have not been defined as PhysicsObjects yet. That’s our next step.

7. Creating a falling pyramid.

For each of the <Rectangles> in our pyramid, we are going to add the same code that we added to our <Ellipse>. Once you’ve done that, your entire XAML file should look like this:

<UserControl x:Class="SilverlightPhysicsPyramid.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:pb="clr-namespace:Spritehand.PhysicsBehaviors;assembly=Spritehand.PhysicsBehaviors"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<
Canvas x:Name="LayoutRoot" Background="Black">
<
i:Interaction.Behaviors>
<
pb:PhysicsControllerBehavior MousePickEnabled="True"/>
</
i:Interaction.Behaviors>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="215" Canvas.Top="433">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="245" Canvas.Top="433">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="433">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="433">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="335" Canvas.Top="433">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="365" Canvas.Top="433">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="230" Canvas.Top="403">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="283">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="313">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="313">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="320" Canvas.Top="343">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="343">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="260" Canvas.Top="343">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="335" Canvas.Top="373">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="373">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="373">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="245" Canvas.Top="373">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="350" Canvas.Top="403">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="320" Canvas.Top="403">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="403">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="260" Canvas.Top="403">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Rectangle Fill="White" StrokeThickness="2" Height="29" Width="640" Canvas.Left="0" Canvas.Top="475">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior IsStatic="True"/>
</
i:Interaction.Behaviors>
</
Rectangle>
<
Ellipse Fill="Red" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Top="173" Canvas.Left="255">
<
i:Interaction.Behaviors>
<
pb:PhysicsObjectBehavior/>
</
i:Interaction.Behaviors>
</
Ellipse>
</
Canvas>
</
UserControl>

8. A quick summary

So, in a few quick minutes, we’ve created an environment that behaves like the real world. Try grabbing and dragging one of the bottom blocks from the pyramid. The structure crumbles much like you’d expect a stack of blocks to crumble. By starting with the simple, we can start to add more and more robust behaviors to our XAML elements, creating some really interesting user interfaces. If you’d like to see more examples of how to use these tools and behaviors, head over to the Codeplex project for the PhysicsHelper and download their Silverlight examples. There’s some neat examples of fluid dynamics, explosions, and even a Pinball game. Here’s our finished application:

Day #21: Rapid Silverlight Prototyping In SketchFlow

Today is day #21 of the 31 Days of Silverlight, and today we are going to be talking about a new tool available to developers called SketchFlow. While SketchFlow can be used in several different ways, I’m going to focus on how it can help you save time (and money) in rapidly getting a “proof of concept” application up and running quickly.

Getting SketchFlow

SketchFlow is a feature of Expression Blend 3, and you can download a 60-day trial of Blend 3 + SketchFlow from the Microsoft Expression website.

Creating a SketchFlow project

In Blend, choose “New Project,” and choose Silverlight 3 SketchFlow application.

What you’ll find is that it creates a pretty standard Silverlight project for you, and then there is an additional project that is the screens of our SketchFlow prototype. Let’s get into the details of what we can do with SketchFlow.

Creating our application’s pages

At the bottom of Expression Blend 3, you will see a tab named “SketchFlow Map.” In this window, there is one blue rectangle named “Screen 1.” Think of this as your home page. In fact, I double-clicked on mine and renamed it “Home.” When you roll over the box, you might also notice that there’s a submenu that appears. To start creating pages for our application, all we need to do is start dragging shapes from the “Home” box.

When you drag them, it will create a new, connected box that represents a new page of your application. I have dragged a few new pages onto my Map. I also changed the color of each section, so that we can visually see which pages belong to which section as it grows. You can do this from the icon on the right of the little submenu.

Representing our navigation

Here’s a more robust version of our site map:

One of the cool things we can do with SketchFlow is represent the navigation visually as well. On the second icon from the left in the submenus, you can connect any page to any other page. Our next step will show why this is an important thing to consider. Drag your pages together, so that they represent how a user would navigate the site. Would there be a button on the “About” page to get to the “Products” page? Then they should be connected! Can you get back to the “Home” page from our 5 navigation sections? Then they should be connected! Hook up your pages like a user should be able to navigate, and then meet me at the next step.

The SketchFlow Player

Go ahead and press your F5 key. (Or choose “Project > Run Project” from the Expression Blend 3 menu.) You’re going to see something new, called the SketchFlow Player. If you were diligent, and actually followed my instructions :), you should see a list of pages on the left hand side of the player. This is a list of pages that your “Home” page is linked to. As you click on those items, you’ll notice that we are actually navigating to those seperate pages, and that the pages that are “linked” to will change. You can always click the Home icon at the top to return to the home page. (click to enlarge)

What I want you to notice is that navigation in this manner is awkward. The reason for that is because

  1. We haven’t put any content on our pages, so it’s not always clear where we are
  2. We don’t have a way to define our hierarchy. All we have done to this point is create a bunch of pages, and link them together.

So let’s add some content to make this much easier to use.

Adding content to our pages

Like any of the other Silverlight tutorials I have done, each “page” of our SketchFlow application is actually just a XAML file. I am going to add a visual title to each page (so we can see easily which is which). Here’s a screenshot of my Products page (click to enlarge):

You’ll notice that I’m not going for “pretty” here in my prototype application. There’s a very specific reason for this.

<soapbox>
When you start working on a prototype application, one of the first tendencies everyone has is to start thinking about “what it will look like”, rather than “how it will work.” This is a fatal flaw in our thinking, and actually penalizes us later. Have you ever presented screenshots of a potential application to your client/manager/sponsor, with the intention of discussing how pages will work, only to be derailed by the fact that they don’t like the color orange? Or that they wish the logo were bigger?

Take an opportunity to call this a “prototype.” It doesn’t have to look pretty, it has to function properly. We can make that functionality look any way the client desires. But it can often be difficult to shoehorn our functionality into the look and feel that has been determined. Ugly prototypes, For The Win!
</soapbox>

Blend 3 even includes a bunch of fonts and control styles that are specifically meant to look hand-written and hand-drawn, so that we can effectively communicate that this is meant to be looked at from a “how it works” perspective. Nobody is going to assume that this ugly look-and-feel is how it will look when we’re done.

If you run the SketchFlow player again (F5), and as you click through the pages in the left navigation, the screen for each page changes as well. Since this is a prototype, let’s add some controls to some of the pages. I’m going to add a few buttons for navigation on the home page, and a few cool things to the product page.

Our SketchFlow navigation

Ideally, in a prototype, our users should be able to click on buttons and links, navigating through the app as if it works like the real thing. They shouldn’t have to use that confusing navigation in the SketchFlow player. I have added 6 buttons to my Home page, and for each of them, I am setting a “Navigate To” property on them. You can do this with any Silverlight element, it doesn’t have to be Buttons, but for my example, buttons suffice. Here’s a shot of my home page with the Navigate To menu open (click to enlarge):

Making A Component Screen

We need this navigation on each page of this site. It would be silly to have to go create this on each page, even if we have to copy and paste it. If we later decide to make a change to it, I want to be able to make that change once. We can do this by creating a Component Screen. Highlight all of the XAML buttons you created (I wrapped mine in a StackPanel, but it’s certainly not necessary), and right-click to choose “Make Into Component Screen.” I named mine Navigation. You should now see a green oval-shaped element on your SketchFlow Map. Drag the “Insert a Component Screen” option from the green oval to each of your top level pages.

You might have to adjust its position, but you should now have your navigation on each main page of your site. Here’s what my SketchFlow Map looks like now:

More about the SketchFlow player

Inside that player are a couple of other cool features, including a feedback component that lets you draw on and markup the prototype. This is a great way to collect feedback from your clients on the app you’re about to build.

You can also access the SketchFlow Map in that same region of the screen. It allows the user to see the full scope of the entire site, much like a site map does. (Click to enlarge.)

Summary

The best part of building a prototype using SketchFlow is that once you’ve gotten sign-off from your customer/client/boss, you’ve got a working Silverlight application. You can re-style your controls, add some live data (if you didn’t already), and you’re off and running. No need to throw your work away!

Click here to download my sample Sketchflow prototype from this demo.

Day #20: Adding Audio to Silverlight Events

And…we’re back. That might be the longest span of time I’ve gone without blogging in quite a while. Anyways, I’m going to pretend like we never stopped this little series I’m calling the 31 Days of Silverlight, and we’ll continue down the path.

Today we’re going to be discussing how to add a sound to a button click. This activity translates to nearly any event in your Silverlight application, but for simplicity’s sake, we’ll stick with the standard button click. So, let’s get started…

1. Find a sound effect.

I found my sound effects at a site called Sound Jay. He offers a whole pile of different sound effects for free, and they’re pretty good. They are offered in .WAV and .MP3, so make sure to download the MP3 version of the sound effect you choose.

2. Add the sound to your ClientBin.

You don’t HAVE to do this, but I recommend using this method over packaging your sound effects directly into the .XAP file. Your application will load faster, and your files will actually be less likely to be “borrowed.” To add it, choose “Add > Existing Item…” from the Solution Explorer in Visual Studio.

3. Add a MediaElement to your XAML page.

This MediaElement tag will be the container that holds our audio file. Here’s the code for my tag:

<MediaElement x:Name="Beep" Source="beep-7.mp3" AutoPlay="False" />

4. We also need a button.

Nothing special about it, but for this example, we’ll need a button on our page. Here’s the code for that:

<Button Click="Button_Click" x:Name="Button" Width="100" Height="100" Content="Beep!" />

5. Hook up the event handler.

In the codebehind, we need one line of code. Here it is:

Beep.Play();

After that, we’re done, right? Wrong. Following the above instructions gets you close, but if you run your application, you’ll notice that only the first “click” of your button works, and after that, nothing. Thankfully, we’re 90% of the way to the “correct” way to handle this. Here’s what we need to do to make this work EVERY time we click the button:

6. Define the source in code.

We are going to remove the Source property from our MediaElement tag. By defining this each time we click the button, we create a new instance of the file. This means that if you have a longer audio file (> 1 second), the audio will start over each time the button is clicked. Here’s the code in our event handler now:

            Beep.Source = new Uri("beep-7.mp3", UriKind.Relative);
Beep.Play();

You should now find that your button click results in your sound effect each time. If you chose a longer sound effect (>1 second), you should also find that the sound effect will stop and start over if you click the button a second time before the sound completes. This is because we are destroying that instance of the sound, and creating a new one on each click.

Click here to download this solution for adding audio to a Silverlight click event.

Tune in tomorrow for another exciting episode of the 31 Days of Silverlight!

kick it on DotNetKicks.com

Day #19: Silverlight Pixel Shader Effects

Today’s post was written by Matt Casto, a former colleague of mine, and my partner in crime for the Stir Trek event we held last May. You can read more from Matt at http://programwith.net.

Pixel shaders, also known as shader effects, are a cool new feature the became available with Silverlight 3. The two most common effects – drop shadow and blur – are included with Silverlight. Its easy to add these effects to any UIElement.

Lets build upon the simple form that was introduced in Jeff’s post Day #10: Styling Silverlight Controls. We can add a drop shadow effect to the email address textbox by changing the Page.xaml to look like this.

<TextBox x:Name="Email" Text="" Grid.Row="4" Style="{StaticResource TextBox}">
    <TextBox.Effect>
        <DropShadowEffect ShadowDepth="2" BlurRadius="3" Direction="300" />
    </TextBox.Effect>
</TextBox>

 

Running the application will show the drop shadow effect has been applied to the textbox.

PixelShaders_1

You can adjust the ShadowDepth, BlurRadius and Direction dependency properties to change the way the effect is rendered. For instance, if we change all of these values to be 10 we end up with this.

PixelShaders_2

Let’s also change the Page.xaml.cs code behind to set a Blur effect on the submit button while the Mailer service is being called.

void Clicky_Click(object sender, RoutedEventArgs e)
{
    if (Email.Text == ""){
        Email.Focus();
    }
    else
    {
        MailerReference.MailerSoapClient mailerClient = new MailerReference.MailerSoapClient();
        mailerClient.SendMailCompleted += new EventHandler<SilverlightStyling.MailerReference.SendMailCompletedEventArgs>(mailerClient_SendMailCompleted);
        string name = FirstName.Text.ToString() + " " + LastName.Text.ToString();
        string body = FirstName.Text.ToString() + "n" + LastName.Text.ToString() + "n" + Address.Text.ToString() + "n" + CityStateZip.Text.ToString();
        mailerClient.SendMailAsync("jeff@jeffblankenburg.com", Email.Text.ToString(), name, body);
 
        Clicky.Effect = new System.Windows.Media.Effects.BlurEffect { Radius = 3 };
    }
}
 
void mailerClient_SendMailCompleted(object sender, SilverlightStyling.MailerReference.SendMailCompletedEventArgs e)
{
    Clicky.Content = "Sent!";
    Clicky.IsEnabled = false;
    Clicky.Effect = null;
}

Run the application now and click Submit after filling in an email address and you’ll see the button get blurry until the service call has completed.

Pixel shaders modify the pixels before they’re rendered to display. This takes place at runtime and doesn’t use hardware acceleration at this point, so don’t expect these effects to be the most performant.

Adding Your Own Shader

You can create your own pixel shaders using High-Level Shading Language (HLSL) compiled with the DirectX SDK. Or you can download the Shazzam application to create, test and debug your pixel shader. Shazzam was created for WPF but all of these effects should work in Silverlight as well. Note that you’ll need the DirectX SDK installed first.

I pulled the Invert Color sample from Shazzam’s Shader Loader samples into the project by selecting Tools->View Compiled Shaders, copying the file (InvertColor.ps) and pasting it into the SilverlightStyling project. Also, I made sure the build action for the file is set to Resource. I then created a class to load the InvertColor.ps file.

using System;
using System.Windows.Media.Effects;
 
namespace SilverlightStyling
{
    public class InvertColor : ShaderEffect
    {
        public InvertColor()
        {
            var uri = new Uri(@"/SilverlightStyling;component/InvertColor.ps", UriKind.Relative);
            PixelShader = new PixelShader { UriSource = uri };
        }
    }
}

Then I applied the shader to the entire form by adding the effect to the LayoutRoot grid element.

<UserControl x:Class="SilverlightStyling.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:SilverlightStyling="clr-namespace:SilverlightStyling" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.Effect>
            <SilverlightStyling:InvertColor />
        </Grid.Effect>

Now our entire form has a beautiful effect.

PixelShaders_3

There are a lot more pixel shaders available from the Windows Presentation Foundation Pixel Shader Effects Library CodePlex project which was updated recently to work with Silverlight 3.