Hemme's Blog

Stories from behind the keyboard

  • RSS
  • Twitter
  • Linkedin

imageWhen you develop a Windows Phone 7 application that reflect the user theme, you are practically limited and bound to an handful of color resources: the background color, the foreground color, the accent color and a few more. Referring to these resources in you XAML is super simple: once you know all the various theme resources,  you can apply any resource in your code via the {StaticResource} markup extension.

Things may get a bit more complicated if you have custom raster graphics, such as a logo or background illustrations, and you want them to observe the user theme. As long as you don’t want to create all possible combinations of [black/white] plus all available accent colors (8 accent colors so far), you can use the following guide.

Step 1: Monchromaticity

Design with only one color. Just think in term of gradations of opacity and paint like on glass. This is similar to drawing in gray scale, but instead of filling a raster image with shades of gray, you start from a transparent canvas and draw with just one color (say white). For instance, using Paint.NET you can easily draw something like this:

image

(The transparency checkerboard is there only to point out what pixels are opaque, and in what measure).

Step 2: Opacity

Technically speaking, you are drawing an alpha channel canvas; during this process, you totally neglect colors and focus on the opacity/transparency of the strokes. The final colors will be the result of the application of user theme settings (that’s to say, the background, the foreground and/or the accent color). For instance, we could give the smile a skin tone of 50% opacity (in Paint.NET you do this by filling the area with the paint bucket, with white, 127 alpha).

image

Step 3: XAML and resources

Now you can save your artwork as a PNG, import the file in your Visual Studio project and use it in your XAML. For instance, let’s put Smile.png to the PhoneApplicationPage background:

image

Now that we have a solid background, our smile looks bald and consistent. Anyway, after we run the application and switch to the “light” theme, Mr. Smile disappear!

image image

Step 4: Overlay masks

Of course the image is still there but it’s the same color of the background, so we cannot see it anymore. On the contrary we can still read the application title (MY APPLICATION) and the page name, because they are written dark over light now. This is the effect we aim to achieve for Mr. Smile: being drawn in white when the background is black, and being drawn in black when the background is white.

Let’s start making an explicit use of a color resource: {StaticResource PhoneForegroundBrush}. We can draw a square and fill it with the theme foreground color:

image

At this point, you can run the application and invert the theme: the square will change to black and won’t disappear, since its color is bound to the theme foreground color now.

The last touch is using Mr. Smile as an opacity mask. This way, its pixels will say how much each corresponding pixel of the rectangle is opaque, based on the smile’s alpha channel. The final result just what we need:

image

..and of course it works fine with the inverted theme.

image 

If you want to use the accent color, just replace {StaticResource PhoneForegroundBrush} with {StaticResource PhoneAccentBrush} and you are done.

image image

Happy masking!

Quick and Dirty: you can enable the Windows Explorer Preview Panel to show the content of various text file format (such as .cs, .inf, .xaml, and so on…). Just open REGEDIT.EXE, browse HKEY_CLASSES_ROOT down to the file extension you want to preview, and add a new string value “PerceivedType” with value “text” and you are done.

For instance, here’s how you enable the text preview handler for C# files:

image

From now on, when you select a .cs file in Windows Explorer, the Preview Panel will show its content.

image

Happy regediting!

One straightforward way to localize a Windows Phone 7 application you are writing is the following:

  • Create and edit a .resx file (for instance LocalizedStrings.resx).
  • Build your project, so that Visual Studio (well, the PublicResXFileCodeGenerator tool) generates the .Designer.cs file. This way your assembly is having a nice LocalizedStrings static class that you can use in your XAML.
  • Register the static class as an application resource, in your App.xaml:
<Application ... 
 xmlns:my="clr-namespace:{your default namespace}">
<!-- .... -->

<Application.Resources>
  <!-- .... -->
  <my:LocalizedStrings x:Key="Loc"/>
</Application.Resources>
  • Feel free to bind to any localized string in your XAML using the built-in Managed Resource Editor. For instance, if you have a string resource called MyLocalizedString, image you can write somewhere in your XAML’s:
<!-- .... -->

<TextBox Text="{Binding MyLocalizedString, Source={StaticResource Loc}}" ../>

<!-- .... -->

At this point you build and run your project….

image

...and sudden notice that your program gives a creepy "AG_E_PARSER_UNKNOWN_TYPE" error. (“WTF!?”): image

This error says that the runtime parser doesn't know a type, but stays absolutely silent about the type’s name! The unknown type is just the LocalizedStrings class and it is unknown to the parser because the PublicResXFileCodeGenerator tool made its constructor internal.

image

Editing by-hand the code behind is pointless, since every time you edit or add a resource in the Managed Resource Designer, the PublicResXFileCodeGenerator tool rebuilds the LocalizedStrings.Designer.cs and (re-)sets the constructor to “internal”.

At this point you can take one of the following steps:

  • Commit to Android development
  • Change your mind about binding to resources
  • Use an IL weaving technique and make the constructor’s access modifier public
  • Follow KISS and YAGNI principles (kind of..) and just replace “internal” with “public” before building your project.

The latter is the path I followed, after a little struggle with NuGet (I couldn’t find any proper NuGet Fody add-on, precisely).

To put it shortly, I wrote a tiny REPLACE.EXE console utility. It takes 3 input parameters: a full filename, a text to find and a text to replace. Then I set the following pre-build action for my WP7 application project - $(ProjectDir) is a Visual Studio macro; you can find it and more on  MSDN’s “Pre-build Event/Post-build Event Command Line Dialog Box” page).

image

image

This way, anytime I build my project, REPLACE.EXE resets the LocalizedStrings contructor to public.

All’s well what ends well; happy programming!

P.S: Here’s the RESET.EXE’s Main()…

image