Vanara/Windows.Forms/Dialogs/TaskDialog/TaskDialog.cs

1736 lines
70 KiB
C#
Raw Normal View History

/*
* Copyright © 2015 David Hall
*
* Design Notes:-
* --------------
* - Maximum size: 150px. Limited by the control itself.
*
* References:
* - http://www.codeproject.com/KB/vista/Vista_TaskDialog_Wrapper.aspx
* - http://www.codeproject.com/Articles/21276/Vista-TaskDialog-Wrapper-and-Emulator
* - http://www.codeproject.com/Articles/17026/TaskDialog-for-WinForms
*
* Revision Control:-
* ------------------
* Created On: 2007 November 26
* Major updates: 2015 Nov 6
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Vanara.Extensions;
using Vanara.PInvoke;
using Vanara.Resources;
using static Vanara.PInvoke.ComCtl32;
using static Vanara.PInvoke.User32;
// ReSharper disable InconsistentNaming
namespace Vanara.Windows.Forms
{
/// <summary>Progress bar state.</summary>
[SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")]
public enum ProgressBarState
{
/// <summary>Normal.</summary>
Normal = ProgressState.PBST_NORMAL,
/// <summary>Error state.</summary>
Error = ProgressState.PBST_ERROR,
/// <summary>Paused state.</summary>
Paused = ProgressState.PBST_PAUSED
}
/// <summary>Indicates how buttons are displayed on a <see cref="TaskDialog"/>.</summary>
public enum TaskDialogButtonDisplay
{
/// <summary>Places buttons as a standard buttons along with common buttons.</summary>
StandardButton,
/// <summary>Places buttons as command links in primary panel.</summary>
CommandLink,
/// <summary>Places buttons as command links with no icons in primary panel.</summary>
CommandLinkNoIcon
}
/// <summary>The TaskDialog common button flags used to specify the built in buttons to show in the TaskDialog.</summary>
[Flags]
public enum TaskDialogCommonButtons
{
/// <summary>No common buttons.</summary>
None = 0,
/// <summary>OK common button. If selected Task Dialog will return DialogResult.OK.</summary>
Ok = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_OK_BUTTON,
/// <summary>Yes common button. If selected Task Dialog will return DialogResult.Yes.</summary>
Yes = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_YES_BUTTON,
/// <summary>No common button. If selected Task Dialog will return DialogResult.No.</summary>
No = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_NO_BUTTON,
/// <summary>
2020-04-02 23:59:18 -04:00
/// Cancel common button. If selected Task Dialog will return DialogResult.Cancel. If this button is specified, the dialog box will
/// respond to typical cancel actions (Alt-F4 and Escape).
/// </summary>
Cancel = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CANCEL_BUTTON,
/// <summary>Retry common button. If selected Task Dialog will return DialogResult.Retry.</summary>
Retry = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_RETRY_BUTTON,
/// <summary>Close common button. If selected Task Dialog will return this value.</summary>
Close = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CLOSE_BUTTON,
}
/// <summary>The System icons the TaskDialog supports.</summary>
[SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32")]
public enum TaskDialogIcon : uint
{
/// <summary>No Icon.</summary>
None = 0,
/// <summary>System warning icon.</summary>
Warning = PInvoke.ComCtl32.TaskDialogIcon.TD_WARNING_ICON,
/// <summary>System Error icon.</summary>
Error = PInvoke.ComCtl32.TaskDialogIcon.TD_ERROR_ICON,
/// <summary>System Information icon.</summary>
Information = PInvoke.ComCtl32.TaskDialogIcon.TD_INFORMATION_ICON,
/// <summary>Shield icon.</summary>
Shield = PInvoke.ComCtl32.TaskDialogIcon.TD_SHIELD_ICON,
/// <summary>Shield icon on a blue background. Only available on Windows 8 and later.</summary>
ShieldBlue = PInvoke.ComCtl32.TaskDialogIcon.TD_SHIELDBLUE_ICON,
/// <summary>Warning Shield icon on a yellow background. Only available on Windows 8 and later.</summary>
SecurityWarning = PInvoke.ComCtl32.TaskDialogIcon.TD_SECURITYWARNING_ICON,
/// <summary>Error Shield icon on a red background. Only available on Windows 8 and later.</summary>
SecurityError = PInvoke.ComCtl32.TaskDialogIcon.TD_SECURITYERROR_ICON,
/// <summary>Success Shield icon on a green background. Only available on Windows 8 and later.</summary>
SecuritySuccess = PInvoke.ComCtl32.TaskDialogIcon.TD_SECURITYSUCCESS_ICON,
/// <summary>Shield icon on a gray background. Only available on Windows 8 and later.</summary>
ShieldGray = PInvoke.ComCtl32.TaskDialogIcon.TD_SHIELDGRAY_ICON
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// A Task Dialog. This is like a MessageBox but with many more features. For Windows version prior to Vista, an emulated version of the
/// system dialog is displayed.
/// </summary>
public class TaskDialog : CommonDialog, IWin32Window
{
2020-04-02 23:59:18 -04:00
/// <summary>
/// Returns true if the current operating system supports TaskDialog. If false TaskDialog.Show should not be called as the results
/// are undefined but often results in a crash.
/// </summary>
private static readonly bool IsAvailable = Environment.OSVersion.Platform == PlatformID.Win32NT && (Environment.OSVersion.Version.CompareTo(requiredOsVersion) >= 0);
// The minimum Windows version needed to support TaskDialog.
private static readonly Version requiredOsVersion = new Version(6, 0, 5243);
private string content;
private Icon customFooterIcon;
private Icon customMainIcon;
private string expandedInformation;
2020-04-02 23:59:18 -04:00
// The otherFlags passed to TaskDialogIndirect.
private EnumFlagIndexer<TASKDIALOG_FLAGS> flags;
2020-04-02 23:59:18 -04:00
private string footer;
private TaskDialogIcon footerIcon;
2020-04-02 23:59:18 -04:00
// When active, holds the handle of the current window.
2018-10-26 14:24:07 -04:00
private HWND handle = HWND.NULL;
2020-04-02 23:59:18 -04:00
private TaskDialogIcon mainIcon;
private string mainInstruction;
/// <summary>Initializes a new instance of the <see cref="TaskDialog"/> class.</summary>
public TaskDialog()
{
ProgressBar = new TaskDialogProgressBar(this);
Reset();
}
/// <summary>Occurs when a button is clicked.</summary>
[Category("Action"), Description("Occurs when a button is clicked.")]
public event EventHandler<ButtonClickedEventArgs> ButtonClicked;
/// <summary>Occurs when the dialog is closed.</summary>
[Category("Behavior"), Description("Occurs when the dialog is closed.")]
public event EventHandler Closed;
/// <summary>Occurs when the expando button is clicked and the dialog expands or contracts.</summary>
[Category("Behavior"), Description("Occurs when the expando button is clicked and the dialog expands or contracts.")]
public event EventHandler<ExpandedEventArgs> Expanded;
/// <summary>Occurs when a link is clicked.</summary>
[Category("Action"), Description("Occurs when a link is clicked.")]
public event LinkClickedEventHandler LinkClicked;
/// <summary>Occurs before the dialog is displayed for the first time.</summary>
[Category("Behavior"), Description("Occurs before the dialog is displayed for the first time.")]
public event EventHandler Load;
/// <summary>Occurs when a radio button is clicked.</summary>
[Category("Action"), Description("Occurs when a radio button is clicked.")]
public event EventHandler<ButtonClickedEventArgs> RadioButtonClicked;
/// <summary>Occurs when the timer fires.</summary>
[Category("Action"), Description("Occurs when the timer fires.")]
public event EventHandler<TimerEventArgs> Timer;
/// <summary>Occurs when the verification check box is checked or unchecked.</summary>
[Category("Action"), Description("Occurs when the verification check box is checked or unchecked.")]
public event EventHandler<VerificationClickedEventArgs> VerificationClicked;
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the dialog should be able to be closed using Alt-F4, Escape and the title bars close button even if no cancel
/// button is specified in either the CommonButtons or Buttons members.
/// </summary>
[DefaultValue(false)]
[Category("Behavior"), Description("Dialog can be closed by keys with no Cancel button.")]
public bool AllowDialogCancellation
{
get => flags[TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION];
set => flags[TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION] = value;
}
/// <summary>Gets or sets the placement of buttons added to the <see cref="Buttons"/> collection.</summary>
/// <value>The button placement.</value>
[DefaultValue(typeof(TaskDialogButtonDisplay), "StandardButton")]
[Category("Appearance"), Description("Determines how Buttons values are displayed")]
public TaskDialogButtonDisplay ButtonDisplay
{
get
{
if (UseCommandLinksNoIcon)
return TaskDialogButtonDisplay.CommandLinkNoIcon;
return UseCommandLinks ? TaskDialogButtonDisplay.CommandLink : TaskDialogButtonDisplay.StandardButton;
}
set
{
switch (value)
{
case TaskDialogButtonDisplay.StandardButton:
UseCommandLinks = UseCommandLinksNoIcon = false;
break;
case TaskDialogButtonDisplay.CommandLink:
UseCommandLinks = true;
UseCommandLinksNoIcon = false;
break;
case TaskDialogButtonDisplay.CommandLinkNoIcon:
UseCommandLinks = false;
UseCommandLinksNoIcon = true;
break;
default:
throw new ArgumentOutOfRangeException(nameof(ButtonDisplay));
}
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Specifies the custom push buttons to display in the dialog. Use CommonButtons member for common buttons; OK, Yes, No, Retry and
/// Cancel, and Buttons when you want different text on the push buttons.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Category("Appearance"), Description("Custom push buttons.")]
public TaskDialogButtonCollection<TaskDialogButton> Buttons { get; } = new TaskDialogButtonCollection<TaskDialogButton>();
/// <summary>Indicates that the TaskDialogs callback should be called approximately every 200 milliseconds.</summary>
[DefaultValue(false)]
[Category("Behavior"), Description("Callback timer should be called every 200 ms.")]
public bool CallbackTimer
{
get => flags[TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER];
set => flags[TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER] = value;
}
2020-04-02 23:59:18 -04:00
/// <summary>
/// Indicates that the TaskDialog can be minimized. Works only if there if parent window is null. Will enable cancellation also.
/// </summary>
[DefaultValue(false)]
[Category("Behavior"), Description("TaskDialog can be minimized.")]
public bool CanBeMinimized
{
get => flags[TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED];
set => flags[TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// The string to be used to label the button for expanding the expanded information. This member is ignored when the
/// ExpandedInformation member is null. If this member is null and the ExpandedControlText is specified, then the
/// ExpandedControlText value will be used for this member as well.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("Button label for expanding the expanded information")]
public string CollapsedControlText { get; set; }
/// <summary>
2020-04-02 23:59:18 -04:00
/// Specifies the push buttons displayed in the dialog box. This parameter may be a combination of otherFlags. If no common buttons
/// are specified and no custom buttons are specified using the Buttons member, the dialog box will contain the OK button by default.
/// </summary>
[DefaultValue(typeof(TaskDialogCommonButtons), "None")]
[Category("Appearance"), Description("Specifies common buttons to display.")]
[Editor(typeof(Design.FlagEnumUIEditor<TaskDialogCommonButtons>), typeof(UITypeEditor))]
public TaskDialogCommonButtons CommonButtons { get; set; }
/// <summary>
2020-04-02 23:59:18 -04:00
/// The string to be used for the dialogs primary content. If the EnableHyperlinks member is true, then this string may contain
/// hyper-links in the form: <A HREF="executablestring">Hyper-link Text</A>.
/// WARNING: Enabling hyper-links when using content from an unsafe source may cause security vulnerabilities.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("Optional text for the primary content area.")]
public string Content
{
get => content;
set
{
if (content == value) return;
content = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_SET_ELEMENT_TEXT, (IntPtr)TASKDIALOG_ELEMENTS.TDE_CONTENT, content);
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Specifies a custom icon for the icon to be displayed in the footer area of the dialog box. If this is set to none and the
/// CustomFooterIcon member is null then no footer icon will be displayed.
/// </summary>
[DefaultValue(null)]
[Category("Appearance"), Description("")]
public Icon CustomFooterIcon
{
get => customFooterIcon;
set
{
if (customFooterIcon == value) return;
customFooterIcon = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_UPDATE_ICON, (IntPtr)TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_FOOTER,
customFooterIcon?.Handle ?? (IntPtr)footerIcon);
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Specifies a custom in icon for the main icon in the dialog. If this is set to none and the CustomMainIcon member is null then no
/// main icon will be displayed.
/// </summary>
[DefaultValue(null)]
[Category("Appearance"), Description("")]
public Icon CustomMainIcon
{
get => customMainIcon;
set
{
if (customMainIcon == value) return;
customMainIcon = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_UPDATE_ICON, (IntPtr)TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_MAIN,
customMainIcon?.Handle ?? (IntPtr)mainIcon);
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates the default button for the dialog. This may be any of the values specified in ButtonId members of one of the
/// TaskDialogButton structures in the Buttons array, or one a DialogResult value that corresponds to a buttons specified in the
/// CommonButtons Member. If this member is zero or its value does not correspond to any button ID in the dialog, then the first
/// button in the dialog will be the default.
/// </summary>
[DefaultValue(0)]
[Category("Behavior"), Description("")]
public int DefaultButton { get; set; }
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates the default radio button for the dialog. This may be any of the values specified in ButtonId members of one of the
/// TaskDialogButton structures in the RadioButtons array. If this member is zero or its value does not correspond to any radio
/// button ID in the dialog, then the first button in RadioButtons will be the default. The property NoDefaultRadioButton can be set
/// to have no default.
/// </summary>
[DefaultValue(0)]
[Category("Behavior"), Description("")]
public int DefaultRadioButton { get; set; }
/// <summary>
2020-04-02 23:59:18 -04:00
/// Enables hyper-link processing for the strings specified in the Content, ExpandedInformation and FooterText members. When
/// enabled, these members may be strings that contain hyper-links in the form: <A HREF="executablestring">Hyper-link Text</A>.
/// WARNING: Enabling hyper-links when using content from an unsafe source may cause security vulnerabilities.
2020-04-02 23:59:18 -04:00
/// Note: Task Dialog will not actually execute any hyper-links. Hyper-link execution must be handled in the callback function
/// specified by Callback member.
/// </summary>
[DefaultValue(false)]
[Category("Behavior"), Description("")]
public bool EnableHyperlinks
{
get => flags[TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS];
set => flags[TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the string specified by the ExpandedInformation member should be displayed when the dialog is initially
/// displayed. This flag is ignored if the ExpandedInformation member is null.
/// </summary>
[DefaultValue(false)]
[Category("Appearance"), Description("")]
public bool ExpandedByDefault
{
get => flags[TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT];
set => flags[TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// The string to be used to label the button for collapsing the expanded information. This member is ignored when the
/// ExpandedInformation member is null. If this member is null and the CollapsedControlText is specified, then the
/// CollapsedControlText value will be used for this member as well.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string ExpandedControlText { get; set; }
/// <summary>
2020-04-02 23:59:18 -04:00
/// The string to be used for displaying additional information. The additional information is displayed either immediately below
/// the content or below the footer text depending on whether the ExpandFooterArea member is true. If the EnameHyperlinks member is
/// true, then this string may contain hyper-links in the form: <A HREF="executablestring">Hyper-link Text</A>.
/// WARNING: Enabling hyper-links when using content from an unsafe source may cause security vulnerabilities.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string ExpandedInformation
{
get => expandedInformation;
set
{
if (expandedInformation == value) return;
expandedInformation = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_SET_ELEMENT_TEXT,
(IntPtr)TASKDIALOG_ELEMENTS.TDE_EXPANDED_INFORMATION, expandedInformation);
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the string specified by the ExpandedInformation member should be displayed at the bottom of the dialogs footer
/// area instead of immediately after the dialogs content. This flag is ignored if the ExpandedInformation member is null.
/// </summary>
[DefaultValue(false)]
[Category("Appearance"), Description("")]
public bool ExpandFooterArea
{
get => flags[TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA];
set => flags[TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// The string to be used in the footer area of the dialog box. If the EnableHyperlinks member is true, then this string may contain
/// hyper-links in the
/// form: <A HREF="executablestring">Hyper-link Text</A>.
/// WARNING: Enabling hyper-links when using content from an unsafe source may cause security vulnerabilities.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string Footer
{
get => footer;
set
{
if (footer == value) return;
footer = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_SET_ELEMENT_TEXT, (IntPtr)TASKDIALOG_ELEMENTS.TDE_FOOTER, footer);
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Specifies a built in icon for the icon to be displayed in the footer area of the dialog box. If this is set to none and the
/// CustomFooterIcon member is null then no footer icon will be displayed.
/// </summary>
[DefaultValue(typeof(TaskDialogIcon), "None")]
[Category("Appearance"), Description("")]
public TaskDialogIcon FooterIcon
{
get => footerIcon;
set
{
if (footerIcon == value) return;
footerIcon = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_UPDATE_ICON, (IntPtr)TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_FOOTER,
(IntPtr)footerIcon);
}
}
/// <summary>Gets the image for the configured footer icon.</summary>
/// <value>The main icon image.</value>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public Image FooterIconImage => GetSmallImage(customFooterIcon ?? IconFromTaskDialogIcon(footerIcon));
/// <summary>Gets the handle for the active dialog.</summary>
/// <value>The handle. This value will be <c>IntPtr.Zero</c> if no active dialog is being displayed.</value>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
2018-10-26 14:24:07 -04:00
public IntPtr Handle => (IntPtr)handle;
/// <summary>
2020-04-02 23:59:18 -04:00
/// Specifies a built in icon for the main icon in the dialog. If this is set to none and the CustomMainIcon is null then no main
/// icon will be displayed.
/// </summary>
[DefaultValue(typeof(TaskDialogIcon), "None")]
[Category("Appearance"), Description("")]
public TaskDialogIcon MainIcon
{
get => mainIcon;
set
{
if (mainIcon != value)
{
mainIcon = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_UPDATE_ICON, (IntPtr)TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_MAIN,
(IntPtr)mainIcon);
}
}
}
/// <summary>Gets the image for the configured main icon.</summary>
/// <value>The main icon image.</value>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public Image MainIconImage => (customFooterIcon ?? IconFromTaskDialogIcon(footerIcon)).ToBitmap();
/// <summary>The string to be used for the main instruction.</summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string MainInstruction
{
get => mainInstruction;
set
{
if (mainInstruction != value)
{
mainInstruction = value;
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_SET_ELEMENT_TEXT, (IntPtr)TASKDIALOG_ELEMENTS.TDE_MAIN_INSTRUCTION,
mainInstruction);
}
}
}
/// <summary>Indicates that the TaskDialog should have no default radio button.</summary>
[DefaultValue(false)]
[Category("Behavior"), Description("")]
public bool NoDefaultRadioButton
{
get => flags[TASKDIALOG_FLAGS.TDF_NO_DEFAULT_RADIO_BUTTON];
set => flags[TASKDIALOG_FLAGS.TDF_NO_DEFAULT_RADIO_BUTTON] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the TaskDialog should be positioned (centered) relative to the owner window passed when calling Show. If not set
/// (or no owner window is passed), the TaskDialog is positioned (centered) relative to the monitor.
/// </summary>
[DefaultValue(false)]
[Category("Window Style"), Description("")]
public bool PositionRelativeToWindow
{
get => flags[TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW];
set => flags[TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// The progress bar for the <see cref="TaskDialog"/>. This will only be visible if the <see cref="TaskDialogProgressBar.Visible"/>
/// property is set to <c>true</c>.
/// </summary>
/// <value>The progress bar.</value>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Category("Appearance"), Description("")]
public TaskDialogProgressBar ProgressBar { get; }
/// <summary>Specifies the radio buttons to display in the dialog.</summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Category("Appearance"), Description("")]
public TaskDialogButtonCollection<TaskDialogRadioButton> RadioButtons { get; } =
new TaskDialogButtonCollection<TaskDialogRadioButton>();
/// <summary>Gets the full set of results for the last showing of the <see cref="TaskDialog"/>.</summary>
/// <value>The result set.</value>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public TaskDialogResult Result { get; private set; }
/// <summary>Indicates that the TaskDialog should have right to left layout.</summary>
[DefaultValue(false)]
[Category("Appearance"), Description("")]
public bool RightToLeftLayout
{
get => flags[TASKDIALOG_FLAGS.TDF_RTL_LAYOUT];
set => flags[TASKDIALOG_FLAGS.TDF_RTL_LAYOUT] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the width of the task dialog is determined by the width of its content area. This flag is ignored if <see
/// cref="Width"/> is not set to 0.
/// </summary>
[DefaultValue(false)]
[Category("Layout"), Description("")]
public bool SizeToContent
{
get => flags[TASKDIALOG_FLAGS.TDF_SIZE_TO_CONTENT];
set => flags[TASKDIALOG_FLAGS.TDF_SIZE_TO_CONTENT] = value;
}
/// <summary>Gets or sets a value indicating whether the form should be displayed as a topmost form.</summary>
[DefaultValue(true)]
[Category("Window Style"), Description("")]
public bool TopMost
{
get => !flags[TASKDIALOG_FLAGS.TDF_NO_SET_FOREGROUND];
set => flags[TASKDIALOG_FLAGS.TDF_NO_SET_FOREGROUND] = !value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the verification checkbox in the dialog should be checked when the dialog is initially displayed. This flag is
/// ignored if the VerificationText parameter is null.
/// </summary>
[DefaultValue(false)]
[Category("Appearance"), Description("")]
public bool VerificationFlagChecked
{
get => flags[TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED];
set => flags[TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// The string to be used to label the verification checkbox. If this member is null, the verification checkbox is not displayed in
/// the dialog box.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string VerificationText { get; set; }
/// <summary>width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width.</summary>
[DefaultValue(0)]
[Category("Layout"), Description("")]
public int Width { get; set; }
2020-04-02 23:59:18 -04:00
/// <summary>
/// The string to be used for the dialog box title. If this parameter is NULL, the filename of the executable program is used.
/// </summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string WindowTitle { get; set; }
/// <summary>Indicates that an Marquee Progress Bar should be displayed.</summary>
[DefaultValue(false)]
internal bool ShowMarqueeProgressBar
{
get => flags[TASKDIALOG_FLAGS.TDF_SHOW_MARQUEE_PROGRESS_BAR]; set => flags[TASKDIALOG_FLAGS.TDF_SHOW_MARQUEE_PROGRESS_BAR] = value;
}
/// <summary>Indicates that a Progress Bar should be displayed.</summary>
[DefaultValue(false)]
internal bool ShowProgressBar
{
get => flags[TASKDIALOG_FLAGS.TDF_SHOW_PROGRESS_BAR];
set => flags[TASKDIALOG_FLAGS.TDF_SHOW_PROGRESS_BAR] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the buttons specified in the Buttons member should be displayed as command links (using a standard task dialog
/// glyph) instead of push buttons. When using command links, all characters up to the first new line character in the ButtonText
/// member (of the TaskDialogButton
/// structure) will be treated as the command links main text, and the remainder will be treated as the command links note. This
/// flag is ignored if the Buttons member has no entires.
/// </summary>
[DefaultValue(false), Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
internal bool UseCommandLinks
{
get => flags[TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS];
set => flags[TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS] = value;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Indicates that the buttons specified in the Buttons member should be displayed as command links (without a glyph) instead of
/// push buttons. When using command links, all characters up to the first new line character in the ButtonText member (of the
/// TaskDialogButton structure) will be treated as the command links main text, and the remainder will be treated as the command
/// links note. This flag is ignored if the Buttons member has no entires.
/// </summary>
[DefaultValue(false), Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
internal bool UseCommandLinksNoIcon
{
get => flags[TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS_NO_ICON];
set => flags[TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS_NO_ICON] = value;
}
/// <summary>Gets or sets a value indicating whether this instance can raise events.</summary>
/// <value><c>true</c> if this instance can raise events; otherwise, <c>false</c>.</value>
protected override bool CanRaiseEvents => true;
/// <summary>
2020-04-02 23:59:18 -04:00
/// Displays a task dialog in front of the specified window and with the specified main instruction, content, caption, buttons, and icon.
/// </summary>
/// <param name="win32Window">An implementation of <see cref="IWin32Window"/> that will own the modal dialog box.</param>
/// <param name="mainInstruction">The text to display as the main instruction.</param>
/// <param name="content">The text to show as content below the main instruction. Value can be <c>null</c>.</param>
/// <param name="caption">The text to display in the title bar.</param>
2020-04-02 23:59:18 -04:00
/// <param name="buttons">
/// One or more of the <see cref="TaskDialogCommonButtons"/> values that specifies which buttons to display in the task dialog.
/// </param>
/// <param name="icon">One of the <see cref="TaskDialogIcon"/> values that specifies which icon to display in the task dialog.</param>
/// <returns>One of the <see cref="DialogResult"/> values.</returns>
public static int Show(IWin32Window win32Window, string mainInstruction, string content = null, string caption = "",
TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Ok, TaskDialogIcon icon = TaskDialogIcon.None)
{
if (mainInstruction == null) throw new ArgumentNullException(nameof(mainInstruction));
var dlg = new TaskDialog
{
MainInstruction = mainInstruction,
Content = content,
WindowTitle = caption,
CommonButtons = buttons,
MainIcon = icon
};
dlg.PrivateShow(win32Window?.Handle ?? IntPtr.Zero);
return dlg.Result.DialogResult;
}
2020-04-02 23:59:18 -04:00
/// <summary>
/// Displays a task dialog in front of the specified window and with the specified main instruction, content, caption, buttons, and icon.
/// </summary>
/// <param name="win32Window">An implementation of <see cref="IWin32Window"/> that will own the modal dialog box.</param>
/// <param name="mainInstruction">The text to display as the main instruction.</param>
/// <param name="content">The text to show as content below the main instruction. Value can be <c>null</c>.</param>
/// <param name="caption">The text to display in the title bar.</param>
/// <param name="radioButtons">Array of labels for radio buttons.</param>
2020-04-02 23:59:18 -04:00
/// <param name="buttons">
/// One or more of the <see cref="TaskDialogCommonButtons"/> values that specifies which buttons to display in the task dialog.
/// </param>
/// <param name="icon">One of the <see cref="TaskDialogIcon"/> values that specifies which icon to display in the task dialog.</param>
2020-04-02 23:59:18 -04:00
/// <returns>
/// The 1-based index of the selected radio button, or <c>0</c> if no radio button was selected or the task dialog was cancelled.
/// </returns>
public static int Show(IWin32Window win32Window, string mainInstruction, string content, string caption,
string[] radioButtons, TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Ok | TaskDialogCommonButtons.Cancel,
TaskDialogIcon icon = TaskDialogIcon.None)
{
if (mainInstruction == null) throw new ArgumentNullException(nameof(mainInstruction));
var dlg = new TaskDialog
{
MainInstruction = mainInstruction,
Content = content,
WindowTitle = caption,
CommonButtons = buttons,
MainIcon = icon
};
foreach (var s in radioButtons)
dlg.RadioButtons.Add(new TaskDialogRadioButton(s));
dlg.PrivateShow(win32Window?.Handle ?? IntPtr.Zero);
return dlg.RadioButtons.FindIndex(b => b.ButtonId == dlg.Result.SelectedRadioButton) + 1;
}
/// <summary>Displays a task dialog with the specified main instruction, content, caption, buttons, and icon.</summary>
/// <param name="mainInstruction">The text to display as the main instruction.</param>
/// <param name="content">The text to show as content below the main instruction. Value can be <c>null</c>.</param>
/// <param name="caption">The text to display in the title bar.</param>
2020-04-02 23:59:18 -04:00
/// <param name="buttons">
/// One or more of the <see cref="TaskDialogCommonButtons"/> values that specifies which buttons to display in the task dialog.
/// </param>
/// <param name="icon">One of the <see cref="TaskDialogIcon"/> values that specifies which icon to display in the task dialog.</param>
/// <returns>One of the <see cref="DialogResult"/> values.</returns>
public static int Show(string mainInstruction, string content = null, string caption = "",
TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Ok, TaskDialogIcon icon = TaskDialogIcon.None) =>
Show(null, mainInstruction, content, caption, buttons, icon);
2020-04-02 23:59:18 -04:00
/// <summary>
/// Displays a task dialog in front of the specified window and with the specified main instruction, caption, custom buttons, and icon.
/// </summary>
/// <param name="win32Window">An implementation of <see cref="IWin32Window"/> that will own the modal dialog box.</param>
/// <param name="mainInstruction">The text to display as the main instruction.</param>
/// <param name="caption">The text to display in the title bar.</param>
/// <param name="buttons">
2020-04-02 23:59:18 -04:00
/// One or more strings to display on separate Command Link buttons in the task dialog. To specify a secondary string within a
/// button string, include a line-feed "\n" character.
/// </param>
/// <param name="icon">One of the <see cref="TaskDialogIcon"/> values that specifies which icon to display in the task dialog.</param>
/// <returns>
2020-04-02 23:59:18 -04:00
/// The value of the button clicked starting with 101. Each subsequent button's id will increment by 1. (e.g. Three strings for
/// buttons would have the identifiers of 101, 102, and 103.).
/// </returns>
public static int Show(IWin32Window win32Window, string mainInstruction, string caption, string[] buttons,
TaskDialogIcon icon = TaskDialogIcon.None)
{
if (mainInstruction == null) throw new ArgumentNullException(nameof(mainInstruction));
if (buttons == null) throw new ArgumentNullException(nameof(buttons));
if (buttons.Length == 0)
throw new ArgumentException(@"At least one string must be supplied for the buttons.", nameof(buttons));
var dlg = new TaskDialog
{
MainInstruction = mainInstruction,
WindowTitle = caption,
CommonButtons = TaskDialogCommonButtons.Cancel,
ButtonDisplay = TaskDialogButtonDisplay.CommandLink,
MainIcon = icon
};
var id = 101;
foreach (var s in buttons) dlg.Buttons.Add(new TaskDialogButton(s, id++));
dlg.PrivateShow(win32Window?.Handle ?? IntPtr.Zero);
return dlg.Result.DialogResult;
}
/// <summary>Displays a task dialog with the specified main instruction, caption, custom buttons, and icon.</summary>
/// <param name="mainInstruction">The text to display as the main instruction.</param>
/// <param name="caption">The text to display in the title bar.</param>
/// <param name="buttons">
2020-04-02 23:59:18 -04:00
/// One or more strings to display on separate Command Link buttons in the task dialog. To specify a secondary string within a
/// button string, include a line-feed "\n" character.
/// </param>
/// <param name="icon">One of the <see cref="TaskDialogIcon"/> values that specifies which icon to display in the task dialog.</param>
/// <returns>
2020-04-02 23:59:18 -04:00
/// The value of the button clicked starting with 101. Each subsequent button's id will increment by 1. (e.g. Three strings for
/// buttons would have the identifiers of 101, 102, and 103.).
/// </returns>
public static int Show(string mainInstruction, string caption, string[] buttons,
TaskDialogIcon icon = TaskDialogIcon.None) =>
Show(null, mainInstruction, caption, buttons, icon);
/// <summary>
2020-04-02 23:59:18 -04:00
/// Simulate the action of a button click in the TaskDialog. This can be a DialogResult value or the ButtonID set on a
/// TasDialogButton set on TaskDialog.Buttons.
/// </summary>
/// <param name="buttonId">Indicates the button ID to be selected.</param>
/// <returns>If the function succeeds the return value is true.</returns>
// TDM_CLICK_BUTTON = WM_USER+102, // wParam = Button ID
public void PerformButtonClick(int buttonId)
{
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_CLICK_BUTTON, (IntPtr)buttonId, IntPtr.Zero);
}
/// <summary>Check or uncheck the verification checkbox in the TaskDialog.</summary>
/// <param name="checkedState">The checked state to set the verification checkbox.</param>
/// <param name="setKeyboardFocusToCheckBox">True to set the keyboard focus to the checkbox, and false otherwise.</param>
public void PerformVerificationClick(bool checkedState, bool setKeyboardFocusToCheckBox)
{
// TDM_CLICK_VERIFICATION = WM_USER+113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus)
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_CLICK_VERIFICATION, (checkedState ? new IntPtr(1) : IntPtr.Zero),
(setKeyboardFocusToCheckBox ? new IntPtr(1) : IntPtr.Zero));
}
/// <summary>Resets the Task Dialog to the state when first constructed, all properties set to their default value.</summary>
public override void Reset()
{
Buttons.Clear();
CollapsedControlText = null;
CommonButtons = 0;
Content = null;
CustomFooterIcon = null;
CustomMainIcon = null;
DefaultButton = 0;
DefaultRadioButton = 0;
ExpandedControlText = null;
ExpandedInformation = null;
flags = (TASKDIALOG_FLAGS)0;
Footer = null;
FooterIcon = TaskDialogIcon.None;
MainIcon = TaskDialogIcon.None;
MainInstruction = null;
ProgressBar.Reset();
RadioButtons.Clear();
VerificationText = null;
Width = 0;
WindowTitle = null;
}
internal static Image GetSmallImage(Icon icon)
{
if (icon == null) return null;
var sz = SystemInformation.SmallIconSize;
var bmp = new Bitmap(sz.Width, sz.Height);
using (var g = Graphics.FromImage(bmp))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(icon.ToBitmap(), new Rectangle(Point.Empty, sz));
}
return bmp;
}
internal static Icon IconFromTaskDialogIcon(TaskDialogIcon icon)
{
if (Environment.OSVersion.Version >= requiredOsVersion)
{
var ie = new ResourceFile(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "imageres.dll"));
switch (icon)
{
case TaskDialogIcon.None:
return null;
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.Warning:
return ie.GroupIcons[79];
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.Error:
return ie.GroupIcons[93];
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.Information:
return ie.GroupIcons[76];
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.SecurityWarning:
return ie.GroupIcons[102];
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.SecurityError:
return ie.GroupIcons[100];
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.SecuritySuccess:
return ie.GroupIcons[101];
2020-04-02 23:59:18 -04:00
default:
return ie.GroupIcons[73];
}
}
switch (icon)
{
case TaskDialogIcon.None:
return null;
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.Warning:
return SystemIcons.Warning;
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.Error:
return SystemIcons.Error;
2020-04-02 23:59:18 -04:00
case TaskDialogIcon.Information:
return SystemIcons.Information;
2020-04-02 23:59:18 -04:00
default:
return SystemIcons.Shield;
}
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Enable or disable a button in the TaskDialog. The passed buttonID is the ButtonID set on a TaskDialogButton set on
/// TaskDialog.Buttons or a common button ID.
/// </summary>
/// <param name="buttonId">Indicates the button ID to be enabled or disabled.</param>
/// <param name="enable">Enable the button if true. Disable the button if false.</param>
internal void EnableButton(int buttonId, bool enable)
{
// TDM_ENABLE_BUTTON = WM_USER+111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_ENABLE_BUTTON, (IntPtr)buttonId, (IntPtr)(enable ? 1 : 0));
}
2020-04-02 23:59:18 -04:00
/// <summary>
/// Enable or disable a radio button in the TaskDialog. The passed buttonID is the ButtonID set on a TaskDialogButton set on TaskDialog.RadioButtons.
/// </summary>
/// <param name="buttonId">Indicates the button ID to be enabled or disabled.</param>
/// <param name="enable">Enable the button if true. Disable the button if false.</param>
internal void EnableRadioButton(int buttonId, bool enable)
{
// TDM_ENABLE_RADIO_BUTTON = WM_USER+112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_ENABLE_RADIO_BUTTON, (IntPtr)buttonId, (IntPtr)(enable ? 1 : 0));
}
internal void InitializeButtonState()
{
foreach (var b in Buttons)
{
if (!b.Enabled)
EnableButton(b.ButtonId, false);
if (b.ElevatedStateRequired)
SetButtonElevationRequiredState(b.ButtonId, true);
}
}
/// <summary>Raises the <see cref="ButtonClicked"/> event.</summary>
/// <param name="id">The button identifier.</param>
/// <returns><c>true</c> to prevent close; otherwise, <c>false</c>. Ignored for radio buttons.</returns>
internal virtual bool OnButtonClicked(int id)
{
var btn = Buttons.Find(b => b.ButtonId == id);
var e = new ButtonClickedEventArgs(id, btn);
ButtonClicked?.Invoke(this, e);
btn?.OnClick(e);
return e.Cancel;
}
/// <summary>Raises the <see cref="Closed"/> event.</summary>
2018-10-26 14:24:07 -04:00
internal virtual void OnClosed() => Closed?.Invoke(this, EventArgs.Empty);
/// <summary>Called when the expando button is clicked and the dialog expands or contracts.</summary>
/// <param name="expanded"><c>true</c> if dialog is expanded; otherwise <c>false</c>.</param>
2018-10-26 14:24:07 -04:00
internal virtual void OnExpanded(bool expanded) => Expanded?.Invoke(this, new ExpandedEventArgs(expanded));
/// <summary>Raises the <see cref="LinkClicked"/> event.</summary>
/// <param name="url">The URL of the link.</param>
2018-10-26 14:24:07 -04:00
internal virtual void OnLinkClicked(string url) => LinkClicked?.Invoke(this, new LinkClickedEventArgs(url));
/// <summary>Raises the <see cref="Load"/> event.</summary>
2018-10-26 14:24:07 -04:00
internal virtual void OnLoad() => Load?.Invoke(this, EventArgs.Empty);
/// <summary>Raises the <see cref="RadioButtonClicked"/> event.</summary>
/// <param name="id">The radio button identifier.</param>
internal virtual void OnRadioButtonClicked(int id)
{
var btn = RadioButtons.Find(b => b.ButtonId == id);
RadioButtonClicked?.Invoke(this, new ButtonClickedEventArgs(id, btn));
btn?.OnClick(EventArgs.Empty);
}
/// <summary>Raises the <see cref="Timer"/> event.</summary>
/// <param name="ticks">The tick count.</param>
/// <returns><c>true</c> to reset tick count; otherwise, <c>false</c> to continue to increment.</returns>
internal virtual bool OnTimer(int ticks)
{
var a = new TimerEventArgs(ticks);
Timer?.Invoke(this, a);
return a.Reset;
}
/// <summary>Called when the verification check box is checked or unchecked.</summary>
/// <param name="verificationChecked"><c>true</c> if check box is checked; otherwise <c>false</c>.</param>
2018-10-26 14:24:07 -04:00
internal virtual void OnVerificationClicked(bool verificationChecked) => VerificationClicked?.Invoke(this, new VerificationClickedEventArgs(verificationChecked));
/// <summary>
2020-04-02 23:59:18 -04:00
/// Simulate the action of a radio button click in the TaskDialog. The passed buttonID is the ButtonID set on a TaskDialogButton set
/// on TaskDialog.RadioButtons.
/// </summary>
/// <param name="buttonId">Indicates the button ID to be selected.</param>
internal void PerformRadioButtonClick(int buttonId)
{
// TDM_CLICK_RADIO_BUTTON = WM_USER+110, // wParam = Radio Button ID
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_CLICK_RADIO_BUTTON, (IntPtr)buttonId, IntPtr.Zero);
}
/// <summary>Designate whether a given Task Dialog button or command link should have a User Account Control (UAC) shield icon.</summary>
/// <param name="buttonId">ID of the push button or command link to be updated.</param>
/// <param name="elevationRequired">
2020-04-02 23:59:18 -04:00
/// False to designate that the action invoked by the button does not require elevation; true to designate that the action does
/// require elevation.
/// </param>
internal void SetButtonElevationRequiredState(int buttonId, bool elevationRequired)
{
2020-04-02 23:59:18 -04:00
// TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER+115, // wParam = Button ID, lParam = 0 (elevation not required), lParam !=
// 0 (elevation required)
2018-10-26 14:24:07 -04:00
if (!handle.IsNull)
SendMessage(handle, (uint)TaskDialogMessage.TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, (IntPtr)buttonId,
(IntPtr)(elevationRequired ? 1 : 0));
}
2020-04-02 23:59:18 -04:00
/// <summary>
/// Defines the common dialog box hook procedure that is overridden to add specific functionality to a common dialog box.
/// </summary>
/// <param name="hWnd">The handle to the dialog box window.</param>
/// <param name="msg">The message being received.</param>
/// <param name="wparam">Additional information about the message.</param>
/// <param name="lparam">Additional information about the message.</param>
/// <returns>
2020-04-02 23:59:18 -04:00
/// A zero value if the default dialog box procedure processes the message; a nonzero value if the default dialog box procedure
/// ignores the message.
/// </returns>
protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
{
//ActiveTaskDialog activeDialog = new ActiveTaskDialog(hWnd);
handle = hWnd;
switch ((TaskDialogNotification)msg)
{
case TaskDialogNotification.TDN_CREATED:
ProgressBar.Initialize();
InitializeButtonState();
OnLoad();
break;
case TaskDialogNotification.TDN_BUTTON_CLICKED:
return (IntPtr)(OnButtonClicked((int)wparam) ? 1 : 0);
case TaskDialogNotification.TDN_RADIO_BUTTON_CLICKED:
OnRadioButtonClicked((int)wparam);
break;
case TaskDialogNotification.TDN_HELP:
OnHelpRequest(EventArgs.Empty);
break;
case TaskDialogNotification.TDN_HYPERLINK_CLICKED:
OnLinkClicked(Marshal.PtrToStringUni(lparam));
break;
case TaskDialogNotification.TDN_TIMER:
return (IntPtr)(OnTimer((int)wparam) ? 1 : 0);
case TaskDialogNotification.TDN_VERIFICATION_CLICKED:
OnVerificationClicked(wparam != IntPtr.Zero);
break;
case TaskDialogNotification.TDN_EXPANDO_BUTTON_CLICKED:
OnExpanded(wparam != IntPtr.Zero);
break;
case TaskDialogNotification.TDN_DESTROYED:
OnClosed();
handle = IntPtr.Zero;
break;
}
return base.HookProc(hWnd, msg, wparam, lparam);
}
/// <summary>The required implementation of CommonDialog that shows the Task Dialog.</summary>
/// <param name="hwndOwner">Owner window. This can be null.</param>
/// <returns>
2020-04-02 23:59:18 -04:00
/// If this method returns true, then ShowDialog will return DialogResult.OK. If this method returns false, then ShowDialog will
/// return DialogResult.Cancel. The user of this class must use the TaskDialogResult member to get more information.
/// </returns>
protected override bool RunDialog(IntPtr hwndOwner)
{
var res = PrivateShow(hwndOwner);
return (res.DialogResult != (int)DialogResult.Cancel);
}
/// <summary>The callback from the native Task Dialog. This prepares the friendlier arguments and calls the simpler callback.</summary>
/// <param name="hwnd">The window handle of the Task Dialog that is active.</param>
/// <param name="msg">The notification. A TaskDialogNotification value.</param>
2020-04-02 23:59:18 -04:00
/// <param name="wparam">
/// Specifies additional notification information. The contents of this parameter depends on the value of the msg parameter.
/// </param>
/// <param name="lparam">
/// Specifies additional notification information. The contents of this parameter depends on the value of the msg parameter.
/// </param>
/// <param name="refData">Specifies the application-defined value given in the call to TaskDialogIndirect.</param>
/// <returns>A HRESULT. It's not clear in the spec what a failed result will do.</returns>
2018-10-26 14:24:07 -04:00
private HRESULT PrivateCallback([In] HWND hwnd, [In] TaskDialogNotification msg, [In] IntPtr wparam, [In] IntPtr lparam,
[In] IntPtr refData) => HookProc((IntPtr)hwnd, (int)msg, wparam, lparam).ToInt32();
/// <summary>
2020-04-02 23:59:18 -04:00
/// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, verification check
/// box, command links and push buttons, plus any combination of predefined icons and push buttons as specified on the other members
/// of the class before calling Show.
/// </summary>
/// <param name="hwndOwner">Owner window the task Dialog will modal to.</param>
/// <returns>The set of results of the dialog.</returns>
2018-10-26 14:24:07 -04:00
private TaskDialogResult PrivateShow(HWND hwndOwner)
{
if (!IsAvailable)
{
#if TASKDIALOG_EMULATE
// Hand it off to emulator.
using (var taskDialogEmulate = new EmulateTaskDialog(this))
{
taskDialogEmulate.HandleCreated += (s, e) => handle = taskDialogEmulate.Handle;
taskDialogEmulate.ShowDialog();
handle = IntPtr.Zero;
Result = new TaskDialogResult(taskDialogEmulate.TaskDialogResult,
taskDialogEmulate.TaskDialogVerificationFlagChecked, taskDialogEmulate.TaskDialogRadioButtonResult);
}
return Result;
#else
throw new PlatformNotSupportedException("TaskDialog requires Windows Vista or later.");
#endif
}
var config = new TASKDIALOGCONFIG
{
hwndParent = hwndOwner,
dwFlags = flags,
dwCommonButtons = (TASKDIALOG_COMMON_BUTTON_FLAGS)CommonButtons
};
if (!string.IsNullOrEmpty(WindowTitle))
config.WindowTitle = WindowTitle;
if (CustomMainIcon != null)
{
config.dwFlags |= TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN;
config.mainIcon = CustomMainIcon.Handle;
}
else
config.mainIcon = (IntPtr)MainIcon;
if (!string.IsNullOrEmpty(MainInstruction))
config.MainInstruction = MainInstruction;
if (!string.IsNullOrEmpty(Content))
config.Content = Content;
foreach (var b in Buttons) b.parent = this;
config.pButtons = (IntPtr)Buttons;
config.cButtons = (uint)Buttons.Count;
config.nDefaultButton = DefaultButton;
foreach (var b in RadioButtons) b.parent = this;
config.pRadioButtons = (IntPtr)RadioButtons;
config.cRadioButtons = (uint)RadioButtons.Count;
config.nDefaultRadioButton = DefaultRadioButton;
if (!string.IsNullOrEmpty(VerificationText))
config.VerificationText = VerificationText;
if (!string.IsNullOrEmpty(ExpandedInformation))
config.ExpandedInformation = ExpandedInformation;
if (!string.IsNullOrEmpty(ExpandedControlText))
config.ExpandedControlText = ExpandedControlText;
if (!string.IsNullOrEmpty(CollapsedControlText))
config.CollapsedControlText = CollapsedControlText;
config.footerIcon = (IntPtr)FooterIcon;
if (CustomFooterIcon != null)
{
config.dwFlags |= TASKDIALOG_FLAGS.TDF_USE_HICON_FOOTER;
config.footerIcon = CustomFooterIcon.Handle;
}
else
config.footerIcon = (IntPtr)FooterIcon;
if (!string.IsNullOrEmpty(Footer))
config.Footer = Footer;
config.pfCallbackProc = PrivateCallback;
config.cxWidth = (uint)Width;
// Check to see if a button of some kind is defined, otherwise set to OK button.
if (config.dwCommonButtons == 0 && config.cButtons == 0)
config.dwCommonButtons = TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_OK_BUTTON;
using (new ComCtl32v6Context())
{
TaskDialogResult res;
TaskDialogIndirect(config, out res.dialogResult, out res.selectedRadioButton, out res.verificationFlagChecked).ThrowIfFailed();
Result = res;
}
return Result;
}
//private bool ShouldSerializeProgressBar() { return ProgressBar != TaskDialogProgressBar.Default; }
/// <summary>Results from running the <see cref="TaskDialog"/>.</summary>
public struct TaskDialogResult
{
internal int dialogResult, selectedRadioButton;
internal bool verificationFlagChecked;
internal TaskDialogResult(int result, bool verCheck, int selRadio)
{
dialogResult = result;
verificationFlagChecked = verCheck;
selectedRadioButton = selRadio;
}
/// <summary>
2020-04-02 23:59:18 -04:00
/// Gets the dialog result. This is the value of one of the <see cref="TaskDialogCommonButtons"/> enumerate type or the ID of a
/// <see cref="TaskDialogButton"/> that has been clicked.
/// </summary>
/// <value>The task dialog result.</value>
public int DialogResult => dialogResult;
/// <summary>If a radio button was supplied and selected, gets the value of the selected radio button's identifier.</summary>
2020-04-02 23:59:18 -04:00
/// <value>
/// The selected radio button id. A value of <c>0</c> indicates that no radio button was selected or the task dialog was cancelled.
/// </value>
public int SelectedRadioButton => selectedRadioButton;
/// <summary>Gets a value indicating whether the verification flag was checked.</summary>
/// <value><c>true</c> if verification flag checked; otherwise, <c>false</c>.</value>
public bool VerificationFlagChecked => verificationFlagChecked;
/// <summary>Returns a <see cref="string"/> that represents this instance.</summary>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
public override string ToString()
=> $"{dialogResult} : {(verificationFlagChecked ? "checked" : "unchecked")} : {selectedRadioButton}";
}
/// <summary>Provides data for the <see cref="ButtonClicked"/> and the <see cref="RadioButtonClicked"/> events.</summary>
public class ButtonClickedEventArgs : CancelEventArgs
{
2020-04-02 23:59:18 -04:00
internal ButtonClickedEventArgs(int id, TaskDialogButtonBase button)
{
ButtonId = id; Button = button;
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets the button that was clicked.</summary>
/// <value>The button.</value>
public TaskDialogButtonBase Button { get; }
/// <summary>Gets the id of the button clicked.</summary>
/// <value>The button id.</value>
public int ButtonId { get; }
}
/// <summary>Provides data for the <see cref="Expanded"/> event.</summary>
public class ExpandedEventArgs : EventArgs
{
2018-10-26 14:24:07 -04:00
internal ExpandedEventArgs(bool exp) => Expanded = exp;
/// <summary>Gets a value indicating whether the <see cref="TaskDialog"/> is expanded.</summary>
/// <value><c>true</c> if expanded; otherwise, <c>false</c>.</value>
public bool Expanded { get; }
}
/// <summary>A custom button for the TaskDialog.</summary>
[DefaultEvent("Clicked"), DefaultProperty("ButtonId")]
public abstract class TaskDialogButtonBase : IEquatable<TaskDialogButtonBase>
{
internal static int idSeed = 101;
internal TASKDIALOG_BUTTON nativeButton;
internal TaskDialog parent;
/// <summary>Initializes a new instance of the <see cref="TaskDialogButtonBase"/> class.</summary>
protected TaskDialogButtonBase() : this(null) { }
/// <summary>Initialize the custom button.</summary>
/// <param name="id">
2020-04-02 23:59:18 -04:00
/// The ID of the button. This value is returned by TaskDialog.Show when the button is clicked. Typically this will be a value
/// in the DialogResult enum.
/// </param>
/// <param name="text">The string that appears on the button.</param>
protected TaskDialogButtonBase(string text, int id = -1)
{
if (id == -1) id = idSeed++;
nativeButton.buttonId = id;
nativeButton.buttonText = text;
}
/// <summary>The ID of the button. This value is returned by TaskDialog.Show when the button is clicked.</summary>
[DefaultValue(0)]
[Category("Behavior"), Description("")]
public int ButtonId
{
get => nativeButton.buttonId; set => nativeButton.buttonId = value;
}
/// <summary>The string that appears on the button.</summary>
[DefaultValue(null), Localizable(true),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
[Category("Appearance"), Description("")]
public string ButtonText
{
get => nativeButton.buttonText; set => nativeButton.buttonText = value;
}
/// <summary>Gets or sets a value indicating whether this <see cref="TaskDialogButtonBase"/> is enabled.</summary>
/// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
[DefaultValue(true)]
[Category("Appearance"), Description("")]
public virtual bool Enabled { get; set; } = true;
/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
2018-10-26 14:24:07 -04:00
public override bool Equals(object obj) => obj is TaskDialogButtonBase bb ? Equals(bb) : base.Equals(obj);
/// <summary>Determines whether the specified <see cref="TaskDialogButtonBase"/>, is equal to this instance.</summary>
/// <param name="other">The <see cref="TaskDialogButtonBase"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="TaskDialogButtonBase"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(TaskDialogButtonBase other)
=> other.nativeButton.buttonId == nativeButton.buttonId && other.nativeButton.buttonText == nativeButton.buttonText;
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode() => new { a = ButtonId, b = ButtonText }.GetHashCode();
/// <summary>Returns a <see cref="string"/> that represents this instance.</summary>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
public override string ToString() => $"{ButtonText} ({ButtonId})";
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
// Would be unused code as not required for usage.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
internal struct TASKDIALOG_BUTTON
{
/// <summary>The ID of the button. This value is returned by TaskDialog.Show when the button is clicked.</summary>
public int buttonId;
/// <summary>The string that appears on the button.</summary>
[MarshalAs(UnmanagedType.LPWStr)] public string buttonText;
}
}
/// <summary>A collection of <see cref="TaskDialogButton"/> elements.</summary>
public class TaskDialogButtonCollection<T> : List<T>, IDisposable where T : TaskDialogButtonBase
{
private const int hashSeed = 17;
private IntPtr ptr = IntPtr.Zero;
private int ptrHash = hashSeed;
/// <summary>Initializes a new instance of the <see cref="TaskDialogButtonCollection{T}"/> class.</summary>
internal TaskDialogButtonCollection() { }
/// <summary>Explicitly converts the <see cref="TaskDialogButtonCollection{T}"/> to an in-memory array.</summary>
/// <param name="c">The <see cref="TaskDialogButtonCollection{T}"/> instance.</param>
/// <returns>
2020-04-02 23:59:18 -04:00
/// An IntPtr pointing to a marshaled memory pointer of the array created with AllocHGlobal. This does not need to be freed as
/// the class maintains it.
/// </returns>
public static explicit operator IntPtr(TaskDialogButtonCollection<T> c)
{
// Get hash for set
var h = hashSeed;
unchecked
{
foreach (var item in c)
h = h * 23 + item.GetHashCode();
}
// If new has doesn't equal old hash, reset IntPtr
if (h != c.ptrHash)
{
// Clean up old array
((IDisposable)c).Dispose();
// Build new
c.ptr = c.Select(b => b.nativeButton).MarshalToPtr<TaskDialogButtonBase.TASKDIALOG_BUTTON>(Marshal.AllocHGlobal, out var _);
// Set hash to new value
c.ptrHash = h;
}
return c.ptr;
}
/// <summary>Clears this instance.</summary>
public new void Clear()
{
base.Clear();
((IDisposable)this).Dispose();
}
/// <summary>Releases unmanaged and managed resources.</summary>
void IDisposable.Dispose()
{
if (ptr == IntPtr.Zero) return;
lock (this)
{
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
ptrHash = hashSeed;
}
}
}
2020-04-02 23:59:18 -04:00
/// <summary>Represents the progress bar that can be displayed in a task dialog.</summary>
[TypeConverter(typeof(BetterExpandableObjectConverter)), Serializable]
public class TaskDialogProgressBar
{
private readonly TaskDialog taskDialog;
private short max = 100, min;
private int mSpeed = 100, val;
private ProgressBarState state = ProgressBarState.Normal;
private ProgressBarStyle style = ProgressBarStyle.Continuous;
2018-10-26 14:24:07 -04:00
internal TaskDialogProgressBar(TaskDialog td) => taskDialog = td;
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets the marquee animation speed.</summary>
/// <value>The marquee animation speed.</value>
[DefaultValue(100)]
public int MarqueeAnimationSpeed
{
get => mSpeed; set { if (mSpeed != value) SetMarqueeSpeed(mSpeed = value); }
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets the maximum progress value.</summary>
/// <value>The maximum.</value>
[DefaultValue((short)100)]
public short Maximum
{
get => max; set
{
if (max == value) return;
max = value;
SetProgressBarRange();
}
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets the minimum progress value.</summary>
/// <value>The minimum.</value>
[DefaultValue((short)0)]
public short Minimum
{
get => min; set
{
if (min == value) return;
min = value;
SetProgressBarRange();
}
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets the current state of the progress bar.</summary>
/// <value>The state.</value>
[DefaultValue(typeof(ProgressBarState), "Normal")]
public ProgressBarState State
{
get => state; set { if (state != value) SetState(state = value); }
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets the style of the progress bar.</summary>
/// <value>The style.</value>
/// <exception cref="System.NotSupportedException">TaskDialog does not support Block style progress bars.</exception>
[DefaultValue(typeof(ProgressBarStyle), "Continuous")]
public ProgressBarStyle Style
{
get => style; set
{
if (style != value)
{
if (value == ProgressBarStyle.Blocks)
throw new NotSupportedException("TaskDialog does not support Block style progress bars.");
style = value;
if (taskDialog == null) return;
var cont = (style == ProgressBarStyle.Continuous);
taskDialog.ShowProgressBar = cont;
taskDialog.ShowMarqueeProgressBar = !cont;
2018-10-26 14:24:07 -04:00
if (taskDialog.Handle != IntPtr.Zero)
SendMessage(taskDialog.handle, (uint)TaskDialogMessage.TDM_SET_MARQUEE_PROGRESS_BAR,
(value == ProgressBarStyle.Marquee ? (IntPtr)1 : IntPtr.Zero), IntPtr.Zero);
}
}
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets the value of the progress bar.</summary>
/// <value>The value.</value>
[DefaultValue(0)]
public int Value
{
get => val; set { if (val != value) SetValue(val = value); }
}
2020-04-02 23:59:18 -04:00
/// <summary>Gets or sets a value indicating whether this <see cref="TaskDialogProgressBar"/> is visible.</summary>
/// <value><see langword="true"/> if visible; otherwise, <see langword="false"/>.</value>
[DefaultValue(false)]
public bool Visible
{
get => taskDialog != null && (taskDialog.ShowProgressBar || taskDialog.ShowMarqueeProgressBar); set
{
if (!value || taskDialog == null) return;
if (style == ProgressBarStyle.Continuous)
taskDialog.ShowProgressBar = true;
else
taskDialog.ShowMarqueeProgressBar = true;
}
}
internal void Initialize()
{
if (Visible)
{
if (Style == ProgressBarStyle.Marquee)
{
SetMarqueeSpeed(mSpeed);
}
else
{
SetProgressBarRange();
SetValue(val);
}
SetState(state);
}
}
internal void Reset()
{
mSpeed = max = 100;
val = min = 0;
state = ProgressBarState.Normal;
style = ProgressBarStyle.Continuous;
}
private static uint MakeLong(short low, short high) => ((ushort)low | (uint)(high << 16));
private void SetMarqueeSpeed(int value)
{
2018-10-26 14:24:07 -04:00
if (taskDialog != null && taskDialog.Handle != IntPtr.Zero)
SendMessage(taskDialog.handle, (uint)TaskDialogMessage.TDM_SET_PROGRESS_BAR_MARQUEE, (IntPtr)(value != 0 ? 1 : 0), (IntPtr)value);
}
private void SetProgressBarRange()
{
2018-10-26 14:24:07 -04:00
if (taskDialog != null && taskDialog.Handle != IntPtr.Zero)
SendMessage(taskDialog.handle, (uint)TaskDialogMessage.TDM_SET_PROGRESS_BAR_RANGE, IntPtr.Zero, (IntPtr)MakeLong(min, max));
}
private void SetState(ProgressBarState value)
{
2018-10-26 14:24:07 -04:00
if (taskDialog != null && taskDialog.Handle != IntPtr.Zero)
SendMessage(taskDialog.handle, (uint)TaskDialogMessage.TDM_SET_PROGRESS_BAR_STATE, (IntPtr)value, IntPtr.Zero);
}
private void SetValue(int value)
{
2018-10-26 14:24:07 -04:00
if (taskDialog != null && taskDialog.Handle != IntPtr.Zero)
SendMessage(taskDialog.handle, (uint)TaskDialogMessage.TDM_SET_PROGRESS_BAR_POS, (IntPtr)value, IntPtr.Zero);
}
}
/// <summary>Provides data for the <see cref="Timer"/> event.</summary>
public class TimerEventArgs : EventArgs
{
2018-10-26 14:24:07 -04:00
internal TimerEventArgs(int ticks) => TickCount = ticks;
/// <summary>Gets or sets a value indicating whether to reset the tick count.</summary>
/// <value><c>true</c> to reset tick count; otherwise, <c>false</c> to continue to increment.</value>
public bool Reset { get; set; } = false;
/// <summary>Gets the tick count for this instance of the <see cref="TaskDialog"/>.</summary>
/// <value>The tick count.</value>
public int TickCount { get; }
}
/// <summary>Provides data for the <see cref="VerificationClicked"/> event.</summary>
public class VerificationClickedEventArgs : EventArgs
{
2018-10-26 14:24:07 -04:00
internal VerificationClickedEventArgs(bool check) => Checked = check;
/// <summary>Gets a value indicating whether the verification check box is checked.</summary>
/// <value><c>true</c> if checked; otherwise, <c>false</c>.</value>
public bool Checked { get; }
}
}
2020-04-02 23:59:18 -04:00
/// <summary>Represents a button on a task dialog.</summary>
/// <seealso cref="Vanara.Windows.Forms.TaskDialog.TaskDialogButtonBase"/>
public class TaskDialogButton : TaskDialog.TaskDialogButtonBase
{
private bool shield;
/// <summary>Initializes a new instance of the <see cref="TaskDialogButton"/> class.</summary>
public TaskDialogButton() : this(null) { }
/// <summary>Initialize the custom button.</summary>
/// <param name="text">The string that appears on the button.</param>
/// <param name="id">
2020-04-02 23:59:18 -04:00
/// The ID of the button. This value is returned by TaskDialog.Show when the button is clicked. Typically this will be a value in
/// the DialogResult enum. Specifying a value of (-1) will insert a potentially non-unique value.
/// </param>
public TaskDialogButton(string text, int id = -1) : base(text, id)
{
if (ButtonText == null) ButtonText = $"Button{ButtonId}";
}
/// <summary>Occurs when the button is clicked.</summary>
[Category("Action"), Description("")]
public event CancelEventHandler Click;
/// <summary>
/// Gets or sets a value indicating whether to close the <see cref="TaskDialog"/> on click and returns this button's <see
/// cref="TaskDialog.TaskDialogButtonBase.ButtonId"/> as the result.
/// </summary>
/// <value><c>true</c> if dialog closes on click; otherwise, <c>false</c>.</value>
[DefaultValue(true)]
[Category("Behavior"), Description("")]
public bool CloseOnClick { get; set; } = true;
/// <summary>Gets or sets a value indicating whether button shows elevated state shield.</summary>
/// <value><c>true</c> if elevated state shield displayed; otherwise, <c>false</c>.</value>
[DefaultValue(false)]
[Category("Appearance"), Description("")]
public bool ElevatedStateRequired
{
2020-04-02 23:59:18 -04:00
get => shield;
set
{
if (shield != value)
{
parent?.SetButtonElevationRequiredState(ButtonId, value);
shield = value;
}
}
}
/// <summary>Gets or sets a value indicating whether this <see cref="TaskDialogButton"/> is enabled.</summary>
/// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
[DefaultValue(true)]
public override bool Enabled
{
get => base.Enabled; set
{
if (base.Enabled != value)
{
parent?.EnableButton(ButtonId, value);
base.Enabled = value;
}
}
}
/// <summary>Raises the <see cref="E:Click"/> event.</summary>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
public void OnClick(CancelEventArgs e)
{
e.Cancel = !CloseOnClick;
Click?.Invoke(this, e);
}
/// <summary>Generates a <see cref="Click"/> event for the button.</summary>
public void PerformClick() => parent?.PerformButtonClick(ButtonId);
}
2020-04-02 23:59:18 -04:00
/// <summary>Represents a radio button on a task dialog.</summary>
/// <seealso cref="Vanara.Windows.Forms.TaskDialog.TaskDialogButtonBase"/>
public class TaskDialogRadioButton : TaskDialog.TaskDialogButtonBase
{
/// <summary>Initializes a new instance of the <see cref="TaskDialogButton"/> class.</summary>
public TaskDialogRadioButton() : this(null) { }
/// <summary>Initialize the custom radio button.</summary>
/// <param name="text">The string that appears on the radio button.</param>
/// <param name="id">
2020-04-02 23:59:18 -04:00
/// The ID of the readio button. This value is returned by TaskDialog.Show when the button is clicked. Specifying a value of (-1)
/// will insert a potentially non-unique value.
/// </param>
public TaskDialogRadioButton(string text, int id = -1) : base(text, id)
{
if (ButtonText == null) ButtonText = $"RadioButton{ButtonId}";
}
/// <summary>Occurs when the radio button is clicked.</summary>
public event EventHandler Click;
/// <summary>Gets or sets a value indicating whether this <see cref="TaskDialogRadioButton"/> is enabled.</summary>
/// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
[DefaultValue(true)]
public override bool Enabled
{
get => base.Enabled; set
{
if (base.Enabled != value)
{
parent?.EnableRadioButton(ButtonId, value);
base.Enabled = value;
}
}
}
/// <summary>Raises the <see cref="E:Click"/> event.</summary>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
2018-10-26 14:24:07 -04:00
public void OnClick(EventArgs e) => Click?.Invoke(this, e);
/// <summary>Generates a <see cref="Click"/> event for the button.</summary>
2018-10-26 14:24:07 -04:00
public void PerformClick() => parent?.PerformRadioButtonClick(ButtonId);
}
}