WPF Tips n' Tricks – Use Segoe UI on Vista and Tahoma on XP (and whatever else wherever else)

A question that's often asked is how to make it so that your elements in WPF use the latest greatest fonts on Windows Vista, but fallback nicely on Windows XP.

As with CSS, WPF supports font fallback. That means you can define a font to use if present on the target system, and a second one to use if a first one is not found, as in the following example:

<Page

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <StackPanel>

        <TextBlock FontFamily="Segoe UI, Verdana" FontSize="20">Using Fallback</TextBlock>

    </StackPanel>

</Page>

This will show Segoe UI, followed by Verdana. That said, WPF supports composite fonts, which are essentially virtual fonts that redirect each portion of Unicode (symbols, asian text, Greek text, Latin text, ASCII, you get the drill) to the correct font. It replaces the way font substitution is done in Win32. And you have the following fonts you can use:

  • GlobalMonospace.CompositeFont
    Monospaced, for example used to show snippets of code.
  • GlobalSanSerif.CompositeFont
    SanSerif, so without the heavy bits that decorate a font. Arial, Segoe UI and Tahoma are part of that family.
  • GlobalSerif.CompositeFont
    With, Con, Mit Serif (useless Eddie Izzard Reference), for those that want the little decoration. Times New Roman is the most well known
  • GlobalUserInterface.CompositeFont
    The one used for user-interface elements.

You can go and have a look at these files in your %windir%\fonts folder. You'll see each mapping and each code point.

So to answer the question, if you want Segoe UI and a fallback on Tahoma on XP, you can either use the composite font like this:

<Page

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <StackPanel>

        <TextBlock FontFamily="Global User Interface" FontSize="20">Using Composite font</TextBlock>

    </StackPanel>

</Page>

 Or more simply do nothing and do not specify a font, it will default to the right one. But as WPF is multi-platform, my best advice: Define the fonts you use in a resource, and try your app on both Segoe and Tahoma, just to have a feel of what your app looks like under XP.

[Thanks to Mikhail Leonov for the pointer to composite fonts on the forum]

Ads

WPF Tips n' Tricks – Have all your dates, times, numbers... in the local culture

This is the first instance of a series where I'll try to publish at least 

Technorati tags: , ,

one trick a day you'll find useful in your .net 3 development life. Some of it I came up with myself, some of it comes from the forums. I'll make sure to give credit where credit is due :)

WPF has a very annoying tendency. All dates are by default in the en-US format. You need to understand first why, and then I'll give a few potential solutions, and one that is now my favorite.

You'll notice that UIElement has a property called Language. This property is supposed to define what language the element has been written in. That way, WPF can know when some content is en-US (American English), or en-GB (British English), etc. It is also bound to the xml:lang property you can set on any xml document.

Now if you read the documentation the way I did, you realize that xml:lang by *default* is set to the empty string, and as such doesn't have any associated culture. But by default, the matching Language property has a default of... en-US! And because of the way bindings work, that's why all your dates will always show up in American English format.

Whenever you bind an element's property to a DateTime object, the binding is going to covert the DateTime to the type of the property you're binding to. Take for example the following binding:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:sys="clr-namespace:System;assembly=mscorlib">

    <Grid>

        <TextBlock Text="{Binding Path={x:Static sys:DateTime.Now}}" />

    </Grid>

</Window>

This will convert from DateTime to a String (the type of the Text property). But to do so, it is going to use a default converter. If you check the documentation for bindings, you'll see that you can specify an IValueConverter in the Converter property. And you'll also see a ConverterCulture property that specify which culture you want to use to convert your data, here our DateTime object.

As I said before, without a Converter specified, WPF will find one automatically for you, either built-in ones or using the existing conversion infrastructure that has been around for now three versions. But guess what happens when you don't specify a ConverterCulture?

WPF selects the culture of the Language property of the element on which the binding is applied. In our case, the default: en-US again!

So here's my trick of the day. To ensure your application defaults to the current culture *on the client machine* and *at run time*, you can add one simple line in your App.xaml.cs.

    public partial class App : Application

    {

        static App()

        {

            FrameworkElement.LanguageProperty.OverrideMetadata(

                typeof(FrameworkElement),

                new FrameworkPropertyMetadata(

                    XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

        }

    }

What this bit of code does is override the default value of the Language property on all the FrameworkElement inherited classes in your application to the CurrentCulture of the computer you run on. In this case, we're interested in overriding this value so that any content is assumed by default to be in the language associated with the way you want your localization to be made. This is quite wrong, as explained by Michael in his Why we have both CurrentCulture and CurrentUICulture post, but it's the solution approaching the most an acceptable outcome.

As for what Microsoft probably should have done? Set by default the Binding.ConverterCulture property to the CultureInfo.CurrentCulture value. But that's just my opinion :)

Ads

Goodbye MacBook Pro, Hello PowerShell

Well, I am mourning the departure of my MacBook Pro to the hands of a thief in All Bar One on a friday evening with my colleagues.

If anyone ever see a MacBook Pro 17inches Core2 Duo with glossy screen and, more specific and probably unique to mine, a big bump next to the opening of the superdrive, please report it immediately to the London City police in Islington.

And of course, thanks to Murphy's law, the insurance I thought was covering it didn't, and am off £2,200, and no more computer to work. Now that's a major blow! I'll wait till the next revision of the macbook before buying a new one, that I will insure to the maximum coverage!

I've also decided to ditch my old backup system using cds and dvds after a few got corrupted and i ended up loosing a huge amount of stuff. From now on it will be a RAID5 1TB windows server running somewhere hidden in the house.

But on a brighter note, my beloved PowerShell is finally released for Windows Vista and you can download it here.

Ads