/// <summary> /// Creates a new localized value. /// </summary> /// <param name="targetObject"></param> /// <param name="targetProperty"></param> /// <param name="binding"></param> /// <param name="bindings"></param> /// <returns></returns> public static LocalizedValue Create( DependencyObjectProperty objectProperty, LocalizationOptions options ) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var localizedValue = new LocalizedValue(objectProperty.TargetObject, objectProperty.TargetProperty) { Key = options.Key, StringFormat = options.StringFormat, Callback = options.Callback, CallbackParameter = options.CallbackParameter, Converter = options.Converter, ConverterParameter = options.ConverterParameter, }; if (options.Binding != null || options.Bindings?.Count > 0) { if (false == (objectProperty.TargetProperty.PropertyObject is DependencyProperty)) { // The what bindings are implemented in WPF provides no way to obtain the value // produced by the binging. The only way is to update the property directly. Therefore, // the extension cannot support bindings on non-dependency properties (same as WPF). throw new ArgumentException("Bindings are supported only on dependency properties.", nameof(options)); } // Create a binding var localizedBinding = new MultiBinding() { Mode = BindingMode.OneWay, }; if (options.Binding != null) { localizedBinding.Bindings.Add(options.Binding); } if (options.Bindings?.Count > 0) { foreach (var item in options.Bindings) { localizedBinding.Bindings.Add(item); } } localizedBinding.Converter = localizedValue; localizedValue.BindingExpression = (BindingExpressionBase)localizedBinding.ProvideValue(objectProperty); } return(localizedValue); }
/// <summary> /// Localizes the specified objectProperty. /// </summary> /// <param name="objectProperty">The objectProperty to localize.</param> /// <param name="options">The options describing how the objectProperty is to be localized.</param> /// <exception cref="ArgumentException">A binding is specified and the objectProperty is a non-dependency objectProperty.</exception> public static void Localize(this DependencyObjectProperty objectProperty, LocalizationOptions options) { var localizedValue = LocalizedValue.Create(objectProperty, options); LocalizationManager.Add(localizedValue); // Set the value initially if (localizedValue.BindingExpression != null) { // The value uses bindings localizedValue.TargetProperty.SetValue(localizedValue.TargetObject, localizedValue.BindingExpression); } else { // The value does not use bindings localizedValue.TargetProperty.SetValue(localizedValue.TargetObject, localizedValue.ProduceValue()); } }
public override object ProvideValue(IServiceProvider serviceProvider) { if (serviceProvider == null) { throw new ArgumentNullException(nameof(serviceProvider)); } // Other useful services: // - IDestinationTypeProvider // - IRootObjectProvider if (!(serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget service)) { return(null); } if (service.TargetObject is DependencyObject depObj) { if (Binding != null || _bindings?.Count > 0) { if (false == (service.TargetProperty is DependencyProperty)) { // The what bindings are implemented in WPF provides no way to obtain the value // produced by the binging. The only way is to update the property directly. Therefore, // the extension cannot support bindings on non-dependency properties (same as WPF). throw new NotSupportedException("Bindings are supported only on dependency properties."); } } LocalizableProperty localizableProperty; if (service.TargetProperty is DependencyProperty depProperty) { localizableProperty = new LocalizableDepProperty(depProperty); } else if (service.TargetProperty is PropertyInfo propertyInfo) { localizableProperty = new LocalizableNonDepProperty(propertyInfo); } else { throw new NotSupportedException($"The extension supports only dependency and non-dependency properties of dependency objects. Properties of type {service.TargetProperty.GetType()} are not supported."); } var options = new LocalizationOptions() { Key = Key, StringFormat = StringFormat, Binding = Binding, Bindings = _bindings, Callback = Callback, CallbackParameter = CallbackParameter, Converter = Converter, ConverterParameter = ConverterParameter, }; var localizedValue = LocalizedValue.Create(new DependencyObjectProperty(depObj, localizableProperty), options); LocalizationManager.Add(localizedValue); if (localizedValue.BindingExpression != null) { // The value uses bindings return(localizedValue.BindingExpression); } else { // The value does not use bindings if (localizedValue.IsInDesignMode) { // At design time VS designer does not set the parent of any control // before its properties are set. For this reason the correct values // of inherited attached properties cannot be obtained. // Therefore, to display the correct localized value it must be updated // later after the parent of the control has been set. depObj.Dispatcher.BeginInvoke( DispatcherPriority.ApplicationIdle, new SendOrPostCallback(x => ((LocalizedValue)x).UpdateValue()), localizedValue ); return(localizableProperty.DefaultValue); } else { return(localizedValue.ProduceValue()); } } } else if (service.TargetObject is Setter) { var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider)); // IRootObjectProvider is never null // IRootObjectProvider.RootObject is null when the style is located in a separate resource dictionary file // or the application's resource dictionary in App.xaml // Otherwise, the value can be Window or UserControl depending on the where the style is declared. // Therefore, it can be assumed that once root object (if any) is disposed the localized value // can be disposed as well. var rootObject = rootObjectProvider?.RootObject as DependencyObject; if (rootObject == null) { // There is no way to access the resource manager (apart from the resource manager of the entry assembly). // In order to avoid misunderstanding and bugs localizing setters is not supported unless they are delcared inside a Window or a UserControl throw new NotSupportedException("Setters are supported only inside a Window or a UserControl. They are not supported inside a ResourceDictionary file or App.xaml."); } var options = new LocalizationOptions() { Key = Key, StringFormat = StringFormat, Binding = Binding, Bindings = _bindings, Callback = Callback, CallbackParameter = CallbackParameter, Converter = Converter, ConverterParameter = ConverterParameter, }; var localizedValueTuple = LocalizedSetterValue.Create(rootObject, options); LocalizationManager.Add(localizedValueTuple.Item1); return(localizedValueTuple.Item2.ProvideValue(serviceProvider)); } else if (service.TargetProperty is DependencyProperty || service.TargetProperty is PropertyInfo) { // The extension is used in a template and will be evaluated once the template is instantiated return(this); } else { throw new NotSupportedException($"The localization extension can be used only with {nameof(DependencyObject)}s."); } }
/// <summary> /// Creates a new localized value. /// </summary> /// <returns></returns> public static Tuple <LocalizedSetterValue, BindingBase> Create( DependencyObject rootObject, LocalizationOptions options ) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var localizedValue = new LocalizedSetterValue(rootObject) { Key = options.Key, StringFormat = options.StringFormat, Callback = options.Callback, CallbackParameter = options.CallbackParameter, Converter = options.Converter, ConverterParameter = options.ConverterParameter, }; BindingBase finalBinding; if (options.Binding != null || options.Bindings?.Count > 0) { // Create a binding var localizedBinding = new MultiBinding() { Mode = BindingMode.OneWay, }; if (options.Binding != null) { localizedBinding.Bindings.Add(options.Binding); } if (options.Bindings?.Count > 0) { foreach (var item in options.Bindings) { localizedBinding.Bindings.Add(item); } } // Add a binding that can be used to update the value localizedBinding.Bindings.Add(new Binding() { Mode = BindingMode.OneWay, Source = localizedValue, Path = new PropertyPath(nameof(Value)), }); localizedBinding.Converter = localizedValue; finalBinding = localizedBinding; } else { // Create a binding var localizedBinding = new Binding() { Mode = BindingMode.OneWay, Source = localizedValue, Path = new PropertyPath(nameof(Value)), }; localizedBinding.Converter = localizedValue; finalBinding = localizedBinding; } return(Tuple.Create(localizedValue, finalBinding)); }