「アダプター」を使用して、このイベントを他の多くのイベントから抽象化することもできます。
たとえば、私のプロジェクトの1つから...
    #region Copyright
    /*
    This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/      
 */
#endregion
namespace Media.Sockets
{
    #region NetworkConnection
    /// <summary>
    /// Represents a <see cref="Connection"/> specific to the Network.
    /// </summary>
    public class NetworkConnection : Connection, Common.ISocketReference
    {
        #region NetworkConnectionState
        [System.Flags]
        protected enum NetworkConnectionState : long
        {
            None = 0,
            Initialized = 1,
            Bound = 2,
            Connected = 4,
        }
        #endregion
        #region Fields
        /// <summary>
        /// Created in <see cref="CreateWaitHandle"/>, Disposed in <see cref="Dispose"/>.
        /// </summary>
        Common.Extensions.WaitHandle.DisposableWaitHandle WaitHandle;
        /// <summary>
        /// The date and time when the Connection was started.
        /// </summary>
        protected System.DateTime LasRemoteConnectionStartedDateTime;
        /// <summary>
        /// The date and time when the Connection was started.
        /// </summary>
        protected System.DateTime LastRemoteConnectionCompletedDateTime;
        #endregion
        #region Properties
        /// <summary>
        /// Gets the amount of time taken to connect to the <see cref="RemoteEndPoint"/>
        /// </summary>
        public System.TimeSpan RemoteConnectionTime { get { return LastRemoteConnectionCompletedDateTime - LasRemoteConnectionStartedDateTime; } }
        /// <summary>
        /// The <see cref="System.Net.NetworkInformation.NetworkInterface"/> assoicated with the NetworkConnection.
        /// </summary>
        public System.Net.NetworkInformation.NetworkInterface NetworkInterface { get; protected set; }
        /// <summary>
        /// The <see cref="System.Net.Sockets.Socket"/> assoicated with the NetworkConnection.
        /// </summary>
        public System.Net.Sockets.Socket ConnectionSocket { get; protected set; }
        /// <summary>
        /// Indicates if the NetworkConnection has a <see cref="NetworkInterface"/> which is not null.
        /// </summary>
        public bool HasNetworkInterface { get { return NetworkInterface != null; } }
        /// <summary>
        /// The <see cref="System.Net.EndPoint"/> from which this NetworkConnection connects to the <see cref="RemoteEndPoint"/>
        /// </summary>
        public System.Net.EndPoint LocalEndPoint { get; protected set; }
        /// <summary>
        /// Indicates if this NetworkConnection has a <see cref="LocalEndPoint"/> which is not null.
        /// </summary>
        public bool HasLocalEndPoint { get { return LocalEndPoint != null; } }
        /// <summary>
        /// The <see cref="System.Net.EndPoint"/> from which this NetworkConnection is connected to via the <see cref="LocalEndPoint"/>
        /// </summary>
        public System.Net.EndPoint RemoteEndPoint { get; protected set; }
        /// <summary>
        /// Indicates if this NetworkConnection has a <see cref="RemoteEndPoint"/> which is not null.
        /// </summary>
        public bool HasRemoteEndPoint { get { return RemoteEndPoint != null; } }
        /// <summary>
        /// Indicates the <see cref="NetworkConnectionState"/> assoicated with this NetworkConnection
        /// </summary>
        protected NetworkConnectionState NetworkConnectionFlags
        {
            get { return (NetworkConnectionState)Flags; }
            set { Flags = (long)value; }
        }
        #endregion
        #region Constructor
        public NetworkConnection()
            : base() { }
        public NetworkConnection(string name, bool shouldDispose)
            : base(name, shouldDispose) { }
        public NetworkConnection(System.Net.Sockets.Socket existingSocket, bool ownsHandle, bool shouldDispose)
            : this("System.Net.Socket-" + ownsHandle.ToString(), shouldDispose)
        {
            if (existingSocket == null) throw new System.ArgumentNullException("existingSocket");
            //Assign the ConnectionSocket
            ConnectionSocket = existingSocket;
            //Flag Initialized.
            FlagInitialized();
            //Assign the NetworkInterface
            NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(ConnectionSocket);
            //Create a WaitHandle 
            CreateWaitHandle(ConnectionSocket.Handle, ownsHandle);
            //Check IsBound
            if (ConnectionSocket.IsBound)
            {
                //Flag Bound.
                FlagBound();
                //Serialize and Assign LocalEndPoint
                LocalEndPoint = existingSocket.LocalEndPoint;
            }
            //Check Connected
            if (ConnectionSocket.Connected)
            {
                //Sample the clock
                LasRemoteConnectionStartedDateTime = System.DateTime.UtcNow;
                //Serialize and Assign RemoteEndPoint
                RemoteEndPoint = existingSocket.RemoteEndPoint;
                //Call Connect to FlagConnected and call base logic.
                Connect();
                //Sample the clock
                LastRemoteConnectionCompletedDateTime = System.DateTime.UtcNow;
            }
        }
        #endregion
        #region NetworkChange Event Handlers
        void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e)
        {
            Refresh();
        }
        void NetworkChange_NetworkAddressChanged(object sender, System.EventArgs e)
        {
            Refresh();
        }
        #endregion
        #region Bound
        protected void FlagBound()
        {
            //Indicate Bound
            Flags |= (long)NetworkConnectionState.Bound;
        }
        protected void UnFlagBound()
        {
            //Indicate not Bound
            Flags &= (long)NetworkConnectionState.Bound;
        }
        #endregion
        #region Initialize
        protected void FlagInitialized()
        {
            //Indicate Connected
            Flags |= (long)NetworkConnectionState.Initialized;
        }
        protected void UnFlagInitialized()
        {
            //Indicate Not Connected
            Flags &= (long)NetworkConnectionState.Initialized;
        }
        public virtual void Initialize(bool registerForEvents)
        {
            //Check not already Initialized.
            if (false == NetworkConnectionFlags.HasFlag(NetworkConnectionState.Initialized))
            {
                //Indicate Initialized
                FlagInitialized();
                if (registerForEvents)
                {
                    //Attach events
                    System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
                    System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
                }
            }
        }
        #endregion
        #region Refresh
        public override void Refresh()
        {
            base.Refresh();
        }
        #endregion
        #region CreateConnectionSocket
        public void CreateConnectionSocket(System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType)
        {
            if (ConnectionSocket == null)
            {
                ConnectionSocket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
                CreateWaitHandle(ConnectionSocket.Handle, true);
            }
        }
        #endregion
        #region CreateWaitHandle
        public void CreateWaitHandle(System.IntPtr handle, bool ownsHandle)
        {
            if (WaitHandle == null)
            {
                WaitHandle = new Common.Extensions.WaitHandle.DisposableWaitHandle(handle, ownsHandle);
            }
        }
        #endregion
        #region Connect
        protected void FlagConnected()
        {
            //Indicate Connected
            Flags |= (long)NetworkConnectionState.Connected;
        }
        protected void UnFlagConnected()
        {
            //Indicate Not Connected
            Flags &= (long)NetworkConnectionState.Connected;
        }
        public override void Connect()
        {
            //Check not already Connected.
            if (false == NetworkConnectionFlags.HasFlag(NetworkConnectionState.Connected))
            {
                //Check IsEstablished
                if (IsEstablished) return;
                if (NetworkInterface == null) throw new System.InvalidOperationException("NetworkInterface must be assigned before calling Connect.");
                if (LocalEndPoint == null) throw new System.InvalidOperationException("LocalEndPoint must be assigned before calling Connect.");
                if (RemoteEndPoint == null) throw new System.InvalidOperationException("RemoteEndPoint must be assigned before calling Connect.");
                //Set established
                base.Connect();
                //Indicate Connected
                FlagConnected();
                //Refresh the connection
                Refresh();
            }
        }
        /// <summary>
        /// Creates the <see cref="CreateConnectionSocket"/> using the specified options and connects the socket.
        /// Assigns <see cref="LocalEndPoint"/> and <see cref="RemoteEndPoint"/>
        /// </summary>
        /// <param name="addressFamily"></param>
        /// <param name="socketType"></param>
        /// <param name="protocolType"></param>
        /// <param name="addressList"></param>
        /// <param name="port"></param>
        public virtual void Connect(System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType, System.Net.IPAddress[] addressList, int port)
        {
            try
            {
                //Create the socket
                CreateConnectionSocket(addressFamily, socketType, protocolType);
                //Sample the clock
                LasRemoteConnectionStartedDateTime = System.DateTime.UtcNow;
                //Connect the socket
                ConnectionSocket.Connect(addressList, port);
                //Sample the clock
                LastRemoteConnectionCompletedDateTime = System.DateTime.UtcNow;
            }
            finally
            {
                //Assign the NetworkInterface
                NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(ConnectionSocket);
                //Assign the LocalEndPoint
                LocalEndPoint = (System.Net.IPEndPoint)ConnectionSocket.LocalEndPoint;
                //Assign the RemoteEndPoint
                RemoteEndPoint = (System.Net.IPEndPoint)ConnectionSocket.RemoteEndPoint;
                //Call Connect to FlagConnected and call base logic.
                Connect();
            }
        }
        #endregion
        #region Disconnect
        public virtual void Disconnect(bool allowReuse = false)
        {
            //Check not already Connected.
            if (((NetworkConnectionState)Flags).HasFlag(NetworkConnectionState.Connected))
            {
                ConnectionSocket.Disconnect(allowReuse);
                base.Disconnect();
                UnFlagConnected();
                Refresh();
            }
        }
        public override void Disconnect()
        {
            Disconnect(false);
        }
        #endregion
        #region Dispose
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            using (WaitHandle)
            {
                System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
                System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
                ConnectionSocket = null;
                LocalEndPoint = RemoteEndPoint = null;
                NetworkInterface = null;
            }
        }
        #endregion
        System.Collections.Generic.IEnumerable<System.Net.Sockets.Socket> Common.ISocketReference.GetReferencedSockets()
        {
            yield return ConnectionSocket;
        }
    }
    #endregion
}
「接続」基本クラスが必要な場合は、これを参照できます
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
 Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)   
 * v//
 */
#endregion
namespace Media.Sockets
{
    #region Connection
    /// <summary>
    /// Provides a base class to facilitate the concept of a Connection.
    /// </summary>
    public abstract class Connection : Common.BaseDisposable
    {
        #region Statics
        /// <summary>
        /// A string with the format of:
        ///     `TypeName Id Flags Name`
        /// </summary>
        const string FormatString = "{0} {1} ({2}) {3}";
        #endregion
        #region Properties
        /// <summary>
        /// The unique identifier assoicated with this instance.
        /// </summary>
        public readonly System.Guid Id = System.Guid.NewGuid();
        /// <summary>
        /// The date and time the instance was created.
        /// </summary>
        public readonly System.DateTime Created = System.DateTime.UtcNow;
        /// <summary>
        /// The name assigned to this instance.
        /// </summary>
        public readonly string Name;
        /// <summary>
        /// Indicates if <see cref="Disconnect"/> will be called when disposing.
        /// </summary>
        public bool IsPersistent
        {
            get
            {
                return ShouldDispose == false;
            }
            set
            {
                ShouldDispose = value == false;
            }
        }
        /// <summary>
        /// Provided for derived implementations
        /// </summary>
        protected long Flags { get; set; }
        /// <summary>
        /// Indicates if the Connection is established.
        /// </summary>
        public virtual bool IsEstablished { get; protected set; }
        /// <summary>
        /// The date and time the Connection was established.
        /// </summary>
        public System.DateTime EstablishedDateTime { get; protected set; }
        /// <summary>
        /// The amount of time the connection has been established.
        /// </summary>
        public System.TimeSpan TimeEstablished { get { return IsEstablished ? System.DateTime.UtcNow - EstablishedDateTime : System.TimeSpan.Zero; } }
        #endregion
        #region Connect
        /// <summary>
        /// If <see cref="IsDisposed"/> is false, Sets <see cref="IsEstablished"/> to true.
        /// </summary>
        public virtual void Connect()
        {
            if (IsDisposed) return;
            EstablishedDateTime = System.DateTime.UtcNow;
            IsEstablished = true;
        }
        #endregion
        #region Disconnect
        /// <summary>
        /// If <see cref="IsDisposed"/> is false, Sets <see cref="IsEstablished"/> to false.
        /// </summary>
        public virtual void Disconnect()
        {
            if (IsDisposed) return;
            IsEstablished = false;
        }
        #endregion
        #region Refresh
        /// <summary>
        /// Refreshes the details of the Connection.
        /// Throws a <see cref="System.ObjectDisposedException"/> if <see cref="IsDisposed"/> is true.
        /// </summary>
        public virtual void Refresh()
        {
            CheckDisposed();
        }
        #endregion
        #region Dispose
        /// <summary>
        /// If <see cref="IsDisposed"/> is True the call returns immediately.
        /// Calls <see cref="Disconnect"/> if <see cref="IsPersistent"/> is False and calls <see cref="Common.BaseDisposable.Dispose"/>
        /// </summary>
        public override void Dispose()
        {
            if (IsDisposed) return;
            if (false == IsPersistent) Disconnect();
            base.Dispose();
        }
        #endregion
        #region Constructor
        public Connection(string name, bool shouldDispose)
            : base(shouldDispose)
        {
            Name = name;
        }
        public Connection()
            : this(string.Empty, true) { }
        #endregion
        #region ToString
        public override string ToString()
        {
            return string.Format(FormatString, GetType().Name.ToString(), Id.ToString(), Flags, Name);
        }
        #endregion
    }
    #endregion
}