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."); } } LocalizedProperty localizedProperty; if (service.TargetProperty is DependencyProperty depProperty) { localizedProperty = new LocalizedDepProperty(depProperty); } else if (service.TargetProperty is PropertyInfo propertyInfo) { localizedProperty = new LocalizedNonDepProperty(propertyInfo); } else { throw new NotSupportedException($"The default property provider supports only dependency and non-dependency properties of dependency objects. Properties of type {service.TargetProperty.GetType()} are not supported."); } var localizedValue = new LocalizedValue(depObj, localizedProperty) { Key = this.Key, StringFormat = this.StringFormat, Callback = this.Callback, CallbackParameter = this.CallbackParameter, Binding = this.Binding, Bindings = this._bindings, Converter = this.Converter, ConverterParameter = this.ConverterParameter, }; LocalizationManager.Add(localizedValue); 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(localizedProperty.DefaultValue); } else { return(localizedValue.GetValue(depObj)); } } else if (service.TargetObject is Setter) { if (Binding != null || _bindings?.Count > 0) { throw new NotSupportedException("Bindings are not supported in style setters."); } var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider)); Debug.Assert(rootObjectProvider != null); var rootObject = rootObjectProvider.RootObject as DependencyObject; Debug.Assert(rootObject != null); #if DEPRECATED // Unfortunately "GetDestinationType" throws NullReferenceException therefore, this approach is not applicable for retrieving the property's type var destinationTypeProvider = (IDestinationTypeProvider)serviceProvider.GetService(typeof(IDestinationTypeProvider)); Debug.Assert(destinationTypeProvider != null); var targetPropertyType = destinationTypeProvider.GetDestinationType(); var localizedValue = new SetterLocalizedValue(rootObject, targetPropertyType) { Key = this.Key, Callback = this.Callback, CallbackParameter = this.CallbackParameter, Converter = this.Converter, ConverterParameter = this.ConverterParameter, }; #endif var localizedValue = new SetterLocalizedValue(rootObject) { Key = this.Key, Callback = this.Callback, CallbackParameter = this.CallbackParameter, Converter = this.Converter, ConverterParameter = this.ConverterParameter, }; var binding = new Binding(nameof(SetterLocalizedValue.Value)) { Source = localizedValue, Mode = BindingMode.OneWay, Converter = localizedValue, }; LocalizationManager.Add(localizedValue); return(binding.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> /// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension. /// </summary> /// <param name="serviceProvider">Object that can provide services for the markup extension.</param> /// <returns> /// The object value to set on the property where the extension is applied. /// </returns> public override object ProvideValue(IServiceProvider serviceProvider) { var service = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; if (service == null) { return(null); } if (service.TargetObject is DependencyObject) { LocalizedProperty property; if (service.TargetProperty is DependencyProperty) { property = new LocalizedDependencyProperty( (DependencyObject)service.TargetObject, (DependencyProperty)service.TargetProperty ); } else if (service.TargetProperty is PropertyInfo) { property = new LocalizedNonDependencyProperty( (DependencyObject)service.TargetObject, (PropertyInfo)service.TargetProperty ); } else { return(null); } property.Converter = Converter; property.ConverterParameter = ConverterParameter; var localizedValue = CreateLocalizedValue(property); if (localizedValue == null) { return(null); } LocalizationManager.InternalAddLocalizedValue(localizedValue); if (property.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 ater the parrent of the control has been set. ((DependencyObject)service.TargetObject).Dispatcher.BeginInvoke( new SendOrPostCallback(x => ((LocalizedValue)x).UpdateValue()), DispatcherPriority.ApplicationIdle, localizedValue ); } return(localizedValue.GetValue()); } else if (service.TargetProperty is DependencyProperty || service.TargetProperty is PropertyInfo) { // The extension is used in a template return(this); } else { return(null); } }