cool hit counter Share a task executor with a wait form_Intefrankly

Share a task executor with a wait form


-------------201504161039 update-------------

Updated to include.

  1. IWaitForm interface removes the System.Windows.Forms.DialogResult DialogResult property. That is, the way to hide the waiting form is no longer divided into SetDialogResult harmony Call Hide()two, Change to only Call Hide() one type of, Simplified design。 thanks toHide() Part of the access control, The executor needs to handle this method accordingly depending on whether it will be called across threads
  2. WaitUI adds private method HideWaitForm to hide the wait form (since it will be called in a background thread, there is cross-thread handling internally), replacing the original setDialogResult
  3. WaitForm's FormClosing event was changed from registering the event to overriding the OnFormClosing method, adding Visible to the condition of preventing the form from closing, i.e. preventing the form from closing and triggering the UserCancelling event only when the form is visible, which is to more accurately distinguish whether the executor calls Hide() to hide the waiting form or whether the user closes the waiting form only by e. CloseReason is unreliable because when the user has tapped the Close button, e.CloseReason will be UserClosing, and later on when the executor calls Hide to hide the form, it will still go to OnFormClosing, at which point e. If the CloseReason is still UserClosing, it will trigger the UserCancelling event again, which has no effect, but it should not. If you add Visible, after the executor Hide form, Visible will be false, and the UserCancelling event will not be triggered again. Of course, it is still recommended that custom waiting forms block the close button, so that the user can only cancel the task by clicking on the cancel control, and there is less to do. But it's not recommended to hide the entire top right corner of those three buttons by making ControlBox=false, because I always think it's important to give the user the right to minimize, and I hate that restriction as a user with other software
  4. Wait for the form's【 cancellation】 button clicked will no longerEnabled place asfalse。 The reason for this is that in the case of theBackgroundWorker in the programme, Waiting for the formHide After the possibility of anotherShowDialog, That is, to execute again mandate When still ensuring cancelable
  5. willWaitFormNullException The definition of the exception is moved toWaitForm.cs file( formerly inWaitUI.cs in)。 The reason is that waiting for something related to the form should together with Actuators remain independent

-------------20150415 original article (updated) -------------

Applicable environment. Winform project for .net 2.0+.

First, let me explain what I call【 with waiting form mandate actuators】 What the hell is it?, is that you can use this class to execute any time-consuming method( The following will refer to the method being executed as mandate perhaps Methodology of the mission), During execution, a mode Waiting for the form, Let the user know mandate Being implemented, The program isn't stuck.。 Let's see the results first:

Function.

  • You can use the default form that comes with the executor (as shown in the picture above), or you can use your own well-designed form, or even build it based on a beautiful third-party form like Devexpress, C1, etc. It's perfectly fine too!
  • Controls like Label, ProgressBar on the wait form can be updated in the task to provide progress feedback. If you're too lazy to give feedback, just default to "Please wait..." + Marquee-style scrolling
  • If the task is allowed to be terminated, the user can terminate the task execution by some action (e.g. by clicking the [Cancel] button in the image above); if not, you can hide the Cancel button or just not respond to the user's termination request in the task
  • mandate of the implementation results of the( includeref/out parameters)、 Is there an anomaly、 Whether or not it was cancelled, etc. can be obtained

Principle.

  • Call BeginInvoke of the delegate to which the task belongs to let the task execute in the background thread, and then call ShowDialog of the waiting form in the UI thread (usually the main thread) to pop up the modal form to let the user know that the task is executing while preventing the user from performing other actions. Since the task and the wait form run in separate threads, the wait form will not be stuck
  • mandate A set of properties that can be provided by the actuator during execution harmony method manipulates the controls on the waiting form, This group of properties harmony method is internalized by calling the wait form'sInvoke perhapsBeginInovke Performing operations on controls, Implementing cross-threaded access to controls
  • mandate During execution the user can select the user's name by clicking on the wait form on the【 cancellation】 buttons( If you let it show.) perhaps Click on the top right corner close Button to issue termination mandate of requesting( Waiting for the window to intercept close operations), The result is that the actuator'sUserCancelling attribute will be set totrue, So in mandate You can access this property in the requesting Cancellation of operations, If you agree to terminate, Actuator to be setCancelled=true, and forthwithreturn happen Methodology of the mission
  • mandate After execution( Whether successful、 anomaly、 cancellation) will automatically enter the asynchronous callback method, The callback method will first access theCancelled get to know mandate Cancelled or not, If cancelled, directreturn Out callback method; If not cancelled, then call mandate EntrustedEndInvoke get mandate Implementation results perhaps anomaly。 Finally regardless of cancellation together with deny,finally The block will call theHideWaitForm(), in order to ensure close Waiting for the form
  • Waiting for the form close back, The actuator will continue to executeShowDialog The latter statement。 in case mandate Cancelled, then a specific exception is thrown to report the caller; in case mandate Exceptions, then the exception is thrown; If none of the above conditions exist, return to mandate result

As stated, the functionality is simple and easy to implement, I just generalized this need so that those who don't already have a similar wheel can take it and just use it. There is also a BackgroundWorker based implementation that I may share in my next post.

Let's start by looking at a general example of use.

 //WaitUI is the actuator
private void button1_Click(object sender, EventArgs es)
{
     // Can detect if the actuator is performing another task. It's actually basically impossible to have IsBusy=true, because the user can't do anything else while the actuator is working
     // Honestly I was torn about whether to make this IsBusy public or not, because it wouldn't do much good to make it public, but it wouldn't do any harm either, since the setter is private
     //Whatever~ I chose to go public in the end, probably~ because of love
    //if (WaitUI.IsBusy) { return; }

    try
    {
         //WaitUI.RunXXX method is used to execute the task
         // The return value of the method is the return value of the task
         // Exceptions thrown by the task are thrown via the RunXXX method

         //WaitUI.RunAction(Foo, 33, 66);                                       // Execute methods with no return value
         int r = WaitUI.RunFunc(Foo, 33, 66);                                   // Execute methods with return values
        //object r = WaitUI.RunDelegate(new Func<int, int, int>(Foo), 33, 66);// Executive Delegation
//WaitUI.RunAction(new MyWaitForm(), Foo);//Specify a custom wait form to perform the task, several RunXXX methods have overloads that can be specified for custom forms

        MessageBox.Show(" mandate accomplish。" + r);
    }
     catch (WorkCancelledException)// A task being cancelled is reported by throwing this exception
    {
        MessageBox.Show(" mandate Cancelled!");
    }
     catch (Exception ex)//Exception thrown by the task
    {
        MessageBox.Show(" mandate develop abnormally!" + ex.Message);
    }
}

 //Time consuming tasks. Because the method will be executed in a background thread, there can be no code in the method to access the control
int Foo(int a, int b)
{
     // UI elements of the waiting form can be manipulated indirectly through a set of public properties and methods of the executor
     WaitUI.CancelControlVisible = true;// set the visibility of the control that cancels the task, i.e. whether the user is allowed to cancel the task (default is false: not visible)
     WaitUI.BarStyle = ProgressBarStyle.Continuous;//Set the scrollbar style (default is Marquee: circular shuttle style)
     WaitUI.BarMaximum = 100;       // set the upper limit of the scrollbar value (default is 100)
     WaitUI.BarMinimum = 0;         // Set the lower limit of the scrollbar value (default is 0)
     WaitUI.BarStep = 1;            // Set the scrollbar step (default is 10)
     WaitUI.BarVisible = true;      // set whether the scrollbar is visible (default is true: visible)

    int i;
    for (i = a; i < b; i++)
    {
         if (WaitUI.UserCancelling)//respond to the user's cancellation request
        {
             WaitUI.Cancelled = true;// tells the executor that the task has been cancelled
            return 0;
        }

         // you can try throwing an exception
        //if (i == 43) { throw new NotSupportedException(" Anomaly testing"); }

         // Various UI elements of the waiting form can be manipulated again at any time
         //if (i % 10 == 0) { WaitUI.CancelControlVisible = false;  } // Hide the cancel control
         //else if (i % 5 == 0) { WaitUI.CancelControlVisible = true;  }//Display the cancel control
        WaitUI.WorkMessage = " while (doing)XXOO, Completed " + i + "  downwards..."; // update Description of progress
         WaitUI.BarValue = i;//Update the progress value
         //WaitUI.BarPerformStep();//Step progress bar

        Thread.Sleep(50);
    }
    return i;
}

After reading the example, familiar with the set of you may have been able to understand the implementation details, but as a program to share the article, I still talk about the use of the instructions first, and then break the design instructions, first look at the class diagram.

Instructions for use.

  1. WaitUI pass (a bill or inspection)RunAction、RunFunc、RunDelegate these3 A basic approach harmony Their overloaded execution mandate, You can tell by the name., They are, in turn, the execution of the no-return-value method、 Methods with return values harmony Custom Delegation, Each method has Do not specify a waiting form harmony Specify the waiting form The two overloaded forms, when not specified use the WaitForm that comes with the solution as the wait form. Custom wait forms are required to implement the IWaitForm interface, details of which are described later in the Design Notes section. Here it means that the wait form is passed in only when the task is executed, and that WaitUI destroys the wait form when the task execution is complete, this is to allow WaitUI, as a static class, to hold the object as briefly as possible and save memory. So if you pass in a variable for a custom wait form, please be careful not to use the variable again after WaitRun, as it will have been destroyed, the recommended practice is to just new a custom wait form in RunXXX. Of course if you don't mind the self-contained wait form, you don't have to pass it in directly, so naturally you don't have this problem. The first two methods are generic methods, according to Action and Func these two generic delegate overloads, these two delegates support to a maximum of 16 parameters, but in order to save space, the scheme only overloads the case of 0 ~ 8 parameters, the user can add overloads as needed. It can execute any return or no-return method with no more than 8 arguments, and thanks to the compiler's intelligent inference, it is very easy to use, directly RunAction(Foo, arg1, arg2, ...) Just fine, don't even bother with which reload to use. For the RunDelegate method, a delegate instance is accepted, which means that you can't pass in the method directly, you have to sleeve the method with a delegate to do so. Any delegate can be passed in, so RunDelegate is the most versatile method, and you can and will only use RunDelegate when your method has ref/out parameters, or when the number of parameters is perverted to more than 16. But there is a restriction, delegates have and only bind one method, and RunXXX refuses to execute the delegate chain
  2. RunFunc harmonyRunDelegate method has a return value, The return type of the former together with Methodology of the mission with the same return type as the, The latter isobject。 The return value for both of them is Methodology of the mission return value of。 equivalent, mandate The same exceptions that are thrown will be thrown in the3 kindRunXXX Throw it in the method, tantamount to usefulnessRunXXX execute mandate together with Direct call mandate compare, Except for the difference in writing style: The call experience is the same, So you can take it and use it., There is no need to be interested in Methodology of the mission Make what changes, Just bring a condom and be done with it., unless Methodology of the mission The following situation exists
int a = WaitUI.RunFunc(Foo,33);
int b = Foo(33);
  1. It says in the Principle,RunXXX method is actually a call to the mandate EntrustedBeginInvoke approach, That is, asynchronous execution of mandate, that is mandate will be executed in another thread。 consequently mandate The control cannot be accessed in the, I'm afraid this is the biggest inconvenience of the programme, But it's true that the principle is limited, So if your mandate There is code for accessing the controls, Changes need to be made.。 You have to ask why you have to let mandate in the background, And waiting for the form to be in the foreground, Can't you switch over?? That way, there's no this one Inconvenience?? That's because waiting for the form isn't on the main threadShowDialog, It can't be reached mode effect, the user can still sing and dance, which I'm afraid is something you don't want
  2. The task can be used to report the progress of the task execution to the user by updating the text rendering controls and progress indicator controls (not limited to Label and ProgressBar, depending on the design of the wait form) in the wait form via a set of WaitUI properties and methods (WorkMessage, BarValue, BarPerformStep, etc.). Of course, it's fine to leave the user with a "Please wait..." and a circular scrollbar, depending on the default settings of the wait form
  3. WaitUI There's oneCancelControlVisible attribute, Can be set totrue/false Controls whether the wait form appears【 cancellation】 Controls such as buttons( Not limited toButton, Depends on the design of the waiting form, So the cancel button is not mentioned below, Say cancel the control)。 The cancellation of the scheme needs to be elaborated here mandate mechanism, In fact together withBackgroundWorker the mechanism is consistent( Well, I borrowed it), familiarity withbgw Please skip the veterans of。 Displaying the cancel control only means that the user can requesting terminate the mission, as to whether you (or the mission) responsiveness this one requesting( Consent to termination together with deny) It's a different matter.。 What do you mean?, It's when the user clicks the cancel control, Not to say mandate will automatically terminate~ Why would it end?, mandate In the thread pool, It's impossibleAbort, consequently mandate Whether or not to terminate depends entirely on you mandate Processing in code, Like you're here mandate Let's have one in the middlereturn perhapsthrow ex, this one It's called termination, Let the code go, It's called no end, So the user requesting terminate together with mandate Is it really terminated without necessarily linking。 What does it mean to say so much?, That is, if you want users to see the cancel control, Then you should responsiveness The user's requesting, Turn around if you don't want to mandate was terminated, Then don't let the user have an initiation requesting possible, Of course it is together with Something purely human-computer interaction concept that has nothing to do with technology, There is no right or wrong., Anyway, I am suggesting not to cheat users, Here's how responsiveness terminate requesting。 When the user initiates termination of the requesting back,WaitUI ofUserCancelling will becometrue, at mandate You can base it on this one value to make the termination mandate processing, But before it's terminated, You'll have to trouble you to set a tag, Don't forget, It's what makes WaitUI.Cancelled = true, This is equivalent to telling the actuator mandate It did end, After you've set the tag, It's a good idea to follow the termination code, Don't do anything else, letCancelled together with The facts are the same。 Actuator based onCancelled to learn mandate Whether it has been terminated, And then make the corresponding treatment harmony return to。 Why notUserCancelling butCancelled I'm sure you understand, The former is the user's will, The latter is the developer's decision, Of course it was decided to be reliable。 return toCancelControlVisible attribute, this one The attributes are suggested in the Methodology of the mission Set it at the top., Because a mandate Terminability should be determined, generally speaking, Loop class mandate can be terminated, For example, batch processing of pictures, Process one in a circle, That's it mandate can and should be allowed to terminate; instead of a loop class mandate, perhaps is more atomic mandate, You can only wait for the result when you start perhaps Error, This mandate On the one hand, it may not allow users to terminate, On the other hand, it can't be terminated even if you want to (e.g. WebRequest. GetResponse, SqlCommand.ExecuteNonQuery and so on), This mandate It is best not to provide cancellation controls to users。 ButCancelControlVisible It's like thatWorkMessage the same properties as, Yes, it can be mandate at any time+ Set over and over again, So yours mandate There may be stages that can be terminated, Sometimes termination is not allowed, It's okay to open and close,as you wish
  4. RunXXX have3 Type of implementation outcome:① Successful implementation mandate, return to mandate return value~ in case mandate If there is a return value;② mandate generate anomalies,RunXXX The exception is thrown as is;③ mandate was terminated, ThrownWorkCancelledException anomaly( There is a description of why you chose to throw an exception this way)。 You do it yourself according to different results
  5. For yesref/out The parameter Methodology of the mission, If you want to be in mandate Retrieved after execution, Be careful to do so: That is, you have to construct an array of parameters first( Even if only1 parameters), The incoming array is finished, The last element to be taken from the array is the one that has been ravaged。 A single parameter variable cannot be passed directly in, That way you can't get the changed value back from the variable, The specific reason for their own understanding
// properly
object[] prms = { a, b };
WaitUI.RunDelegate(new Action(Foo), prms);
a = prms[0];
b = prms[1];

// mistakes
WaitUI.RunDelegate(new Action(Foo), a, b);

Programme source code.

WaitUI.cs containclass WaitUI harmony2 exception classWorkIsBusyException、WorkCancelledException

using System;
using System.Reflection;
using System.Windows.Forms;

namespace AhDung.WinForm
{
    /// <summary>
     /// Execute the task and display the waiting form
    /// </summary>
    public static class WaitUI
    {
         static IWaitForm waitForm;  //Waiting form
         static object result;       // Task return results
         static Exception exception;// Task execution exception

         static object[] parmsInput;         // Parameters passed in by the caller
         static ParameterInfo[] parmsMethod;//parameters required for the task
         static bool isCallBackCompleted;    // indicates whether the callback method has been executed

        /// <summary>
         /// Indicates whether the user has requested to cancel the task
        /// </summary>
        public static bool UserCancelling
        {
            get;
            private set;
        }

        /// <summary>
         /// Indicates whether a task has been cancelled
        /// </summary>
        public static bool Cancelled
        {
            private get;
            set;
        }

        /// <summary>
         /// Indicates whether a task is in progress
        /// </summary>
        public static bool IsBusy
        {
            get;
            private set;
        }

         #region A set of properties/methods that operate the waiting form UI

        /// <summary>
         /// Get or set the progress description
        /// </summary>
        public static string WorkMessage
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return waitForm.Invoke(new Func<string>(() => waitForm.WorkMessage)) as string;
                }
                return waitForm.WorkMessage;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.WorkMessage = value));
                    return;
                }
                waitForm.WorkMessage = value;
            }
        }

        /// <summary>
         /// Get or set progress bar visibility
        /// </summary>
        public static bool BarVisible
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.BarVisible)));
                }
                return waitForm.BarVisible;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarVisible = value));
                    return;
                }
                waitForm.BarVisible = value;
            }
        }

        /// <summary>
         /// Get or set the progress bar animation style
        /// </summary>
        public static ProgressBarStyle BarStyle
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return (ProgressBarStyle)(waitForm.Invoke(new Func<ProgressBarStyle>(() => waitForm.BarStyle)));
                }
                return waitForm.BarStyle;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarStyle = value));
                    return;
                }
                waitForm.BarStyle = value;
            }
        }

        /// <summary>
         /// Get or set the progress value
        /// </summary>
        public static int BarValue
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarValue)));
                }
                return waitForm.BarValue;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarValue = value));
                    return;
                }
                waitForm.BarValue = value;
            }
        }

        /// <summary>
         /// Get or set the progress bar step value
        /// </summary>
        public static int BarStep
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarStep)));
                }
                return waitForm.BarStep;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarStep = value));
                    return;
                }
                waitForm.BarStep = value;
            }
        }

        /// <summary>
         /// Make the progress bar step
        /// </summary>
        public static void BarPerformStep()
        {
            if (waitForm == null) { return; }

            if (waitForm.InvokeRequired)
            {
                waitForm.BeginInvoke(new Action(() => waitForm.BarPerformStep()));
                return;
            }
            waitForm.BarPerformStep();
        }

        /// <summary>
         /// Get or set the progress bar upper limit
        /// </summary>
        public static int BarMaximum
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMaximum)));
                }
                return waitForm.BarMaximum;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarMaximum = value));
                    return;
                }
                waitForm.BarMaximum = value;
            }
        }

        /// <summary>
         /// Get or set the lower limit of the progress bar
        /// </summary>
        public static int BarMinimum
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMinimum)));
                }
                return waitForm.BarMinimum;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarMinimum = value));
                    return;
                }
                waitForm.BarMinimum = value;
            }
        }

        /// <summary>
         /// Get or set the visibility of the control that cancels the task
        /// </summary>
        public static bool CancelControlVisible
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.CancelControlVisible)));
                }
                return waitForm.CancelControlVisible;
            }
            set
            {
                if (waitForm == null) { return; }

                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.CancelControlVisible = value));
                    return;
                }
                waitForm.CancelControlVisible = value;
            }
        }

        #endregion

         #region public method: no return value + default form

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction(Action method)
        {
            RunDelegate(method);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T>(Action<T> method, T arg)
        {
            RunDelegate(method, arg);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2>(Action<T1, T2> method, T1 arg1, T2 arg2)
        {
            RunDelegate(method, arg1, arg2);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3>(Action<T1, T2, T3> method, T1 arg1, T2 arg2, T3 arg3)
        {
            RunDelegate(method, arg1, arg2, arg3);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4>(Action<T1, T2, T3, T4> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            RunDelegate(method, arg1, arg2, arg3, arg4);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
        {
            RunDelegate(method, arg1, arg2, arg3, arg4, arg5);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
        {
            RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
        {
            RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
        }

        #endregion

         #region public method: no return value + custom form

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction(IWaitForm fmWait, Action method)
        {
            RunDelegate(fmWait, method);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T>(IWaitForm fmWait, Action<T> method, T arg)
        {
            RunDelegate(fmWait, method, arg);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2>(IWaitForm fmWait, Action<T1, T2> method, T1 arg1, T2 arg2)
        {
            RunDelegate(fmWait, method, arg1, arg2);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3>(IWaitForm fmWait, Action<T1, T2, T3> method, T1 arg1, T2 arg2, T3 arg3)
        {
            RunDelegate(fmWait, method, arg1, arg2, arg3);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4>(IWaitForm fmWait, Action<T1, T2, T3, T4> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            RunDelegate(fmWait, method, arg1, arg2, arg3, arg4);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
        {
            RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5, T6>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5, T6> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
        {
            RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5, T6, T7>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5, T6, T7> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
        {
            RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static void RunAction<T1, T2, T3, T4, T5, T6, T7, T8>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5, T6, T7, T8> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
        }

        #endregion

         #region public method: with return value + default form

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<TResult>(Func<TResult> method)
        {
            return (TResult)RunDelegate(method);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T, TResult>(Func<T, TResult> method, T arg)
        {
            return (TResult)RunDelegate(method, arg);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, TResult>(Func<T1, T2, TResult> method, T1 arg1, T2 arg2)
        {
            return (TResult)RunDelegate(method, arg1, arg2);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> method, T1 arg1, T2 arg2, T3 arg3)
        {
            return (TResult)RunDelegate(method, arg1, arg2, arg3);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, TResult>(Func<T1, T2, T3, T4, T5, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
        {
            return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, T6, TResult>(Func<T1, T2, T3, T4, T5, T6, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
        {
            return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
        {
            return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        }

        /// <summary>
         /// Execute the method and display the default waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
        }

        #endregion

         #region public methods: with return values + custom forms

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<TResult>(IWaitForm fmWait, Func<TResult> method)
        {
            return (TResult)RunDelegate(fmWait, method);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T, TResult>(IWaitForm fmWait, Func<T, TResult> method, T arg)
        {
            return (TResult)RunDelegate(fmWait, method, arg);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, TResult>(IWaitForm fmWait, Func<T1, T2, TResult> method, T1 arg1, T2 arg2)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, TResult>(IWaitForm fmWait, Func<T1, T2, T3, TResult> method, T1 arg1, T2 arg2, T3 arg3)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, T6, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, T6, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, T6, T7, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        }

        /// <summary>
         /// Execute the method and display the custom waiting form
        /// </summary>
        public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
        }

        #endregion

        /// <summary>
         /// Execute the delegate and display the default waiting form
        /// </summary>
        public static object RunDelegate(Delegate del, params object[] args)
        {
            return RunDelegate(new WaitForm(), del, args);
        }

        /// <summary>
         /// Execute the delegate and display the custom waiting form
        /// </summary>
        public static object RunDelegate(IWaitForm fmWait, Delegate del, params object[] args)
        {
            if (IsBusy) { throw new WorkIsBusyException(); }

            if (fmWait == null) { throw new WaitFormNullException(); }
            if (del == null || del.GetInvocationList().Length != 1) { throw new ApplicationException(" Delegation cannot be empty, and can only be bound to1 individual approach!"); }
            if (args == null) { throw new ArgumentNullException("args"); }

            MethodInfo beginInvoke = del.GetType().GetMethod("BeginInvoke");
            object[] parmsBeginInvoke = new object[beginInvoke.GetParameters().Length];
            if (args.Length > parmsBeginInvoke.Length - 2)
            {
                throw new ArgumentException(" Provide more parameters than required by the method!");
            }

             parmsMethod = del. Method.GetParameters();// Assume that GetParameters always returns an array sorted by the parameter Position, and check this assumption if there is a problem in the future
            parmsInput = args;

            try
            {
                 // Assign the BeginInvoke parameter
                 parmsInput.CopyTo(parmsBeginInvoke, 0);  // Stuff incoming parameters
                for (int i = parmsInput.Length; i < parmsMethod.Length; i++) // Assign default values to arguments that are not passed in
                {
                    ParameterInfo p = parmsMethod[i];
                    object pVal;

                     if ((pVal = p.DefaultValue) == DBNull.Value) //throw exception if the parameter does not have a default value
                    { throw new ArgumentException(string.Format(" Parameters required for the method{0} No default value defined, Must be passed in!", p.Name)); }

                    parmsBeginInvoke[i] = pVal;
                }
parmsBeginInvoke[parmsBeginInvoke.Length - 2] = new AsyncCallback(Callback);// the penultimate parameter
                 parmsBeginInvoke[parmsBeginInvoke.Length - 1] = del;                         / / penultimate parameter

                 // Reset status
                IsBusy = true;
                Cancelled = false;
                exception = null;
                isCallBackCompleted = false;

                waitForm = fmWait;
                 fmWait.UserCancelling += WaitForm_UserCancelling;//register the user cancellation task event

                beginInvoke.Invoke(del, parmsBeginInvoke);

                 if (!isCallBackCompleted)//There is a judgment call here, in extreme cases it is possible that the callback will be executed before the ShowDialog is finished
                {
                     fmWait.ShowDialog();  // Make sure ShowDialog doesn't throw exceptions
                }

                 //return
                if (Cancelled) { throw new WorkCancelledException(); }
                if (exception != null) { throw exception; }
                return result;
            }
            finally
            {
                Release();
                UserCancelling = false;
                IsBusy = false;
            }
        }

        /// <summary>
         /// Callback methods
        /// </summary>
        private static void Callback(IAsyncResult ar)
        {
            try
            {
                 if (Cancelled) { return;  } // If the task is cancelled there is no need to EndInvoke

                MethodInfo endInvoke = ar.AsyncState.GetType().GetMethod("EndInvoke");
                object[] parmsEndInvoke = new object[endInvoke.GetParameters().Length];

                 if (parmsEndInvoke.Length != 1)//if there is a ref or out parameter to the method, assign it to the endInvoke parameter
                {
                    int i = 0;
                    foreach (ParameterInfo p in parmsMethod)
                    {
                        if (p.ParameterType.IsByRef) { parmsEndInvoke[i++] = parmsInput[p.Position]; }
                    }
                }
                parmsEndInvoke[parmsEndInvoke.Length - 1] = ar;

                result = endInvoke.Invoke(ar.AsyncState, parmsEndInvoke);

                 if (parmsEndInvoke.Length != 1)//retrieve the value from the endInvoke parameter and return it to the input parameter
                {
                    int i = 0;
                    foreach (ParameterInfo p in parmsMethod)
                    {
                        if (p.ParameterType.IsByRef) { parmsInput[p.Position] = parmsEndInvoke[i++]; }
                    }
                }
            }
            catch (TargetInvocationException ex)
            {
                exception = ex.InnerException;
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                HideWaitForm();
                isCallBackCompleted = true;
            }
        }

        /// <summary>
         /// Hide the waiting form
        /// </summary>
        /// <remarks> Because the method is called in the callback, So do cross-thread processing</remarks>
        static void HideWaitForm()
        {
            if (waitForm == null) { return; }

            if (waitForm.InvokeRequired)
            {
                waitForm.BeginInvoke(new Action(() => waitForm.Hide()));
                return;
            }
            waitForm.Hide();
        }

        /// <summary>
         /// When a user requests to cancel a task
        /// </summary>
        private static void WaitForm_UserCancelling(object sender, EventArgs e)
        {
            UserCancelling = true;
        }

        /// <summary>
         /// Release of resources
        /// </summary>
        private static void Release()
        {
             parmsInput = null;//this doesn't affect the object[] instance passed in by the caller here, because it's not ref in
            parmsMethod = null;
            IDisposable disp;
            if ((disp = waitForm as IDisposable) != null) { disp.Dispose(); }
        }
    }

    /// <summary>
     /// Task in progress
    /// </summary>
    public class WorkIsBusyException : InvalidOperationException
    {
        public WorkIsBusyException() : base(" mandate Executing!") { }
    }

    /// <summary>
     /// The mission has been cancelled
    /// </summary>
    public class WorkCancelledException : ApplicationException
    {
        public WorkCancelledException() : base(" mandate Has been canceled!") { }
    }
}

WaitForm.cs contains interface IWaitForm, class WaitForm and exception class WaitFormNullException, where WaitForm uses WinFormHelper.cs in order to mask the close button

using System;
using System.Windows.Forms;

namespace AhDung.WinForm
{
    /// <summary>
     /// Waiting for the form
    /// </summary>
    ///<remarks>IWaitForm the default implementation of</remarks>
    public class WaitForm : Form, IWaitForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private readonly System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.lbMsg = new System.Windows.Forms.Label();
            this.bar = new System.Windows.Forms.ProgressBar();
            this.btnCancel = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // lbMsg
            // 
            this.lbMsg.Location = new System.Drawing.Point(10, 20);
            this.lbMsg.Name = "lbMsg";
            this.lbMsg.Size = new System.Drawing.Size(386, 55);
            this.lbMsg.TabIndex = 0;
            this.lbMsg.Text = " Processing, Please wait a moment...";
            // 
            // bar
            // 
            this.bar.Location = new System.Drawing.Point(12, 78);
            this.bar.Name = "bar";
            this.bar.Step = 1;
            this.bar.Size = new System.Drawing.Size(384, 16);
            this.bar.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
            this.bar.TabIndex = 1;
            // 
            // btnCancel
            // 
            this.btnCancel.Location = new System.Drawing.Point(321, 109);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(75, 23);
            this.btnCancel.TabIndex = 2;
            this.btnCancel.Text = " cancellation";
            this.btnCancel.UseVisualStyleBackColor = true;
            this.btnCancel.Visible = false;
            // 
            // FmWaitForDesign
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(408, 155);
            this.Controls.Add(this.btnCancel);
            this.Controls.Add(this.bar);
            this.Controls.Add(this.lbMsg);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.Name = "FmWaitForDesign";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.Text = " Please wait a moment...";
            this.ResumeLayout(false);
        }

        #endregion

        System.Windows.Forms.Label lbMsg;
        System.Windows.Forms.Button btnCancel;
        System.Windows.Forms.ProgressBar bar;

        public WaitForm()
        {
            InitializeComponent();

             btnCancel.Click += btnCancel_Click;//register the cancel button click event
        }

         #region Treats [Cancel] button clicks, form closures, etc. as triggering [Cancel Task] events

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
             // Prevents the user from closing the form and raises the UserCancelling event
            // addVisible It's because Call Hide() The event is also triggered, to avoid againOnUserCancelling That's it
            if (e.CloseReason == CloseReason.UserClosing && this.Visible)
            {
                e.Cancel = true;
                this.OnUserCancelling();
            }
            base.OnFormClosing(e);
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.OnUserCancelling();
        }

        protected virtual void OnUserCancelling()
        {
            if (UserCancelling != null) { UserCancelling(this, EventArgs.Empty); }
        }

         //Mask window close button
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (this.Visible) { AhDung.WinForm.WinFormHelper.DisableCloseButton(this); }
        }
        #endregion

         #region Implementing interfaces

        public string WorkMessage
        {
            get { return lbMsg.Text; }
            set { lbMsg.Text = value; }
        }

        public bool BarVisible
        {
            get { return bar.Visible; }
            set { bar.Visible = value; }
        }

        public ProgressBarStyle BarStyle
        {
            get { return bar.Style; }
            set { bar.Style = value; }
        }

        public int BarValue
        {
            get { return bar.Value; }
            set { bar.Value = value; }
        }

        public int BarStep
        {
            get { return bar.Step; }
            set { bar.Step = value; }
        }

        public void BarPerformStep()
        {
            bar.PerformStep();
        }

        public bool CancelControlVisible
        {
            get { return btnCancel.Visible; }
            set { btnCancel.Visible = value; }
        }

        public int BarMaximum
        {
            get { return bar.Maximum; }
            set { bar.Maximum = value; }
        }

        public int BarMinimum
        {
            get { return bar.Minimum; }
            set { bar.Minimum = value; }
        }

        public event EventHandler UserCancelling;
        #endregion
    }

    /// <summary>
     /// Waiting for the form specification
    /// </summary>
    public interface IWaitForm
    {
#region for manipulating properties and methods that wait for the UI representation of the form, implemented without worrying about threading, let the client (task executor) worry about it

        /// <summary>
         /// Get or set the progress description
        /// </summary>
        /// <remarks> The recommended default is“ Please wait a moment...” words like that</remarks>
        string WorkMessage { get; set; }

        /// <summary>
         /// Get or set the visibility of the progress bar
        /// </summary>
        /// <remarks> The recommended default istrue</remarks>
        bool BarVisible { get; set; }

        /// <summary>
         /// Get or set the animation style of the progress bar
        /// </summary>
        /// <remarks> The recommended default isMarquee</remarks>
        ProgressBarStyle BarStyle { get; set; }

        /// <summary>
         /// Get or set the value of the progress bar
        /// </summary>
        /// <remarks> The recommended default is0</remarks>
        int BarValue { get; set; }

        /// <summary>
         /// Get or set the step of the progress bar
        /// </summary>
        int BarStep { get; set; }

        /// <summary>
         /// Make the progress bar step
        /// </summary>
        void BarPerformStep();

        /// <summary>
         /// Get or set the visibility of the control that cancels the task
        /// </summary>
        /// <remarks> The recommended default isfalse</remarks>
        bool CancelControlVisible { get; set; }

        /// <summary>
         /// Get or set the upper limit of the value of the progress bar
        /// </summary>
        /// <remarks> The recommended default is100</remarks>
        int BarMaximum { get; set; }

        /// <summary>
         /// Get or set the lower limit of the value of the progress bar
        /// </summary>
        /// <remarks> The recommended default is0</remarks>
        int BarMinimum { get; set; }

        #endregion

        /// <summary>
         /// Display mode wait form
        /// </summary>
        /// <remarks> Recommended useForm The default implementation of the class</remarks>
        DialogResult ShowDialog();

         #region Invoke related for clients to manipulate the form UI across threads

        /// <summary>
         /// Indicates if Invoke is required to manipulate the form control
        /// </summary>
        /// <remarks> Recommended useForm The default implementation of the class</remarks>
        bool InvokeRequired { get; }

        /// <summary>
         /// Forms Invoke method
        /// </summary>
        /// <remarks> Recommended useForm The default implementation of the class</remarks>
        object Invoke(Delegate method);

        /// <summary>
         /// Forms BeginInvoke method
        /// </summary>
        /// <remarks> Recommended useForm The default implementation of the class</remarks>
        IAsyncResult BeginInvoke(Delegate method);

        #endregion

        /// <summary>
         /// Hide the waiting form
        /// </summary>
        /// <remarks> Recommended useForm The default implementation of the class</remarks>
        void Hide();

        /// <summary>
         /// When the user requests to cancel a task
        /// </summary>
        /// <remarks> The control should be cancelled at the user interaction、 close The event is triggered when the form</remarks>
        event EventHandler UserCancelling;
    }

    /// <summary>
     /// Waiting for the form to be empty
    /// </summary>
    public class WaitFormNullException : ApplicationException
    {
        public WaitFormNullException() : base(" Waiting for a form cannot be anull!") { }
    }
}
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace AhDung.WinForm
{
    public static class WinFormHelper
    {
        [DllImport("User32.dll ")]
        private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("User32.dll ")]
        private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags);

        const int MF_REMOVE = 0x1000;
        //const int SC_RESTORE = 0xF120;     // restore to the original state 
        //const int SC_MOVE = 0xF010;   // portable 
        //const int SC_SIZE = 0xF000;   // size 
        //const int SC_MINIMIZE = 0xF020;   // minimize (computing) 
        //const int SC_MAXIMIZE = 0xF030;   // maximize 
        const int SC_CLOSE = 0xF060;   // close 

        /// <summary>
        ///  Block window closing function
        /// </summary>
        public static void DisableCloseButton(IWin32Window form)
        {
            IntPtr hMenu = GetSystemMenu(form.Handle, false);
            RemoveMenu(hMenu, SC_CLOSE, MF_REMOVE);
        }
    }
}

Poor .net 2.0~3.5 doesn't have enough built-in delegates, so you might also need Delegates.cs

namespace System
{
    // No return commission
    public delegate void Action();
    //public delegate void Action<in T>(T arg);// this one2.0 Yes, there is.
    public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
    public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);
    public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
    //public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

    // With return commission
    public delegate TResult Func<out TResult>();
    public delegate TResult Func<in T, out TResult>(T arg);
    public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
    public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
    public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
    //public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
}

-------------- gorgeous dividers --------------

The following is dedicated to the children who have nothing better to do, or if you want to despise and educate me on what not to do here and what to do there, please read it before continuing.

Design Notes.

  • Why would you putWaitUI Make it a static class。new An actuator performs mandate, Wouldn't it be natural to destroy the actuator when it's done?, Make it a static class and you won't be afraid of resource hogging、 Poor status management causesBUG (question tag)。 I did consider making it an instance class, But after thinking about it, I decided to keep it static., There are two reasons for this:① Easy to use。 This is from considering doing this one Principles that are always a priority from the beginning to the implementation of things,new It doesn't cost much, butnew Do you have to set some properties after you're done?, getRun, have to be released, Like this: It's not as good as a sentenceWaitUI.RunAction(Foo) come simple;② There is no need to remodel Methodology of the mission。 Imagine, In the case of instance classes, mandate think of update Waiting for the form, Isn't it necessary to get a reference to the actuator instance, perhaps is an instance of some class that wraps an actuator instance, How to get, Naturally by Methodology of the mission The parameters of the, Like this: int Foo(int a, int b, WaitUI w) { w.WorkMessage = ""; ... The result is a transformation Methodology of the mission, And my goal is to make it 0-50 for users to take, As a result, I'm idle to change that; The second is to let Methodology of the mission You can either put the actuator on it, It can also be performed as usual without a sleeve, consequentlyWorkMessage Those attributes are written green without public nuisance, Wait for the form with or without, will not throw exceptions, The purpose is even Methodology of the mission These statements have been added to, It can also be performed as usual without a sleeve
using(WaitUI w = new WaitUI())
{
    w.CancelControlVisible = true;
    w.RunAction(Foo);
}
  • Why get a fat interface like IWaitForm. Indeed this place I admit to get into the base class is more appropriate, in addition to not make a fat interface, more importantly, you can do some basic implementation, not everything to custom wait for the form writer to achieve, saving is the second, the key is to do some necessary control, such as UserCancelling event, require the user to click the cancel button and close the form when triggered, but the writer only in one of the operations triggered or not triggered at all that can not be helped, a reason, excessive flexibility is not good. And why I still choose the interface is also precisely because to ensure flexibility is to allow the writer to inherit from other third-party Forms and design beautiful waiting forms, which, if designed as a base class, would have blocked that possibility, equating to me choosing the former between flexibility and robustness. Of course the writer can change the base class of WaitFormBase to the target third-party Form, and Label, ProgressBar, Button to three-party controls, anyway, the source code is there, so play with it how you like
  • WaitForm RewriteForm.OnVisibleChanged approach, is to shield the upper right corner close buttons, It's okay not to shield, But it must beFormClosing The form is blocked in the event close, Triggered at the same timeUserCancelling event, I did both, It is also recommended that custom waiting form writers do a full set, Because it is not blocked close button of the words, The user ordered it but couldn't turn it off, It feels weird.。 Another word on whyUserCancelling To make it an event., Instead of making it abool attribute, Set this property to when the user cancelstrue, over forWaitUI.UserCancelling Access the property directly, Why? The reason is this oneIWaitForm, I don't want it to be dedicatedWaitUI use, Other actuators perhaps Similar scenarios can be used, That's the other option requesting cancellation mandate The operation is not necessarily done by givingUserCancelling Similar properties are marked, It is possible that someone is executing a method, Like whatBackgroundWorker It's a callCancelAsync()( Although it is also internally set to mark), thatIWaitForm If you are setting a property, It's like asking the actuator to actively fetch the marker, Instead of waiting for the form to initiate notices actuators, It is clear that there is no doubt aboutBackgroundWorker This won't work well., You can't get a separatetimer Loop to get markers。 It's much more flexible to make an event, Waiting for the form is only responsible for triggering when appropriate this one event, As for the actuator responsiveness this one event, Self-disposal,WaitUI Can be setUserCancelling, but (not)BackgroundWorker You can callCancelAsync(), each one for his own mother。 additionally,WaitForm act asIWaitForm the default implementation of, It can be used as an implementation reference for custom waiting forms
  • Why does task cancellation have to be in the form of throwing an exception, and why not just let the caller determine the Cancelled property. I wrestled with this here as well, and finally decided to go with the former on the grounds that RunXXX is responsible for returning the results of the task, and if the task is cancelled, then the return value of RunXXX is unreliable, and it would be irresponsible to the caller to allow them to receive this unreliable value, so an exception must be thrown to prevent the caller from getting an unreliable return value. BackgroundWorker uses the Cancelled approach because it already prevents the caller from getting the error result in another way, which is when e. When Cancelled is true, visit e. Result will throw exceptions, which equals the same idea and the same effect
  • For WaitUI.IsBusy, this one, please see Example of use annotations in the public members as optional

Finally, I sincerely hope that the passing prawns will give me some pointers on what's wrong with the scheme, so I thank you.

-Bunbi-


Recommended>>
1、IBMPushing the worlds smallest computer Its performance is comparable to that of a fighter jet20
2、政府在区块链时代的角色转变
3、Penn State Talent Development Promotion Association and the Department of Computer Science of the University of Lincoln UK signed a cooperation agreement
4、2017 the time is right for Chinese CIOs to embrace AI
5、Modern browser exploration navigating the daily frontend nightly conversation

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号