using System; using System.Collections.Generic; using System.Reflection; using System.Windows; using System.Windows.Markup; namespace Developpez.Dotnet.Windows.Markup { /// /// Implémente une MarkupExtension qui peut mettre à jour sa cible /// /// /// Pour créer une classe dérivée de UpdatableMarkupExtension, implémentez la méthode ProvideValueInternal. /// public abstract class UpdatableMarkupExtension : MarkupExtension { private readonly List _targetObjects = new List(); private object _targetProperty; /// /// Fournit la liste des objets cibles de cette markup extension /// protected IEnumerable TargetObjects { get { return _targetObjects; } } /// /// Indique la propriété cible de cette markup extension /// protected object TargetProperty { get { return _targetProperty; } } /// /// Fournit la valeur de cette markup extension /// /// Objet qui peut fournir des services pour la markup extension /// La valeur de cette markup extension /// /// Cette méthode est scellée et ne peut être redéfinie. Redéfinissez ProvideValueInternal à la place. /// public sealed override object ProvideValue(IServiceProvider serviceProvider) { // Retrieve target information IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; if (target != null && target.TargetObject != null) { // In a template the TargetObject is a SharedDp (internal WPF class) // In that case, the markup extension itself is returned to be re-evaluated later if (target.TargetObject.GetType().FullName == "System.Windows.SharedDp") return this; // Save target information for later updates _targetObjects.Add(target.TargetObject); _targetProperty = target.TargetProperty; } // Delegate the work to the derived class return ProvideValueInternal(serviceProvider); } /// /// Met à jour les cibles de la markup extension avec la valeur spécifiée /// /// La nouvelle valeur pour les cibles de la markup extension protected virtual void UpdateValue(object value) { if (_targetObjects.Count > 0) { // Update the target property of each target object foreach (var target in _targetObjects) { if (_targetProperty is DependencyProperty) { DependencyObject obj = (DependencyObject)target; DependencyProperty prop = (DependencyProperty)_targetProperty; Action updateAction = () => obj.SetValue(prop, value); // Check whether the target object can be accessed from the // current thread, and use Dispatcher.Invoke if it can't if (obj.CheckAccess()) updateAction(); else obj.Dispatcher.Invoke(updateAction); } else if (_targetProperty is PropertyInfo) { PropertyInfo prop = (PropertyInfo)_targetProperty; prop.SetValue(target, value, null); } } } } /// /// Fournit la valeur de cette markup extension /// /// Objet qui peut fournir des services pour la markup extension /// La valeur de cette markup extension /// /// Cette méthode est abstraite et doit être implémentées par les classes dérivées. /// protected abstract object ProvideValueInternal(IServiceProvider serviceProvider); } }