Introduction
You can find a lot of questions about this issue on the internet. There are also a lot more answers about this - but which one is best? If you understand the problem, you can simply choose the best one. I will try to explain how it works inside. At first, let’s define what is actually the problem with Binding and values formatting.
If you suppose that your application will be used in a multi-language environment, you would like to format the values in the application according to regional customs. Moreover, the default regional formatting customs may be modified by a user of a computer where the application is running.
In Czech environment, it is common to format decimal number as following: 10 000,5. In English speaking countries, it would be: 10,000.5. Nevertheless there can be a user (maybe a Czech programmer) who would like to use the English formatting and therefore he has changed the default formatting of the decimal numbers to the English one in its Region and Language settings of operating system. We would like to respect the settings in our application, i.e., we would like all mechanisms which care about the formatting of values to use CultureInfo.CurrentCulture static
property-the property holds the user settings.
Step by Step to Solution
If you try to bind your View to a property (type of double) of your ViewModel
, the first thing which you notice (if you are not from an English speaking country) is that Binding defaults formatting of decimal numbers to the English customs as is shown in following piece of simplified XAML code and its resulting window. Note that the window has set DataContext
to double
value 100.5
.
<Window>
<TextBlock Text="{Binding}"/>
?</Window>
The reason is that the Binding (its underlying converting mechanism) formats the value according to FrameworkElement.Language
property. The default value of this property is “en-US
”. Here comes the first possible solution into mind how to make it to format the value according to CultureInfo.CurrentCulture
.
Because the value of this property is inheritable, you can set the value of the property Language
on the root element (Window
) to the one which you want and the right formatting will be ensured.
<Window Language="cs">
<TextBlock Text="{Binding}"/>
?</Window>
Now you can see that the value is formatted as is usual in the Czech country. But the solution is still not perfect with respect to our expectations.
The property Language
is of type of XmlLanguage
. An instance of the XmlLanguage
can be retrieved by a static
method GetLanguage(string ietfLanguageTag)
. The XmlLanguage
has a method GetSpecificCulture()
which returns a CultureInfo
which is used for the formatting but the CultureInfo
is not the same as the one in CultureInfo.CurrentCulture static
property. It is a standard CultureInfo
which corresponds to ietfLanguageTag
passed to the GetLanguage
method - there aren't any user modifications of formatting.
If you set decimal places delimiter to #
, you will see that it does not influence the formatted value.
The resulting window for the last XAML is still the same which is not desired.
Modification of the Language
property is not simply the right way how to achieve the goal. Don’t worry. The reliable solution really exists.
Binding has a property ConverterCulture
which is of type CultureInfo
. The documentation for this property says:
Gets or sets the culture in which to evaluate the converter.
…
If you do not set this property, the binding engine uses the Language property of the binding target object. In XAML this defaults to "en-US" or inherits the value from the root element (or any element) of the page, if one has been explicitly set.
The value of this property is passed into IValueConverter
as the last argument of its two methods, Convert
and ConvertBack
but moreover the argument is also used for formatting value into and from string
. As the text from the documentation says, the ConverterCulture
has a priority. So if you want to format your values exactly according to the user settings, set the ConverterCulture
of your Binding
to CultureInfo.CurrentCulture
.
New XAML file and the resulting window will look like this one:
<Window xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib">
<TextBlock Text="{Binding ConverterCulture={x:Static globalization:CultureInfo.CurrentCulture}}"/>
</Window>
It is exactly what we want.
If you are too lazy (like me) to set the ConverterCulture
property everywhere in your binding, you can use the following class instead of the standard Binding.
public class CustomBinding : System.Windows.Data.Binding
{
public CustomBinding()
{
ConverterCulture = CultureInfo.CurrentCulture;
}
?}
The class does only one simple thing. It sets ConverterCulture
property to CultureInfo.CurrentCulture
by default. Which is exactly what we want and can be used everywhere where you use standard Binding.
Usage of the class is simple:
<Window xmlns:wpfApplication="clr-namespace:WpfApplication">
<TextBlock Text="{wpfApplication:CustomBinding}"/>
?</Window>
That’s all. I believe that it will help you.