How to build a good install UX with Silverlight

How to build a good install UX with Silverlight

Rate This
  • Comments 5

Technorati Tags:

del.icio.us Tags:

The Silverlight object model exposes events that can be used to build a very friendly end user experience for installing Silverlight.

When it comes to using a Web site that requires a plug-in to render content, the user is generally faced with a choice. Is it worth spending the time and effort to install the plug in to get to the content that I want? Is it clear to me what I am installing? Do I want to install it?

Through research with popular web sites such as March Madness On-Demand the NBC Olympics and the Democratic National Conference and also a myriad of Microsoft owned sites, Microsoft have found a number of key learnings that make this decision easier for the user, manage them through the process of installation, and make it more likely, ultimately, for more people to choose the plug-in to interact with your content.

This post outlines the possible scenarios that an end user will encounter when they are installing Silverlight, and the code that you can write to overcome any issues that may arise in these scenarios. There are more of these than you may expect. Sometimes the user will not have Silverlight to begin with, sometimes they’ll have an older version, sometimes they’ll be in a state where they need to restart the browser and yet others they only need to refresh.

Programming the Install UX

Any Silverlight project that is build using Visual Studio Tools for Silverlight will give a default installation experience (called the Silverlight ‘Badge’) for end users that do not have the Silverlight runtime already installed. It’s a very simple experience that is designed to be a ‘lowest common denominator’ approach.

It’s important to note that this experience is generic in nature, and as such is not tailored towards any particular application. Thus, when the end user sees the install badge they may become confused.

Consider this with a scenario where the user visits a site that provides casual games. They select to play a game, but instead of the game, they get a blank screen with the Silverlight badge at the top left corner. Is it a banner ad? Did they click the wrong place? There’s a high probability that they’d not click it, not get Silverlight and not play the game.

Additionally, if they do click the banner, then what happens? Clicking alone doesn’t install the application, it triggers the download of an executable that has to be acted upon by the user in order to install. After installation, there’s no guarantee that the content will work straight away. Sometimes a refresh is enough. Sometimes a browser restart is necessary. To give the best possible experience to your end user, it is necessary to manage all of these scenarios effectively and coherently.

To do this, there are two main artifacts that you need to understand. The first is the technology and the code that can be used to provide the best install UX. The second is the solicitation and the correct language and prompts to use to ensure that the end user fully understands and is properly guided through the installation experience.

Before getting your hands dirty with the code, it’s a good idea to understand all the installation cases that you are likely to face.

Once the installation experience has been designed, a web author should generate several variants of that experience to account for special states that a user may be in when visiting the Silverlight-enabled application. These variations are different only in text, but will greatly improve the user's confidence in the application and the platform.

A user can be viewing the Silverlight installation experience on your website in one of six states. The message they are presented with, if any, should be a variant of the installation experience which is semantically equivalent to the following recommendations:

State

Message Type

Silverlight is installed and loaded

Don’t give a message, just show the content.

The right version of Silverlight is installed but not loaded

Thank the user, and ask them to restart the browser before coming back to this page.

An older version of Silverlight is installed

Tell them that they need to upgrade to the latest version of Silverlight, and direct them to where they can get it.

Upgrade started

Inform them that the upgrade is under way, and that once its done they’ll have to restart the browser.

Silverlight is not installed

Prompt them that in order to get the content they’ll need to install the Silverlight plug in. Emphasize the content, not Silverlight.

Install started

Thank them for installing Silverlight, and let them know that they may need to refresh their browser when the install is done.

Incompatible Configuration

Prompt and show user an HTML view that is delivered for people who cannot install Silverlight in their environment. This can be a note that discusses the compatibility issue or an alternative HTML experience.

These states are represented visually here:

f06xx04

These states can be managed and users expectations managed by following these steps in your code.

Task 1. Integrate Silverlight.js and use the OBJECT Tag

Step 1. Integrate Silverlight.js

Silverlight.js must be included using a <script> tag within the page’s <head> element. This JavaScript file defines the required APIs and includes the code required to check if Silverlight is installed to begin with.

   1:  <head> 
   2:  <script src="Silverlight.js" type="text/javascript" ></script> 
   3:  </head>

Step 2. Use an <Object> tag for Silverlight

As we saw earlier, the web page embeds Silverlight on the page using an HTML <object> tag. This must include the data and type attributes. You will notice that the default state for Silverilght projects is to use “application/x-silverlight-2” as the MIME type for these attributes.

Note that in order to detect the installation state for Silverlight 1.0 users, you should use the Silverlight 1.0 MIME type for both the data and type attributes.

By doing this, you force the user to upgrade the control with minimal impact on the Web site author.

Thus, these attributes should be defined like this:

type="application/x-silverlight"

and

data="data:application/x-silverlight,"

Step 3. Use the minRuntimeVersion parameter

This parameter is part of the <object> tag that is used to ensure that the user has the proper version of Silverlight installed. If not, the control will not download the XAP, and will instead ask the user to upgrade the control. Additionally this state will trigger the OnError event with the args.ErrorCode set to 8001 [Upgrade Required] or 8002 [Restart Required]

Do note that as Silverlight 1.0 did not support this parameter, checking the error state is not enough to see if an action is required on the part of the end user. Only by following the steps in this document, and by using Silverlight.js can this be achieved.

The correct value for the minRuntimeVersion parameter is “2.0.31005” for the RTM of Silverlight 2.

Step 4. Use the autoUpgrade parameter

When autoUpgrade is ‘true’, the default Silverlight experience for upgrading will take place. If you want to control this with your own UX, you should set it to ‘false’.

Note that you can test this experience by creating a Silverlight object on a page with data and type properties, as well as minRuntime and autoUpgrade properties set like this:

<object data="data:application/x-silverlight," type="application/x-silverlight">
     <param name="minRuntimeVersion" value="9.9.99999" />
     <param name="autoUpgrade" value="true" /> 
</object>
 

Step 5. Turn on Error handling

The <Object> tag must use the onError parameter and its definition function must call Silverlight.IsVersionAvailableOnerror(sender,args)

If this function returns ‘true’ then the right version of Silverlight is already installed and loaded so normal error handling code should be executed.

So if the parameter on the <Object> tag looks like this:

<param name="onError" value="onSilverlightError" />

You would have a handler that looks like this:

function onSilverlightError(sender, args) 
{ 
     if ( Silverlight.IsVersionAvailableOnError(sender, args) ) { 
     //run error handling code 
     }
}

Step 6. Capture the onLoad event.

The onLoad parameter of the object tag must defined a handler function and this must call Silverlight.IsVersionAvailableOnLoad(sender) . Calling this function allows you to identify earlier versions of Silverlight (beta builds etc.) and trigger an upgrade or restart in order to handle them.

So, if the parameter on the <Object> tag looks like this:

<param name="onLoad" value="onSilverlightLoad" />

You would have a handler that looks like this:

function onSilverlightLoad (sender) 
{ 
     Silverlight. IsVersionAvailableOnLoad (sender);
}

Step 7. Address incompatible configuration .

While the Silverlight control is available for installation by a majority of the Internet's users, there are some platforms which are not currently supported. When a user on an unsupported platform clicks on the Silverlight installation URL they will be redirected to a Web page on www.microsoft.com/silverlight which informs them that they are not supported. This experience is fine for most pages, but some Web sites will want to be able to identify these users without redirecting to www.microsoft.com. There are several available methods for accomplishing this goal:

· Identify the user as being unsupported server-side based on the HTTP request

· Identify the user as being unsupported client-side based on navigator.userAgent

A default implementation of client-side supported user detection is available in Silverlight.supportedUserAgent.js (http://code.msdn.microsoft.com/SLsupportedUA).

One way that this could be used is as follows:

First, add a reference to the script file to your page.

<script type="text/javascript" src="Silverlight.supportedUserAgent.js"></script>

Then, create a Prompt HTML for the Not Supported Scenario and load it into a JavaScript var.

var PromptNotSupported = "<div><p>This browser doesn't support Silverlight, sorry!</p></div>";

Finally, create a JavaScript function that uses the supportedUserAgent API to determine if the current browser is supported. Note that for this to work, the Silverlight object must be contained within a <div> called ‘silverlightControlHost’.

<script type="text/javascript">
    function CheckSupported() {
        var tst = Silverlight.supportedUserAgent();
        if (tst) {
        // Do nothing
        }
        else{
            document.getElementById("silverlightControlHost").innerHTML = PromptNotSupported;
        }
    }
</script>

To use this, you will then just have to call this script when the page loads.

<body onload="CheckSupported()">

It is very important to note that as Web Browsers and the Silverlight platform evolve, the supported user agent detection code will also change. Therefore, the Web developer should be sure to check the Silverlight.supportedUserAgent Web page often to ensure that they have the latest version.

Task 2. Render the UI prompts at the appropriate time.

In this figure you can see the potential install states and from it you can derive that there are 5 main prompts that need to be given to the user.

f06xx05

Reading from left to right, the first path is the simple state – the correct version of Silverlight is installed and present, so just show the content.

The next is followed when the user does not have Silverlight installed. In this case, they are first prompted with a ‘Click to Install’ and once installation is done they are requested to refresh their browser.

The next is followed when the user has Silverlight, but it is an older version. In this case they are prompted with a ‘Click to Upgrade’ and once installation is done, they are requested to restart their browser.

The next is followed when the correct version of Silverlight is detected, but it hasn’t been loaded. In this case the user needs to restart their browser.

The last is followed when an incompatible configuration is detected.

Note that the substates on the paths were Silverlight needs to either be installed or updated are not automatically detected. You will have to generate these prompts in response to the user selecting the ‘Click to Install’ or ‘Click to Upgrade’ options. You will see how to do this later.

So, to summarize, there are 6 ways that the user needs to be prompted, and they are for these states:

· Silverlight is not installed, click to install.

· You are now installing Silverlight, refresh when done.

· An older version of Silverlight is installed, click to upgrade.

· You are not upgrading Silverlight, restart when done.

· Please restart your browser.

· Incompatible configuration HTML

Step 1. Define the HTML for Silverlight not being installed

The <Object> tag definition allows you to render HTML that shows when the object can not be created. This will fire if Silverlight is not installed. This is very straightforward to do – just add a <div> after the parameter installs that renders the HTML.

Note that somewhere in this HTML you should capture a click and use it to run a JavaScript function. This JavaScript is necessary to render the ‘installing’ message.

Here’s an example of a fully formed object tag containing this HTML.

<object data="data:application/x-silverlight," type="application/x-silverlight" 
    width="100%" height="100%">
  <param name="source" value="bin/debug/Memory.xap"/>
  <param name="background" value="white" />
  <param name="minRuntimeVersion" value="2.0.31005.0" />
  <param name="autoUpgrade" value="false" />
  <param name="onerror" value="onSilverlightError" />
  <param name="onload" value="onSilverlightLoad" />
  <div id="SLInstallFallback" class="silverlightInstall" >
  <img src="images/install.PNG" onclick='InstallClicked();' class="silverlightInstallImage" 
       alt='Click to Install' style='cursor:pointer;'/>
</div>
</object>

This defines an image (images/install.PNG) to show when Silverlight isn’t installed. You can replace this HTML with any of your own, depending on your situation. Do be sure to have an onclick handler though. You’ll explore that in Step 3.

Step 2. Define UI for other Prompt States.

The other 4 prompt states can be defined as JavaScript variables.

Here are the example variables that are used for the states in this example:

· var PromptFinishInstall for ‘You are now installing Silverlight, refresh when done.’

· var PromptUpgrade for ‘An older version of Silverlight is installed, click to upgrade.’

· var PromptFinishUpgrade for ‘You are not upgrading Silverlight, restart when done.’

· var PromptRestart for ‘Please restart your browser.’

· Var PromptIncompatible for ‘Your browser is incompatible with this experience’

These should simply be HTML div’s that will be used to replace the innerHTML of a portion of your page when you need to issue that prompt to the user.

Do note that the PromptUpgrade should (similar to the prompt in step 1) should have a call to a JavaScript function when an area within it is clicked. This JavaScript function will change the onscreen prompt to the ‘You are now upgrading Silverlight, restart when done’ state. You’ll see this in Step 3.

Here’s an example of what that should look like. Note the definition of the onclick event handler:

var PromptUpgrade =
  "<div id='SLInstallFallback' class='silverlightInstall' >" +
  " <img src='images/upgrade.PNG' onclick='UpgradeClicked();'  class='silverlightInstallImage'" +
  " alt='Click to Upgrade' style='cursor:pointer;'/>" +
  "</div>";

Step 3. JavaScript functions to handle user actions for Install and Upgrade.

In Step 1 you defined the prompt to solicit the user to click an area on your page to install Silverlight. The response to this should be to trigger the download of the installer, and to update the screen to inform the user that they are not in the installation state.

The JavaScript to achieve this will look like this:

function InstallClicked()
{
  window.location = "http://go2.microsoft.com/fwlink/?linkid=124807";
  document.getElementById("silverlightControlHost").innerHTML =
  PromptFinishInstall;
}

Note that it changers the innerHTML of the <Object> tag to the value of PromptFinishInstall as defined in Step 2.

In Step 2, when defining the upgrade prompt you specified an onClick event handler called ‘UpgradeClicked’. This is similar to the InstallClicked event handler in that it downloads the software and changes the prompt, this time to the one to finish the Upgrade.

function UpgradeClicked()
{
  window.location = "http://go2.microsoft.com/fwlink/?linkid=124807";
  document.getElementById("silverlightControlHost").innerHTML = 
  PromptFinishUpgrade;
}

Task 3. Capture the Callbacks from Silverlight.js

Silverlight.js has some helper functions that trap the different states and allows you to update the UI accordingly.

These functions are:

· Silverlight.onRequiredVersionAvailable

The right version of Silverlight is installed and available. You can use this to let the user know that they are good to go, or just ignore it and render the content.

· Silverlight.onRestartRequired

You need to restart the browser. In this case you will change the prompt area HTML to the contents of your PromptRestart var.

· Silverlight.onUpgradeRequired

You need to upgrade from an older version of Silverlight. In this case you will change the prompt area HTML to the contents of your PromptUpgrade var.

· Silverlight.onInstallrequired

Silverlight isn’t installed but needs to be. You don’t need to take any action here as you are capturing this state in the <Object> tag.

Here’s the code:

function onSilverlightLoad(sender)
{
  Silverlight.IsVersionAvailableOnLoad(sender);
}
 
Silverlight.onRequiredVersionAvailable = function()
{
};
 
Silverlight.onRestartRequired = function()
{
  document.getElementById("silverlightControlHost").innerHTML = PromptRestart;
};
 
Silverlight.onUpgradeRequired = function()
{
  document.getElementById("silverlightControlHost").innerHTML = PromptUpgrade;
};
 
Silverlight.onInstallRequired = function()
{
};

Task 4. Work around known Issues

There is a known issue that affects Firefox users that are upgrading from Silverlight 1 or a beta of Silverlight 2 to the release of Silverlight 2. It has been fixed for future versions of Silverlight, but will need to be worked around for Silverlight 2.

FireFox users will see the <Object> tag’s fallback experience after an upgrade to Silverlight 2 unless they restart their browser.

This is fixed by using the following script after the <Object> definition.

<script type="text/javascript">
try
{
  if (navigator.plugins["Silverlight Plug-In"].description)
  {
    document.getElementById("SLInstallFallback").innerHTML = PromptRestart;
  }
}
catch (e)
{
}
 
</script>

Another issue is that Mac Firefox users will be misidentified as being in the ‘upgrade required’ state when they are actually in the ‘restart required’ state. There is no known workaround at this time, but the cases that lead to this are complex, and in most cases this state will not be encountered.

Exploring the finished page with Install UX

Visual Studio creates a default HTML page to host your Silverlight content. It’s pretty easy to follow the above steps to upgrade this page from the default UX to one that manages the installation states as shown above.

Here’s the complete listing:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>SilverlightApplication1</title>
<style type="text/css">
  html, body {
  height: 100%;
  overflow: auto;
  }
  body {
  padding: 0;
  margin: 0;
  }
 
  #silverlightControlHost {
    height: 100%;
  }
</style>
 
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="Silverlight.supportedUserAgent.js"></script>
<script type="text/javascript">
  var PromptFinishInstall = "<div><p>You are now installing Silverlight, refresh your browser when       
      done.</p></div>";
 
  var PromptUpgrade = "<div><p onclick='UpgradeClicked'>This application needs you to upgrade the       
      Silverlight plugin that runs it. An older version is installed. Click here to upgrade it.</p></div>";
 
  var PromptFinishUpgrade = "<div><p>You are now upgrading Silverlight. When this is done, please restart your 
      browser.</p></div>";
 
  var PromptRestart = "<div><p>Please restart your browser.</p></div>";
 
  var PromptNotSupported = "<div><p>This browser doesn't support Silverlight, sorry!</p></div>";
 
function onSilverlightError(sender, args) {
  if (Silverlight.IsVersionAvailableOnerror(sender, args)) {
    var appSource = "";
 
  if (sender != null && sender != 0) {
    appSource = sender.getHost().Source;
  }
 
  var errorType = args.ErrorType;
  var iErrorCode = args.ErrorCode;
  var errMsg = "Unhandled Error in Silverlight 2 Application " + appSource + "\n";
  errMsg += "Code: " + iErrorCode + " \n";
  errMsg += "Category: " + errorType + " \n";
  errMsg += "Message: " + args.ErrorMessage + " \n";
  if (errorType == "ParserError") {
    errMsg += "File: " + args.xamlFile + " \n";
    errMsg += "Line: " + args.lineNumber + " \n";
    errMsg += "Position: " + args.charPosition + " \n";
  }
 
  else if (errorType == "RuntimeError") {
    if (args.lineNumber != 0) {
      errMsg += "Line: " + args.lineNumber + " \n";
      errMsg += "Position: " + args.charPosition + " \n";
    }
  errMsg += "MethodName: " + args.methodName + " \n";
  }
 
  throw new Error(errMsg);
  }
}
 
  function onSilverlightLoad(sender) {
    Silverlight.IsVersionAvailableOnLoad(sender);
  }
 
  Silverlight.onRequiredVersionAvailable = function() {
  };
 
  Silverlight.onRestartRequired = function() {
    document.getElementById("silverlightControlHost").innerHTML = PromptRestart;
  };
 
  Silverlight.onUpgradeRequired = function() {
    document.getElementById("silverlightControlHost").innerHTML = PromptUpgrade;
  };
 
  Silverlight.onInstallRequired = function() {
  };
 
  function UpgradeClicked() {
    window.location = "http://go2.microsoft.com/fwlink/?linkid=124807";
    document.getElementById("silverlightControlHost").innerHTML = PromptFinishUpgrade;
  }
 
  function InstallClicked() {
    window.location = "http://go2.microsoft.com/fwlink/?linkid=124807";
    document.getElementById("silverlightControlHost").innerHTML = PromptFinishInstall;
  }
 
<script type="text/javascript">
  function CheckSupported() {
    var tst = Silverlight.supportedUserAgent();
    if (tst) {
      // Do nothing
    }
    else{
      document.getElementById("silverlightControlHost").innerHTML = PromptNotSupported;
    }
  }
  </script>
</script>
</head>
<body onload="CheckSupported()">
<!-- Runtime errors from Silverlight will be displayed here. This will contain debugging information and 
should be removed or hidden when debugging is completed -->
 
<div id='errorLocation' style="font-size: small;color: Gray;"></div>
<div id="silverlightControlHost" style="height:100%;">
<object data="data:application/x-silverlight," type="application/x-silverlight" width="100%" height="100%">
  <param name="source" value="ClientBin/SilverlightApplication1.xap"/>
  <param name="background" value="white" />
  <param name="minRuntimeVersion" value="2.0.31005.0" />
  <param name="autoUpgrade" value="false" />
  <param name="onerror" value="onSilverlightError" />
  <param name="onload" value="onSilverlightLoad" />

<div id="SLInstallFallback"><div><p onclick='UpgradeClicked'>This application needs you to use the

Silverlight plugin to use it. Click here to install it.</p></div></div>

</object>
 
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>
 
<div id="silverlightExperienceHost" style="visibility:hidden;">
</div>
 
<script type="text/javascript">
  try {
    if (navigator.plugins["Silverlight Plug-In"].description) {
      document.getElementById("SLInstallFallback").innerHTML = PromptRestart;
  }
}
 
catch (e) {
 
}
</script>
</body>
</html>

In this scenario, you’ve built the code, but not the installation solicitation. It’s recommended that you build the solicitation carefully for your application, and focus on your application content, and not Silverlight. So, for example if you are building a site to show off a foo-bar widget, you should have big friendly text with the value proposition of the foo-bar widget, with a short and smaller indication that in order to access it they need to install a plugin, which is quick, easy and secure. Take a look at some existing sites to see what works and what doesn’t. A good example of an install solicitation can be found on http://movies.msn.com/pretty-in-ink/. You can see the solicitation here:

f06xx06

By following a well designed install solicitation along with a well managed set of install states, you should expect less ‘drop off’ of users and more access to your new, rich, Silverlight content.

Comments
Page 1 of 1 (5 items)
Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post