所以,我终于想出了一个解决方案,允许我在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);
}
public static readonly DependencyProperty ResourceProperty =
DependencyProperty.RegisterAttached("Resource", typeof(object), typeof(Localization), new PropertyMetadata(null, OnResourceChanged));
private static void OnResourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d.ReadLocalValue(ResourceProperty).GetType().Name == "ResourceReferenceExpression")
return;
var fe = d as FrameworkElement;
if (fe == null)
return;
fe.SetResourceReference(ResourceProperty, e.NewValue);
}
}
这个类允许从ResourceDictionary中获取的值被用作String.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: 在这个示例中,我使用FormatStringConverter将其绑定集合转换为所需的输出。例如,如果“SomeKey”的值为“The object id is {0}”,而“Id”的值为“1”,那么输出将变成“The object id is 1”。
<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:在这个示例中,我使用绑定和转换器来将资源键更改为更详细的内容,以防止键冲突。例如,如果我有枚举值Enum.Value(默认显示为“Value”),我使用转换器将其命名空间附加到更具唯一性的键上。因此,该值变为“My.Enums.Namespace.Enum.Value”。然后,Text属性将根据ResourceDictionary中“My.Enums.Namespace.Enum.Value”的值进行解析。
<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中对应的值。例如,如果“SomeKey”具有值“SomeValue”,则它将简单地输出“SomeValue”。
<TextBlock ap:Localization.Resource="SomeKey"
Text="{Binding Path=ap:Localization.Resource), RelativeSource={RelativeSource Self}}"/>