/// <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."); } }