WPF本地化:带StringFormat的DynamicResource?

时间:2015-06-18 20:24:04

标签: c# .net wpf localization

我正在使用ResourceDictionary在.NET 4中进行本地化。有没有人有一个使用字符串格式值的解决方案?

例如,假设我有一个带有“SomeKey”键的值:

<ResourceDictionary ...>
    <s:String x:Key="SomeKey">You ran {0} miles</s:String>
</ResourceDictionary>

在TextBlock中使用它:

<TextBlock Text="{DynamicResource SomeKey}" />

如何将具有SomeKey值的整数组合为格式字符串?

3 个答案:

答案 0 :(得分:3)

您需要以某种方式绑定到ViewModel.Value,然后使用(嵌套)绑定到格式字符串。

当您只有一个值时:

<TextBlock 
  Text="{Binding Path=DemoValue, StringFormat={StaticResource SomeKey}}" />        

当你还有{1}等时,你需要MultiBinding。

编辑:

如果您真的想要在实时表单中更改语言,那么明智的方法可能是在ViewModel中进行所有格式化。无论如何,我很少在MVVM中使用StringFormat或MultiBinding。

答案 1 :(得分:1)

如果您尝试将Miles属性绑定并格式化为&#39; TextBlock&#39;你可以这样做:

<TextBlock Text="{Binding Miles, StringFormat={StaticResource SomeKey}}"/>

答案 2 :(得分:1)

所以,我最终提出了一个解决方案,允许我在ResourceDictionary中使用格式字符串,并能够在运行时动态更改语言。我认为它可以改进,但它确实有效。

此类将资源键转换为ResourceDictionary中的值:

public class Localization
{
    public static object GetResource(DependencyObject obj)
    {
        return (object)obj.GetValue(ResourceProperty);
    }

    public static void SetResource(DependencyObject obj, object value)
    {
        obj.SetValue(ResourceProperty, value);
    }

    // Using a DependencyProperty as the backing store for Resource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ResourceProperty =
        DependencyProperty.RegisterAttached("Resource", typeof(object), typeof(Localization), new PropertyMetadata(null, OnResourceChanged));

    private static void OnResourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //check if ResourceReferenceExpression is already registered
        if (d.ReadLocalValue(ResourceProperty).GetType().Name == "ResourceReferenceExpression")
            return;

        var fe = d as FrameworkElement;
        if (fe == null)
            return;

        //register ResourceReferenceExpression - what DynamicResourceExtension outputs in ProvideValue
        fe.SetResourceReference(ResourceProperty, e.NewValue);
    }
}

此类允许将ResourceDictionary中的值用作String.Format()中的format参数

public class FormatStringConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values[0] == DependencyProperty.UnsetValue || values[0] == null)
            return String.Empty;

        var format = (string)values[0];
        var args = values.Where((o, i) => { return i != 0; }).ToArray();

        return String.Format(format, args);
    }

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

示例用法1 :在此示例中,我使用MultiBinding中的FormatStringConverter将其Binding集合转换为所需的输出。例如,如果&#34; SomeKey&#34;的价值是&#34;对象ID是{0}&#34;以及&#34; Id&#34;的价值是&#34; 1&#34;然后输出将变为&#34;对象id为1&#34;。

                <TextBlock ap:Localization.Resource="SomeKey">
                    <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource formatStringConverter}">
                            <Binding Path="(ap:Localization.Resource)" RelativeSource="{RelativeSource Self}" />
                            <Binding Path="Id" />
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>

示例用法2 :在此示例中,我使用与Converter的绑定将资源键更改为更详细的内容以防止键冲突。例如,如果我有枚举值Enum.Value(默认显示为&#34;值&#34;),我使用转换器附加其命名空间以创建更独特的键。因此,该值变为&#34; My.Enums.Namespace.Enum.Value&#34;。然后Text属性将解析为&#34; My.Enums.Namespace.Enum.Value&#34;的任何值。在ResourceDictionary中。

        <ComboBox ItemsSource="{Binding Enums}"
                  SelectedItem="{Binding SelectedEnum}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock ap:Localization.Resource="{Binding Converter={StaticResource enumToResourceKeyConverter}}"
                               Text="{Binding Path=ap:Localization.Resource), RelativeSource={RelativeSource Self}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

示例用法3 :在此示例中,键是文字,仅用于在ResourceDictionary中查找其对应的值。例如,如果&#34; SomeKey&#34;有价值&#34; SomeValue&#34;那么它只会输出&#34; SomeValue&#34;。

                    <TextBlock ap:Localization.Resource="SomeKey"
                               Text="{Binding Path=ap:Localization.Resource), RelativeSource={RelativeSource Self}}"/>