How to avoid duplication of event subscription?

309 views Asked by At

I have 3 classes namely Login, Barcode, and the Main.
Login class just contains the authentication of the users.
Barcode class has the following snippet code:

    class Barcode
    {
      public delegate void BarcodeReadHandler(object sender, BarcodeEventArgs e);
      public event BarcodeReadHandler BarcodeReadOut;

      public Barcode()
      {
        //.. some codes for getting data on the scanner
        BarcodeEventArgs args = new BarcodeEventArgs(scannedData);
        BarcodeReadOut(this, args);
      }

    }

While in Main class, the subsciption of the Barcode event is done:

    public partial class Main : Form
    {
      private Barcode barcode = null;

      public Main()
      {
        barcode.BarcodeReadOut += new barcode.BarcodeReadHandler(getBarcodeStr);
      }

      //This is called before log-out.
      public void removeInstance() 
      {
        barcode.BarcodeReadOut -= new barcode.BarcodeReadHandler(getBarcodeStr);
      }

      private void getBarcodeStr(object sender, BarcodeEventArgs e)
      {
        //some code
      }

    }

The duplication of event subscription happens when I try to logout and login again.
When I tried to debug, BarcodeReadOut is called twice.
In logout, the removeInstance() is called and the Main form is Close() and Dispose() before opening the login screen.
Can someone help me on how can I avoid the duplication of the said events?

I also have done this before registering the event but nothing happens:

    public Main()
    {
        barcode.BarcodeReadOut -= new barcode.BarcodeReadHandler(getBarcodeStr);
        barcode.BarcodeReadOut += new barcode.BarcodeReadHandler(getBarcodeStr);
    }
2

There are 2 answers

0
Jon G Stødle On

You should add and remove the handler as follows:

public partial class Main : Form
{
  private Barcode barcode = null;

  public Main()
  {
    barcode.BarcodeReadOut += getBarcodeStr;
  }

  //This is called before log-out.
  public void removeInstance() 
  {
    barcode.BarcodeReadOut -= getBarcodeStr;
  }

  private void getBarcodeStr(object sender, BarcodeEventArgs e)
  {
    //some code
  }

}

Also: You don't need to define a custom delegate, you can use the generic EventHandler:

public event EventHandler<BarcodeEventArgs> BarcodeReadOut;
0
Fabjan On

It would be good to move all your logic that works with Barcode to a separate class. And it might be good to add a custom event that notifies other classes (a Form class in your case) that event has occurred :

class Barcode
{
  public delegate void BarcodeReadHandler(object sender, BarcodeEventArgs e);
  public event BarcodeReadHandler BarcodeReadOut;

  public Barcode()
  {
    //.. some codes for getting data on the scanner
    BarcodeEventArgs args = new BarcodeEventArgs(scannedData);
    BarcodeReadOut(this, args);
  }

}

class BarcodeWorker
{
    private Barcode barcode = null;
    private BarcodeReadHandler handler;
    public event BarcodeEventArgs scanComplete;

    BarcodeWorker(Barcode barcode) 
    {
       if(barcode == null) this.barcode = barcode;
    }

    public AddEventHandler()
    {
       if(handler != null) return;
       handler = new BarcodeReadHandler(getBarcodeStr);
       barcode.BarcodeReadOut += handler;
    }

    //This is called before log-out.
    public void RemoveEventHandler() 
    {
       barcode.BarcodeReadOut -= handler;
       handler = null;
    }

    private void getBarcodeStr(object sender, BarcodeEventArgs e)
    {
       scanComplete(sender, e);
    }
}

And use it like this:

BarcodeWorker barcode = new BarcodeWorker();

barcode.scanComplete += // your delegate with event handler or with anonymous method here;