Vanara/Windows.Shell/TaskBar/TaskbarButton.cs

315 lines
13 KiB
C#

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
{
/// <summary>Provides access to the functionality of the taskbar button.</summary>
/// <seealso cref="System.ComponentModel.Component"/>
[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<Form>, INotifyPropertyChanged
{
private const string category = "Taskbar Button";
static TaskbarButton() => Application.AddMessageFilter(new ThumbButtonMessageFilter());
/// <summary>Initializes a new instance of the <see cref="TaskbarButton"/> class.</summary>
public TaskbarButton()
{
TaskbarButtonCreated += OnTaskbarButtonCreated;
ThumbnailButtonClick += OnThumbnailButtonClick;
}
/// <summary>Initializes a new instance of the <see cref="TaskbarButton"/> class.</summary>
/// <param name="container">The container of this component.</param>
/// <exception cref="System.ArgumentNullException">container</exception>
public TaskbarButton(IContainer container) : this()
{
if (container is null)
throw new ArgumentNullException(nameof(container));
container.Add(this);
}
/// <summary>
/// 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.
/// </summary>
public static event Action<HWND> TaskbarButtonCreated;
/// <summary>
/// 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.
/// </summary>
public static event Action<HWND, int> ThumbnailButtonClick;
/// <summary>Occurs when a property has changed.</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>Gets a value indicating whether the taskbar button has been created.</summary>
/// <value><see langword="true"/> if the taskbar button was created; otherwise, <see langword="false"/>.</value>
[Browsable(false)]
public bool IsTaskbarButtonCreated { get; internal set; } = false;
/// <summary>Signals the object that initialization is starting.</summary>
public override void BeginInit()
{
base.BeginInit();
if (Container is Form f && f.ShowInTaskbar)
TaskbarList.ActivateTaskbarItem(f.Handle);
}
/// <summary>Gets the application identifier.</summary>
/// <param name="form">The form.</param>
/// <returns>The application identifier.</returns>
[Category(category), DisplayName("AppID"), DefaultValue(null)]
[Description("Gets or sets the application identifier.")]
public string GetAppID(Form form) => GetPropertyValue<string>(form);
/// <summary>Gets the jumplist to display on this taskbar button.</summary>
/// <param name="form">The form.</param>
/// <returns>The jumplist.</returns>
[Category(category), DisplayName("JumpList"), Localizable(true)]
[Description("Gets the jumplist to display with the taskbar button.")]
public JumpList GetJumpList(Form form)
{
var ret = GetPropertyValue<JumpList>(form);
if (ret is null)
{
ret = new JumpList();
SetPropertyValue(form, ret, "JumpList");
}
return ret;
}
/// <summary>Gets the overlay icon to dispaly on a taskbar button to indicate application status or a notification to the user.</summary>
/// <param name="form">The form.</param>
/// <returns>The overlay icon.</returns>
[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<Icon>(form);
/// <summary>
/// Gets the overlay tooltip to dispaly on a taskbar button to indicate application status or a notification to the user.
/// </summary>
/// <param name="form">The form.</param>
/// <returns>The overlay tooltip.</returns>
[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<string>(form);
/// <summary>Gets the state of the progress indicator displayed on a taskbar button.</summary>
/// <param name="form">
/// The window in which the progress of an operation is being shown. This window's associated taskbar button will display the
/// progress bar.
/// </param>
/// <returns>The current state of the progress button.</returns>
[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);
/// <summary>
/// Displays or updates a progress bar hosted in a taskbar button to show the specific percentage completed of the full operation.
/// </summary>
/// <param name="form">The window whose associated taskbar button is being used as a progress indicator.</param>
/// <returns>The proportion of the operation that has been completed at the time the method is called.</returns>
[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);
/// <summary>Gets the taskbar button thumbnails.</summary>
/// <param name="form">The window owning the taskbar button thumbnails.</param>
/// <returns>A collection of thumbnails.</returns>
[Category(category), DisplayName("TaskbarButtonThumbnails")]
[Description("Gets the list of thumbnails associated with the taskbar button.")]
public TaskbarButtonThumbnails GetTaskbarButtonThumbnails(Form form)
{
var ret = GetPropertyValue<TaskbarButtonThumbnails>(form);
if (ret is null)
{
ret = new TaskbarButtonThumbnails(form);
SetPropertyValue(form, ret, "TaskbarButtonThumbnails");
}
return ret;
}
/// <summary>Gets the description displayed on the tooltip of the taskbar button.</summary>
/// <param name="form">The form.</param>
/// <returns>The description</returns>
[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<string>(form);
/// <summary>Sets the application identifier.</summary>
/// <param name="form">The form.</param>
/// <param name="value">The value.</param>
public void SetAppID(Form form, string value)
{
if (SetPropertyValue(form, value) && IsTaskbarButtonCreated)
ApplySetting(form, value);
}
/// <summary>Sets the overlay icon to dispaly on a taskbar button to indicate application status or a notification to the user.</summary>
/// <param name="form">The form.</param>
/// <param name="value">The overlay icon to apply.</param>
public void SetTaskbarButtonOverlay(Form form, Icon value)
{
if (SetPropertyValue(form, value) && IsTaskbarButtonCreated)
ApplySetting(form, value);
}
/// <summary>
/// Gets the overlay tooltip to dispaly on a taskbar button to indicate application status or a notification to the user.
/// </summary>
/// <param name="form">The form.</param>
/// <param name="value">The overlay tooltip.</param>
public void SetTaskbarButtonOverlayTooltip(Form form, string value)
{
if (SetPropertyValue(form, value) && IsTaskbarButtonCreated)
ApplySetting(form, value);
}
/// <summary>Sets the type and state of the progress indicator displayed on a taskbar button.</summary>
/// <param name="form">
/// The window in which the progress of an operation is being shown. This window's associated taskbar button will display the
/// progress bar.
/// </param>
/// <param name="value">The current state of the progress button. Specify only one of the enum values.</param>
public void SetTaskbarButtonProgressState(Form form, TaskbarButtonProgressState value)
{
if (SetPropertyValue(form, value) && IsTaskbarButtonCreated)
ApplySetting(form, value);
}
/// <summary>
/// Displays or updates a progress bar hosted in a taskbar button to show the specific percentage completed of the full operation.
/// </summary>
/// <param name="form">The window whose associated taskbar button is being used as a progress indicator.</param>
/// <param name="value">
/// The proportion of the operation that has been completed at the time the method is called. This value must be between 0.0f and
/// </param>
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);
}
/// <summary>Sets the description displayed on the tooltip of the taskbar button.</summary>
/// <param name="form">The form.</param>
/// <param name="value">The description.</param>
public void SetTaskbarButtonTooltip(Form form, string value)
{
if (SetPropertyValue(form, value) && IsTaskbarButtonCreated)
ApplySetting(form, value);
}
/// <summary>Calls the <see cref="PropertyChanged"/> event.</summary>
/// <param name="form">The form.</param>
/// <param name="propName">Name of the changed property.</param>
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;
}
}
}
}