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.");
            }
        }
Beispiel #2
0
        /// <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);
            }
        }