Vra

Oorweeg a hipoteties metode van 'n voorwerp wat dinge vir jou doen:

public class DoesStuff
{
    BackgroundWorker _worker = new BackgroundWorker();

    ...

    public void CancelDoingStuff()
    {
        _worker.CancelAsync();

        //todo: Figure out a way to wait for BackgroundWorker to be cancelled.
    }
}

Hoe kan mens wag dat 'n BackgroundWorker gedoen word?


In die verlede het mense probeer:

while (_worker.IsBusy)
{
    Sleep(100);
}

Maar hierdie dooiepunte, omdat IsBusy word eers na die skoongemaak RunWorkerCompleted gebeurtenis hanteer word, en daardie gebeurtenis kan nie gehanteer word totdat die toepassing ledig gaan nie.Die toepassing sal nie ledig gaan totdat die werker klaar is nie.(Plus, dit is 'n besige lus - walglik.)

Ander het voorgestel om dit in te voeg:

while (_worker.IsBusy)
{
    Application.DoEvents();
}

Die probleem daarmee is dit Application.DoEvents() veroorsaak dat boodskappe tans in die tou verwerk word, wat hertoetredingsprobleme veroorsaak (.NET is nie hertoetreder nie).

Ek sou hoop om 'n oplossing te gebruik wat gebeurtenissinchronisasie-voorwerpe behels, waar die kode wag vir 'n geleentheid - wat die werker s'n RunWorkerCompleted gebeurtenis hanteerders stelle.Iets soos:

Event _workerDoneEvent = new WaitHandle();

public void CancelDoingStuff()
{
    _worker.CancelAsync();
    _workerDoneEvent.WaitOne();
}

private void RunWorkerCompletedEventHandler(sender object, RunWorkerCompletedEventArgs e)
{
    _workerDoneEvent.SetEvent();
}

Maar ek is terug na die dooiepunt:die gebeurtenishanteerder kan nie loop totdat die toepassing idle gaan nie, en die toepassing sal nie ledig gaan nie, want dit wag vir 'n gebeurtenis.

So hoe kan jy wag dat 'n BackgroundWorker klaar is?


OpdateerDit lyk asof mense verward is deur hierdie vraag.Dit lyk asof hulle dink dat ek die BackgroundWorker sal gebruik as:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += MyWork;
worker.RunWorkerAsync();
WaitForWorkerToFinish(worker);

Dit is nie dit, dit wil sê nie wat ek doen, en dit is nie wat hier gevra word.As dit die geval was, sou dit geen sin wees om 'n agtergrondwerker te gebruik nie.

Was dit nuttig?

Oplossing

As ek jou vereiste reg verstaan, kan jy iets soos hierdie doen (kode nie getoets nie, maar wys die algemene idee):

private BackgroundWorker worker = new BackgroundWorker();
private AutoResetEvent _resetEvent = new AutoResetEvent(false);

public Form1()
{
    InitializeComponent();

    worker.DoWork += worker_DoWork;
}

public void Cancel()
{
    worker.CancelAsync();
    _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    while(!e.Cancel)
    {
        // do something
    }

    _resetEvent.Set(); // signal that worker is done
}

Ander wenke

Daar is 'n probleem met hierdie reaksie. Die UI moet voortgaan om boodskappe terwyl jy wag verwerk, anders sal dit nie verf, wat 'n probleem sal wees as jou agtergrond werker neem 'n lang tyd om te reageer op die kanselleer versoek.

'n tweede fout is dat _resetEvent.Set() sal nooit genoem word as die werker draad gooi 'n uitsondering - die verlaat van die belangrikste draad onbepaald wag -. Egter hierdie fout kan maklik vasgestel word met 'n drie / uiteindelik te sluit

Een manier om dit te doen, is om 'n modale dialoog wat 'n timer wat herhaaldelik tjeks indien die agtergrond werker werk klaar (of klaar te kanselleer in jou geval) het vertoon. Sodra die agtergrond werker klaar is, die modale dialoog opbrengste te beheer om jou aansoek. Die gebruiker kan nie kommunikeer met die UI totdat dit gebeur.

Nog 'n metode (as jy het 'n maksimum van een bevat geen venster oop) is om ActiveForm.Enabled = vals, dan loop op aansoek uiteengesit, DoEvents totdat die agtergrond werker klaar te kanselleer, waarna jy ActiveForm.Enabled kan stel = true weer.

Byna almal van julle is verward deur die vraag, en verstaan ​​nie hoe 'n werker gebruik word nie.

Oorweeg 'n RunWorkerComplete gebeurtenis hanteerder:

private void OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (!e.Cancelled)
    {
        rocketOnPad = false;
        label1.Text = "Rocket launch complete.";
    }
    else
    {
        rocketOnPad = true;
        label1.Text = "Rocket launch aborted.";
    }
    worker = null;
}

En alles is goed.

Nou kom 'n situasie waar die oproeper die aftelling moet staak omdat hulle 'n nood-selfvernietiging van die vuurpyl moet uitvoer.

private void BlowUpRocket()
{
    if (worker != null)
    {
        worker.CancelAsync();
        WaitForWorkerToFinish(worker);
        worker = null;
    }

    StartClaxon();
    SelfDestruct();
}

En daar is ook 'n situasie waar ons die toegangshekke na die vuurpyl moet oopmaak, maar nie terwyl ons 'n aftelling doen nie:

private void OpenAccessGates()
{
    if (worker != null)
    {
        worker.CancelAsync();
        WaitForWorkerToFinish(worker);
        worker = null;
    }

    if (!rocketOnPad)
        DisengageAllGateLatches();
}

En uiteindelik moet ons die vuurpyl ontbrand, maar dit word nie tydens 'n aftelling toegelaat nie:

private void DrainRocket()
{
    if (worker != null)
    {
        worker.CancelAsync();
        WaitForWorkerToFinish(worker);
        worker = null;
    }

    if (rocketOnPad)
        OpenFuelValves();
}

Sonder die vermoë om te wag vir 'n werker om te kanselleer, moet ons al drie metodes na die RunWorkerCompletedEvent skuif:

private void OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (!e.Cancelled)
    {
        rocketOnPad = false;
        label1.Text = "Rocket launch complete.";
    }
    else
    {
        rocketOnPad = true;
        label1.Text = "Rocket launch aborted.";
    }
    worker = null;

    if (delayedBlowUpRocket)
        BlowUpRocket();
    else if (delayedOpenAccessGates)
        OpenAccessGates();
    else if (delayedDrainRocket)
        DrainRocket();
}

private void BlowUpRocket()
{
    if (worker != null)
    {
        delayedBlowUpRocket = true;
        worker.CancelAsync();
        return;
    }

    StartClaxon();
    SelfDestruct();
}

private void OpenAccessGates()
{
    if (worker != null)
    {
        delayedOpenAccessGates = true;
        worker.CancelAsync();
        return;
    }

    if (!rocketOnPad)
        DisengageAllGateLatches();
}

private void DrainRocket()
{
    if (worker != null)
    {
        delayedDrainRocket = true;
        worker.CancelAsync();
        return;
    }

    if (rocketOnPad)
        OpenFuelValves();
}

Nou kan ek my kode so skryf, maar ek gaan net nie.Ek gee nie om nie, ek is net nie.

Jy kan kyk na die RunWorkerCompletedEventArgs in die RunWorkerCompletedEventHandler wat die status is te sien. Sukses, gekanselleer of 'n fout.

private void RunWorkerCompletedEventHandler(sender object, RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
    {
        Console.WriteLine("The worker was cancelled.");
    }
}

Update : Om te sien of jou werker .CancelAsync () het 'n beroep deur die gebruik van hierdie:

if (_worker.CancellationPending)
{
    Console.WriteLine("Cancellation is pending, no need to call CancelAsync again");
}

Jy nie wag vir die agtergrond werker neem om te voltooi. Wat pretty much nederlae die doel van die launch van 'n aparte draad. In plaas daarvan, moet jy toelaat dat jou metode afwerking, en beweeg enige kode wat afhanklik is van die voltooiing van 'n ander plek. Jy laat die werker jy vertel wanneer dit gedoen is en noem enige oorblywende kode dan.

As jy wil wag vir iets om gebruik te voltooi 'n ander threading konstruk wat 'n WaitHandle bied.

Hoekom kan jy nie net bind in die BackgroundWorker.RunWorkerCompleted Event. Dit is 'n terugbel wat sal "vind plaas wanneer die agtergrond operasie voltooi, is gekanselleer, of het 'n uitsondering opgewek."

Ek verstaan ​​nie hoekom jy wil wag vir 'n BackgroundWorker om te voltooi nie;dit lyk regtig soos presies die teenoorgestelde van die motivering vir die klas.

Jy kan egter elke metode begin met 'n oproep na worker.IsBusy en laat hulle verlaat as dit loop.

Just wanna sê ek hier gekom, want ek het 'n agtergrond werker te wag terwyl ek 'n asinkroniseer proses hardloop terwyl in 'n lus, my fix was weg makliker as al hierdie ander dinge ^^

foreach(DataRow rw in dt.Rows)
{
     //loop code
     while(!backgroundWorker1.IsBusy)
     {
         backgroundWorker1.RunWorkerAsync();
     }
}

Net gedink ek wil deel, want dit is waar ek beland, terwyl die soek vir 'n oplossing. Ook, dit is my eerste post op stapel oorloop so as sy sleg of iets wat ek sou graag kritici! :)

Hm miskien ek nie reg om jou vraag.

Die Background noem die WorkerCompleted gebeurtenis een keer sy 'workermethod' (die metode / funksie / sub dat die backgroundworker.doWork-gebeurtenis ) is klaar so daar is geen rede vir die beheer as die BW is steeds aan die gang. As jy wil hê dat jou werker stop check die kansellasie hangende eiendom binne jou 'n werker metode.

Die workflow van 'n BackgroundWorker voorwerp basies vereis dat jy die RunWorkerCompleted gebeurtenis te hanteer vir beide normale uitvoering en gebruikers kansellasie gebruik gevalle. Dit is die rede waarom die eiendom RunWorkerCompletedEventArgs.Cancelled bestaan. Basies, om dit te doen vereis behoorlik dat jy kyk na jou styl metode om 'n asinchrone metode op sigself wees.

Hier is 'n voorbeeld:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;

namespace WindowsFormsApplication1
{
    public class AsyncForm : Form
    {
        private Button _startButton;
        private Label _statusLabel;
        private Button _stopButton;
        private MyWorker _worker;

        public AsyncForm()
        {
            var layoutPanel = new TableLayoutPanel();
            layoutPanel.Dock = DockStyle.Fill;
            layoutPanel.ColumnStyles.Add(new ColumnStyle());
            layoutPanel.ColumnStyles.Add(new ColumnStyle());
            layoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
            layoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

            _statusLabel = new Label();
            _statusLabel.Text = "Idle.";
            layoutPanel.Controls.Add(_statusLabel, 0, 0);

            _startButton = new Button();
            _startButton.Text = "Start";
            _startButton.Click += HandleStartButton;
            layoutPanel.Controls.Add(_startButton, 0, 1);

            _stopButton = new Button();
            _stopButton.Enabled = false;
            _stopButton.Text = "Stop";
            _stopButton.Click += HandleStopButton;
            layoutPanel.Controls.Add(_stopButton, 1, 1);

            this.Controls.Add(layoutPanel);
        }

        private void HandleStartButton(object sender, EventArgs e)
        {
            _stopButton.Enabled = true;
            _startButton.Enabled = false;

            _worker = new MyWorker() { WorkerSupportsCancellation = true };
            _worker.RunWorkerCompleted += HandleWorkerCompleted;
            _worker.RunWorkerAsync();

            _statusLabel.Text = "Running...";
        }

        private void HandleStopButton(object sender, EventArgs e)
        {
            _worker.CancelAsync();
            _statusLabel.Text = "Cancelling...";
        }

        private void HandleWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                _statusLabel.Text = "Cancelled!";
            }
            else
            {
                _statusLabel.Text = "Completed.";
            }

            _stopButton.Enabled = false;
            _startButton.Enabled = true;
        }

    }

    public class MyWorker : BackgroundWorker
    {
        protected override void OnDoWork(DoWorkEventArgs e)
        {
            base.OnDoWork(e);

            for (int i = 0; i < 10; i++)
            {
                System.Threading.Thread.Sleep(500);

                if (this.CancellationPending)
                {
                    e.Cancel = true;
                    e.Result = false;
                    return;
                }
            }

            e.Result = true;
        }
    }
}

As jy regtig wil nie jou metode om af te sluit, wil ek voorstel om 'n vlag soos 'n AutoResetEvent op 'n afgeleide BackgroundWorker, dan ignoreer OnRunWorkerCompleted om die vlag te stel. Dit is nog steeds soort kludgy al; Ek sou aanbeveel behandeling van die gebeurtenis te kanselleer soos 'n asinchrone metode en doen wat dit tans doen in die RunWorkerCompleted hanteerder.

Ek is 'n bietjie laat om die party hier (oor 4 jaar), maar wat oor die opstel van 'n asinchrone draad wat 'n besige lus kan hanteer sonder om te sluit die UI, dan het die callback van daardie draad wees die bevestiging dat die Background klaar te kanselleer?

Iets soos hierdie:

class Test : Form
{
    private BackgroundWorker MyWorker = new BackgroundWorker();

    public Test() {
        MyWorker.DoWork += new DoWorkEventHandler(MyWorker_DoWork);
    }

    void MyWorker_DoWork(object sender, DoWorkEventArgs e) {
        for (int i = 0; i < 100; i++) {
            //Do stuff here
            System.Threading.Thread.Sleep((new Random()).Next(0, 1000));  //WARN: Artificial latency here
            if (MyWorker.CancellationPending) { return; } //Bail out if MyWorker is cancelled
        }
    }

    public void CancelWorker() {
        if (MyWorker != null && MyWorker.IsBusy) {
            MyWorker.CancelAsync();
            System.Threading.ThreadStart WaitThread = new System.Threading.ThreadStart(delegate() {
                while (MyWorker.IsBusy) {
                    System.Threading.Thread.Sleep(100);
                }
            });
            WaitThread.BeginInvoke(a => {
                Invoke((MethodInvoker)delegate() { //Invoke your StuffAfterCancellation call back onto the UI thread
                    StuffAfterCancellation();
                });
            }, null);
        } else {
            StuffAfterCancellation();
        }
    }

    private void StuffAfterCancellation() {
        //Things to do after MyWorker is cancelled
    }
}

In wese wat dit doen is vuur af 'n ander draad uit te voer in die agtergrond wat net wag in dis besig lus om te sien of die MyWorker voltooi. Sodra MyWorker klaar te kanselleer die draad sal verlaat en ons kan gebruik dit AsyncCallback om uit te voer wat ook al manier wat ons nodig het om die suksesvolle kansellasie volg - dit sal werk soos 'n psuedo-gebeurtenis. Aangesien dit is apart van die UI draad sal dit nie die UI sluit terwyl ons wag vir MyWorker om klaar te kanselleer. As jou bedoeling is regtig aan te sluit en wag vir die kanselleer dan is dit nutteloos om jou, maar as jy net wil om dit te wag kan jy nog 'n proses begin dan werk dit mooi.

Ek weet dit is regtig laat (5 jaar), maar wat jy is op soek na is aan 'n draadjie en 'n SynchronizationContext . Jy gaan hê om veiligheidsbeampte UI oproepe terug na die UI draad "met die hand" eerder as laat die raamwerk doen dit outomaties mettertyd.

Dit laat jou toe om 'n onderwerp wat jy kan nie wag vir indien nodig gebruik.

Imports System.Net
Imports System.IO
Imports System.Text

Public Class Form1
   Dim f As New Windows.Forms.Form
  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
   BackgroundWorker1.WorkerReportsProgress = True
    BackgroundWorker1.RunWorkerAsync()
    Dim l As New Label
    l.Text = "Please Wait"
    f.Controls.Add(l)
    l.Dock = DockStyle.Fill
    f.StartPosition = FormStartPosition.CenterScreen
    f.FormBorderStyle = Windows.Forms.FormBorderStyle.None
    While BackgroundWorker1.IsBusy
        f.ShowDialog()
    End While
End Sub




Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

    Dim i As Integer
    For i = 1 To 5
        Threading.Thread.Sleep(5000)
        BackgroundWorker1.ReportProgress((i / 5) * 100)
    Next
End Sub

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    Me.Text = e.ProgressPercentage

End Sub

 Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

    f.Close()

End Sub

End Class

Fredrik Kalseth se oplossing vir hierdie probleem is die beste wat ek tot dusver gevind het.Ander oplossings gebruik Application.DoEvent() wat probleme kan veroorsaak of eenvoudig nie werk nie.Laat ek sy oplossing in 'n herbruikbare klas gooi.Sedert BackgroundWorker nie verseël is nie, kan ons ons klas daaruit aflei:

public class BackgroundWorkerEx : BackgroundWorker
{
    private AutoResetEvent _resetEvent = new AutoResetEvent(false);
    private bool _resetting, _started;
    private object _lockObject = new object();

    public void CancelSync()
    {
        bool doReset = false;
        lock (_lockObject) {
            if (_started && !_resetting) {
                _resetting = true;
                doReset = true;
            }
        }
        if (doReset) {
            CancelAsync();
            _resetEvent.WaitOne();
            lock (_lockObject) {
                _started = false;
                _resetting = false;
            }
        }
    }

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        lock (_lockObject) {
            _resetting = false;
            _started = true;
            _resetEvent.Reset();
        }
        try {
            base.OnDoWork(e);
        } finally {
            _resetEvent.Set();
        }
    }
}

Met vlae en behoorlike sluiting maak ons ​​seker dat _resetEvent.WaitOne() word regtig net gebel as daar met werk begin is, anders _resetEvent.Set(); dalk nooit genoem nie!

Die probeerslag verseker dit _resetEvent.Set(); sal geroep word, selfs al sou 'n uitsondering in ons DoWork-hanteerder voorkom.Andersins kan die toepassing vir ewig vries wanneer u bel CancelSync!

Ons sal dit so gebruik:

BackgroundWorkerEx _worker;

void StartWork()
{
    StopWork();
    _worker = new BackgroundWorkerEx { 
        WorkerSupportsCancellation = true,
        WorkerReportsProgress = true
    };
    _worker.DoWork += Worker_DoWork;
    _worker.ProgressChanged += Worker_ProgressChanged;
}

void StopWork()
{
    if (_worker != null) {
        _worker.CancelSync(); // Use our new method.
    }
}

private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 1; i <= 20; i++) {
        if (worker.CancellationPending) {
            e.Cancel = true;
            break;
        } else {
            // Simulate a time consuming operation.
            System.Threading.Thread.Sleep(500);
            worker.ReportProgress(5 * i);
        }
    }
}

private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressLabel.Text = e.ProgressPercentage.ToString() + "%";
}

Jy kan ook 'n hanteerder by die RunWorkerCompleted gebeurtenis soos hier getoon:
     AgtergrondWerkerklas (Microsoft dokumentasie).

Die sluiting van die vorm sluit my oop loglêer. My agtergrond werker skryf dat loglêer, so ek kan nie toelaat dat MainWin_FormClosing() afwerking totdat my agtergrond werker beëindig. As ek nie wag vir my agtergrond werker te beëindig, uitsonderings gebeur.

Hoekom is dit so moeilik?

'n eenvoudige Thread.Sleep(1500) werk, maar dit vertraag afsluit (as te lank), of veroorsaak dat uitsonderings (indien te kort).

Om af te sluit direk na die agtergrond werker beëindig, net gebruik om 'n veranderlike. Dit werk vir my:

private volatile bool bwRunning = false;

...

private void MainWin_FormClosing(Object sender, FormClosingEventArgs e)
{
    ... // Clean house as-needed.

    bwInstance.CancelAsync();  // Flag background worker to stop.
    while (bwRunning)
        Thread.Sleep(100);  // Wait for background worker to stop.
}  // (The form really gets closed now.)

...

private void bwBody(object sender, DoWorkEventArgs e)
{
    bwRunning = true;

    BackgroundWorker bw = sender as BackgroundWorker;

    ... // Set up (open logfile, etc.)

    for (; ; )  // infinite loop
    {
        ...
        if (bw.CancellationPending) break;
        ...
    } 

    ... // Tear down (close logfile, etc.)

    bwRunning = false;
}  // (bwInstance dies now.)

Jy kan terug piggy af van die RunWorkerCompleted gebeurtenis. Selfs as jy reeds 'n event handler vir _worker bygevoeg het, kan jy 'n ander voeg 'n hulle sal uit te voer in die volgorde waarin hulle is bygevoeg.

public class DoesStuff
{
    BackgroundWorker _worker = new BackgroundWorker();

    ...

    public void CancelDoingStuff()
    {
        _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((sender, e) => 
        {
            // do whatever you want to do when the cancel completes in here!
        });
        _worker.CancelAsync();
    }
}

Dit kan nuttig wees indien jy meer redes waarom 'n kanselleer mag voorkom, maak die logika van 'n enkele RunWorkerCompleted hanteerder meer ingewikkeld as wat jy wil. Byvoorbeeld, kanselleer wanneer 'n gebruiker probeer om die vorm te sluit:

void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    if (_worker != null)
    {
        _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((sender, e) => this.Close());
        _worker.CancelAsync();
        e.Cancel = true;
    }
}

Ek gebruik async metode en await om te wag vir die werker afwerking sy werk:

    public async Task StopAsync()
    {
        _worker.CancelAsync();

        while (_isBusy)
            await Task.Delay(1);
    }

en in DoWork metode:

    public async Task DoWork()
    {
        _isBusy = true;
        while (!_worker.CancellationPending)
        {
            // Do something.
        }
        _isBusy = false;
    }

Jy kan ook omsluit die while lus in DoWork met try ... catch te stel _isBusy is false op uitsondering nie. Of, kyk net _worker.IsBusy in die StopAsync terwyl loop.

Hier is 'n voorbeeld van 'n volledige implementering:

class MyBackgroundWorker
{
    private BackgroundWorker _worker;
    private bool _isBusy;

    public void Start()
    {
        if (_isBusy)
            throw new InvalidOperationException("Cannot start as a background worker is already running.");

        InitialiseWorker();
        _worker.RunWorkerAsync();
    }

    public async Task StopAsync()
    {
        if (!_isBusy)
            throw new InvalidOperationException("Cannot stop as there is no running background worker.");

        _worker.CancelAsync();

        while (_isBusy)
            await Task.Delay(1);

        _worker.Dispose();
    }

    private void InitialiseWorker()
    {
        _worker = new BackgroundWorker
        {
            WorkerSupportsCancellation = true
        };
        _worker.DoWork += WorkerDoWork;
    }

    private void WorkerDoWork(object sender, DoWorkEventArgs e)
    {
        _isBusy = true;
        try
        {
            while (!_worker.CancellationPending)
            {
                // Do something.
            }
        }
        catch
        {
            _isBusy = false;
            throw;
        }

        _isBusy = false;
    }
}

Om die werker te stop en wag vir dit loop aan die einde:

await myBackgroundWorker.StopAsync();

Die probleme met hierdie metode is:

  1. Jy moet asinkroniseer metodes gebruik al die pad.
  2. wag Task.Delay is verkeerd. Op my PC, Task.Delay (1) eintlik wag ~ 20ms.

oh man, 'n paar van hierdie gekry belaglik kompleks. al wat jy hoef te doen is seker die eiendom BackgroundWorker.CancellationPending binne die DoWork hanteerder. jy kan dit kyk op enige tyd. nadat dit hangende, stel e.Cancel = Ware en borgtog van die metode.

// metode hier private leemte Worker_DoWork (voorwerp sender, DoWorkEventArgs e) {     Background bw = (sender as Background);

// do stuff

if(bw.CancellationPending)
{
    e.Cancel = True;
    return;
}

// do other stuff

}

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top