mirror of https://github.com/dahall/Vanara.git
166 lines
7.3 KiB
C#
166 lines
7.3 KiB
C#
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
|
|
{
|
|
/// <summary>Extends standard WinForms controls with post-Vista capabilities.</summary>
|
|
/// <seealso cref="Component"/>
|
|
/// <seealso cref="IExtenderProvider"/>
|
|
[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<Component, Dictionary<string, (object value, Action<Control, object> setter)>> bag = new Dictionary<Component, Dictionary<string, (object value, Action<Control, object> setter)>>();
|
|
private readonly Container components = new Container();
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="VistaControlExtender"/> class.</summary>
|
|
public VistaControlExtender() { }
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="VistaControlExtender"/> class.</summary>
|
|
/// <param name="container">The container.</param>
|
|
public VistaControlExtender(IContainer container) => container.Add(this);
|
|
|
|
private static bool IsMinVista { get; } = Environment.OSVersion.Version.Major >= 6;
|
|
|
|
/// <summary>Gets the text that is displayed as a prompt for an unselected <see cref="ComboBox"/>.</summary>
|
|
/// <param name="comboBox">The <see cref="ComboBox"/> instance.</param>
|
|
/// <returns>The cue text to display.</returns>
|
|
[DisplayName(CueBanner), DefaultValue(null), Category("Appearance")]
|
|
[Description("Text that is displayed as a prompt for an unselected ComboBox.")]
|
|
public string GetCueBanner(ComboBox comboBox) => GetValue<string>(comboBox, CueBanner, out _);
|
|
|
|
/// <summary>Sets the text that is displayed as a prompt for an unselected <see cref="ComboBox"/>.</summary>
|
|
/// <param name="comboBox">The <see cref="ComboBox"/> instance.</param>
|
|
/// <param name="value">The cue text to display.</param>
|
|
public void SetCueBanner(ComboBox comboBox, string value) => SetValue(comboBox, CueBanner, value, SetCueBannerValue);
|
|
|
|
/// <summary>Gets the minimum number of visible items in the drop-down list of a <see cref="ComboBox"/>.</summary>
|
|
/// <param name="comboBox">The <see cref="ComboBox"/> instance.</param>
|
|
/// <returns>The minimum number of visible items in the drop-down list.</returns>
|
|
[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());
|
|
|
|
/// <summary>Sets the minimum number of visible items in the drop-down list of a <see cref="ComboBox"/>.</summary>
|
|
/// <param name="comboBox">The <see cref="ComboBox"/> instance.</param>
|
|
/// <param name="value">The minimum number of visible items in the drop-down list.</param>
|
|
public void SetMinVisibleItems(ComboBox comboBox, int value) => SetValue(comboBox, MinVisibleItems, value, SetMinVisibleItemsValue);
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="btn">The Button instance.</param>
|
|
/// <returns><see langword="true"/> if the shield should be shown; <see langword="false"/> otherwise.</returns>
|
|
[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<bool>(btn, ShowShield, out _);
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="btn">The Button instance.</param>
|
|
/// <param name="value"><see langword="true"/> if the shield should be shown; <see langword="false"/> otherwise.</param>
|
|
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<Control>())
|
|
key.HandleCreated += OnComponentHandleCreated;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Releases the unmanaged resources used by the <see cref="T:System.ComponentModel.Component"/> and optionally releases the managed resources.
|
|
/// </summary>
|
|
/// <param name="disposing">
|
|
/// <see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.
|
|
/// </param>
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
foreach (var key in bag.Keys.OfType<Control>())
|
|
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<string>(textBox, CueBanner);
|
|
|
|
public void SetCueBanner(TextBox textBox, string value)
|
|
{
|
|
if (SetValue(textBox, CueBanner, value))
|
|
textBox.SetCueBanner(value);
|
|
}*/
|
|
|
|
private T GetValue<T>(Control comp, string propName, out Action<Control, object> 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<T>(Control comp, string propName, T value, Action<Control, object> setter)
|
|
{
|
|
if (Equals(value, GetValue<T>(comp, propName, out _))) return false;
|
|
if (!bag.ContainsKey(comp))
|
|
bag.Add(comp, new Dictionary<string, (object value, Action<Control, object> setter)>());
|
|
bag[comp][propName] = (value, setter);
|
|
return true;
|
|
}
|
|
}
|
|
} |