I have two class libraries say A and B. A has reference of B. so I can call any function of B. But now the need is, I want to raise event(or function; actually just want to send a little info) of A from B. I cant add reference because of circular dependency. Is there any way to do this ?
please give me code sample; how to register and call
Thanks
Define event in class B (you can use one of Action delegates for event):
public class B
{
public event Action<int> SomethingHappened; // define event
private void Something()
{
if (SomethingHappened != null) // check if somebody subscribed
SomethingHappened(42); // raise event and pass data
}
}
And subscribe to that event in class A:
public class A
{
private B _b;
public A(B b)
{
_b = b;
_b.SomethingHappened += SomethingHappenedWithB; // subscribe
}
private void SomethingHappenedWithB(int data)
{
// handle event, use data
}
}
Consider reading C# Events Tutorial
Related
I think my question is best descirbed by a code snippet:
class A
{
public void FunctionToBeCalled();
}
class B
{
public void FunctionToBeCalledAfter();
}
Now, after a FunctionToBeCalledAfter() call, FunctionToBeCalled() needs to "know" it must be called. B cannot have an A member, but A can have a B member. Is there any way this can be implemented in C#?
Why i need this:
Class A is Application level on OSI stack. Classes B and C(unmentioned before) are Transport Level. C makes calls to FunctionToBeCalledAfter, and after this FunctionToBeCalled needs to be called. But sincer A is a higher level, B and C cannot depend(have a member A), i don't know how to call FunctionToBeCalled.
I see 2 ways to accomplish this, one easier but (arguably) less elegant, one a little more involved but (arguably) more elegant
The less elegant solution: Singleton
A Singleton pattern enforces that there can only ever be one instance of a class at any given time, this seems to line up with your description of A (which from here on out I'll call Foo, and I'll be calling B Bar). So let's implement it:
public class Foo
{
private static Foo _instance;
public static Foo Instance => _instance ?? (_instance = new Foo());
// Private constructor so no one else can instantiate Foo
private Foo() { }
public void FunctionToBeCalled() { /* your code here */ }
}
public class Bar
{
public void FunctionToBeCalledAfter()
{
// Your existing code here
Foo.Instance.FunctionToBeCalled();
}
}
Now, the problem here is if your requirements ever change and you need multiple Foos, that'll be quite a refactor to implement it. Another (larger) downside is that we explicitly reference (i.e depend on) Foo, which isn't great and a problem if Bar is inside a project/ library that cannot directly reference Foo. Luckily solution 2 fixes those problems:
The more elegant solution: Events
public class Foo
{
// We don't need Foo to be a singleton anymore
public void FunctionToBeCalled() { /* Your code here */ }
}
public class Bar
{
public delegate void FunctionToBeCalledAfterEventHandler();
public event FunctionToBecalledAfterEventHandler FunctionToBeCalledAfterEvent;
public void FunctionToBeCalledAfter()
{
// Your existing code here
OnFunctionToBeCalledAfterEvent(); // Fire the event
}
private void OnFunctionToBeCalledAfterEvent()
{
FunctionToBeCalledEvent?.Invoke();
}
}
Now, everywhere where you're creating an instance of Bar you need to have a reference to Foo and subscribe to the event like so:
// foo = instance of class Foo
var bar = new Bar();
// The compiler is smart enough to find out that 'FunctionToBeCalledAfterEvent'
// has the same signature as 'FunctionToBeCalledAfterEvent' and can call it directly
// If this just so happens to not be case, see second way to subscribe to events
bar.FunctionToBeCalledAfterEvent += foo.FunctionToBeCalled;
// Or
bar.FunctionToBeCalledAfterEvent += () => foo.FunctionToBeCalled();
Events are great
Class B can have an event that other parties can handle. At the end of B.FunctionToBeCalledAfter this event would be invoked. Anyone who registered for this event would then be notified. Usual boilerplate code involves one virtual method that invokes one event. It's the standard way of adding events. If there is no need for additional data in the event then EventArgs is used. If additional data is needed then you could replace EventArgs with EventArgs<YourData>, or as an alternative, introduce a class XxxArgs derived from EventArgs with this additional data.
Class B
{
public event EventHandler FinishedFunctionToBeCalledAfter;
protected virtual void OnFinishedFunctionToBeCalledAfter(EventArgs e)
{
EventHandler handler = FinishedFunctionToBeCalledAfter;
handler?.Invoke(this, e);
}
public void FunctionToBeCalledAfter()
{
...
OnFinishedFunctionToBeCalledAfter(EventArgs.Empty);
}
}
Now when class A gets a hold of an object of class B it would add its event handler to it:
class A
{
public void FunctionToBeCalled();
public void FinishedFunctionToBeCalledAfter(object source, EventArgs e);
public void IntroduceObject(B b)
{
b.FinishedFunctionToBeCalledAfter += FinishedFunctionToBeCalledAfter;
}
}
When this object b of class B should end its life class A must know about it so that it can remove its event handler:
b.FinishedFunctionToBeCalledAfter -= FinishedFunctionToBeCalledAfter;
Suppose I have two classes - one that is provided to me (but suppose I am not allowed to change it as it is maintained by someone else), and one that I control and can change.
// Class A is provided to me by someone else, and suppose I can't modify it
public class A
{
public A()
{
...
}
public void DoSomethingInA()
{
...
}
}
// Class B is what I control
public class B
{
public A MyClassAInstance;
public B(A myClassAInstance)
{
MyClassAInstance = myClassAInstance;
// *** HERE IS WHERE I NEED HELP
// NEED TO WRITE AN EVENT / EVENT HANDLER, WITH / WITHOUT REFLECTION
// THAT RUNS DoSomethingInB WHENEVER MyClassAInstance's DoSomethingInA
// METHOD IS CALLED (AND COMPLETED)
}
public void DoSomethingInB()
{
...
}
}
How can I define a Event / EventHandler in class B that kicks off its DoSomethingInB method whenever the class A instance MyClassAInstance's method DoSomethingInA is called (and completed).
I tried lot of options, but none seem to work.
For instance, I tried:
public class B
{
public A MyClassAInstance;
public B(A myClassAInstance)
{
MyClassAInstance = myClassAInstance;
var eventInfo = GetType().GetEvent("MyEvent");
var methodInfo = myClassAInstance.GetType().GetMethod("DoSomethingInA");
Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, myClassAInstance, methodInfo);
eventInfo.AddEventHandler(this, handler);
MyEvent += DoSomethingInB;
}
public event EventHandler MyEvent;
public void DoSomethingInB()
{
...
}
}
But this doesn't work.
Any suggestions or help would be greatly appreciated.
Suppose you have two classes:
public class A
{
int x = 0;
public void Increase()
{
x++;
}
}
public class B
{
A a;
private void DoSomething();
}
Is there a way for B to be "messaged" and execute DoSomething() when anything has changed in a (i.e. x has increased)? I know how I could make a subscribe to B, such that if B does RaiseSomeEvent(..), a reacts, but not the other way round.
Background: I'm trying to create a custom control
public class BattleshipCanvas : Canvas
{
public BSGrid BattleshipGrid {...}
...
}
that should redraw once anything inside the BattleshipGrid (BSGrid is a class encapsulating a two-dimensional array) changes, where BattleshipGrid will be bound to a certain BSGrid in the ViewModel. I thought about adding an event to BSGrid that is raised whenever I modify its data, but I don't know how to notify the BattleshipCanvas of that event.
I hope I could make it a little clear (it's hard for me to express what I want exactly here) and understandable, but if there arise any questions, feel free to comment and I'll try to answer them. Thanks!
You may be looking for events in c#. In your specific case you may like to make use of the INotifyPropertyChanged Interface. You can use it to inform other classes by events if a property inside the implementing class has changed.
This is also the base to use binding in your project later on.
public class A: INotifyPropertyChanged
{
//Event used to announce a change inside a property of your class
public event PropertyChangedEventHandler PropertyChanged;
int _x = 0;
public int X
{
get { return _x; }
set
{
if (_x != value)
{
_x = value;
OnPropertyChanged("X"); //invokes the event.
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) //make sure somebody subscribed to the event
handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); //this calls all eventhandler methods which subscribed to your classes PropertyChanged event.
}
public void Increase()
{
X++; //use the property to invoke a property changed event.
}
}
public class B
{
A a;
public B()
{
a = new A();
a.PropertyChanged += new PropertyChangedEventHandler(a_PropertyChanged); //subscribe up to the event. (use -= to unsubscribe)
a.Increase()
}
//Catch the event
void a_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//execute what you would like to do.
//you can use e.PropertyName to lookup which property has actually changed.
DoSomething();
}
private void DoSomething(){}
}
Events are probably the way to go. You can make any class in your project react to any event being raised in your program, no matter where the event is created/handled.
In your instance, it looks like you don't even need to send over any custom EventArgs.
The most simple example I could find of this is here:
http://timok.tumblr.com/post/57441520214/simplistic-event-example-in-c
I am new to C# and programming in general and am trying to figure out how to use events. Previously I have been programming with ActionScript3, and there events are a special class that you inherit from if you want to create your own events, and then that event can be called by any other class.
With C# I have tried to do something similar, like so:
public class EventManager
{
public delegate void TempDelegate();
public static event TempDelegate eSomeEvent;
}
public class SomeOtherClass
{
//doing some stuff, then:
if (EventManager.eSomeEvent != null)
{
EventManager.eSomeEvent();
}
}
This gives me a compiler error CS0070: The event 'EventManager.eSomeEvent' can only appear on the left hand side of += or -= (except when used from within the type 'EventManager')
The information about this error over on the msdn indicates that I should use += instead of trying to call the event, but I don't really understand this. I'm not trying to subscribe anything from SomeOtherClass to the event delegate, I am just trying to call this event so that it starts executing those functions that are already subscribed to that event.
So is it possible to do it this way? If not, is it at all possible to call an event that is of one class, from another class? I simply wish to reuse certain events in my classes rather than creating many similar ones in multiple classes.
Any advice with this would be greatly appreciated!
You can wrap the event call in a public method and use that from your other classes.
public void OnSomeEvent()
{
var handler = eSomeEvent;
if (handler != null) handler(this, null);
}
However you might want to look at the design again, if you are really sure the event should be on a different class than the one triggering it.
Well, the typical solution is to put eSomeEvent invocation into the EventManager class
public class EventManager
{
public delegate void TempDelegate();
public static event TempDelegate eSomeEvent;
// Not thread safe as well as your code
// May be internal, not public is better (if SomeOtherClass is in the same namespace)
public static void PerformSomeEvent() {
if (!Object.ReferenceEquals(null, eSomeEvent))
eSomeEvent(); // <- You can do it here
}
}
public class SomeOtherClass
{
//doing some stuff, then:
EventManager.PerformSomeEvent();
}
I have class A that is data context of my main window.
I have class B that is view model of one of the windows of the application.
No relation between the classes.
I need somehow to raise an event in class B , while the event handler is located in class A.
Is it possible to do so ?
Example of what I am doing is: I am tring to change the main window Title from class B.
Thanks for help
In my book you should be looking at messenger / event aggregator for pub/sub. PRISM comes with one, so do things like the MVVM Light toolkit, or you can grab my own "drop in cs file" one from Github - TinyMessenger.
This allows decoupled communication - the only thing the publisher and subscriber have in common is the aggregator and the message format itself. If the classes are unrelated, and probably constructed separately, you shouldn't be coupling them with an event. If you do use an event you need to be aware of the GC implications of subscribing to an event, if the lifetimes of the two classes are expected to be different.
So, in a very simple example, in class A you'd do something like
this.messenger.Subscribe<TitleChangeMessage>(m => <do some stuff>);
Then in class B, whenever you want to fire the "event" you'd do:
this.messenger.Publish(new TitleChangedMessage("new title"));
You just need to make the event in class B public and attach a delegate from class A to it.
Here is an example: B's constructor starts a background task, which waits for 2 secs and then raises the event. A's constructor creates an object b of type B and attaches its delegate to b's event. In the main function an object of class A is created and then the thread is put to sleep for 5 sec. Before that time passes the event has already been fired and handled.
class A
{
private B b;
public A()
{
b = new B();
b.MyEvent += MyHandler;
}
public void MyHandler(string s)
{
}
public static void Main(string[] args)
{
A a = new A();
Thread.Sleep(5000);
}
}
class B
{
public B()
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
MyEvent("");
});
}
public delegate void MyDelegate(string s);
public event MyDelegate MyEvent;
}