Add this somewhere in your code: (Usually I put this in a static helper class called ISynchronizedInvoke, so I can call ISynchronizedInvoke.Invoke (...));
public static void Invoke(ISynchronizeInvoke sync, Action action) { if (!sync.InvokeRequired) { action(); } else { object[] args = new object[] { }; sync.Invoke(action, args); } }
Then inside OnDataReceived you can do:
Invoke(consumer, () => consumer.PresentData());
This calls "consumer.PresentData" on the "consumer".
As for your design problem (communicator for consumer links), you can enter a method inside the communicator, for example:
class Communicator { private ISynchronizeInvoke sync; private Action syncAction; public void SetSync(ISynchronizeInvoke sync, Action action) { this.sync = sync; this.syncAction = action; } protected virtual void OnDataReceived(...) { if (!sync.InvokeRequired) { syncAction(); } else { object[] args = new object[] { }; sync.Invoke(action, args); } } }
This will give you the opportunity to go to ISynchronizedInvoke from your consumer class. This way you create ISynchronizedInvoke in the assembly for consumers.
class Consumer { public void Foo() { communicator.SetSync(this, () => this.PresentData()); } }
So, basically, you create everything you need for a call and simply transfer it to your communicator. This solves your need to have an instance or reference to the consumer in the communicator.
Also note that I have not tested this, I do all of this theoretically, but it should work well.