using System; using System.Reflection; using System.Resources; using System.Windows; using System.Windows.Markup; using Developpez.Dotnet.Windows.Properties; namespace Developpez.Dotnet.Windows.Localization { /// /// Classe de base pour les markup extensions renvoyant une ressource localisée /// [MarkupExtensionReturnType(typeof(object))] public abstract class LocResourceExtensionBase : MarkupExtension { /// /// Initialise une nouvelle instance de LocResourceExtensionBase /// protected LocResourceExtensionBase() { } /// /// Initialise une nouvelle instance de LocResourceExtensionBase, avec la clé de ressource spécifiée /// /// Clé de ressource pour cette instance de LocResourceExtensionBase protected LocResourceExtensionBase(string resourceKey) { this.ResourceKey = resourceKey; } /// /// Clé de la ressource souhaitée /// [ConstructorArgument("resourceKey")] public string ResourceKey { get; set; } // Objet à mettre à jour lors d'un changement de culture // On ne garde qu'une référence faible pour ne pas empêcher que l'objet soit ramassé par le GC private WeakReference _targetObjectRef; // Propriété à mettre à jour lors d'un changement de culture private object _targetProperty; // ResourceManager à utiliser pour récupérer les resources private ResourceManager _resourceManager; #region Implémentation de MarkupExtension /// /// Renvoie une version localisée de la ressource spécifiée /// /// Objet qui peut fournir des services pour la markup extension /// Une version localisée de la ressource spécifiée public sealed override object ProvideValue(IServiceProvider serviceProvider) { if (string.IsNullOrEmpty(ResourceKey)) throw new InvalidOperationException(ExceptionMessages.ResourceKeyNotSet); // On récupère le ResourceManager en fonction de l'URI IUriContext uriContext = serviceProvider.GetService(typeof(IUriContext)) as IUriContext; if (uriContext != null) { _resourceManager = LocalizationManager.GetResourceManager(uriContext); } // On récupère l'objet et la propriété cible pour pouvoir la mettre à // jour lors d'un changement de culture IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; if (target != null) { // En mode design, la cible n'est pas définie : elle ne sera donc pas mise à jour if (target.TargetObject != null && target.TargetProperty != null) { this._targetObjectRef = new WeakReference(target.TargetObject); this._targetProperty = target.TargetProperty; // On s'abonne à l'évènement UICultureChanged pour mettre à jour la propriété LocalizationManager.UICultureChanged += LocManager_UICultureChanged; } } return ProvideValueInternal(_resourceManager); } #endregion /// /// Quand elle est redéfinie dans une classe dérivée, cette méthode renvoie une ressource à partir du ResourceManager spécifié /// /// ResourceManager à partir duquel obtenir la ressource /// La ressource dont la clé est spécifiée par la propriété ResourceKey protected abstract object ProvideValueInternal(ResourceManager resourceManager); private void LocManager_UICultureChanged(object sender, EventArgs e) { Refresh(); } // Cette méthode met à jour la cible pour prendre en compte le changement de culture private void Refresh() { object targetObject = _targetObjectRef.Target; // On vérifie que l'objet à mettre à jour existe encore if (targetObject == null) { // L'objet a été ramassé par le GC, on se désabonne de l'évènement UICultureChanged LocalizationManager.UICultureChanged -= LocManager_UICultureChanged; return; } object value = ProvideValueInternal(_resourceManager); // Si targetProperty est une DependencyProperty, targetObject est un DependencyObject // Sinon, targetProperty est un PropertyInfo, et targetObject un object quelconque if (_targetProperty is DependencyProperty) { DependencyObject obj = targetObject as DependencyObject; DependencyProperty prop = _targetProperty as DependencyProperty; obj.SetValue(prop, value); } else { PropertyInfo prop = _targetProperty as PropertyInfo; prop.SetValue(targetObject, value, null); } } } }