using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
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();
private readonly Container components = new();
/// 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((string?)value);
comboBox.Invalidate();
}
private static void SetMinVisibleItemsValue(Control comboBox, object? value)
{
if (!IsMinVista) return;
comboBox.SendMessage((uint)ComboBoxMessage.CB_SETMINVISIBLE, (IntPtr)(int)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((Control)sender!, 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;
}
}