The FrameworkElement.Language property and why should you care!

The first time I came aware of this issue was when reading a post by Portuguese MVP Paulo Morgado on the App Hub Forums:

If all the emulator settings are set to “Portuguese (Portugal)” (both interface as all regional settings), how come when I use an IValueConverter on any Binding expression, the “culture” parameter has a “en-US” CultureInfo?…

To properly research on the subject, I created a small app with two TextBlock controls that show the Thread.CurrentThread.CurrentCulture and Thread.CurrentThread.CurrentUICulture current values, and a third TextBlock with an IValueConverter that basically returns the culture.Name he is using, and the result was quite surprising!

Here is the code for my CultureDebugValueConverter class, implementing an IValueConverter:

public class CultureDebugValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return culture.Name;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Notice that no conversion is actually being made (the value parameter isn’t even being used), it just returns the “culture.Name” value from it.

Here’s the main ContentPanel on the MainPage.xaml:

<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Style="{StaticResource PhoneTextSubtleStyle}">CurrentCulture</TextBlock>
<TextBlock Text="{Binding CurrentCulture}" Style="{StaticResource PhoneTextTitle2Style}" />
<TextBlock Style="{StaticResource PhoneTextSubtleStyle}">CurrentUICulture</TextBlock>
<TextBlock Text="{Binding CurrentUICulture}" Style="{StaticResource PhoneTextTitle2Style}" />
<TextBlock Style="{StaticResource PhoneTextSubtleStyle}">Converter Culture</TextBlock>
<TextBlock Text="{Binding Converter={StaticResource CultureDebugValueConverter}}" Style="{StaticResource PhoneTextTitle2Style}" />
</StackPanel>

As you can see, the last TextBlock just sets the Binding.Converter to a StaticResource of CultureDebugValueConverter type.

This is the remaining code placed on MainPage.xaml.cs:

public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
this.DataContext = this;
}
public string CurrentCulture
{
get
{
return Thread.CurrentThread.CurrentCulture.Name;
}
}
public string CurrentUICulture
{
get
{
return Thread.CurrentThread.CurrentUICulture.Name;
}
}
}

Finally, I started the emulator, changed all the regional settings to “Portuguese (Portugal), and this is what I got after running the app:

LanguageTestApp original version

So the real question right now is: If the operating system interface, the CurrentCulture, and the CurrentUICulture are all set to “pt-PT”, from where did that “en-US” came from?

There is no trivial reason for this behavior, and to completely understand it, we first need to know how the “culture” parameter on IValueConverter.Convert method works; on the documentation, you can read the following: * The culture is determined in the following order:

  • The converter looks for the ConverterCulture property on the Binding object.
  • If the ConverterCulture value is null, the value of the Language property is used.

Given that I didn’t set the Binding.ConverterCulture property, this means it will fallback to the FrameworkElement.Language, which in turn has this in the docs:

The default is an XmlLanguage object that has its IetfLanguageTag value set to the string “en-US”**

We have finally found the “guilty” one!!!

Now that we know this, we can fix it just by setting the Page.Language property! The fixed code should look something like this:

public MainPage()
{
Language = System.Windows.Markup.XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentUICulture.Name);
InitializeComponent();
this.DataContext = this;
}

If you look closely on the 3rd line, you’ll see the Language property set to a XmlLanguage instance created with the CurrentUICulture.Name.

Be aware that for this to work, you must set the Language property before the InitializeComponent method gets invoked!

And here’s the final result:

LanguageTestApp fixed version

I honestly don’t know the reason for this strange behavior, but this is a problem to account for if you have localization needs for your Windows Phone app!

The demo project I created and used for this article can be downloaded from here!

How to force a focused Textbox binding to update when I tap an app bar item

If you have TextBox controls in your app and you’re binding to the Text property (two-way mode), you should by now have noticed that the binding source isn’t updated when you tap an icon or menu item in the app bar!

The first thing you need to know in order to understand why this is happening, is that the TextBox control only updates the Text binding source when the control looses focus.

Second reason is that the ApplicationBar control can’t get focus, nor can it’s ApplicationBarIconButton or ApplicationBarMenuItem controls, so when you tap on them, the click event will be invoked without the TextBox control ever loosing focus!

To fix this behavior we need to force an update on the binding source when the click event get’s invoked, and here’s some code on how to achieve this:

var focusedElement = FocusManager.GetFocusedElement();
var focusedTextBox = focusedElement as TextBox;
if (focusedTextBox != null)
{
var binding = focusedTextBox.GetBindingExpression(TextBox.TextProperty);
if (binding != null)
{
binding.UpdateSource();
}
}

We start by using FocusManager.GetFocusedElement method to get the current focused element. Then we check if that is a TextBox control, and if so, force it to update the Text property binding source!

The same problem will happen with PasswordBox, so it’s best just to handle both situations and encapsulate this in a reusable method:

public static void FocusedTextBoxUpdateSource()
{
var focusedElement = FocusManager.GetFocusedElement();
var focusedTextBox = focusedElement as TextBox;
if (focusedTextBox != null)
{
var binding = focusedTextBox.GetBindingExpression(TextBox.TextProperty);
if (binding != null)
{
binding.UpdateSource();
}
}
else
{
var focusedPasswordBox = focusedElement as PasswordBox;
if (focusedPasswordBox != null)
{
var binding = focusedPasswordBox.GetBindingExpression(PasswordBox.PasswordProperty);
if (binding != null)
{
binding.UpdateSource();
}
}
}
}

All you now need is to call the FocusedTextBoxUpdateSource method in the start of the app bar item control click event handler so that it will update the binding source before the rest of the code runs!

You can find this problem fixed on some toolkits and frameworks, like Caliburn.Micro and my own Cimbalino Windows Phone Toolkit ApplicationBarBehavior.

Another way to fix this would be by updating the binding source on text changed rather than when it looses focus, and for that you can use the TextBinding helper from Coding4Fun Toolkit for Windows Phone.

Windows Phone Choosers with async/await

Currently, Windows Phone Choosers work is by invoking the Show method and then subscribing the Completed event and waiting for it to be invoked.

Wouldn’t it be great to just use await chooser.ShowAsync() and get the results immediately?

All choosers extend the ChooserBase<TTaskEventArgs> class, and it’s exactly for this class that we are going to use to create a ShowAsync extension method.

We start by creating the extension method signature:

public static class ExtensionMethods
{
public static Task<TTaskEventArgs> ShowAsync<TTaskEventArgs>(this ChooserBase<TTaskEventArgs> chooser)
where TTaskEventArgs : TaskEventArgs
{
}
}

The async methods are required to return void, Task, or Task<TResult> in order to be invoked with the await keyword. So our method will return a Task<TTaskEventArgs> value, where the TTaskEventArgs generic type must be a TaskEventArgs subtype.

We will need to use a TaskCompletionSource object so we can return a Task and later on set the result of the asynchronous operation.

var taskCompletionSource = new TaskCompletionSource<TTaskEventArgs>();

Next we will add the code for the normal Chooser handling:

EventHandler<TTaskEventArgs> completed = null;
completed = (s, e) => {
chooser.Completed -= completed;
taskCompletionSource.SetResult(e);
};
chooser.Completed += completed;
chooser.Show();

Notice that we are removing the event handler after it gets invoked as not to have a memory leak! All that is missing now is just returning the Task object:

return taskCompletionSource.Task;

And that’s it!

Here’s how the full extension method should look:

public static class ExtensionMethods {
public static Task<TTaskEventArgs> ShowAsync<TTaskEventArgs>(this ChooserBase<TTaskEventArgs> chooser)
where TTaskEventArgs : TaskEventArgs
{
var taskCompletionSource = new TaskCompletionSource<TTaskEventArgs>();
EventHandler<TTaskEventArgs> completed = null;
completed = (s, e) => {
chooser.Completed -= completed;
taskCompletionSource.SetResult(e);
};
chooser.Completed += completed;
chooser.Show();
return taskCompletionSource.Task;
}
}

You can download a sample code for this directly from the Microsoft Code Gallery.

The PhoneApplicationFrame bug is still alive!

This is an issue that I stomped about 6 months ago, blogged about it, reported and got it confirmed by Microsoft, and just found out that after all this time, they didn’t fix it on Windows Phone 8!!

When the Windows Phone SDK started to allow developers to remove entries from the navigation back stack, they (inadvertly?) introduced a bug in PhoneApplicationFrame, more specifically in the CanGoBack property!

Here’s how to simulate the issue:

  • Start by creating two separate pages
  • On the application start page, add a Button that when clicked will just navigate to the second page (thus adding an item to the navigation stack)
  • On the second page Loaded event, call the NavigationService.RemoveBackEntry (removing the previously added item from the navigation stack)
  • Get the current PhoneApplicationFrame instance with (PhoneApplicationFrame)App.Current.RootVisual
  • Compare the NavigationService.CanGoBack and PhoneApplicationFrame.CanGoBack property values: the first indicates false, the correct and expected value, while the second indicates true, something that should not happen because we just cleared the navigation back stack when we removed the only entry that was there!!

By using a Reflection tool to look at the PhoneApplicationFrame implementation, one could easily realize that while the methods Navigate, GoBack, RemoveBackEntry and others are just proxies to the same ones on NavigationService, this is not true for the CanGoBack and CanGoForward properties, which have local values and only get updated after a navigation event!

And this is where lies the whole problem: the values ​​of these properties should be obtained directly from NavigationService like the methods are, or at least they should also be updated when RemoveBackEntry method gets called!

You can test and confirm this bug by downloading this sample application.

All you need to do is run the app, click on “Navigate to self”, check that the stack count is now 1, click on one of the two buttons for the “RemoveBackEntry” and realize that the CanGoBack properties now have different values!

This situation has been fixed in the implementation of the INavigationService on Cimbalino Windows Phone Toolkit, but be aware that there are still a lot of similar services implementations from other toolkits and frameworks that have this bug…

Updated on 20/01/2013: After a few tweets with Joost van Schaik, he updated the INavigationService implementation on Wp7nl utilities to match the Cimbalino Windows Phone Toolkit.

Welcome!

My name is Pedro Lamas, I’m a Portuguese developer specialized in Microsoft Technologies, and this is my English blog for Windows and Windows Phone Development.

For a while this address was home for my Portuguese blog Nação do Cimbalino. Rest assure that the blog still exists, it just got moved to a new address!

I’ll be working to get the blog up and running in the next few days, so please bare with me.

I promise it will be worth it! ;)