Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Bikes, a Windows Phone application for bike sharing systems

My latest Windows Phone application found its way to the Microsoft marketplace.

Bikes is designed to help bicyclists that use city bicycle sharing systems across Europe to find nearest stations, provide some basic info about available bikes and free parking slots for each of those stations.

Here’s a short video:

[Short note: the video about shows how the next version will look like (v1.0.1), current marketplace version is v1.0.0]

The main purpose I’ve decided to create this app was to support the new bicycle sharing system in my city (started May this year), but since the same system is use in other (mostly) European cities as well, I added some of those as well. I’m planning to support other systems and adding more cities in future releases.

You can follow the following twitter account – bikeswp7 – for latest news regarding the app, send suggestions, bug reports and any comments you have.

You can download application directly from the marketplace. If you can’t access the Marketplace link with your desktop browser, here’s another link.



Localizing the August 2011 Windows Phone Toolkit

Great news! A new version of Windows Phone Toolkit was released today. These bits target the “Mango” OS (which translates to SDK v7.1). The “pre-Mango” version (7.0) will follow in a short-while.

Download the Toolkit from Codeplex. Available also on NuGet.

One of the new features coming with this release is localization support. Localized strings are there mostly to support brand new Date and Time converters, but they also include a few strings used by Date and Time picker controls that were available in the previous release.

The strings are localized to 22 languages that are the languages, available the “Mango” OS. Chances are you’re going to be writing an application localized to a “non-Mango” language (yes, there are us who are still waiting!), so here’s a tip how to extend the toolkit localization features to your “unsupported” language. I’ll be using the Slovenian (my native) language as the example.

1. Download the toolkit binaries and source code from Codeplex:

2. Unzip the source code package and open the solution (PhoneToolkit.sln).

3. In Solution Explorer, locate the LocalizedResources folder. Copy the neutral language (US English) control resources file and rename it by appending target culture code to the filename (sl-SI is for Slovenian language):

loc1

4. Open the new ControlResources file by double clicking on it in Solution Explorer. Managed Resources Editor should appear, listing original strings.

5. Take some time and translate all strings into the target language. It will probably take an iteration or two to get it right (have to test it in a real case example). In case of Slovenian language, there’s also a slight problem with missing dual  forms (e.g. there are singular and plural, like 1 hour and >1 hours, but I can’t specify the string for 2 hours), plus some other language specifics I have yet to figure out how to work around them.

loc2

6. Build the project. It should compile (make sure you’re using tools for v7.1).

7. Go to the Bin\Debug folder (or Bin\Release, depending on your build configuration) and locate the sl-SI folder (or the one that matches your culture code). In it, there should be a Microsoft.Phone.Controls.Toolkit.resources.dll file. Copy folder to the safe place on your disk. You’ll need it whenever you start a new project leveraging the Windows Phone Toolkit..

8. You’re done with the Toolkit. Start a new Windows Phone project, add a reference to the new Toolkit, add resource files, etc., and start developing your localized application.

9. Because you’re targeting the unsupported language, don’t forget to add the following line to the application start:

Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

That’s usually the first line in my App constructor. The other usual localization steps apply: Edit .csproj file to add supported cultures, set the neutral language, …

10. After building your application, you’ve got the application package (.Xap file). Before deploying it on your device or marketplace, copy the culture-specific folder containing the new localized dll (from step 7) into it. If you’ve chosen English as the neutral language, the folder with your culture code (sl-SI in my case) should already be in place.

Note: I didn’t have to change the AppManifest.xml file in Xap to include the new localized resource dll, but perhaps it’s a good idea to do so. You may also choose a more convenient method of including the resource file at design time to avoid file copying and changing the manifest file after each build.

11. That’s it! With localized resource file in place, your application should now display Toolkit’s resources in your own language.

loc3

This is a screen shot from the Sample application that comes with the new Toolkit.



On a path to a generic About page

Since every Windows Phone application should have some kind of About page, I wanted to see if I could build a generic page that I would reuse in my other apps. These are a few tips I picked up during building such a page:

1. The About page is rarely accessed so I put it in a separate assembly. This way I took some initial load off the main assembly and the About assembly can now easily be shared with other apps.

2. If you want to display the application icon on your About page, there is no need to create new graphics. Depending on your target size, you can choose from either ApplicationIcon.png (62x62) or Background.png (173x173) icons. To put the icon on your About page, use:

<Image Source="/ApplicationIcon.png" Stretch="None" />

And of course you can specify your own size and adjust the stretching attribute.

But don’t worry about the ApplicationIcon.png not being included in the About page project. With application icons being marked as Content, the contents of a Xap should look something like this:

image

By specifying an external link reference to the ApplicationIcon.png, the icon will be displayed regardless of it not being part of the project that contains it.

3. Static text. This includes titles, labels and text that will likely be the same across every application. If you’re not localizing your apps, you may as be well hard-coding strings into your XAML. But if you are, you would most definitely want to pull them from your resource files. In latter case, the standard localization guidelines apply. Again, don’t worry if your if your localization files are in your main assembly. The application will pick them up correctly regardless (even at design time).

<TextBlock x:Name="PageTitle" 
           Text="{Binding Strings.AboutTitle, 
                  Source={StaticResource LanguageResources}}" 
           Margin="9,-7,0,0" 
           Style="{StaticResource PhoneTextTitle1Style}"/>

4. Dynamic text. This includes the version number, application title and other text that will be unique to every application or its version. Some of these texts could be stored in resource files as well, but let’s look at the alternative options.

If you take a look at the AssemblyInfo.cs file of your main project (you’ll find it in the Properties folder), you’ll see it’s populated with some weird assembly attributes you don’t even care about (that’s because you’re setting and changing them from Visual Studio’s dedicated project properties page, but that’s not the point).
The point is that you can access all of these strings from code. All you have to do is get to the main assembly and read its custom attributes (which is what those lines from the AssemblyInfo file really). Here’s how:

Getting the main / entry assembly

The first thing is getting access to the correct – main (or entry) assembly. There are many ways to do that. At least one of those listed below should play nice with your your application architecture :

Assembly.GetExecutingAssembly() will get a reference to an assembly that’s executing that same code.

Assembly.GetCallingAssembly()will get a reference to an assembly of the method that called into this code.

The above methods don’t work well if the call is originating from the same dll. Exploring further…

Deployment.Current.EntryPointAssembly returns a name of the main assembly in pure string. You can use that to load the assembly with Assembly.Load(System.Windows.Deployment.Current.EntryPointAssembly). This will get you the main assembly, but it doesn’t feel right, so I finally settled with:

Application.Current.GetType().Assembly depends on using the Application static class, but since this is only used for a simple About page, that shouldn’t be  a significant problem.

Reading the attributes

I created the following helper method to read the attributes off an assembly:

private string GetAttribute<T>(Func<T, string> selector)
    where T: Attribute
{
    object[] attributes = assembly.GetCustomAttributes(typeof(T), true);
    if (attributes.Length == 0)
    {
        return "N/A";
    }
    T attribute = attributes[0] as T;
    return attribute == null ? "N/A" : selector(attribute);
}

GetCustomAttributes method overload above will return the only specified type of attribute you’re requesting, and the selector Func will read the value off of it. In the example of getting the Version attribute, here’s how you would use the function:

private string version;
public string Version
{
  get 
  {
    return version ?? 
      (version = GetAttribute<AssemblyFileVersionAttribute>(a => a.Version)); 
  }
}

For the application title, you would use the AssemblyTitle attribute:

private string title;
public string Title
{
  get 
  {
    return title ?? 
       (title = GetAttribute<AssemblyTitleAttribute>(a => a.Title)); 
  }
}

And so on…

And if you’d like, you can even create your own attributes, for example:

[AttributeUsage(AttributeTargets.Assembly, Inherited = false)]
[ComVisible(true)]
public class AssemblyContactAttribute : Attribute
{
    public string Email { get; private set; }
    public AssemblyContactAttribute(string email)
    {
        Email = email;
    }
}

Put that into the AssemblyInfo.cs file, as seen with other assembly attributes:

[assembly: AssemblyContact("myapp@tozon.info")]

and use the GetAttribute method similar to above examples.

You have just decorated your assembly with a new custom attribute that you can pull out at runtime.

By following those four points I was able to completely isolate my About page from main app(s) and adding the About page in my new apps is a matter of seconds. There is some convention involved of course (like the name of resources reference holding class), but I don’t see this as a problem. What do you think?



Windows Phone Pivot and loading content

Rewatching the Windows Phone Application Performance MIX10 talk by Jeff Wilcox, I took a note of one particular part where he clearly answers a question I’ve been asked a few times by now already. This question is based around the confusing statement that Pivot controls are supposed to be lazy loading their content pages, in contrast to Panoramas, which, at startup, would load all pages at once. The part that confuses developers the most is that when they start debugging their apps, they find out that Pivots load all their pages at startup too! How come? Aren’t Pivots loading pages only when needed?

Jeff explains this very clearly (fast forward to approx. minute 25) : “So the instant you go to a page, we pop up the Pivot, we’ll load  the content there. … …  Trouble is, we need to load more, because we want to provide a smooth experience when you pivot around. So we’re actually also loading, right after that first page comes up, we’ll kick off a load for both items on the left and the right.

See Jeff’s talk on the Channel 9 site.

What this means is that if your Pivot has only 2 or 3 pages, the startup performance won’t be that much different than when using a Panorama. If those 3 content pages are heavy on the load, use a lot of bindings etc., you can get into trouble. In some cases, loading a single content page on startup (and the rest when pivoted to) might actually result in a better experience than preloading all 3 pages.

Is there a way to override the default Pivot behavior and load only one content page on startup?

Of course there is.

The trick is to create a user control for each content page (which is a good idea anyway) and start it off with a Pivot control by specifying empty pages:

<controls:Pivot Title="My Pivot"
                LoadingPivotItem="OnLoadingPivotItem">
    <controls:PivotItem Header="Page 1" />
    <controls:PivotItem Header="Page 2" />
    <controls:PivotItem Header="Page 3" />
</controls:Pivot>

The LoadingPivotItem event will fire each time the Pivot would load a new content page. From MSDN documentation: “[LoadingPivotItem is an] Event for offering an opportunity to dynamically load or change the content of a pivot item before it is displayed.”

What you do during this event is check whether the content is loaded yet and if it isn’t, kick off the load. Something like:

private void OnLoadingPivotItem(object sender, PivotItemEventArgs e)
{
    if (e.Item.Content != null)
    {
        // Content loaded already
        return;
    }

    Pivot pivot = (Pivot)sender;

    if (e.Item == pivot.Items[0])
    {
        e.Item.Content = new Page1Control();
    }
    else if (e.Item == pivot.Items[1])
    {
        e.Item.Content = new Page2Control();
    }
    else if (e.Item == pivot.Items[2])
    {
        e.Item.Content = new Page3Control();
    }
}

One thing to have in mind though: make sure that any data you want to display on those content pages are loaded on the background thread (again – always a good idea) to allow the pages to load as quickly as possible.