Search code examples
c#oopbackgroundworkernetworkcomms.net

How to stop a BackgroundWorker externally


I have a BackgroundWorker_DoWork method in my client application which sends a tcp message using NetworkComms.Net to a server and check for an answer.

The method for that last part is NetworkComms.AppendGlobalIncomingPacketHandler where I can verify if the answer has a certain type and if yes, invoke another method to handle the answer message itself.

What I want to do is to stop the BackgroundWorker from within the handler, but I can't figure out how. Any help is greatly appreciated, as I'm very new to Object-Oriented Programming and I'm probably missing something fundamental.

Here's the relevant piece of code:

private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{

    if (backgroundWorker2.CancellationPending)
    {
        e.Cancel = true;
        return;
    }

    string serverIP = entr_serverIP.Text;

    int serverPORT;
    int.TryParse(entr_serverPORT.Text, out serverPORT);
    bool loop = true;

    while (loop == true)
    {
        if (backgroundWorker2.CancellationPending)
        {
            e.Cancel = true;
            return;
        }

        try
        {
            NetworkComms.SendObject("Message", serverIP, serverPORT, "status");

            NetworkComms.AppendGlobalIncomingPacketHandler<string>("ReturnHere", DoSomething2);


        }
        catch(DPSBase.CommsException ex2)
        {
            MessageBox.Show(ex2.ToString());

            e.Cancel = true;
            return;

        }


        Thread.Sleep(100);

    }

}


private static void DoSomething2(PacketHeader header, Connection connection, string message)
{
    bool svAlarmSent = false;
    while (svAlarmSent == false)
    {
        if (message == "KEYWORD")
        {
            string svInfo = connection.ConnectionInfo.RemoteEndPoint.ToString();

            Form4 form4 = new Form4("KEYWORD", null, svInfo);
            form4.Show();
            svAlarmSent = true;


            backgroundWorker2.CancelAsync();
            loop = false;


        }

    }

}   

The two last lines of the above code don't work because the CancelAsync method and the loop variable don't exist in that context.


Solution

  • The first step to fixing this is to enable cancellation from the DoSomething2 method. To do this it needs access to the backgroundWorker2 variable. This is a field (attribute), hence you can give it access by making the method non-static:

    private void DoSomething2(PacketHeader header, Connection connection, string message)
    

    The next step is to simple remove the access of the loop value from DoSomething2. The responsibility of this method is to signal the cancellation only. It is the job of the backgroundWorker2_DoWork method to respond to this cancellation.

    In fact the loop variable doesn't even need to be set. Once CancelAsync is called the following conditional will be met:

    if (backgroundWorker2.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
    

    By virtue of returning this code will break the while loop by itself.

    Overall I would say that this isn't really the intended use of a BackgroundWorker though. Cancellation is supposed to be used to allow the user, or some operation, to signal that the background task should cancel the work and return without completing (if possible). In this case you are using cancellation to signal the succesful completion of the code. This works but is somewhat of an unintended use case.