using System; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Runtime.CompilerServices; using System.Security.Permissions; using System.Windows.Forms; using Vanara.PInvoke; namespace Vanara.Windows.Shell { /// Provides access to the functionality of the taskbar button. /// [ProvideProperty("AppID", typeof(Form))] [ProvideProperty("TaskbarButtonTooltip", typeof(Form))] [ProvideProperty("TaskbarButtonOverlay", typeof(Form))] [ProvideProperty("TaskbarButtonOverlayTooltip", typeof(Form))] [ProvideProperty("TaskbarButtonProgressState", typeof(Form))] [ProvideProperty("TaskbarButtonProgressValue", typeof(Form))] [ProvideProperty("JumpList", typeof(Form))] [ProvideProperty("TaskbarButtonThumbnails", typeof(Form))] public class TaskbarButton : ExtenderProviderBase
, INotifyPropertyChanged { private const string category = "Taskbar Button"; static TaskbarButton() => Application.AddMessageFilter(new ThumbButtonMessageFilter()); /// Initializes a new instance of the class. public TaskbarButton() { TaskbarButtonCreated += OnTaskbarButtonCreated; ThumbnailButtonClick += OnThumbnailButtonClick; } /// Initializes a new instance of the class. /// The container of this component. /// container public TaskbarButton(IContainer container) : this() { if (container is null) throw new ArgumentNullException(nameof(container)); container.Add(this); } /// /// Occurs when the system reports a taskbar button has been created. The first parameter will contain the HWND of the window for /// which the button was created. /// public static event Action TaskbarButtonCreated; /// /// Occurs when the system reports a thumbnail button has been clicked. The first parameter contains the HWND of the window shown by /// the thumbnail and the second contains the Command ID of the button that was clicked. /// public static event Action ThumbnailButtonClick; /// Occurs when a property has changed. public event PropertyChangedEventHandler PropertyChanged; /// Gets a value indicating whether the taskbar button has been created. /// if the taskbar button was created; otherwise, . [Browsable(false)] public bool IsTaskbarButtonCreated { get; internal set; } = false; /// Signals the object that initialization is starting. public override void BeginInit() { base.BeginInit(); if (Container is Form f && f.ShowInTaskbar) TaskbarList.ActivateTaskbarItem(f.Handle); } /// Gets the application identifier. /// The form. /// The application identifier. [Category(category), DisplayName("AppID"), DefaultValue(null)] [Description("Gets or sets the application identifier.")] public string GetAppID(Form form) => GetPropertyValue(form); /// Gets the jumplist to display on this taskbar button. /// The form. /// The jumplist. [Category(category), DisplayName("JumpList"), Localizable(true)] [Description("Gets the jumplist to display with the taskbar button.")] public JumpList GetJumpList(Form form) { var ret = GetPropertyValue(form); if (ret is null) { ret = new JumpList(); SetPropertyValue(form, ret, "JumpList"); } return ret; } /// Gets the overlay icon to dispaly on a taskbar button to indicate application status or a notification to the user. /// The form. /// The overlay icon. [Category(category), DisplayName("TaskbarButtonOverlay"), DefaultValue(null), Localizable(true)] [Description("Gets or sets the overlay icon to dispaly on a taskbar button.")] public Icon GetTaskbarButtonOverlay(Form form) => GetPropertyValue(form); /// /// Gets the overlay tooltip to dispaly on a taskbar button to indicate application status or a notification to the user. /// /// The form. /// The overlay tooltip. [Category(category), DisplayName("TaskbarButtonOverlayTooltip"), DefaultValue(null), Localizable(true)] [Description("Gets or sets the overlay tooltip to dispaly on a taskbar button.")] public string GetTaskbarButtonOverlayTooltip(Form form) => GetPropertyValue(form); /// Gets the state of the progress indicator displayed on a taskbar button. /// /// The window in which the progress of an operation is being shown. This window's associated taskbar button will display the /// progress bar. /// /// The current state of the progress button. [Category(category), DisplayName("TaskbarButtonProgressState"), DefaultValue(TaskbarButtonProgressState.None)] [Description("Gets or sets the state of the progress indicator displayed on a taskbar button.")] public TaskbarButtonProgressState GetTaskbarButtonProgressState(Form form) => GetPropertyValue(form, TaskbarButtonProgressState.None); /// /// Displays or updates a progress bar hosted in a taskbar button to show the specific percentage completed of the full operation. /// /// The window whose associated taskbar button is being used as a progress indicator. /// The proportion of the operation that has been completed at the time the method is called. [Category(category), DisplayName("TaskbarButtonProgressValue"), DefaultValue(0.0f)] [Description("Gets or sets the percentage completion for the progress bar hosted in a taskbar button.")] public float GetTaskbarButtonProgressValue(Form form) => GetPropertyValue(form, 0.0f); /// Gets the taskbar button thumbnails. /// The window owning the taskbar button thumbnails. /// A collection of thumbnails. [Category(category), DisplayName("TaskbarButtonThumbnails")] [Description("Gets the list of thumbnails associated with the taskbar button.")] public TaskbarButtonThumbnails GetTaskbarButtonThumbnails(Form form) { var ret = GetPropertyValue(form); if (ret is null) { ret = new TaskbarButtonThumbnails(form); SetPropertyValue(form, ret, "TaskbarButtonThumbnails"); } return ret; } /// Gets the description displayed on the tooltip of the taskbar button. /// The form. /// The description [Category(category), DisplayName("TaskbarButtonTooltip"), DefaultValue(null), Localizable(true)] [Description("Gets or sets the description displayed on the tooltip of the taskbar button.")] public string GetTaskbarButtonTooltip(Form form) => GetPropertyValue(form); /// Sets the application identifier. /// The form. /// The value. public void SetAppID(Form form, string value) { if (SetPropertyValue(form, value) && IsTaskbarButtonCreated) ApplySetting(form, value); } /// Sets the overlay icon to dispaly on a taskbar button to indicate application status or a notification to the user. /// The form. /// The overlay icon to apply. public void SetTaskbarButtonOverlay(Form form, Icon value) { if (SetPropertyValue(form, value) && IsTaskbarButtonCreated) ApplySetting(form, value); } /// /// Gets the overlay tooltip to dispaly on a taskbar button to indicate application status or a notification to the user. /// /// The form. /// The overlay tooltip. public void SetTaskbarButtonOverlayTooltip(Form form, string value) { if (SetPropertyValue(form, value) && IsTaskbarButtonCreated) ApplySetting(form, value); } /// Sets the type and state of the progress indicator displayed on a taskbar button. /// /// The window in which the progress of an operation is being shown. This window's associated taskbar button will display the /// progress bar. /// /// The current state of the progress button. Specify only one of the enum values. public void SetTaskbarButtonProgressState(Form form, TaskbarButtonProgressState value) { if (SetPropertyValue(form, value) && IsTaskbarButtonCreated) ApplySetting(form, value); } /// /// Displays or updates a progress bar hosted in a taskbar button to show the specific percentage completed of the full operation. /// /// The window whose associated taskbar button is being used as a progress indicator. /// /// The proportion of the operation that has been completed at the time the method is called. This value must be between 0.0f and /// public void SetTaskbarButtonProgressValue(Form form, float value) { if (value < 0f || value > 1.0f) throw new ArgumentOutOfRangeException(nameof(value), "Progress value must be a number between 0 and 1, inclusive."); if (SetPropertyValue(form, value) && IsTaskbarButtonCreated) ApplySetting(form, value); } /// Sets the description displayed on the tooltip of the taskbar button. /// The form. /// The description. public void SetTaskbarButtonTooltip(Form form, string value) { if (SetPropertyValue(form, value) && IsTaskbarButtonCreated) ApplySetting(form, value); } /// Calls the event. /// The form. /// Name of the changed property. protected virtual void OnProperyChanged(Form form, string propName) => PropertyChanged?.Invoke(form, new PropertyChangedEventArgs(propName)); private void ApplySetting(Form form, object value, [CallerMemberName] string propName = "") { if (propName.StartsWith("Set")) propName = propName.Remove(0, 3); switch (propName) { case "AppID": TaskbarList.SetWindowAppId(form.Handle, (string)value); break; case "TaskbarButtonTooltip": TaskbarList.SetThumbnailTooltip(form.Handle, (string)value); break; case "TaskbarButtonOverlay": TaskbarList.SetOverlayIcon(form.Handle, ((Icon)value).Handle, GetTaskbarButtonOverlayTooltip(form)); break; case "TaskbarButtonOverlayTooltip": TaskbarList.SetOverlayIcon(form.Handle, GetTaskbarButtonOverlay(form)?.Handle ?? default, (string)value); break; case "TaskbarButtonProgressState": TaskbarList.SetProgressState(form.Handle, (TaskbarButtonProgressState)value); break; case "TaskbarButtonProgressValue": TaskbarList.SetProgressValue(form.Handle, (ulong)(100000 * (float)value), 100000); break; case "TaskbarButtonThumbnails": GetTaskbarButtonThumbnails(form).ResetToolbar(); break; case "JumpList": GetJumpList(form).ApplySettings(GetAppID(form)); break; default: throw new InvalidOperationException("Unrecognized setting name."); } OnProperyChanged(form, propName); } private void OnTaskbarButtonCreated(HWND hWnd) { IsTaskbarButtonCreated = true; // Apply any settings for this window var form = ExtendedComponents.FirstOrDefault(f => f.Handle == hWnd); if (form is null) return; foreach (var kv in propHash[form]) ApplySetting(form, kv.Value, kv.Key); } private void OnThumbnailButtonClick(HWND hWnd, int buttonId) { var form = ExtendedComponents.FirstOrDefault(f => f.Handle == hWnd); if (form is null) return; var th = GetTaskbarButtonThumbnails(form); if (th is null) return; if (buttonId >= 0 && buttonId < th.Toolbar.Buttons.Count) th.Toolbar.Buttons[buttonId].InvokeClick(); } #pragma warning disable IDE0051 // Remove unused private members private void ResetJumpList(Form form) => propHash[form].Remove("JumpList"); private void ResetTaskbarButtonThumbnails(Form form) => propHash[form].Remove("TaskbarButtonThumbnails"); private bool ShouldSerializeJumpList(Form form) => GetJumpList(form).Count > 0; private bool ShouldSerializeTaskbarButtonThumbnails(Form form) => GetTaskbarButtonThumbnails(form).Count > 0; #pragma warning restore IDE0051 // Remove unused private members [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] private class ThumbButtonMessageFilter : IMessageFilter { public bool PreFilterMessage(ref Message m) { if (m.Msg == Shell32.WM_TASKBARBUTTONCREATED) TaskbarButtonCreated(m.HWnd); else if (m.Msg == (int)User32.WindowMessage.WM_COMMAND && Macros.HIWORD(m.WParam) == Shell32.THBN_CLICKED) { ThumbnailButtonClick(m.HWnd, Macros.LOWORD(m.WParam)); return true; } return false; } } } }