When you are developing a web site and want to use a custom font, via font-face, you might find that IE on Windows Phone refuses to use it. Turns out that IIS doesn’t include the mime-type by default so you need to add it. If you don’t have access to the site directly (maybe Azure web site or a shared server) you can add it in your site’s web.config webserver section;

<system.webServer>
    <staticContent>
      <mimeMap fileExtension=".woff" mimeType="application/x-font-woff" />
    </staticContent>
</system.webServer>

1080p 6 inch Silverlight vs. Jupiter

Anyone know how to resolve this? Given the simple XAML;

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>

        <Border Background="Red"  Grid.Row="0" >
            <TextBlock Text="Silverlight"  />
        </Border>

        <Rectangle Fill="Blue" Grid.Row="1" />
        <Rectangle Fill="Green" Grid.Row="2" />

    </Grid>

This results in some very different results;

Silverlight Jupiter
image image

The Silverlight version scales nicely with the phone, whereas the Jupiter version renders the text without scaling it. How do you resolve this?

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 Visual State Manager to share a Universal App page

I was having a chat about how Universal Apps work and how you might use the Visual State Manager to support both Win8 and Phone layouts in a single page.  Here goes;

image

  1. Create a new Universal App
  2. Cut MainPage.xaml from Windows 8.1 and paste it into Shared
  3. Delete MainPage.xaml from Phone
  4. Add a few simple Visual States to represent the screen sizes/orientations you want. In this case I have; MinimalOrPhonePortrailLayout, PortraitLayout, DefaultLayout
        <Grid>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup>
                    <VisualState x:Name="DefaultLayout">
                    </VisualState>
                    <VisualState x:Name="MinimalOrPhonePortrailLayout">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Text" Storyboard.TargetName="SimpleMessage">
                                <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="Phone Layout" />
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="PortraitLayout">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Text" Storyboard.TargetName="SimpleMessage">
                                <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="Big Device Portrait" />
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Grid>
                <TextBlock Name="SimpleMessage" Text="Hello Default World" TextTrimming="WordEllipsis" Foreground="Blue" FontSize="60"/>
            </Grid>
        </Grid>
    
  5. Add a SizeChanged event to the page, this will be used to select the state
            public MainPage()
            {
                this.InitializeComponent();
    
                this.NavigationCacheMode = NavigationCacheMode.Required;
                this.SizeChanged += Page_SizeChanged;
            }
    
            void Page_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                if (e.NewSize.Width < 520)
                {
                    VisualStateManager.GoToState(this, "MinimalOrPhonePortrailLayout", true);
                }
                else if (e.NewSize.Width < e.NewSize.Height)
                {
                    VisualStateManager.GoToState(this, "PortraitLayout", true);
                }
                else
                {
                    VisualStateManager.GoToState(this, "DefaultLayout", true);
                }
            }
    
  6. Add changes to the StoryBoards of the Visual States, in this quick example the text in a TextBlock will be changed.

Here’s the results;

image imageimageimage

imageimage

Hopefully you can see that it is possible to share a single page…although I’m not saying you should 😉

HttpClient redirect gotcha

Just a quick post as I’ve just fallen foul of this.

Recently I changed by web-client to use the nice await/async HttpClient, e.g.

   
  HttpClient client = new HttpClient();   
  string result = await webClient.GetStringAsync(serviceRequest); 

The problem is that my service decided to be a good web citizen and change their API by sending a redirect. Unfortunatley the above code simple fell over…legs in the air.

The trick is to configure the HttpClient to allow redirects;

   
  HttpClientHandler handler = new HttpClientHandler();   
  handler.AllowAutoRedirect = true;   
  HttpClient webClient = new HttpClient(handler);            
  string result = await webClient.GetStringAsync(serviceRequest); 

Testing localisation on Windows Phone

Localising (or localizing) a Windows Phone application is straightforward, however, testing that you have correctly localised the text is harder. One method is to use a pseudo language but I found that has a couple of problems; you need to overwrite a locale (although you can use my previous posts to create a new ‘unsupported’ language), you need to maintain that language with your default language, and…I just find it over noisy. So I present an alternative.

 

Here is an example of an application I am working on;

image

If I switch on the ‘test localisation’ then the page looks like;

image

Argh, I’ve not localised ‘save’! The idea is that all the localised strings show up as their resource name surrounded by a ‘%’. I think this makes it easier to spot the non-localised text, plus you could turn it on during a test session therefore allowing you to report the resource id that is incorrectly localised for a specific language.

The code is based on a previous post but I’ll show the code again with the slight adjustments;

Note, if you want to dynamically support switching between a language and testing it, then you need to change the GetString to call the base class

public class TestResourceManager : ResourceManager
{
    public TestResourceManager()
        : base("MyApp.Localisation.StringLibrary", typeof(StringLibrary).Assembly)
    {
    }

    public override string GetString(string name, System.Globalization.CultureInfo culture)
    {
        return "%" + name + "%";
    }
}

Then add a constructor to the default string library.

    public class LocalisedStrings
    {
        private static readonly StringLibrary _localizedResources = new StringLibrary();

#if DEBUG_LOCALE
        static LocalisedStrings()
       {
           Type type = _localizedResources.GetType();
           FieldInfo info = type.GetField("resourceMan", BindingFlags.NonPublic | BindingFlags.Static);
           info.SetValue(null, new TestResourceManager());
       }
#endif

        public StringLibrary LocalizedResources { get { return _localizedResources; } }
    }

Automatic text hyphenation for Windows Phone

Recently the topic of text hyphenation for Windows Phone has cropped up. So I thought I’d give it a quick go. Note, this is an initial stab at a solution, I’m not suggesting it’s fully functional but certainly could be built upon.

The problem

image

 <TextBox> 
      FontSize="40"                     
      Width="170"
      TextWrapping="Wrap"
      Text="Hello world combinations can be extremely worrying" />                

Possible Solution

The design is pretty simple (although is it Right-To-Left compatible?), check when the text moves from one line to the next. When it does, check to see if the last character is part of a word. It it is, the add a hyphen.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace Pauliom.Behaviors
{
    public class HyphenationBehavior : Behavior<TextBox>
    {
        private int lastLength = 0;
        protected override void OnAttached()
        {

            var textBox = this.AssociatedObject;
            textBox.TextChanged += textBox_TextChanged;
            textBox.Loaded += textBox_Loaded;
            base.OnAttached();
        }

        void textBox_Loaded(object sender, RoutedEventArgs e)
        {
            Hyphenate(sender);
        }

        void textBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            Hyphenate(sender);
        }

        private void Hyphenate(object sender)
        {
            TextBox textBox = sender as TextBox;
            if (this.lastLength != textBox.Text.Length)
            {
                this.lastLength = textBox.Text.Length;
                Rect lastRectange = textBox.GetRectFromCharacterIndex(1);
                int x = 0;
                while (x < textBox.Text.Length)
                {
                    Rect r = textBox.GetRectFromCharacterIndex(x);
                    if (lastRectange.Top != r.Top)
                    {
                        lastRectange = r;
                        char endChar = textBox.Text[x - 1];
                        if (endChar != ' ' && endChar != '-')
                        {
                            textBox.Text = textBox.Text.Substring(0, x - 1) + "-" + textBox.Text.Substring(x - 1);
                        }
                    }                    
                    x++;
                }
            }
        }

        protected override void OnDetaching()
        {
            var textBox = this.AssociatedObject;
            textBox.TextChanged -= textBox_TextChanged;
            base.OnDetaching();
        }
    }
}

image

 <TextBox> 
      FontSize="40"                     
      Width="170"
      TextWrapping="Wrap"
      Text="Hello world combinations can be extremely worrying">    
      <i:Interaction.Behaviors>
         <pauliom:HyphenationBehavior />
      </i:Interaction.Behaviors>                
 </TextBox>            

As I said, it probably is not production ready code but could be built upon.