mirror of https://github.com/dahall/Vanara.git
248 lines
10 KiB
C#
248 lines
10 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
using Vanara.Extensions;
|
|
using static Vanara.PInvoke.Shell32;
|
|
|
|
namespace Vanara.Windows.Forms
|
|
{
|
|
/// <summary>Display style for a <see cref="ShellProgressDialog"/>.</summary>
|
|
public enum ShellProgressDialogStyle
|
|
{
|
|
/// <summary>Displays a progress bar that tracks to the progress values.</summary>
|
|
Normal,
|
|
|
|
/// <summary>
|
|
/// Sets the progress bar to marquee mode. Use this when you wish to indicate that progress is being made, but the time required for
|
|
/// the operation is unknown.
|
|
/// </summary>
|
|
Marquee,
|
|
|
|
/// <summary>
|
|
/// Do not display a progress bar. Typically, an application can quantitatively determine how much of the operation remains and
|
|
/// periodically pass that value to <c>UpdateProgress</c>. The progress dialog box uses this information to
|
|
/// update its progress bar. This flag is typically set when the calling application must wait for an operation to finish, but does
|
|
/// not have any quantitative information it can use to update the dialog box.
|
|
/// </summary>
|
|
Hidden
|
|
}
|
|
|
|
/// <summary>
|
|
/// Wrapper for IProgressDialog which displays a system progress dialog. This object is a generic way to show a user how an operation is
|
|
/// progressing. It is typically used when deleting, uploading, copying, moving, or downloading large numbers of files. The dialog is shown
|
|
/// on a separate thread and will not block operations in the current thread.
|
|
/// </summary>
|
|
/// <example>This is an example of how to use ShellProgressDialog.
|
|
/// <code>
|
|
/// private void button1_Click(object sender, System.EventArgs e)
|
|
/// {
|
|
/// var dlg = new ShellProgressDialog
|
|
/// {
|
|
/// AutoTimeEstimation = true,
|
|
/// CancelMessage = "Canceling. Please wait...",
|
|
/// Description = "Processing application...",
|
|
/// Title = "MyApp - Long Process"
|
|
/// };
|
|
/// dlg.Start(this);
|
|
/// for (int i = 0; i < steps.Count; i++)
|
|
/// {
|
|
/// dlg.Detail = steps[i].Text;
|
|
/// steps[1].Action.Invoke();
|
|
/// dlg.UpdateProgress(i + 1, steps.Count);
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </example>
|
|
public class ShellProgressDialog : Component
|
|
{
|
|
private string cancelMsg;
|
|
private bool closed = true;
|
|
private string description;
|
|
private string detail;
|
|
private EnumFlagIndexer<PROGDLG> flags;
|
|
private IProgressDialog iDlg;
|
|
private string title = string.Empty;
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ShellProgressDialog"/> class.</summary>
|
|
public ShellProgressDialog()
|
|
{
|
|
iDlg = new IProgressDialog();
|
|
}
|
|
|
|
/// <summary> Gets or sets a value indicating whether to automatically estimate the remaining time and display it.</summary>
|
|
[DefaultValue(false), Category("Behavior"), Description("Automatically estimate the remaining time and display it.")]
|
|
public bool AutoTimeEstimation { get => flags[PROGDLG.PROGDLG_AUTOTIME]; set => flags[PROGDLG.PROGDLG_AUTOTIME] = value; }
|
|
|
|
/// <summary>Gets or sets a message to be displayed if the user cancels the operation.</summary>
|
|
/// <remarks>
|
|
/// Even though the user clicks Cancel, the application cannot immediately call <see cref="Stop"/> to close the dialog box. The
|
|
/// application must wait until the next time it read <see cref="IsCancelled"/> to discover that the user has canceled the operation.
|
|
/// Since this delay might be significant, the progress dialog box provides the user with immediate feedback by clearing the
|
|
/// description and detail lines and displaying this cancel message. The message is intended to let the user know that the delay is
|
|
/// normal and that the progress dialog box will be closed shortly. It is typically is set to something like "Please wait while ...".
|
|
/// </remarks>
|
|
[DefaultValue(null), Category("Appearance"), Description("Message to be displayed if the user cancels the operation.")]
|
|
public string CancelMessage
|
|
{
|
|
get => cancelMsg;
|
|
set
|
|
{
|
|
if (cancelMsg == value) return;
|
|
iDlg.SetCancelMsg(cancelMsg = value);
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets a value indicating whether to compact displayed strings if they are too large to fit on a line.</summary>
|
|
/// <value><see langword="true"/> to have path strings compacted if they are too large to fit on a line.</value>
|
|
[DefaultValue(false), Category("Appearance"), Description("Compact displayed strings if they are too large to fit on a line.")]
|
|
public bool CompactStrings { get; set; }
|
|
|
|
/// <summary>Gets or sets the description that appears on the first line.</summary>
|
|
/// <value>The description.</value>
|
|
[DefaultValue(null), Category("Appearance"), Description("Description that appears on the first line.")]
|
|
public string Description
|
|
{
|
|
get => description;
|
|
set
|
|
{
|
|
if (description == value) return;
|
|
iDlg.SetLine(1, description = value, CompactStrings);
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets the detail that appears on the second line.</summary>
|
|
/// <value>The detail.</value>
|
|
[DefaultValue(null), Category("Appearance"), Description("Detail text that appears on the second line.")]
|
|
public string Detail
|
|
{
|
|
get => detail;
|
|
set
|
|
{
|
|
if (detail == value) return;
|
|
iDlg.SetLine(2, detail = value, CompactStrings);
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets a value indicating whether to show the "time remaining" text.</summary>
|
|
/// <value>Show the "time remaining" text.</value>
|
|
[DefaultValue(false), Category("Appearance"), Description("Show the \"time remaining\" text.")]
|
|
public bool HideTimeRemaining { get => flags[PROGDLG.PROGDLG_NOTIME]; set => flags[PROGDLG.PROGDLG_NOTIME] = value; }
|
|
|
|
/// <summary>Checks whether the user has canceled the operation.</summary>
|
|
/// <returns><see langword="true"/> if the user has canceled the operation; otherwise, <see langword="false"/>.</returns>
|
|
/// <remarks>
|
|
/// The system does not send a message to the component when the user clicks the Cancel button. You must periodically use this
|
|
/// function to poll the progress dialog box object to determine whether the operation has been canceled.
|
|
/// </remarks>
|
|
[Browsable(false)]
|
|
public bool IsCancelled => iDlg.HasUserCancelled();
|
|
|
|
/// <summary>Gets or sets a value indicating whether the Minimize button is displayed in the caption bar of the progress dialog.</summary>
|
|
/// <value>
|
|
/// <see langword="true"/> to display a Minimize button for the dialog; otherwise, <see langword="false"/>. The default is <see langword="true"/>.
|
|
/// </value>
|
|
[DefaultValue(true), Category("Appearance"), Description("Show the Minimize button in the caption bar")]
|
|
public bool MinimizeBox { get => !flags[PROGDLG.PROGDLG_NOMINIMIZE]; set => flags[PROGDLG.PROGDLG_NOMINIMIZE] = !value; }
|
|
|
|
/// <summary>Gets a value indicating whether this form is displayed modally.</summary>
|
|
/// <value><see langword="true"/> if the form is displayed modally; otherwise, <see langword="false"/>.</value>
|
|
[DefaultValue(false), Category("Appearance"), Description("Display this form is modally.")]
|
|
public bool Modal { get => flags[PROGDLG.PROGDLG_MODAL]; set => flags[PROGDLG.PROGDLG_MODAL] = value; }
|
|
|
|
/// <summary>Gets or sets a value indicating whether a Cancel button is displayed on the progress dialog.</summary>
|
|
/// <value>
|
|
/// <see langword="true"/> to display a Cancel button on the progress dialog; otherwise, <see langword="false"/>. The default is <see langword="true"/>.
|
|
/// </value>
|
|
[DefaultValue(true), Category("Appearance"), Description("Display the Cancel button.")]
|
|
public bool ShowCancelButton { get => !flags[PROGDLG.PROGDLG_NOCANCEL]; set => flags[PROGDLG.PROGDLG_NOCANCEL] = !value; }
|
|
|
|
/// <summary>Gets or sets the style of the progress bar on the progress dialog.</summary>
|
|
/// <value>The style of the progress bar.</value>
|
|
[DefaultValue(ShellProgressDialogStyle.Normal), Category("Appearance"), Description("Progress bar style.")]
|
|
public ShellProgressDialogStyle Style
|
|
{
|
|
get => flags[PROGDLG.PROGDLG_NOPROGRESSBAR] ? ShellProgressDialogStyle.Hidden : (flags[PROGDLG.PROGDLG_MARQUEEPROGRESS] ? ShellProgressDialogStyle.Marquee : ShellProgressDialogStyle.Normal);
|
|
set
|
|
{
|
|
switch (value)
|
|
{
|
|
case ShellProgressDialogStyle.Normal:
|
|
flags[PROGDLG.PROGDLG_NOPROGRESSBAR] = false;
|
|
flags[PROGDLG.PROGDLG_MARQUEEPROGRESS] = false;
|
|
break;
|
|
|
|
case ShellProgressDialogStyle.Marquee:
|
|
flags[PROGDLG.PROGDLG_NOPROGRESSBAR] = false;
|
|
flags[PROGDLG.PROGDLG_MARQUEEPROGRESS] = true;
|
|
break;
|
|
|
|
case ShellProgressDialogStyle.Hidden:
|
|
flags[PROGDLG.PROGDLG_NOPROGRESSBAR] = true;
|
|
flags[PROGDLG.PROGDLG_MARQUEEPROGRESS] = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets the file dialog box title.</summary>
|
|
/// <value>The progress dialog box title. The default value is an empty string ("").</value>
|
|
[DefaultValue(""), Category("Appearance"), Description("")]
|
|
public string Title
|
|
{
|
|
get => title;
|
|
set
|
|
{
|
|
if (title == value) return;
|
|
iDlg.SetTitle(title = value);
|
|
}
|
|
}
|
|
|
|
/// <summary>Starts the progress dialog box.</summary>
|
|
/// <param name="hwndParent">The progress dialog box's parent window. This value can be <see langword="null"/>.</param>
|
|
public virtual void Start(IWin32Window hwndParent)
|
|
{
|
|
closed = false;
|
|
iDlg.StartProgressDialog(hwndParent?.Handle ?? IntPtr.Zero, dwFlags: flags);
|
|
iDlg.Timer(PDTIMER.PDTIMER_RESET);
|
|
}
|
|
|
|
/// <summary>Stops the progress dialog box and removes it from the screen.</summary>
|
|
public virtual void Stop()
|
|
{
|
|
if (closed) return;
|
|
iDlg.StopProgressDialog();
|
|
closed = true;
|
|
}
|
|
|
|
/// <summary>Updates the progress dialog box with the current state of the operation.</summary>
|
|
/// <param name="completed">
|
|
/// An application-defined value that indicates what proportion of the operation has been completed at the time the method was
|
|
/// called. If called with this value equaling the value supplied in <paramref name="total"/>, the <see cref="Stop"/> method will be
|
|
/// called to close the progress dialog.
|
|
/// </param>
|
|
/// <param name="total">
|
|
/// An application-defined value that specifies what value <paramref name="completed"/> will have when the operation is complete.
|
|
/// </param>
|
|
public virtual void UpdateProgress(ulong completed, ulong total)
|
|
{
|
|
if (closed) return;
|
|
iDlg.SetProgress64(completed, total);
|
|
if (completed == total) Stop();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
if (disposing)
|
|
return;
|
|
if (!closed)
|
|
Stop();
|
|
iDlg = null;
|
|
}
|
|
}
|
|
} |