3

我在我的程序中使用 WPF 本地化扩展。为了减少类似资源的数量(例如“以米为单位的长度”、“以公里为单位的长度”等),我想使用占位符并将它们设置在 XAML 代码中。

我想过这样的事情

资源“UI_Length”的值

Length in {0}

在 CodeBehind 中,使用 String.Format 非常容易

String.Format(
        LocalizeDictionary.Instance.GetLocalizedObject("UI_Length", null, LocalizeDictionary.Instance.Culture).ToString(), 
       "Meters");

但是如何在 XAML 中添加另一个字符串甚至另一个资源条目?

<Label x:Name="Label" Content="{lex:LocText Key=UI_Length}, Meters" HorizontalAlignment="Left" VerticalAlignment="Top"/>

根据WPF 中资源文件的绑定占位符,这似乎是可能的,但我无法让它为标签运行

[更新]

我设法添加了两个资源值。诀窍是在 Label.Content 中添加一个 TextBlock。见链接

        <Label  Grid.Row="1">
            <Label.Content>
                <TextBlock>
                    <TextBlock.Text>
                        <MultiBinding StringFormat="{}{0} [{1}]">
                            <Binding Source="{lex:LocText Key=UI_Length}" />
                            <Binding Source="{lex:LocText Key=UI_MeterShort}" />
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
            </Label.Content>
        </Label>

但是我这里还是有问题。在启动时这工作正常但是当我尝试切换语言时

LocalizeDictionary.Instance.Culture = new CultureInfo("de-DE");

我收到“绑定使用后无法更改”。错误。是否有类似的方法可以使用多个资源值并且仍然能够在运行时切换语言?

[更新 2]

我尝试了 Liero 的建议,但这里仍然存在问题。

在我的 MainView 中,我将 DataContext 设置为 MainViewModel。VM 有一个 LocalizedTexts 实例。在 ViewModel 中更改语言后,我调用 RaisePropertiesChanged() 但没有得到任何输出。

TextBlock 绑定到 LengthInMeters

<TextBlock Text="{Binding LocalizedTexsts.LengthInMeters}" />

我在更改语言后调用 RaisePorpertyChanged:

    public void ChangeLanguage(string culture)
    {
         LocalizeDictionary.Instance.Culture = new CultureInfo(culture);
         _localizedTexts.RaisePropertyChanged();
    }

LengthInMeters 看起来像这样:

public string LengthInMeters
{
    get
    {
        return String.Format(
                   LocalizeDictionary.Instance.GetLocalizedObject(
                       "UI_Length", null,
                       LocalizeDictionary.Instance.Culture).ToString(),
                   LocalizeDictionary.Instance.GetLocalizedObject(
                       "UI_Meters", null,
                       LocalizeDictionary.Instance.Culture).ToString()
               );
    }
}

但是 TextBlock 保持为空。

4

1 回答 1

3

首先,您可以像这样缩短绑定:

<TextBlock Text="{Binding Source={lex:LocText Key=UI_MeterShort}, 
                          StringFormat={lex:LocText Key=UI_Length}}" />

其次,如果要更新绑定,当语言发生变化时,您需要在代码隐藏中找到 TextBlock 并使用BindingExpression.UpdateTarget()方法手动更新绑定。但这很奇怪,不是吗?

或者,您可以通过删除所有内容并创建新内容来刷新整个窗口。我的意思是从窗口中删除 UserControl 并创建新的 UserControl。

但是,这两种解决方案都很奇怪,因为它只是解决了 WPF 中滥用绑定引起的问题。让我建议更好的方法。

public class LocalizedTexts: INotifyPropertyChanged
{
   public event PropertyChanged;


   public LengthInMeters { get { return String.Format(...); } }

   public LengthInKilometers {get { return String.Format(...); } }


   public void RaisePropertiesChanged()
   {
      foreach (var property in this.GetType().GetProperties())
      {
         PropertyChanged(this, new PropertyChangedEventArgs(property.Name))
      }
   }
}

现在您可以将数据绑定到 LocalizedTexts,当语言发生变化时,只需调用RaisePropertiesChanged().

用法:

<Application.Resources>
    <l:LocalizedTexts x:Key="LocalizedTexts" />
</Application.Resources>

<TextBlock Text="{Binding LengthInMeters, Source={StaticResource LocalizedTexts}}" />


<!-- instead of using StaticResource, you can add l:LocalizedTexts  as a property to your viewmodel -->
<TextBlock Text="{Binding LocalizedTexts.LengthInMeters}" />
于 2016-08-25T07:44:12.260 回答