Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to publish and subscribe to events across different classes

Goal: To change a image on a form when either udp or tcp uses its send method

Problem: I have no idea how to get the event, eventhandler and delegates set up correctly

Send Interface

interface ISendData
{
  void Send();
}

Tcp Connection class

//Need some type of delegate??

public class TCPconnection : ISendData
{
   void Send()
   {
     //how invoke/fire a send Event?
   }
}

UDP Connection class

//Need some type of delegate??

public class UDPConnection : ISendData
{
   void Send()
   {
     //how invoke/fire a send event?
   }
}

the winform which 'should' subscribe to seeing the fired events

public class myForm
{
   private DataWatcher datawatcher = new DataWatcher();
   private Image statusIndicator = null;

   public myform()
   {
     initComponents();

     datawatcher.DataSendActive += new DataWatcherSendHandler(DataSending);
     datawatcher.DataSendInactive += new DataWatcherSendHandler(NoDataSending);
   }

   public void DataSending(object sender, DataWatcherArgs e)
   {
      statusIndicator = Properties.resources.greenLight;
   }

   public void NoDataSending(object sender, DataWatcherArgs e)
   {
      statusIndicator = Properties.resources.redLight;
   }

}

The Event/Event handler?? But I really have no Idea what I'm doing here to make this work

 public delegate void EventHandler(object sender, EventArgs e);

    class DataWatcher
    {
        public event EventHandler DataSendActive;
        public event EventHandler DataSendInactive;

        protected virtual void onDataSendActive(System.EventArgs e)
        {
            if (DataSendActive != null)
            {
                DataSendActive(this, e);
            }
        }
        protected virtual void onDataSendInactive(System.EventArgs e)
        {
            if (DataSendInactive != null)
            {
                DataSendInactive(this, e);
            }
        }
     }
like image 211
stackoverflow Avatar asked Mar 17 '13 00:03

stackoverflow


2 Answers

There are many conventions used to do this. Here's my little implementation.

public enum ActivityState
{
    Sending,
    Receiving,
    Idle
}

public interface IDataTransferManager
{
    // This event will fire when the activity state changes.
    // note that Action<T> is introduced in .NET 3.5
    // if you're using .NET 2.0, you can use a delegate.
    event Action<ActivityState> DataActivityStateChange;
   

    void Send(byte[] data);
    //byte[] Receive(); 
    // ... more methods ... //

}

Now the TcpConnection class will implement this.

public class TcpConnection : IDataTransferManager
{
    public event Action<ActivityState> DataActivityStateChange;

    public void Send(byte[] data)
    {
        // we're sending data. fire the change event
        FireDataActivityStateChange(ActivityState.Sending);

        //TODO: send the data

        // we're done sending. Fire the change event
        FireDataActivityStateChange(ActivityState.Idle);
    }



    private void FireDataActivityStateChange(ActivityState state)
    {
        // helper method, so I don't have to check the event 
        // to avoid null reference exceptions.
        if (DataActivityStateChange != null)
            DataActivityStateChange(state);
    }

}

Here's the setup for your Form.

class MyForm // :Form
{
    IDataTransferManager dataManager;

    public MyForm()
    {   // here, usually an instance will be passed in, 
        // so there's only one instance throughout the application.
        // let's new up an instance for explanation purposes.
        dataManager = new TcpConnection();

        dataManager.DataActivityStateChange += (state) => 
        {
            // NOTE: if you don't like inline, 
            // you can point this labda to a method.
            
            switch (state)
            {
                case ActivityState.Sending:
                    // change the image to the spinning toilet ball
                    break;
                case ActivityState.Receiving:
                    // change the image to the spinning toilet ball, but reverse :P
                    break;
                case ActivityState.Idle:
                    // hide it ?
                    break;
            }
        };
    }
}
like image 171
Madushan Avatar answered Oct 06 '22 00:10

Madushan


Here is a simple example of how you could implement an event for sending and not sending and subscribe to it

public class Connection
{
    //Set up an event
    public event EventHandler DataSending;
    public event EventHandler DataNotSending

    //This method will trigger the event for sending
    private void OnDataSending()
    {
        if (DataSending!= null) { DataSending(this, EventArgs.Empty); }
    }

    //this method will trigger the event for finished sending
    private void OnDataNotSending()
    {
        if (DataNotSending!= null) { DataNotSending(this, EventArgs.Empty); }
    }

    //This method performs your send logic
    public void Send()
    {
         //Call your method that tells the event to be raised
         OnDataSending();
         //Then put your send code
         OnDataNotSending(); //we're done!

    }
}

This is how you use it in a consuming program

public class myForm
{
     //This method is the one that sets up the 
     //instance and subscribes to the event
     public myForm()
     {
         Connection con = new Connection();

         con.DataSending += new EventHandler(con_DataSending);
         con.DataNotSending += new EventHander(con_DataNotSending);

     }

     void con_DataSending(object sender, EventArgs e)
     {
         //Put your subscription logic here.
         //Whatever you want to do in response to a send
     }

     void con_DataNotSending(object sender, EventArgs e)
     {
         //Put your subscription logic here.
         //Respond to it not sending
     }
}
like image 30
Bill Avatar answered Oct 06 '22 00:10

Bill