Controlling the StatusBar (SystemTray) in a Universal App

One of the problems of using Universal Apps is that some components only exist in one platform and not in another. One such example is the StatusBar (formally known as SystemTray) for Windows Phone 8.1. For example, to change the colour of the StatusBar you have to use code rather than xaml. This makes life a bit awkward when you want to use a shared page. So to avoid this issue I’ve created a User Control (ChromeController.xaml) that exists in both platforms;

image

The ChromeController is just dropped into the shared page like any other control, except this one doesn’t have any visuals (I could have used a real control, but I’m being lazy).

User Control

<UserControl
    x:Class="UniApp.ChromeController"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    />

Snippet from shared page;

<Grid>
            <local:ChromeController Background="Pink" Opacity="0.6" />

For the Windows 8.1 variant the code does absolutely nothing, although in the long term it could easily control win81 only assets. However, for the Windows Phone 8.1 it reuses the elements Background and Opacity settings and sets the StatusBar to the same values.

    public sealed partial class ChromeController : UserControl
    {
        public ChromeController()
        {
            this.InitializeComponent();

            this.Loaded += ChromeController_Loaded;
     
        }

        void ChromeController_Loaded(object sender, RoutedEventArgs e)
        {            
            var solidColorBrush = this.Background as SolidColorBrush;
            if (solidColorBrush != null)
            {
                var color = solidColorBrush.Color;
                var statusBar = StatusBar.GetForCurrentView();
                statusBar.BackgroundOpacity = this.Opacity;
                statusBar.BackgroundColor = color;
            }
        }
    }

Here’s the result.

image

Using a resource for an unsupported culture in Windows Phone

I was talking to a fellow dev about why the Resource Manager cannot support languages that the phone platform itself does not support. However, I thought that there probably would be a workaround…and here it is.

Step 1 – Create your basic project

Create phone project, by default this will create;

Resources\AppResources.resx

Step 2 – Add a test resource

Open the AppResources and add a new string called ‘ColourLabel’. I’m making the horrible assumption that you have defaulted to en-US so please enter the value of ‘Color’.

Step 3 – Add a new resource culture

Project->Add->Resource, e.g. AppResources.en-GB.resx

This should have copied our resource string from the master resource, so please change ‘ColourLabel’ to the correct spelling of ‘Colour’ Winking smile

Step 4 – Add a new unknown resource culture

Copy AppResource.en-GB.resx over to AppResources.en-XX.resx

Change ‘ColourLabel’ value from ‘Colour’ to our alien value of ‘ColourXX’

Step 5 – Change Build Action

If you try to use the ResourceManager to access en-XX it will fail because the culture is alien to the platform. So starts the workaround, change the BuildAction of en-XX to ‘Content’

Step 6 – Execute the resource manager

Running the following code…

 
AlienResourceManager britishResourceManager = new AlienResourceManager("en-GB");  
System.Diagnostics.Debug.WriteLine("en-GB: " + britishResourceManager.GetString("ColourLabel")); 
AlienResourceManager alienResourceManager = new AlienResourceManager("en-XX");  
System.Diagnostics.Debug.WriteLine("en-XX: " + alienResourceManager.GetString("ColourLabel"));  

results in the following output;

 
en-GB: Colour  
en-XX: ColourXX  

all done?

It’s fairly obvious that isn’t standard code, but it’s actually just a little over-riding of the standard ResourceManager. Here is my quick version, hope you find it useful.

  
public class AlienResourceManager : ResourceManager     
{         
  private string alienCultureName;         
  private Dictionary alienStrings = null;         
  private CultureInfo currentCulture;         
  public AlienResourceManager(string alienCultureName) :  base("MyPhoneApp.Resources.AppResources", typeof(AppResources).Assembly)         
  {             
    this.alienCultureName = alienCultureName;              
    try             
    {                 
      CultureInfo ci = new CultureInfo(alienCultureName);                 
      this.currentCulture = ci;             
    }             
    catch (Exception)             
    {                 
      LoadAlienStrings(alienCultureName);                 
      this.IsAlienCulture = true;             
    }         
  }          

  private void LoadAlienStrings(string alienCultureName)         
  {             
    var localisation = Application.GetResourceStream(new Uri("Resources/AppResources." + alienCultureName + ".resx", UriKind.Relative));             
    StreamReader resx = new StreamReader(localisation.Stream);             
    string resXml = resx.ReadToEnd();             
    XElement resourceFile = XElement.Parse(resXml);             
    this.alienStrings = new Dictionary();             
    var resourceStrings =              
      (from r in resourceFile.Descendants("data")              
      select new  { Name= r.Attribute("name").Value, Value = r.Element("value").Value}).ToList();              

    resourceStrings.ForEach(r => this.alienStrings.Add(r.Name, r.Value));          
  }           

  public bool IsAlienCulture { get; set; }          
  
  public override string GetString(string name)         
  {             
    if (this.IsAlienCulture)             
    {                 
      return this.alienStrings[name];             
    }             
    else             
    {                 
      return base.GetString(name, currentCulture);             
    }         
  }     
} 

What is stored on the Windows Phone back stack?

Recently I was in a conversation about memory usage on the Windows Phone. The conversation turned to the Phone back stack and the question became, “what is stored on the back stack?” So I created a very simple application; MainPage.xaml allows the user to select and show a picture. It also contains a link to Page1.xaml. Page1 displays a count of the back stack plus a simple view model that contains a large chunk of dummy data and a creation timestamp. It also has a link to MainPage.xaml. To be clear, there is no code that reloads or stores/restores state, everything is creating either in the constructor or from user input. This allowed me to create a test with the following stack;

MainPage.xaml (pic1) –> Page1.xaml (Count=1) –> MainPage (pic2) –> Page1.xaml (Count=3), etc.

The results show that EVERYTHING is stored on the stack, user selected pictures, view models, everything . As you move back through the stack all the pictures and the old timestamps are all correctly displayed. The only limit on how big the stack can grow is the memory ceiling.

Resume and Tombstoned

Any Windows Phone developer will know the story isn’t as simple as that, what about Resume and Tombstone? If you have travelled through a number of pages and press the Windows key then your app will be deactivated. If you switch back to your app and the OS has allowed you to Resume then all of the state will be ready for you. The implication here is that your entire apps memory footprint can be hanging around until the OS decides you no longer want it. However, if your application is Tombstoned then only the navigation URI history is automatically retained. Consider the following stack with the selected picture and the view model timestamp;

Main Page (pic1) –> Page 1 (T1) –> Main Page (pic2) –> Page 1 (T2)

With a successful Resume you will be able to back-through the application and get;

Page 1 (T2) –> Main Page (pic2) –> Page 1 (T1) –> Main Page (pic1) –> Close

However, if your app is Tombstoned you will get;

Page 1 (T3) –> Main Page (empty) –> Page 1 (T4) –> Main Page (empty) –> Close

Therefore under Tombstoned conditions it is up to you to store and restore any state you wish to present to the user or even remove the back stack if that makes more sense.

Summary

If your application allows an ‘infinite’ stack to form then you should worry about the memory implications and consider using a strategy that will either/or prevent the stack growing too large or clear up resources as you navigate away from a page.

(Edit) What happens when you back-out through the stack?

One thing I didn’t mention was when are the pages fully destroyed? As you move away from a page (in either direction) the page unload is called, but the underlying object remains. As you move back through the stack the page objects are reclaimed. This will not necessarily happen immediately, but you should eventually see the destructors called for pages.

The Windows Phone Emulator wasn’t able to connect to the Windows Phone operating system

Today I fired up Visual Studio to create a Windows Phone application, just like I had done the past couple of days, only to be faced with;

[Window Title]
Windows Phone Emulator

[Content]
The Windows Phone Emulator wasn’t able to connect to the Windows Phone operating system:

The emulator couldn’t determine the host IP address, which is used to communicate with the guest virtual machine.

Some functionality may be disabled.

[Close]

Hmm, what the **? I had a look around the internet and saw some horrible posts about re-installing the SDK. Ergh. One post mentioned an internal developer who had to uninstall VPNs, and remove all the virtual switches. None of which filled me with joy. So I opened Hyper-V manager and looked at the virtual switch settings for the phone emulator. I nodded sagely, then removed it – hoping the emulator would spot it was missing the settings and recreate them. It worked, the emulator recreated the settings and worked. Hurray! Hopefully it won’t happen too often…strange.

Easy theming with Windows Phone

Easy theming with Windows Phone

Windows Phone has the concept of Dark and Light themes. I really like this idea as I typically have my phone in Dark theme and switch to Light when in bright sunshine. Unfortunately not a lot of applications make use of these themes so I wanted to share the method I use to implement it.

The basics

The idea is to provide your designer, or at least the one within, with a nice clean separation of Light and Dark styles.

clip_image001

Figure 1 Basic file structure

Here we can see the three main components; Dark.xaml, Light.xaml and Master.xaml. Let’s first look at the output so you can see the type of changes you can make. Obviously I’m being garish to exaggerate the difference, and normally I’d be more subtle 🙂 />

clip_image003clip_image005

As you can see the explosion is white in the Dark theme and yellow in Light. Also the background brush in the header is red and sky blue for Dark and Light respectively. Essentially any style is available to change. So what have I changed to create this lovely theme sensitive UI?

Example Theme Xaml

Dark;

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="AppBackgroundBrush" Color="Red"/>
<SolidColorBrush x:Key="AppForegroundBrush" Color="#FFFBFFC9"/>
<Color x:Key="PhoneForegroundColor">#FF6E1919</Color>
<SolidColorBrush x:Key="PhoneForegroundBrush" Color="{StaticResource PhoneForegroundColor}"/>
<ImageBrush x:Key="ImageBrushBackground" ImageSource="/Background.png"/>
</ResourceDictionary>  

Light;

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="AppBackgroundBrush" Color="SkyBlue"/>
<SolidColorBrush x:Key="AppForegroundBrush" Color="#FF303026"/>
<Color x:Key="PhoneForegroundColor">#FFF5F908</Color>
<SolidColorBrush x:Key="PhoneForegroundBrush" Color="{StaticResource PhoneForegroundColor}"/>
<ImageBrush x:Key="ImageBrushBackground" ImageSource="/BackgroundLight.png"/>
</ResourceDictionary> 

The idea is that you use the same resource keys and change the underlying value to suite the theme. For example, we can see that the ImageSource for ImageBrushBackground is different for each theme.

How do you use the Theme files?

I owe the technique to a great post from IdentityMine, essentially you derive a new static resource type which loads the correct themed xaml *before* your page has started to load. I’ve wrapped this type in a separate component you can just reference and use. Rather than regurgitate the Identity Mine post I’ll explain how to use it, NB or you can just use the sample;

1. Create the Dark and Light xaml files as shown in Figure 1 Basic file structure

2. Add a reference to Pauliom.Theming.dll (or Pauliom.Phone8.Theming.dll)

3. Add a the Master.xaml to the Resources folder (change assembly as appropriate);
<ResourceDictionary xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ThemingSample"
xmlns:Pauliom="clr-namespace:Pauliom.Theming;assembly=Pauliom.Theming">
<ResourceDictionary.MergedDictionaries>
<Pauliom:ThemeResourceDictionary Kind="Theme"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary> 

4. The role of the Master is to provide a single place to create a master theme concept, you don’t need to use it so long are you put the ThemeResouceDictionary somewhere in your projects MergedDictionaries

5. Change App.xaml to make the resources available anyway in project, ensure the following in App.xaml, the first reference to Dark is your default, it helps the editors/designers;

<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/Dark.xaml"/>
<ResourceDictionary Source="Resources/Master.xaml"/>
</ResourceDictionary.MergedDictionaries>  

6. That is all you need, you are now free to reference those resource keys in the knowledge the changes to the underlying theme will be automatically routed to your specific themed file

The Sample

I hope you find this as useful as I do, and I hope it encourages more applications to use and react to themes. You can find the source and components at https://winphonetheme.codeplex.com