Question

I am working on a card game project in C#. In this game, there are numerous events that are fired that the cards on the table need to subscribe to. However, I need the cards to dynamically subscribe and unsubscribe to the events so that the cards that are not currently active will not respond to the events being fired.

My solution for this is to use an EventManager parent class, with one child for each event. Each of these managers will have subscribe / unsubscribe methods that take an EventHandler as a parameter. When called, the methods will subscribe / unsubscribe the provided handlers from the event assigned to that manager.

The code below is a basic Console application that uses the same design pattern as my card game, and has the same issues. You can paste it directly into Visual Studio and it will run.

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var example = new ExampleCard();
            example.Subscribe();
            example.Events.FireEventOne(null, new EventArgs());
            example.UnSubscribe();
            example.Events.FireEventOne(null, new EventArgs());
            Console.ReadLine();
        }
    }

    public class EventContainer
    {
        public delegate void EventOne(Object sender, EventArgs r);
        public event EventOne OnEventOne;

        public EventContainer()
        {
            OnEventOne += Default_Handler;
        }

        public void Default_Handler(object sender, EventArgs e)
        {

        }

        public void FireEventOne(object sender, EventArgs e)
        {
            OnEventOne(sender, e);
        }
    }

    public class EventManager
    {
        protected EventContainer Events;

        public EventManager(EventContainer events)
        {
            Events = events;
        }

        public virtual void Subscribe(EventHandler handler)
        {
        }

        public virtual void Unsubscribe(EventHandler handler)
        {
        }
    }

    public class EventOneManager : EventManager
    {
        public EventOneManager(EventContainer events)
            : base(events)
        {
        }

        public override void Subscribe(EventHandler handler)
        {
            Events.OnEventOne += new EventContainer.EventOne(handler);
        }

        public override void Unsubscribe(EventHandler handler)
        {
            Events.OnEventOne -= new EventContainer.EventOne(handler);
        }
    }

    public class ExampleCard
    {
        public EventContainer Events = new EventContainer();
        private readonly List<EventManager> _subscribedEvents = new List<EventManager>();

        public ExampleCard()
        {
            _subscribedEvents.Add(new EventOneManager(Events));
        }

        public void Example_OnEventOneFired(object sender, EventArgs e)
        {
            Console.WriteLine("Event One was fired.");
        }

        public void Subscribe()
        {
            _subscribedEvents[0].Subscribe(Example_OnEventOneFired);
        }

        public void UnSubscribe()
        {
            _subscribedEvents[0].Unsubscribe(Example_OnEventOneFired);
        }
    }
}

EventOneManager.Subscribe() seems to work, but EventOneManager.Unsubscribe() does not; after calling that method, the example card stays subscribed to the event and I can't figure out why, or how to fix it.

One thing I tried was removing the 'new EventContainer.EventOne' call making it look like this:

public override void Unsubscribe(EventHandler handler)
            {
                Events.OnEventOne -= handler;
            }

But I get this error: Cannot implicitly convert type 'System.EventHandler' to 'ConsoleApplication1.EventContainer.EventOne" Any suggestions?

Also I would like to be able to use a custom EventArgs class, but I can't figure out how to pass in a generic handler which will work with any of the events I am using. This I can work around, but I would prefer to use custom EventArgs.

Was it helpful?

Solution

You need to change the event to be of type EventHandler.
You should not make your own delegate type.

To pass additional data, use EventHandler<T>.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top