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); }
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)); }