using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Linq; using System.Runtime.CompilerServices; namespace Vanara.Windows { /// A generic base to implement for a single extender type. /// The type of the type that can be extended. public abstract class ExtenderProviderBase : Component, IExtenderProvider, ISupportInitialize where TExtend : Component { /// A dictionary that holds a property bag for each extended type. protected readonly Dictionary> propHash = new(); /// Initializes a new instance of the class. protected ExtenderProviderBase() { } /// Initializes a new instance of the class. /// The parent. protected ExtenderProviderBase(TExtend parent) => OnAddingExtender(parent); /// Initializes a new instance of the class. /// The container. /// container protected ExtenderProviderBase(IContainer container) : this() { if (container is null) throw new ArgumentNullException(nameof(container)); container.Add(this); } /// Occurs when a new extender is being added. protected event EventHandler AddingExtender; /// Sets the site. /// The site. public override ISite Site { set { base.Site = value; var parent = (value?.GetService(typeof(IDesignerHost)) as IDesignerHost)?.RootComponent as TExtend; if (parent != null) OnAddingExtender(parent); } } /// Gets all extended components that have properties assigned. /// Returns a value. protected IEnumerable ExtendedComponents => propHash.Keys; /// Gets the known properties stored against all components. /// Returns a value. protected IEnumerable KnownProperties => propHash.Values.SelectMany(d => d.Keys).Distinct(); /// Signals the object that initialization is starting. public virtual void BeginInit() { } /// Determines whether this instance can extend the specified extendee. /// The extendee. /// if this instance can extend the specified extendee; otherwise, . public virtual bool CanExtend(object extendee) => extendee is TExtend; /// Signals the object that initialization is complete. public virtual void EndInit() { } /// Gets the property value. /// The type of the property to get. /// The form. /// The default value. /// Name of the field. /// protected virtual T GetPropertyValue(TExtend form, T defaultValue = default, [CallerMemberName] string propName = "") { if (propName.StartsWith("Get")) propName = propName.Remove(0, 3); return propHash.TryGetValue(form, out var props) && props.TryGetValue(propName, out var prop) ? (T)prop : defaultValue; } /// Calls the event. /// The extender being added. protected virtual void OnAddingExtender(TExtend extender) { var args = new AddExtenderEventArgs(extender); AddingExtender?.Invoke(this, args); propHash[extender] = args.ExtenderProperties; } /// Sets the property value. /// The type of the property to set. /// The form. /// The value. /// Name of the field. protected virtual bool SetPropertyValue(TExtend form, T value, [CallerMemberName] string propName = "") { if (!propHash.ContainsKey(form)) OnAddingExtender(form); if (propName.StartsWith("Set")) propName = propName.Remove(0, 3); if (propHash[form].TryGetValue(propName, out var prop) && Equals(prop, value)) return false; propHash[form][propName] = value; return true; } /// Arguments for the event. public class AddExtenderEventArgs : EventArgs { internal AddExtenderEventArgs(TExtend parent) { Extender = parent; ExtenderProperties = new Dictionary(); } /// Gets the extender being added. /// The extender. public TExtend Extender { get; } /// Gets or sets the property bag to be associated with this extender. /// The extender property bag. public Dictionary ExtenderProperties { get; set; } } } }