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;
}
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;
This is more a design question, and I hope I express my question clear.
I have a complex process, that needs to log messages. When some of these logs are written, a event is raised and I need to respond to this.
The problem is that the CreateLog method are called from different classes during the process and currently my code only catches the events raised from the first class (MyForm).
Is there a better design where I can respond to all events from that class?
Hopefully the pseudo code below will shed some light on my problem.
File 1:
Class CreateLog
{
Log Message
Raise event
}
File 2:
Class MyForm
{
private CreateLog _log = new CreateLog();
void StartProcess()
{
Do stuff
Call _log.LogMessage //1
Call MethodB()
Call MethodC()
}
void MethodB()
{
Call _log.LogMessage //2
}
void RespondToEvent
{
//Show Progress on screen
}
}
File 2:
Class AnotherClass
{
void MethodC()
{
_log2.LogMessage() //3
}
}
So, when I run this, the message log at nr 1 and 2 will fire the RespondToEvent() method, but obviously not at nr 3, because it's a different instance of the CreateLog class.
One solution is to pass _log as a parameter to MehodC, but that does not feel like the best solution.
Any other clean way of achieving this besides adding everything into 1 class?
You can add an event to AnotherClass and raise that event in MethodC. And in MyForm handle the event and call _log.LogMessage
Example:
Class MyForm
{
//your code
RespondToEventFromAnotherClass() //handles delegateToForm Event from 'AnotherClass'
{
Call _log.LogMessage
}
}
Class AnotherClass
{
Event delegateToForm;
void MethodC()
{
_log2.LogMessages(); // you can Eleminate this line if it is not necessary
Raise Event delegateToForm
}
}
Is that possible somehow to trigger an event which belongs another class in C#, such:
class foo
{
public delegate void myEvntHandler();
public event myEvntHandler onTesting;
.
.
.
}
class Main
{
public static void Main()
{
foo obj = new foo();
...
obj.onTesting.Invoke();
}
}
on this sample I mean: obj.onTesting.Invoke();
No you can't invoke it directly from another class. That's the point of events (Encapsulation).
You need a helper method
class foo
{
public delegate void myEvntHandler();
public event myEvntHandler onTesting;
public void RaiseEvent()
{
if(onTesting !=null)
onTesting ();
}
}
Then call RaiseEvent method instead
class Main
{
public static void Main()
{
foo obj = new foo();
...
obj.RaiseEvent();
}
}
If you need to invoke it the way you did, just remove the event keyword and use a delegate. Which doesn't prevent you form doing so.(I don't recommend it)
No. The whole purpose of events is to wrap a delegate while explicitly prohibiting all access to it other than adding/removing an event handler. The event keyword is there specifically to prevent any class other than the class that declares the event from invoking it.
Short answer: No.
Longer answer: under the hood there no such thing as an "event" unlike delegates which are real objects. event is just a convenience for two methods (to add and remove handlers) and a private hidden field of type myEvntHandler.
Logically it makes no sense to raise an event from outside the class: The whole point of an event is that it is raised by the class when the class detects some trigger.
If you just want it to raise an event in order to test another class that has added a handler then the correct way to go is to:
move the event to an interface
implement the interface in your real class
create a test class that also implements the interface and add your "RaiseEvent" method to that.
Inject the interface into your unit under test
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
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();
}