Как переключить UI Культура привязки данных на лету в Silverlight - PullRequest
3 голосов
/ 22 октября 2010

У меня есть элемент управления TextBlock, который привязывает данные к свойству DateTime.

Текст отображается примерно так:

Четверг, 21 октября 2010 г.

Мне нужно переключить UI Culture на лету, используя что-то вроде этого:

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

Я пробовал это сделать, чтобы принудительно привязать к recalc:

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

Но я все еще вижу четверг вместо Доннерстага ...

Как мне поступить? Есть идеи?

Ответы [ 2 ]

8 голосов
/ 22 октября 2010

Я нашел лучший подход, который требует обновления только корневого визуала.

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;
}

Теперь добавим этот экземпляр к ресурсам приложения:

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

Теперь свяжите его с корневым визуалом (например, Frame, UserControl или Page) следующим образом:

<UserControl ... Language="{Binding Language, Source={StaticResource Localizer}}">
0 голосов
/ 22 октября 2010

Вы можете использовать следующий конвертер:

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
}

Затем вы можете установить CurrentUICulture и принудительно изменить привязку, и конвертер будет использовать новую культуру.

Если вы хотите отобразить дату в длинном формате, объявите конвертер в XAML следующим образом:

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

А затем используйте его в своем текстовом блоке так:

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

В коде вы можете сделать что-то вроде этого, чтобы принудительно изменить привязку:

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

Конечно, есть и другие способы форсировать изменения, и, вероятно, вам нужно изменить и другие поля на новую культуру, но это общая идея, как справиться с этим.

...