Reputation: 93
OS: WP8
I'm trying to format a string which is the result of a converter taking a binding. All of it works except for the localization of the string format data, which I haven't the foggiest idea how to incorporate. Microsoft's documentation hasn't been all that clear on this and I'm wondering if someone could point me in the right direction.
<TextBlock Text="{Binding Date, StringFormat='Received On: {0}', ConverterParameter=shortdatewithyear, Converter={StaticResource DateTimeToTimeConvert}}"/>
It doesn't see like a totally off the wall thing to want to do.
Thanks!
-Cord
Upvotes: 3
Views: 5216
Reputation: 2763
To generalize the answer from @Jakob Möllås:
The problem with
<TextBlock Text="{Binding Date, StringFormat='Received On: {0}', ConverterParameter=shortdatewithyear, Converter={StaticResource DateTimeToTimeConvert}}"/>
is that bindings somehow caches the value of StringFormat, even if you have let's say a GroupStyle in a DataGrid and reload the content of the DataGrid, it will not be updated. Changing of Bindings after using it is not possible (you get an exception). So the solution is to use a Converter like this:
public class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var formatString = parameter as string;
if(string.IsNullOrEmpty(formatString))
return null;
return string.Format(formatString, value);
}
// ...
}
Then in XAML:
<!-- ... declare your converter at some place ... -->
<!-- then -->
<TextBlock Text="{Binding Date, Converter={StaticResource LocalizationConverter}, ConverterParameter={x:Static names:MyClass.LocalizedStringFormat}}"/>
So when you update the value of MyClass.LocalizedStringFormat (maybe you change the display language in your program), all you need to do is to throw a PropertyChanged for the properties that are using a localized StringFormat.
Note: the converter is executed on every PropertyChanged, so might or might not be somewhat slower than using StringFormat with DataBinding.
Upvotes: 0
Reputation: 4369
One way of dealing with this without using additional converters or modifying the underlying model is to split the string into two separate UI elements. For example two TextBlock
inside a StackPanel
, like so:
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Static properties:Resources.ReceivedOn}" Margin="0,0,5,0"/>
<TextBlock Text="{Binding Date, ConverterParameter=shortdatewithyear, Converter={StaticResource DateTimeToTimeConvert}}"/>
</StackPanel>
That way you can use normal localization for the string "Received On:"
Upvotes: 0
Reputation: 137118
In your particular case I'd pull the string out of the resource file in the converter, then the .Net provided localisation can work. This is probably more important where you are building strings and the order you build it might change in different languages.
You create a resource file in the standard way - "MyResource.resx" to store the strings for your default language and then you can create a localised version of that called "MyResource.Fr-fr.resx" (if you were doing French). This will be automatically loaded and searched in the first instance for a string. If it doesn't find one the code will pull out the string from the default resource file. This way you don't have to translate everything - useful for US/GB spelling differences.
In general once you have this you can have localised strings in your XAML
Add a Localize class:
public class Localize : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(String name)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
}
#endregion
#region 'Public Properties'
//Declarations
private static Resources.MyResources _myResources = new Resources.MyResources();
public Resources.MyResources myResources
{
get { return _myResources; }
set { NotifyChange("MyResources"); }
}
#endregion
}
Then in your XAML add this to your user control's resources:
<local:Localize x:Key="myResource"
xmlns:local="clr-namespace:MyProject" />
Then you can use it:
<TextBlock Text="{Binding myResource.MyString, Source={StaticResource myResource}}"/>
Upvotes: 2