Silverlight 2 and HTML 5 – Being Online/Offline

One of the things that’s coming in IE8 and is already present in FireFox 3 as far as I know is HTML 5’s ability to detect whether the browser is online or offline and to provide some offline storage ( alongside cookies ) for the application.

You can find some details about that here;

http://www.w3.org/TR/offline-webapps/

It occurred to me that this might be pretty useful to pick up from Silverlight and so I wrote a little base class for an application which would surface this info.

I didn’t go into the “offline storage” idea because I can’t really see the point with Silverlight because it already has IsolatedStorage which would work regardless of whether the browser can currently see the network or not.

Here’s the class, very simple. If someone knows how I answer my TODO: then please let me know – I’m not “great” at Javascript;

namespace SLOnlineOffline
{
  public enum NetworkStatus
  {
    Online,
    Offline,
    Unknown
  }
  public class NetworkStatusEventArgs : EventArgs
  {
    public NetworkStatus NetworkStatus { get; set; }
  }
  public class NetworkAwareApplication : Application 
  {
    public NetworkAwareApplication()
    {
      HookBrowserOnlineOfflineEvents();
    }
    private void HookBrowserOnlineOfflineEvents()
    {
      // TODO: Figure out how we find out whether the DOM actually _has_
      // an "onoffline" and an "ononline" event. Don't want to get into
      // checking the UserAgent here so someone tell me how to do it please 🙂
      HtmlPage.Document.Body.AttachEvent("onoffline", (EventHandler)OnOffline);
      HtmlPage.Document.Body.AttachEvent("ononline", (EventHandler)OnOnline);
    }
    private void OnOffline(object sender, EventArgs args)
    {
      FireNetworkStatusChange(NetworkStatus.Offline);
    }
    private void OnOnline(object sender, EventArgs args)
    {
      FireNetworkStatusChange(NetworkStatus.Online);
    }
    private void FireNetworkStatusChange(NetworkStatus networkStatus)
    {
      if (NetworkStatusChange != null)
      {
        NetworkStatusChange(this, new NetworkStatusEventArgs() { NetworkStatus = networkStatus });
      }
    }
    public NetworkStatus NetworkStatus 
    {
      get
      {
        // Ask the browser...
        NetworkStatus status = NetworkStatus.Unknown;

        try
        {
          ScriptObject navigator = (ScriptObject)HtmlPage.Window.GetProperty("navigator");

          if (navigator != null)
          {
            bool navigatorStatus = (bool)navigator.GetProperty("onLine");

            status = navigatorStatus ? NetworkStatus.Online : NetworkStatus.Offline;
          }
        }
        catch // Gulp.
        {
        }
        return (status);
      }
    }
    public event EventHandler<NetworkStatusEventArgs> NetworkStatusChange;
  }
}

and then I can use that as my base class for my Silverlight application instead of System.Windows.Application so I can author some XAML such as;

<local:NetworkAwareApplication
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SLOnlineOffline.App"
  xmlns:local="clr-namespace:SLOnlineOffline">
  <local:NetworkAwareApplication.Resources>

  </local:NetworkAwareApplication.Resources>
</local:NetworkAwareApplication>

and then the code behind that app.xaml looks like this;

namespace SLOnlineOffline
{
  public partial class App : NetworkAwareApplication
  {

so we’re producing a NetworkAwareApplication rather than a plain old Application and then I can write a little UI for my Page;

<UserControl x:Class="SLOnlineOffline.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
      <Button
      Content="Hello" 
        Click="OnClick"/>
    <TextBlock
      x:Name="txtStatus"
      Text="Not Set" Grid.Row="1"/>
  </Grid>
</UserControl>

and a little code behind that;

namespace SLOnlineOffline
{
  public partial class Page : UserControl
  {
    public Page()
    {
      InitializeComponent();

      Application.NetworkStatusChange += OnNetworkStatusChange;
    }
    void OnNetworkStatusChange(object sender, NetworkStatusEventArgs e)
    {
      txtStatus.Text = string.Format(
        "Automatically determined new status is {0}", e.NetworkStatus);
    }
    void OnClick(object sender, EventArgs args)
    {
      txtStatus.Text = string.Format(
        "Manually checked status is {0}",
        Application.NetworkStatus.ToString());
    }
    NetworkAwareApplication Application
    {
      get
      {
        return ((NetworkAwareApplication)System.Windows.Application.Current);
      }
    }
  }
}

and then I’ve got a Silverlight application that I can view in FireFox 3 ( I don’t have IE8 installed just yet ) and I can unplug my network cable and the Browser knows that it’s gone offline and I can plug my network cable back in and the browser knows that it’s back online and all seems well and this information filters through into my Silverlight application.