using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Forms; using Vanara.Extensions; using static Vanara.PInvoke.User32; namespace Vanara.Windows.Forms { /// Extends standard WinForms controls with post-Vista capabilities. /// /// [ProvideProperty(ShowShield, typeof(ButtonBase))] [ProvideProperty(CueBanner, typeof(ComboBox))] [ProvideProperty(MinVisibleItems, typeof(ComboBox))] //[ProvideProperty(CueBanner, typeof(TextBox))] public sealed class VistaControlExtender : Component, IExtenderProvider, ISupportInitialize { internal const string CueBanner = "CueBanner"; internal const string MinVisibleItems = "MinVisibleItems"; internal const string ShowShield = "ShowShield"; private readonly Dictionary setter)>> bag = new Dictionary setter)>>(); private readonly Container components = new Container(); /// Initializes a new instance of the class. public VistaControlExtender() { } /// Initializes a new instance of the class. /// The container. public VistaControlExtender(IContainer container) => container.Add(this); private static bool IsMinVista { get; } = Environment.OSVersion.Version.Major >= 6; /// Gets the text that is displayed as a prompt for an unselected . /// The instance. /// The cue text to display. [DisplayName(CueBanner), DefaultValue(null), Category("Appearance")] [Description("Text that is displayed as a prompt for an unselected ComboBox.")] public string GetCueBanner(ComboBox comboBox) => GetValue(comboBox, CueBanner, out _); /// Sets the text that is displayed as a prompt for an unselected . /// The instance. /// The cue text to display. public void SetCueBanner(ComboBox comboBox, string value) => SetValue(comboBox, CueBanner, value, SetCueBannerValue); /// Gets the minimum number of visible items in the drop-down list of a . /// The instance. /// The minimum number of visible items in the drop-down list. [DisplayName(MinVisibleItems), DefaultValue(30), Category("Appearance")] [Description("The minimum number of visible items in the drop-down list of a combo box.")] public int GetMinVisibleItems(ComboBox comboBox) => GetValue(comboBox, MinVisibleItems, out _, comboBox.SendMessage((uint)ComboBoxMessage.CB_SETMINVISIBLE).ToInt32()); /// Sets the minimum number of visible items in the drop-down list of a . /// The instance. /// The minimum number of visible items in the drop-down list. public void SetMinVisibleItems(ComboBox comboBox, int value) => SetValue(comboBox, MinVisibleItems, value, SetMinVisibleItemsValue); /// /// Gets a value which indicates whether a shield is shown on the button to indicate that elevated permissions are required to /// perform the action of the button. /// /// The Button instance. /// if the shield should be shown; otherwise. [DisplayName(ShowShield), DefaultValue(false), Category("Appearance")] [Description("Indicates whether a shield is shown on the button to indicate that elevated permissions are required to perform the action of the button.")] public bool GetShowShield(ButtonBase btn) => GetValue(btn, ShowShield, out _); /// /// Sets a value which indicates whether a shield is shown on the button to indicate that elevated permissions are required to /// perform the action of the button. /// /// The Button instance. /// if the shield should be shown; otherwise. public void SetShowShield(ButtonBase btn, bool value) => SetValue(btn, ShowShield, value, SetShowShieldValue); void ISupportInitialize.BeginInit() { } bool IExtenderProvider.CanExtend(object extendee) => extendee is ComboBox || (extendee is ButtonBase && extendee.GetType().GetProperty(ShowShield) is null); void ISupportInitialize.EndInit() { if (!DesignMode) { foreach (var key in bag.Keys.OfType()) key.HandleCreated += OnComponentHandleCreated; } } /// /// Releases the unmanaged resources used by the and optionally releases the managed resources. /// /// /// to release both managed and unmanaged resources; to release only unmanaged resources. /// protected override void Dispose(bool disposing) { if (disposing) { foreach (var key in bag.Keys.OfType()) try { key.HandleCreated -= OnComponentHandleCreated; } catch { } components?.Dispose(); } base.Dispose(disposing); } private static void SetCueBannerValue(Control comboBox, object value) { (comboBox as ComboBox)?.SetCueBanner(value?.ToString()); comboBox.Invalidate(); } private static void SetMinVisibleItemsValue(Control comboBox, object value) { if (!IsMinVista) return; comboBox.SendMessage((uint)ComboBoxMessage.CB_SETMINVISIBLE, (IntPtr)value); comboBox.Invalidate(); } private static void SetShowShieldValue(Control btn, object value) { (btn as ButtonBase)?.SetElevationRequiredState((bool)value); btn.Invalidate(); } /*[DisplayName(CueBanner), DefaultValue(null), Category("Appearance")] [Description("Text that is displayed as a prompt for an unselected TextBox.")] public string GetCueBanner(TextBox textBox) => GetValue(textBox, CueBanner); public void SetCueBanner(TextBox textBox, string value) { if (SetValue(textBox, CueBanner, value)) textBox.SetCueBanner(value); }*/ private T GetValue(Control comp, string propName, out Action setter, T defValue = default) { if (bag.TryGetValue(comp, out var props) && props.TryGetValue(propName, out var value)) { setter = value.setter; return (T)value.value; } setter = null; return defValue; } private void OnComponentHandleCreated(object sender, EventArgs e) { foreach (var kv in bag.Where(kv => ReferenceEquals(kv.Key, sender))) foreach (var (value, setter) in kv.Value.Values) setter?.Invoke(sender as Control, value); } private bool SetValue(Control comp, string propName, T value, Action setter) { if (Equals(value, GetValue(comp, propName, out _))) return false; if (!bag.ContainsKey(comp)) bag.Add(comp, new Dictionary setter)>()); bag[comp][propName] = (value, setter); return true; } } }