0

I have a C# WPF GUI in ProjectA. I raise an event in ProjectA and want to subscribe/respond to that event from within ProjectB which is a dll that knows nothing about ProjectA. ProjectA has references to objects in ProjectB, but not vice versa.

For example, user clicks a button in ProjectA. Inside ProjectA's button_Click() handler it calls UserClickedButtonX(this, e). ProjectB should subscribe to the UserClickedButtonEvent and handle it when the event is raised.

The code below doesn't work since ProjectB doesn't know about 'MainWindow' in ProjectA. Thanks in advance!

In ProjectA (Mainwindow.xaml.cs):
        private void buttonX_Click(object sender, RoutedEventArgs e) {
            OnUserClickedButtonXEvent(new EventArgs());
        }

        public static event UserClickedButtonXEventHandler UserClickedButtonXEvent;
        public virtual void OnUserClickedButtonXEvent(EventArgs e) {
            if (UserClickedButtonXEvent!= null)
                UserClickedButtonXEvent(this, e);
        }

In Project B (dll):
           MainWindow.UserClickedButtonXEvent+= new UserClickedButtonXEventHandler(UserClickedButtonXFunction);

        void UserClickedButtonXFunction(object source, EventArgs e) {
            Console.WriteLine("User clicked Button X on the GUI in another project!");
        }
nb1forxp
  • 385
  • 2
  • 14
  • Consider the solution proposed by @ScottNimrod, but don't use his implementation of the `EventAggregator`. Take the Prism's `EventAggragator` and `PubSubEvent`s instead. More info [here](http://compositewpf.codeplex.com/). – dymanoid Dec 21 '14 at 13:42
  • Dude, why not just extend the example I provided if necessary? – Scott Nimrod Dec 21 '14 at 14:55

2 Answers2

0

You should be able to put this line into ProjectA (eg. MainWindow contructor):

MainWindow.UserClickedButtonXEvent += ProjectB.ClassB.UserClickedButtonXFunction;

Function has to be public static, or you have to create an instance of ClassB, eg. a singleton.

Jan Zahradník
  • 2,417
  • 2
  • 33
  • 44
  • While the other answers/comments are more generic/robust, I marked this as the solution since it achieves the desired behavior and is much more simple to implement. Thanks to all! – nb1forxp Jan 02 '15 at 20:15
0

Consider using an EventAggregator to decouple classes from each other in regards to publish\subscribe events.

This pattern leverages messages (i.e. strings) that publishers and subscribers can leverage without knowing about each other.

[TestMethod]
public void eventaggregator()
{
    // Setup
    var subscription = "my_subscription";
    bool messageReceived = false;

    EventAggregator.Instance.Register(subscription, (parameter) =>
        {
            // Logic goes here...
            messageReceived = true;
        });

    // Test
    EventAggregator.Instance.Publish(subscription, "a parameter for subscibers");

    // Verify
    Assert.IsTrue(messageReceived);
}


public class EventAggregator
{
    #region Singleton
    static EventAggregator _eventAggregator = null;
    private EventAggregator() { }

    public static EventAggregator Instance
    {
        get
        {
            if (_eventAggregator == null)
            {
                _eventAggregator = new EventAggregator();
            }

            return _eventAggregator;
        }
    }
    #endregion

    List<Observer> _observers = new List<Observer>();

    public void Register(string subscription, Action<object> response)
    {
        var observer = new Observer() { Subscription = subscription, Respond = response };
        _observers.Add(observer);
    }

    public void Publish(string subscription, object payload)
    {
        foreach (var observer in _observers)
        {
            if (observer.Subscription == subscription)
            {
                observer.Respond(payload);
            }
        }
    }
}

public class Observer
{
    public string Subscription { get; set; }
    public Action<object> Respond {get; set; }
}
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • With this implementation, we guaranteed get memory leaks, because you don't provide any possibility to unsubscribe/unregister; so all the registered object references will be constantly held in your EventAggregator instance preventing the garbage collector to clean them up. – dymanoid Dec 21 '14 at 13:40
  • You are correct. I removed the Clear() method for clarity. The focus of my answer is based on the initial question. All other details would obscure the code example. Thanks though. – Scott Nimrod Dec 21 '14 at 14:10