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