public LocalizedValue(DependencyObject targetObject, LocalizableProperty targetProperty)
 {
     if (targetObject == null)
     {
         throw new ArgumentNullException(nameof(targetObject));
     }
     this.TargetProperty = targetProperty ?? throw new ArgumentNullException(nameof(targetProperty));
     this._targetObject  = new WeakReference(targetObject);
 }
示例#2
0
        internal static void RemoveProperty(DependencyObject targetObject, LocalizableProperty targetProperty)
        {
            if (targetObject == null)
            {
                throw new ArgumentNullException(nameof(targetObject));
            }
            if (targetProperty == null)
            {
                throw new ArgumentNullException(nameof(targetProperty));
            }

            if (false == targetObject.Dispatcher.CheckAccess())
            {
                // COMMENT This restriction can be lifted if the DispatcherHandler.Add method becomes thread-safe
                throw new InvalidOperationException($"This method must be called on the UI thread of the {nameof(DependencyObject)} whose value is localized.");
            }

            GetDispatcherHandler(targetObject.Dispatcher)?.RemoveProperty(targetObject, targetProperty);
        }
            /// <summary>
            /// Stops localizing the specified property of the specified <see cref="DependencyObject"/>.
            /// </summary>
            /// <param name="targetObject">The owner of the property</param>
            /// <param name="property"></param>
            /// <exception cref="InvalidOperationException">The method is not called on the UI thread of the specified <see cref="DependencyObject"/>.</exception>
            public void RemoveProperty(DependencyObject targetObject, LocalizableProperty targetProperty)
            {
                if (targetObject == null)
                {
                    throw new ArgumentNullException(nameof(targetObject));
                }
                if (targetProperty == null)
                {
                    throw new ArgumentNullException(nameof(targetProperty));
                }

                Dispatcher.VerifyAccess();

                if (_localizedValueDict.TryGetValue(targetObject, out object oldValue))
                {
                    if (oldValue is LinkedListNode <LocalizedValueBase> oldValueNode)
                    {
                        if (((LocalizedValue)oldValueNode.Value).TargetProperty.Equals(targetProperty))
                        {
                            // Remove the previous value from both the dictionary and the list
                            _localizedValueDict.Remove(targetObject);
                            _localizedValueList.Remove(oldValueNode);
                        }
                    }
                    else if (oldValue is List <LinkedListNode <LocalizedValueBase> > oldValueNodeList)
                    {
                        // Remove the previous localized value
                        var oldValueNodeIndex = oldValueNodeList.FindIndex(x => ((LocalizedValue)x.Value).TargetProperty.Equals(targetProperty));
                        if (oldValueNodeIndex >= 0)
                        {
                            // Remove the previous value from both the dictionary and the list
                            oldValueNode = oldValueNodeList[oldValueNodeIndex];
                            oldValueNodeList.RemoveAt(oldValueNodeIndex);
                            _localizedValueList.Remove(oldValueNode);
                        }
                    }
                }
            }
        protected object ProduceValue(
            LocalizableProperty targetProperty,
            Type propertyType,
            ResourceManager resourceManager,
            CultureInfo culture,
            CultureInfo uiCulture,
            bool dataBound,
            object dataBoundValueOrValues
            )
        {
            if (propertyType == null)
            {
                throw new ArgumentNullException(nameof(propertyType));
            }
            if (resourceManager == null)
            {
                throw new ArgumentNullException(nameof(resourceManager));
            }
            if (culture == null)
            {
                throw new ArgumentNullException(nameof(culture));
            }
            if (uiCulture == null)
            {
                throw new ArgumentNullException(nameof(uiCulture));
            }

            /* Flow:
             * 1. Obtain value
             * 1.1. Binding -> Get binding value
             * 1.2. Multi-binding -> Get all values
             * 1.3. Resource -> Get resource value
             * 2. Convert value
             * 2.1. If Callback -> invoke (with data-bound value only since the resource value (if any) will be used as "StringFormat")
             * 2.2. If Converter -> invoke
             * 2.3. If NO Bindings AND NO Converter AND NO Callback AND NO StringFormat AND Different-Type -> Use default converter
             * 3. Format value
             * 3.1. If StringFormat -> Format
             * 3.2. If NO StringFormat AND (Bindings OR Callback) AND Resource is string -> Use resource for formatting
             */

            #region Obtain value

            object resourceValue;

            if (string.IsNullOrEmpty(this.Key))
            {
                // No resource value specified
                // Even if no data bindings are specified it is possible that a value is produced by the callback.
                // At the very least the StringFormat should be used even if "null" is passed

                /*
                 * if (false == dataBound)
                 * {
                 *  // No data bindings specified so return the default value
                 *  // return TypeUtils.GetDefaultValue(propertyType);
                 *  // Do NOT throw an exception in order to avoid design-time errors
                 *  //throw new InvalidOperationException("At least a resource or a binding must be specified.");
                 * }
                 */
                resourceValue = null;
            }
            else
            {
                if (resourceManager == null)
                {
                    // Resource manager not found - return an error message if possible
                    return(propertyType.IsAssignableFrom(typeof(string)) ? ErrorMessage_ResourceManagerNotFound
                        : targetProperty != null ? targetProperty.DefaultValue : TypeUtils.GetDefaultValue(propertyType));
                }
                else
                {
                    resourceValue = resourceManager.GetObject(this.Key, uiCulture);
                    if (resourceValue == null)
                    {
                        // Resource value not found - return an error message if possible
                        return(propertyType.IsAssignableFrom(typeof(string)) ? string.Format(ErrorMessage_ResourceKeyNotFound, Key)
                            : targetProperty != null ? targetProperty.DefaultValue : TypeUtils.GetDefaultValue(propertyType));
                    }
                }
            }

            #endregion

            if (dataBound && resourceValue != null && false == resourceValue is string)
            {
                throw new NotSupportedException("Bindings can be combined only with string resources (since the string resource is used as 'StringFormat').");
            }
            if (Callback != null && resourceValue != null && false == resourceValue is string)
            {
                throw new NotSupportedException("A callback can be combined only with string resources (since the string resource is used as 'StringFormat').");
            }

            // List of data bound values (multi-bindings only)
            var dataBoundValueList = dataBoundValueOrValues as object[];

            // Indicates if the value is multi-binding
            var isMultiBinding = dataBoundValueList?.Length > 1;

            if (isMultiBinding)
            {
                // Converter is not supported for multi-bindings

                if (Callback != null)
                {
                    throw new NotSupportedException("Callback is not supported for multi-bindings.");
                }
                if (Converter != null)
                {
                    throw new NotSupportedException("Converter is not supported for multi-bindings.");
                }

                // Format the value

                var stringFormat = StringFormat.NullIfEmpty() ?? (resourceValue as string).NullIfEmpty();

                if (stringFormat == null)
                {
                    throw new InvalidOperationException("Either 'StringFormat' or a resource must be specified when multi-binding is used.");
                }

                return(string.Format(culture, stringFormat, dataBoundValueList));
            }
            else if (dataBound)
            {
                // There is a single data-bound value
                var dataValue = dataBoundValueList == null ? dataBoundValueOrValues : dataBoundValueList[0];

                if (Callback != null)
                {
                    // Pass the data-bound value to the callback
                    dataValue = Callback(culture, uiCulture, CallbackParameter, dataValue);
                }
                if (Converter != null)
                {
                    dataValue = Converter.Convert(dataValue, propertyType, ConverterParameter, culture);
                }

                // Format the value
                var stringFormat = StringFormat.NullIfEmpty() ?? (resourceValue as string).NullIfEmpty();
                return(stringFormat == null ? dataValue : string.Format(culture, stringFormat, dataValue));
            }
            else if (Callback != null)
            {
                // The callback will produce the value
                var dataValue = Callback(culture, uiCulture, CallbackParameter, null);

                if (Converter != null)
                {
                    dataValue = Converter.Convert(dataValue, propertyType, ConverterParameter, culture);
                }

                // Format the value
                var stringFormat = StringFormat.NullIfEmpty() ?? (resourceValue as string).NullIfEmpty();
                return(stringFormat == null ? dataValue : string.Format(culture, stringFormat, dataValue));
            }
            else if (resourceValue != null)
            {
                // There is a resource value only
                var dataValue = resourceValue;

                if (Converter != null)
                {
                    dataValue = Converter.Convert(dataValue, propertyType, ConverterParameter, culture);
                }
                else if (false == propertyType.IsAssignableFrom(dataValue.GetType()))
                {
                    // Use the default converter to convert the resource value to the type of the property
                    dataValue = DefaultValueConverter.Instance.Convert(dataValue, propertyType, null, culture);
                }

                if (string.IsNullOrEmpty(StringFormat))
                {
                    return(dataValue);
                }
                else
                {
                    // Format the value
                    return(string.Format(culture, StringFormat, dataValue));
                }
            }
            else
            {
                // There is no binding, callback, or a resource value

                if (string.IsNullOrEmpty(StringFormat))
                {
                    return(targetProperty != null ? targetProperty.DefaultValue : TypeUtils.GetDefaultValue(propertyType));
                }
                else
                {
                    // Format the value
                    return(StringFormat);
                }
            }
        }
 public DependencyObjectProperty(DependencyObject targetObject, LocalizableProperty targetProperty)
 {
     this.TargetObject   = targetObject ?? throw new ArgumentNullException(nameof(targetObject));
     this.TargetProperty = targetProperty ?? throw new ArgumentNullException(nameof(targetProperty));
 }