using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using HandyControl.Data; namespace HandyControl.Controls { public abstract class AdornerElement : Control, IDisposable { protected FrameworkElement ElementTarget { get; set; } public static readonly DependencyProperty TargetProperty = DependencyProperty.Register( "Target", typeof(FrameworkElement), typeof(AdornerElement), new PropertyMetadata(default(FrameworkElement), OnTargetChanged)); private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var ctl = (AdornerElement) d; ctl.OnTargetChanged(ctl.ElementTarget, false); ctl.OnTargetChanged((FrameworkElement) e.NewValue, true); } [Bindable(true), Category("Layout")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public FrameworkElement Target { get => (FrameworkElement) GetValue(TargetProperty); set => SetValue(TargetProperty, value); } public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached( "Instance", typeof(AdornerElement), typeof(AdornerElement), new PropertyMetadata(default(AdornerElement), OnInstanceChanged)); private static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not FrameworkElement target) return; var element = (AdornerElement) e.NewValue; element.OnInstanceChanged(target); } protected virtual void OnInstanceChanged(FrameworkElement target) => Target = target; public static void SetInstance(DependencyObject element, AdornerElement value) => element.SetValue(InstanceProperty, value); public static AdornerElement GetInstance(DependencyObject element) => (AdornerElement) element.GetValue(InstanceProperty); public static readonly DependencyProperty IsInstanceProperty = DependencyProperty.RegisterAttached( "IsInstance", typeof(bool), typeof(AdornerElement), new PropertyMetadata(ValueBoxes.TrueBox)); public static void SetIsInstance(DependencyObject element, bool value) => element.SetValue(IsInstanceProperty, ValueBoxes.BooleanBox(value)); public static bool GetIsInstance(DependencyObject element) => (bool) element.GetValue(IsInstanceProperty); protected virtual void OnTargetChanged(FrameworkElement element, bool isNew) { if (element == null) return; if (!isNew) { element.Unloaded -= TargetElement_Unloaded; ElementTarget = null; } else { element.Unloaded += TargetElement_Unloaded; ElementTarget = element; } } private void TargetElement_Unloaded(object sender, RoutedEventArgs e) { if (sender is FrameworkElement element) { element.Unloaded -= TargetElement_Unloaded; Dispose(); } } protected abstract void Dispose(); void IDisposable.Dispose() => Dispose(); } }