Localización de WPF: DynamicResource con StringFormat?

Estoy haciendo la localización en .NET 4 con un ResourceDictionary. ¿Alguien tiene una solución para usar un valor con formato de cadena?

Por ejemplo, digamos que tengo un valor con la clave “SomeKey”:

 You ran {0} miles  

Usándolo en un TextBlock:

  

¿Cómo combinaría, por ejemplo, un entero con el valor de SomeKey como una cadena de formato?

Debe enlazar a un ViewModel.Value de alguna manera, y luego usar un enlace (nested) a una cadena de formato.

Cuando tienes un solo valor:

  

Cuando también tiene {1} etc. necesita MultiBinding.

Editar:

Cuando realmente desea cambiar los idiomas en un formulario en vivo, la forma más sensata es probablemente hacer todo el formateo en el ViewModel. Raramente uso StringFormat o MultiBinding en MVVM de todos modos.

Si está intentando enlazar y formatear una propiedad de Miles a un ‘TextBlock’, puede hacer lo siguiente:

Entonces, finalmente se me ocurrió una solución que me permite tener cadenas de formato en mi ResourceDictionary y poder cambiar dinámicamente el idioma en tiempo de ejecución. Creo que podría mejorarse, pero funciona.

Esta clase convierte la clave de recursos en su valor del 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); } } 

Esta clase permite que el valor del ResourceDictionary se use como parámetro de formato en 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(); } } 

Ejemplo de Uso 1 : En este ejemplo, uso el FormatStringConverter en el MultiBinding para convertir su colección de Binding en la salida deseada. Si, por ejemplo, el valor de “SomeKey” es “El id del objeto es {0}” y el valor de “Id” es “1”, la salida se convertirá en “El id del objeto es 1”.

          

Ejemplo de uso 2 : en este ejemplo, uso un enlace con un convertidor para cambiar la clave de recursos a algo más detallado para evitar colisiones de claves. Si, por ejemplo, tengo el valor de enumeración Enum.Value (que se muestra de forma predeterminada como “Valor”), uso el convertidor para adjuntar su espacio de nombres para crear una clave más exclusiva. Así que el valor se convierte en “My.Enums.Namespace.Enum.Value”. Luego, la propiedad de Texto se resolverá con el valor de “My.Enums.Namespace.Enum.Value” que se encuentra en el ResourceDictionary.

         

Ejemplo de uso 3 : en este ejemplo, la clave es un literal y se usa solo para encontrar su valor correspondiente en el ResourceDictionary. Si, por ejemplo, “SomeKey” tiene el valor “SomeValue”, simplemente mostrará “SomeValue”.