cool hit counter [C#] BackgroundWorker with Waiting Form_Intefrankly

[C#] BackgroundWorker with Waiting Form


---------------201504170911update---------------

updateelements: Remove the new Start method from bgwUI and instead override both the RunWorkerAsync method of the base class (BackgroundWorker) with and without parameters via the new modifier + optional parameters. So just execute the task still using the familiar RunWorkerAsync and forget about the crappy Start. We would like to thank our garden friends [ A new beginning The] pointers in the comments are much appreciated!

---------------20150416 original text( thenupdate)---------------

Applicable environment. Winform project for .net 2.0+

This is the previous post [Share a task executor with a waiting form]s sister article, it is recommended to read that article first for background. As a brief introduction here, the common purpose of both solutions is to display a modal form (what I call a wait form) to the user when executing a time-consuming task, through which the task can report its execution progress to the user, and through which the user can intervene in the execution of the task (i.e. cancel ~if the task is allowed to be terminated), which amounts to passing information between the task and the user through a wait form. Such a requirement should be very common, and no UX-conscious developer is likely to leave the user with a stuck interface, so I'm sure we all have our own means of dealing with similar scenarios, such as executing tasks asynchronously while getting a scrollbar on the business form or something, like this.

Such means some apes may have formed a very perfect universal solution, more than a hundred times better than I this (here also implore passing veterans do not hesitate to share their own or they know ready-made good solution), some apes may still specific treatment of specific situations, there is no a universal solution, and what I am doing, is to share my solution, so that the apes who do not yet have a similar wheel to take, after a simple process to achieve the effect, but also, I hope to get the guidance of veteran birds, and constantly improve.

The previous post shared an executor called WaitUI that can execute any method and is simple to use. And this one shares something called BackgroundWorkerUI (hereafter referred to as bgwUI), which by its name is based on the implementation of the BackgroundWorker (hereafter probably referred to as bgw) component, so if you are more used to the way bgw is used, this one is for you. Let's start by looking at the results of using.

Function.

  • A waiting form is displayed during the execution of a task by bgwUI (DoWork event) and disappears automatically when the task is completed. Mission accomplished. means that the DoWork event ran out, not the RunWorkerCompleted event, which means that there is no longer a waiting form during the execution of RunWorkerCompleted
  • The wait form can be customized, but must implement the IWaitForm interface
  • A set of properties and methods provided by bgwUI can be accessed in the DoWork event to update the text and progress on the wait form, as well as the ability to control whether the [Cancel] button on the wait form is visible. Yes, there is no need to use the ProgressChanged event again to update the control, in fact the wait form instance (an IWaitForm instance) is hidden from the caller and you can't and don't need to operate on it directly, everything is done through bgwUI
  • If the task is allowed to be terminated, i.e. bgw. WorkerSupportsCancellation is true and the waiting window displays the [Cancel] button, which the user can click to issue a request to terminate the task, which you can access in DoWork as usual to learn about the request from CancellationPending
  • The rest of the functions are the same as bgw

Example of use.

private void button2_Click(object sender, EventArgs e)
{
     //Another overload of the constructor can be passed in an instance of a custom waiting form
    using (BackgroundWorkerUI bgwUI = new BackgroundWorkerUI(/*new MyWaitForm()*/))
    {
         bgwUI.WorkerSupportsCancellation = true;//allow cancellation of tasks

        bgwUI.DoWork += bgwUI_DoWork;
         //bgwUI.ProgressChanged += bgwUI_ProgressChanged;//It's not needed, but you can still register the ProgressChanged event to do other things
         bgwUI.RunWorkerCompleted += bgwUI_RunWorkerCompleted;// also register the RunWorkerCompleted event

        bgwUI.RunWorkerAsync();
    }
}

void bgwUI_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorkerUI bgwUI = sender as BackgroundWorkerUI;

    // This can be done bybgwUI The set of public properties and methods of theupdate Waiting for the form
     //bgwUI.CancelControlVisible = true;// Set the visibility of the control that cancels the task, by default this property will be set according to WorkerSupportsCancellation, but it can still be set freely
     bgwUI.BarStyle = ProgressBarStyle.Continuous;//Set the scrollbar style (default is Marquee: circular shuttle style)
     bgwUI.BarMaximum = 100;       // set the upper limit of the scrollbar value (default is 100)
     bgwUI.BarMinimum = 0;         // Set the lower limit of the scrollbar value (default is 0)
     bgwUI.BarStep = 1;            // Set the scrollbar step (default is 10)
bgwUI.BarVisible = true;      // set whether the scrollbar is visible (default is true: visible)

    int i;
    for (i = Convert.ToInt32(e.Argument); i <= 100; i++)
    {
         if (bgwUI.CancellationPending)//as usual, access CancellationPending to know if the user cancelled the task
        {
            e.Cancel = true;
            return;
        }

        //update The wait form does not need to callReportProgress(), Nor do I need to.WorkerReportsProgress backing
         bgwUI.WorkMessage = i.ToString();//set task progress description
         bgwUI.BarValue = i;               // Set task progress values

         //CancelControlVisible can be set repeatedly and is not restricted by WorkerSupportsCancellation
        //if (i % 10 == 0) { bgw.CancelControlVisible = false; }
        //else if (i % 5 == 0) { bgw.CancelControlVisible = true; }

        Thread.Sleep(50);
    }
    e.Result = i;
}

void bgwUI_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        MessageBox.Show(" Mission cancelled!");
    }
    else if (e.Error != null)
    {
        MessageBox.Show(" Mission anomaly!" + e.Error.Message);
    }
    else
    {
        MessageBox.Show(" Mission accomplished。" + e.Result);
    }
}

Usage differences with BackgroundWorker.

Only the differences are mentioned here, those not mentioned indicate consistency with bgw, so if you are not familiar with bgw usage, pleaseMSDN . First, look at the class diagram.

The class diagram shows that bgwUI is a subclass that inherits from bgw.

  • bgwUI overloads a constructor that can be passed into an instance of IWaitForm, which means that you can pass in a custom wait form, or use the default wait form, WaitForm, if you use the no-parameter constructor
  • DoWork events can be used directly in thebgwUI The set of properties and methods of the(WorkMessage、BarValue、BarPerformStep etc.)update Waiting for the form, Registration is no longer requiredProgressChanged events, It's over.DoWork inbgw.ReportProgress, in additionWorkerReportsProgress None of the attributes need to be set totrue。 But althoughupdate Waiting for a form does not requireProgressChanged events, But if you still need the event to do something else, You can still register and use it as usual

Programme source code.

BackgroundWorkerUI.cs Contains onlyclassBackgroundWorkerUI, It uses theWaitForm.cs Please go to Previous Article taken to help save some space in the garden ~ ha.

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace AhDung.WinForm
{
    /// <summary>
/// BackgroundWorker with waiting form. Report progress with a set of UI manipulation methods
    /// </summary>
    public class BackgroundWorkerUI : BackgroundWorker
    {
         readonly IWaitForm waitForm;//waitForm
         Form activeForm;//Active form before waiting for the form to be displayed
         bool formClosed;// Indicates whether the waiting form has been closed

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

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

        /// <summary>
         /// Get or set progress bar visibility
        /// </summary>
        public bool BarVisible
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.BarVisible)));
                }
                return waitForm.BarVisible;
            }
            set
            {
                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 ProgressBarStyle BarStyle
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return (ProgressBarStyle)(waitForm.Invoke(new Func<ProgressBarStyle>(() => waitForm.BarStyle)));
                }
                return waitForm.BarStyle;
            }
            set
            {
                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarStyle = value));
                    return;
                }
                waitForm.BarStyle = value;
            }
        }

        /// <summary>
         /// Get or set the progress value
        /// </summary>
        public int BarValue
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarValue)));
                }
                return waitForm.BarValue;
            }
            set
            {
                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 int BarStep
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarStep)));
                }
                return waitForm.BarStep;
            }
            set
            {
                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.BarStep = value));
                    return;
                }
                waitForm.BarStep = value;
            }
        }

        /// <summary>
         /// Make the progress bar step
        /// </summary>
        public void BarPerformStep()
        {
            if (waitForm.InvokeRequired)
            {
                waitForm.BeginInvoke(new Action(() => waitForm.BarPerformStep()));
                return;
            }
            waitForm.BarPerformStep();
        }

        /// <summary>
         /// Get or set the progress bar upper limit
        /// </summary>
        public int BarMaximum
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMaximum)));
                }
                return waitForm.BarMaximum;
            }
            set
            {
                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 int BarMinimum
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMinimum)));
                }
                return waitForm.BarMinimum;
            }
            set
            {
                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 bool CancelControlVisible
        {
            get
            {
                if (waitForm.InvokeRequired)
                {
                    return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.CancelControlVisible)));
                }
                return waitForm.CancelControlVisible;
            }
            set
            {
                if (waitForm.InvokeRequired)
                {
                    waitForm.BeginInvoke(new Action(() => waitForm.CancelControlVisible = value));
                    return;
                }
                waitForm.CancelControlVisible = value;
            }
        }

        #endregion

        /// <summary>
         /// Initialize the component
        /// </summary>
        public BackgroundWorkerUI()
            : this(new WaitForm())
        { }

        /// <summary>
         /// Initialize the component and specify the waiting form
        /// </summary>
        /// <param name="fmWait"> Waiting for the form</param>
        public BackgroundWorkerUI(IWaitForm fmWait)
        {
            if (fmWait == null) { throw new WaitFormNullException(); }

            waitForm = fmWait;
             waitForm.UserCancelling += WaitForm_UserCancelling;//register user cancel task event
        }

        /// <summary>
         /// Start executing background operations
        /// </summary>
        /// <param name="argument"> To be inDoWork Parameters used in event handlers</param>
        /// <remarks> The optional parameter allows you to override both the base class without referenceRunWorkerAsync, kill two birds with one stone</remarks>
        public new void RunWorkerAsync(object argument = null)
        {
            Form f;
            activeForm = (f = Form.ActiveForm) != null && f.IsMdiContainer ? f.ActiveMdiChild : f;// Record the active form at the time

            waitForm.CancelControlVisible = this.WorkerSupportsCancellation;
            formClosed = false;
            base.RunWorkerAsync(argument);

// Here is a judgment call, in extreme cases it is possible that the form will be closed before the ShowDialog
            if (!formClosed) { waitForm.ShowDialog(); }
        }

        /// <summary>
         /// When a user requests to cancel a task
        /// </summary>
        private void WaitForm_UserCancelling(object sender, EventArgs e)
        {
            this.CancelAsync();
        }

        protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
        {
            waitForm.Hide();
            formClosed = true;

             // After Hide above, the original active form will not regain focus until after the method completes, so it is necessary to intervene to make the original form gain focus now
             // Otherwise the modal window that pops up in the subsequent RunWorkerCompleted event will behave erratically
            if (activeForm != null && !activeForm.IsDisposed) { activeForm.Activate(); }

            base.OnRunWorkerCompleted(e);
        }

         //Resource release
        protected override void Dispose(bool disposing)
        {
            IDisposable form;
            if (disposing && (form = waitForm as IDisposable) != null) { form.Dispose(); }

            base.Dispose(disposing);
        }
    }
}

----------------- dividers -----------------

The following is not necessary for program use, and in a hurry you can flash it first.

Description of implementation.

  • The reason why you have to pass in the wait form at construction time, and not provide properties like WaitForm for the caller to get/set the wait form at any time, is to avoid doing some egghead control, because then, when setting these properties of bgwUI.BarVisible, the wait form could be null, and then obviously the null determination would have to be added, and there are many other cases to consider. Even now, there is nothing the caller can do if he accidentally passes in a waiting form that has already been Close/Dispose, this problem also exists in the WaitUI solution, maybe later I will change it to only allow passing in the Type of the waiting form, and finish taking full responsibility for the waiting form from birth to death in the solution to avoid external damage
  • Why is there an activeForm field. This is also explained in the source code, which is to make waiting for the form to Hide after base. Before OnRunWorkerCompleted is executed, the original active form is given focus immediately and activeForm is used to record The original active form Used. As for why this intervention is done, it is because the original active form will not get the focus immediately after waiting for the form Hide, but will get it only after the entire method of bgwUI.OnRunWorkerCompleted is executed, that is, there is no active form during the execution of base.OnRunWorkerCompleted, base.OnRunWorkerCompleted is executed by the RunWorkerCompleted event handler, in other words, there is no active form when the RunWorkerCompleted event is executed, then the modal form popped up in the event will not behave normally, as for how it is not normal, it is impossible to say, experience it yourself. Anyway the fundamental problem is that when a form pops up a modal form in an inactive state, that modal form will not work properly, to ask how you can pop up a modal form in an inactive state, this can be implemented by yourself with timer. And why it is not normal, this I also want to know, and please answer high
  • For IWaitForm and WaitForm, please refer to the previous article

-Bunbi-


Recommended>>
1、Inconsistency between bean property fields and database property fields in Mybatis
2、Heard you couldnt find the right soundtrack
3、Great news from our capital we really dont need a drivers license in the future because we dont
4、The piracy terminator is here Hollywood movies to debut on the blockchain
5、Dont blame Google for not giving you face if you dont install SSL certificate on your website

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

    已发送

    朋友将在看一看看到

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

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号