views:

28

answers:

3

I have a TextBlock control, which is data bound to DateTime property.

The text displayed something like this:

Thursday, October 21, 2010

I need to switch UI Culture on the fly, using something like this:

Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture 
                                    = new CultureInfo("de-de");

I've tried this to force binding to recalc:

var bindingExpression = textBlock.GetBindingExpression(TextBlock.TextProperty);
bindingExpression.UpdateSource();

But I still see Thursday instead of Donnerstag...

How do I proceed? Any ideas?

A: 

You can use the following converter:

public class StringFormatter : IValueConverter
{

    public String Format { get; set; }
    public String Culture { get; set; }


    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!String.IsNullOrEmpty(Culture))
        {
            culture = new System.Globalization.CultureInfo(Culture);
        }
        else
        {
            culture = System.Threading.Thread.CurrentThread.CurrentUICulture;
        }
        if (value == null) { return value; }
        if (String.IsNullOrEmpty(Format)) { return value; }
        return String.Format(culture, Format, value).Trim();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

Then you can set the CurrentUICulture and force the binding to change and the converter will use the new culture.

If you want to display the date in long format, declare the converter in XAML like this:

<local:StringFormatter x:Key="LongDateFormatter" Format=" {0:D}" />

And then use it in your TextBlock like this:

<TextBlock x:Name="DateText" Text="{Binding DateTime.Date, Converter={StaticResource LongDateFormatter}, Mode=OneWay}"/>

In code you can do something like this to force the binding to change:

Thread.CurrentThread.CurrentUICulture = new CultureInfo(desiredCultureString);
var tempDateTime = this.DateTime;
this.DateTime = default(DateTime);
this.DateTime = tempDateTime;

Of course there are other ways to force the change, and probably you need to change other fields to the new culture as well, but this is the general idea of how to handle it.

Murven
This works if you have one control that has to be localized.Imagine, you have to update ALL binding expressions in ALL XAML files...
LexL
Yes, this approach is not scalable. The one you describe in your answer is definitely better for full localization. By the way, if you are localizing an application you may want to take a look at this: http://wpflocalizeaddin.codeplex.com/
Murven
Thank you for the link. Unfortunately, it doesn't work with Silverlight.
LexL
+1  A: 

I've found a better approach, which requires to update only the root visual.

public sealed class Localizer : INotifyPropertyChanged
{
  public Localizer() 
  {
    Culture = Thread.CurrentThread.CurrentCulture; 
  }

  XmlLanguage _language;
  public XmlLanguage Language 
  { 
    get { return _language; } 
    private set { _language = value; RaiseOnPropertyChanged("Language"); } 
  }

  CultureInfo _culture;
  public CultureInfo Culture 
  { 
    get { return _culture; }
    set 
    { 
      Contract.Requires(value != null);  

      if (_culture == value) return; 
      _culture = value; 

      Thread.CurrentThread.CurrentCulture =
      Thread.CurrentThread.CurrentUICulture = value;
      Language = XmlLanguage.GetLanguage(value.Name);

      RaiseOnPropertyChanged("Culture");
    }
  }

  protected void RaiseOnPropertyChanged(string propName) 
  {
    var e = OnPropertyChanged;
    if (e != null) e(this, new PropertyChangedEventArgs(propName));
  }

  public event PropertyChangedEventHandler OnPropertyChanged;
}

Now adding this instance to application resources:

<nt:Localizer x:Key="Localizer"/>

Now bind it to your root visual (f.e. Frame, UserControl or Page) like this:

<UserControl ... Language="{Binding Language, Source={StaticResource Localizer}}">
LexL
A: 

(Unfortunatelly cannot comment the right answer. Sorry for wrong place.)
Actually wpflocalizeaddin.codeplex.com does support Silverlight!
Just ensure that "Binding to resource wrapper" mode is selected during resource extraction.

skiba_k