简体   繁体   中英

How can I cancel backgroundWorker in specific case and start the backgroundWorker over?

In form1 top:

ExtractImages ei = new ExtractImages();

In form1 constructor i start the backgroundworker first time

public Form1()
{
     InitializeComponent();

     backgroundWorker1.RunWorkerAsync();
}

In dowork event

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    if (backgroundWorker1.CancellationPending == true)
    {
       e.Cancel = true;
       return; // this will fall to the finally and close everything    
    }
    else
    {              
       ei.ProgressChanged += (senders, eee) => backgroundWorker1.ReportProgress(eee.Percentage, eee.StateText);
       ei.Init();
    }
}

In progresschanged

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    ProgressBar1.Value = e.ProgressPercentage;
    label7.Text = e.UserState.ToString();
    label8.Text = e.ProgressPercentage + "%";
}

In completed

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null) { ProgressBar1.Value = 100; }
    else
    {
    }
}

In the class top

public bool WebProblem = false;

public class ProgressEventArgs : EventArgs
{
    public int Percentage { get; set; }
    public string StateText { get; set; }
}

public event EventHandler<ProgressEventArgs> ProgressChanged;

public void Init()
{
    object obj = null;
    int index = 0;
    ExtractCountires();
    foreach (string cc in countriescodes)
    {
        // raise event here
        ProgressChanged?.Invoke(obj, new ProgressEventArgs { Percentage = 100 * index / countriescodes.Count, StateText = cc });
        ExtractDateAndTime("http://www.sat24.com/image2.ashx?region=" + cc);
        index += 1;
    }
    ImagesLinks();
}

Method in class

public void ExtractDateAndTime(string baseAddress)
{
     try
     {
         var wc = new WebClient();
         wc.BaseAddress = baseAddress;
         HtmlDocument doc = new HtmlDocument();

         var temp = wc.DownloadData("/en");
         doc.Load(new MemoryStream(temp));

         var secTokenScript = doc.DocumentNode.Descendants()
         .Where(e =>
              String.Compare(e.Name, "script", true) == 0 &&
                   String.Compare(e.ParentNode.Name, "div", true) == 0 &&
                         e.InnerText.Length > 0 &&
                             e.InnerText.Trim().StartsWith("var region")
                                 ).FirstOrDefault().InnerText;
         var securityToken = secTokenScript;
         securityToken = securityToken.Substring(0, securityToken.IndexOf("arrayImageTimes.push"));
         securityToken = secTokenScript.Substring(securityToken.Length).Replace("arrayImageTimes.push('", "").Replace("')", "");
         var dates = securityToken.Trim().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
         var scriptDates = dates.Select(x => new ScriptDate { DateString = x });
         foreach (var date in scriptDates)
         {
            DatesAndTimes.Add(date.DateString);
         }
     }
     catch(WebException wex)
     {
         WebProblem = true;
     }
}

What i want to do is once the WebProblem is true stop the loop in the Init() and stop/cancel the backgroundworker in form1.

Then in the backgroundworker completed event throw a message to a label about the problem. And start a timer and after 30 seconds start the backgroundworker again.

If the exception happen and i will use a break point in the catch and click continue it will continue but i want that once there was a problem stop everything and start over again until it will pass without any problem in the middle.

A lot of really peculiar stuff there. I suggest starting with a BackgroundWorker tutorial . Suggestions about what you have posted:

The form constructor is a really bad place to call .RunWorkerAsync ; especially if you want to be able to restart the background process again. If you really want to start your BackgroundWorker immediately, you should call something like this in your Form_Load method:

 backgroundWorker1.RunWorkerAsync(new Uri("http://www.sat24.com/image2.ashx"));

Your DoWorkEventHandler is where you should do your background work, check for cancellation, and report results and you aren't doing any of those. You want something like:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var result = new List<DateString>();
    var baseUri = (Uri)e.Argument;
    var countryCodes = ExtractCountries();
    foreach (var cc in countryCodes)
    {
        if (backgroundWorker1.CancellationPending)
        {
           e.Cancel = true;
           return;
        }

        result.Add(ExtractDateAndTime(new Uri(baseUri, "?region=" + cc));
    }

    e.Result = result;
}

You want ExtractCountries to return an IEnumerable of whatever data you want to enumaerate, and ExtractDateAndTime to accept a complete Uri and return a list of the results. Do not embed that logic in the methods or use globals to return the results; everything you need is already a part of BackgroundWorker , do not create a new class just to hand off the data. Your ExtractDateAndTime declaration should look like this:

private DateString ExtractDateAndTime(Uri source)

Do not catch exceptions in ExtractDateAndTime ; doing that will discard the exception and continue as if nothing was wrong, then return the wrong answer without warning. If you want to display the exception, let it propagate to the RunWorkerCompleted event and inspect RunWorkerCompletedEventArgs.Error .

If you want to restart the BackgroundWorker if you get an error you want to declare a Form.Timer in your Design view or Form constructor and a Tick EventHandler something like:

private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Stop();
    backgroundWorker1.RunWorkerAsync(new Uri("http://www.sat24.com/image2.ashx"));
}

In your RunWorkerCompletedEventHandler do something like:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        AlertUserSomehow(e.Error);
        timer1.Interval = 30000;
        timer1.Start();
        return;
    }

    DoSomethingWith((List<DateString>)e.Result);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM