Given that Silverlight 3 can detect the online/offline status of the network, I thought I’d have a play with a simple control that displays something when the network is online and something else when the network is offline.
I started with a UserControl but ended up just with a Control using the “parts and states” model that had just one group of states called OnlineOfflineStates with 2 states within it named Online and Offline.
The source for the control is here and it’s just a little code ( might have bugs in it as it’s not been tried very much 🙂 );
namespace MikesControls { [TemplateVisualState(Name="Online", GroupName="OnlineOfflineStates")] [TemplateVisualState(Name="Offline", GroupName="OnlineOfflineStates")] [TemplatePart(Name="OnlineContentRoot", Type=typeof(Panel))] [TemplatePart(Name="OfflineContentRoot", Type=typeof(Panel))] public class OnlineOfflineControl : Control { public OnlineOfflineControl() { this.DefaultStyleKey = typeof(OnlineOfflineControl); this.Loaded += OnLoaded; } void OnLoaded(object sender, RoutedEventArgs e) { DetermineNetworkStatus(); NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged; } void DetermineNetworkStatus() { IsOnline = NetworkInterface.GetIsNetworkAvailable(); } void OnNetworkAddressChanged(object sender, EventArgs e) { DetermineNetworkStatus(); UpdateOnlineOfflineUI(); } public override void OnApplyTemplate() { onlineUI = base.GetTemplateChild("OnlineContentRoot") as Panel; offlineUI = base.GetTemplateChild("OfflineContentRoot") as Panel; base.OnApplyTemplate(); UpdateOnlineOfflineUI(); } public static DependencyProperty IsOnlineProperty = DependencyProperty.Register("IsOnline", typeof(bool), typeof(OnlineOfflineControl), null); public bool IsOnline { get { return ((bool)base.GetValue(IsOnlineProperty)); } internal set { base.SetValue(IsOnlineProperty, value); } } public static DependencyProperty OnlineContentProperty = DependencyProperty.Register("OnlineContent", typeof(object), typeof(OnlineOfflineControl), null); public object OnlineContent { get { return (base.GetValue(OnlineContentProperty)); } set { base.SetValue(OnlineContentProperty, value); } } public static DependencyProperty OfflineContentProperty = DependencyProperty.Register("OfflineContent", typeof(object), typeof(OnlineOfflineControl), null); public object OfflineContent { get { return (base.GetValue(OfflineContentProperty)); } set { base.SetValue(OfflineContentProperty, value); } } void UpdateOnlineOfflineUI() { string state = IsOnline ? "Online" : "Offline"; VisualStateManager.GoToState(this, state, true); } Panel onlineUI; Panel offlineUI; } }
and that goes hand in hand with a lump of XAML in the Themes/generic.xaml file;
<?xml version="1.0" encoding="utf-8" ?> <ResourceDictionary xmlns:local="clr-namespace:MikesControls" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Style TargetType="local:OnlineOfflineControl"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:OnlineOfflineControl"> <Grid Background="{TemplateBinding Background}"> <vsm:VisualStateManager.VisualStateGroups> <vsm:VisualStateGroup x:Name="OnlineOfflineStates"> <vsm:VisualState x:Name="Online"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="OfflineContentRoot" Storyboard.TargetProperty="Opacity" To="0.0" /> <DoubleAnimation Duration="0" Storyboard.TargetName="OnlineContentRoot" Storyboard.TargetProperty="Opacity" To="1.0" /> </Storyboard> </vsm:VisualState> <vsm:VisualState x:Name="Offline"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="OfflineContentRoot" Storyboard.TargetProperty="Opacity" To="1.0" /> <DoubleAnimation Duration="0" Storyboard.TargetName="OnlineContentRoot" Storyboard.TargetProperty="Opacity" To="0.0" /> </Storyboard> </vsm:VisualState> </vsm:VisualStateGroup> </vsm:VisualStateManager.VisualStateGroups> <Grid x:Name="OnlineContentRoot"> <ContentPresenter Content="{TemplateBinding OnlineContent}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding HorizontalContentAlignment}" /> </Grid> <Grid x:Name="OfflineContentRoot"> <ContentPresenter Content="{TemplateBinding OfflineContent}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding HorizontalContentAlignment}" /> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
and so the control ends up being;
- A template part called OnlineContentRoot which will, by default, show a ContentPresenter displaying the contents of a property called OnlineContent
- A template part called OfflineContentRoot which will, by default, show a ContentPresenter displaying the contents of a property called OfflineContent
- A couple of states – in the Online state we will display OnlineContentRoot and hide OfflineContentRoot and vice versa in the Offline state
that then means that I can use this control in a simple way by just setting the OnlineContent and OfflineContent as in;
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="clr-namespace:MikesControls;assembly=MikesControls" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" x:Class="OnlineOffline.MainPage"> <StackPanel> <mc:OnlineOfflineControl x:Name="onlineOffline"> <mc:OnlineOfflineControl.OnlineContent> <TextBlock FontSize="36" Text="Online" /> </mc:OnlineOfflineControl.OnlineContent> <mc:OnlineOfflineControl.OfflineContent> <TextBlock FontSize="36" Text="Offline" /> </mc:OnlineOfflineControl.OfflineContent> </mc:OnlineOfflineControl> <Button Content="Click Me When Online" IsEnabled="{Binding ElementName=onlineOffline, Path=IsOnline}" /> </StackPanel> </UserControl>
or perhaps;
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="clr-namespace:MikesControls;assembly=MikesControls" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" x:Class="OnlineOffline.MainPage"> <StackPanel> <mc:OnlineOfflineControl Width="192" Height="192" x:Name="onlineOffline"> <mc:OnlineOfflineControl.OnlineContent> <Image Source="/NetworkUp.png" /> </mc:OnlineOfflineControl.OnlineContent> <mc:OnlineOfflineControl.OfflineContent> <Image Source="/NetworkDown.png" /> </mc:OnlineOfflineControl.OfflineContent> </mc:OnlineOfflineControl> <Button HorizontalAlignment="Center" Content="Click Me When Online" IsEnabled="{Binding ElementName=onlineOffline, Path=IsOnline}" /> </StackPanel> </UserControl>
which displays with these 2 icons (taken from here) when online/offline;
or the whole control can be re-templated by just dropping into Expression Blend and providing new values for the 2 parts OnlineContentRoot and OfflineContentRoot and then controlling the transitions between the states Online and Offline.