| File: MS\Internal\Documents\SigningProgress.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationUI\PresentationUI.csproj (PresentationUI) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // Description: // ProgressDialog invokes a progress notification dialog that runs on // its own thread, with its own message pump. It is used to notify // users when a long, blocking operation on XPSViewer's main thread is // running (and blocking). using System; using System.Threading; using System.Windows.Forms; namespace MS.Internal.Documents { internal sealed partial class ProgressDialog : DialogBaseForm { #region Constructors //------------------------------------------------------ // // Constructors // //------------------------------------------------------ /// <summary> /// Private Constructor /// </summary> private ProgressDialog(string title, string message) { _label.Text = message; Text = title; } #endregion Constructors #region Internal Methods /// <summary> /// Creates an instance of the ProgressDialog in a new thread, returning a /// ProgressDialogReference wrapper which will eventually contain a valid /// reference to the dialog (when the dialog is actually instantiated.) /// </summary> /// <param name="title">The title to appear in the Titlebar of the dialog</param> /// <param name="message">The message to appear in the dialog</param> /// <returns></returns> public static ProgressDialogReference CreateThreaded(string title, string message) { ProgressDialogReference reference = new ProgressDialogReference(title, message); // Spin up a new thread Thread dialogThread = new Thread( new ParameterizedThreadStart(ProgressDialogThreadProc)); // Start it, passing in our reference dialogThread.Start(reference); // Return the reference -- the Form inside will eventually point to // the dialog created in ProgressDialogThreadProc. return reference; } /// <summary> /// Closes an instance of a ProgressDialog on its thread. /// </summary> /// <param name="dialog"></param> public static void CloseThreaded(ProgressDialog dialog) { dialog.Invoke(new MethodInvoker(dialog.CloseThreadedImpl)); } #endregion Internal Methods #region Private Methods /// <summary> /// Creates a new ProgressDialog on its own thread, with its own /// message pump. /// </summary> /// <param name="state"></param> private static void ProgressDialogThreadProc(object state) { ProgressDialogReference reference = state as ProgressDialogReference; Invariant.Assert(reference != null); reference.Form = new ProgressDialog(reference.Title, reference.Message); //Spawn a new message pump for this dialog System.Windows.Forms.Application.Run(); } /// <summary> /// Invokes the ProgressDialog (calls ShowDialog on it) when the Timer is elapsed. /// We do this so that the dialog only appears after the blocking operation /// we're showing status for takes a certain amount of time. (Prevents UI flicker /// in cases where the action doesn't take very long) /// </summary> /// <param name="e"></param> /// <param name="sender"></param> private void OnTimerTick(object sender, EventArgs e) { // Disable the timer so this will only occur once _timer.Enabled = false; ShowDialog(null); } /// <summary> /// Closes the dialog on its own thread. /// </summary> private void CloseThreadedImpl() { System.Windows.Forms.Application.ExitThread(); } #endregion Private Methods /// <summary> /// ProgressDialogReference exists to allow passing a reference to a ProgressDialog /// created on a new thread back to the main UI thread, and to ensure that the main /// thread blocks until the ProgressDialog is ready before using it. /// /// This is a mitigation for an unfortunate design limitation because we have to block /// on a UI thread and show a dialog on a non-blocking thread, instead of the other /// way around. /// </summary> internal class ProgressDialogReference { /// <summary> /// Constructor /// </summary> /// <param name="title"></param> /// <param name="message"></param> public ProgressDialogReference(string title, string message) { _title = title; _message = message; _isReady = new ManualResetEvent(false); } /// <summary> /// The title of the dialog being shown /// </summary> public String Title { get { return _title; } } /// <summary> /// The message in the dialog being shown /// </summary> public String Message { get { return _message; } } public ProgressDialog Form { get { // Wait until the form has been set and instantiated... _isReady.WaitOne(); return _form; } set { _form = value; // Our form is running on a separate thread, setup an event handler // so that we're notified when it is loaded. _form.Load += new EventHandler(FormLoaded); } } /// <summary> /// Handler for the form.Loaded event used to set the ready state. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void FormLoaded(object sender, EventArgs e) { // Since the form has successfully loaded then update the ready state. _isReady.Set(); } private ManualResetEvent _isReady; private ProgressDialog _form; private string _title; private string _message; } //The amount to wait (in msec) before actually invoking the dialog. private const int _timerInterval = 500; } }