Child/Parent event raising - c#

I have a parent abstract class with several children classes. Eventually, I would like the progress done in the children classes to be shown via a progress bar in the GUI.
What I currently have done right now, which I am realizing will not work, is the event method definition declared in the parent class as a virtual method which each child class will overwrite. So something like :
public abstract class Parent
{
public event EventHandler someEvent;
protected virtual void OnSomeEvent(object sender, EventArgs e)
{
EventHandler eh= someEvent;
if (eh!= null)
{
eh(this, e);
}
}
}
And my child classes have something like :
protected override void OnSomeEvent(object sender, EventArgs e)
{
base.OnSomeEvent(sender, e);
}
and the event is raised somewhere in the child class.
However, seeing as the parent class is abstract, I will not be able to listen to the event from my GUI because I can not create an instance of an abstract class.
Am I completely off course and/or is there another method of doing this?

You can attach to the event from the child instance.
public abstract class Parent
{
public event Action Something;
public void OnSomething()
{
if (Something != null)
{
Something();
}
}
}
public class Child : Parent
{
}
Child c = new Child();
c.Something += () => Console.WriteLine("Got event from child");
c.OnSomething();
> Got event from child
You can even declare it as a Parent type that contains a child:
Parent c2 = new Child();
c2.Something += () => Console.WriteLine("Got event from Parent type");
c2.OnSomething();
> Got event from Parent type
An abstract class is just a code template that gets copied into every class that inherits from it (to put it simply). Think of it like, all of your Child classes contain an identical copy of the code that exists in Parent.
Note that this will also produce a unique event handler for each instance of Child. Having a static event handler for all Childs that derive from Parent would look like this, and requires no code in Child:
public abstract class Parent
{
public static event Action Something;
public static void OnSomething()
{
if (Something != null)
{
Something();
}
}
}
Then, you could do something like this, for example:
Parent.Something += () => Console.WriteLine("This will be invoked twice.");
Child c = new Child();
Child c2 = new Child();
c.OnSomething();
c2.OnSomething();
> This will be invoked twice.
> This will be invoked twice.
Both of those objects/event calls will invoke the same event handler even though they come from separate children.

First thing to not, because someEvent does not specify static, every instance of the child class will have its own someEvent. This means you aren't getting a unified view, but a diversified one. This is useful for responding to a button being pressed, since you don't want to respond the same way when they click the background.
Typically rather than using a class hierarchy, you would use composition to handle this kind of situation. For example, adding the following class to yours:
public class ParentContainer
{
private List<Parent> watched = new List<Parent>();
public void Add(Parent watch)
{
watched.Add(watch);
watch.SomeEvent += Handler;
}
private void Handler(object sender, EventArgs args)
{
//Do something
}
}

Related

Subscribing to an event of a base class

I am trying to subscribe to an event that is in my base class but the method in my derived class doesn't seem to trigger whenever that event is triggered. Sample code is below.
public abstract class BaseClass
{
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler Event;
protected virtual void OnEvent(EventArgs ea)
{
if (this.Event!= null)
{
this.Event(null, ea);
}
}
}
public partial class DerivedClass : BaseClass
{
protected override void OnInit(EventArgs e)
{
base.Event+= DoSomething;
}
private void DoSomething(object sender, EventArgs e)
{
//Do Something here.
}
}
BaseClass.OnEvent is called in another control that has the same base class and the derived class where I want to subscribe to is inside another control. Is this possible?
BaseClass.OnEvent is called in another control that has the same base class and the derived class where I want to subscribe to is inside another control. Is this possible?
If you have a derived class and you have two instances of this derived class, the method of instance one won't be called if anything happens in instance two.
In your case you even have two different derived classes, sharing one base class and at runtime you have at least one instance of each derived class, which means, there is no communication between these two.
If you need to link two instances together you have to do something like this:
var instanceOne = new DerivedClassOne();
var instanceTwo = new DerivedClassTwo();
// When something in one happens, let two know:
instanceOne.OnEvent += (sender, e) => instanceTwo.ReactOnOtherChange();

C# Call function from another class

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;

CollectionChanged Event is not firing on a static ObservableCollection

In one class I'm adding objects to my ObservableCollection. And in another class, I'm doing stuff with my added object and then delete it from the collection.
Those two classes cannot communicate with each other, so I decided to go for static collection (I only have access to the class definition for some reason)
In my first class, all elements are added properly (I checked the Count property), in the second class I subscribe to the CollectionChanged event. However, the event is not raising. I think it's because of the statickeyword, but I'm not sure.
Here is a code sample:
static public class A
{
public static ObservableCollection<object> MyCollection = new ObservableCollection<object>();
}
public class B
{
public B()
{
A.MyCollection.CollectionChanged += Func_CollectionChanged;
}
void Func_CollectionChanged(...)
{
//Stuff
}
}
public class C
{
public void func()
{
A.MyCollection.Add(object);
}
}
Here it works fine for me:
class Program
{
static void Main(string[] args)
{
B obj = new B();
}
}
public class A
{
public static ObservableCollection<object> MyCollection = new ObservableCollection<object>();
}
public class B
{
public B()
{
A.MyCollection.CollectionChanged += Func_CollectionChanged;
A.MyCollection.Add(1);
}
private void Func_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// do some stuff here
}
}
by using A.MyCollection.CollectionChangedline you are creating an EventHandler to handle the the collection change event. it fires when ever any changes(add/update/delete) made in the collection. since it is a delegate you are creating you have to specify the sender who own the event and the type of arguments(What it going to handle), in-order to get proper reporting of published event
Updates
You just look into your code. the instance of class b is not yet created, the constructor of this class will automatically invoked only when the new instance of the class is created. You are creating the Event handler inside the constructor of class b. So it is not yet published any event. that is the reason for the collection_Change event is not triggering in your code snippet.
Hence your Definition for class C will be like the following to register the event :
public class C
{
B obj = new B();
public void func()
{
A.MyCollection.Add(1);
}
}

Wrong Derived Class Methods Execution on Event?

public Class A
{
public A()
{
someotherclass.someevent += new EventHandler(HandleEvent);
}
private void HandleEvent(object sender,CustomEventArgs e)
{
if(e.Name == "Type1")
Method1();
else if(e.Name == "Type2")
Method2();
}
protected virtual void Method1(){}
protected virtual void Method2(){}
}
public class B: A
{
public B()
{ /*Something*/}
protected override void Method1(){/*some logic*/}
protected override void Method2(){/*some other logic*/}
}
public class C: A
{
public C()
{ /*Something*/}
protected override void Method1(){/*some logic*/}
protected override void Method2(){/*some other logic*/}
}
public class Main
{
private A;
public Main(){/*Something*/}
private void StartB()
{
A = new B();
}
private void StartC()
{
A = new C();
}
}
Now, what happens is, after I go through a cycle in which both the methods StartB(called first) and StartC(called second) are called, when the someevent is triggered, the code tries to execute the Method in Class B(and later Class C, I hope. I could not get there since it errors out when it calls method in Class B), instead which I want it to call only the method in Class C.
I think that, since the event is subscribed at constructor, Class B methods are still getting fired since it is subscribed initially on the call of StartB.
Question:
I want only the methods of the class that is instantiated the latest should be executed.
For Example: if StartB and StartC are called in order, when someevent is triggered the Methods in Class C should only get executed. Same Vice-Versa. How to do that?
I know am doing something terribly wrong. Any help is much appreciated.
You aren't unsubscribing from the event from your first instance so it will be called. If you don't want it to be called you need to unsubscribe. You could do something like this
class A
{
private static EventHandler lastHandler;
public A()
{
//warning, not thread safe
if(lastHandler != null)
{
someotherclass.someevent -= lastHandler;
}
lastHandler = new EventHandler(HandleEvent);
someotherclass.someevent += lastHandler;
}
but it seems pretty hacky. You are probably better off implementing a method (e.g. IDisposable) to clean up your last instance before a creating a new one.
If I understand you correctly you are saying the methods on B are being called after startC is called and you don't wish this to happen?
I'm guessing your issue is that someotherclass is a static class, or an instance is somehow being shared between all the created B's and C's - in which case you need to unregister the old event handler from someotherclass.someevent when you create the new class. If you don't unregister the handler then the someotherclass object will have a reference to the B or C object that registered with it, so even though you are overwriting the reference in the main class the object is still kept alive by the reference in the event and is still being called when the event is triggered.

c# - how does child and parent comuncate

let's say i have a form and his child
and i want the child to trigger his father without them knowing each other
in other words i want the child to be generic
for example let's say i have a form button and a richTextBox and i want with evey click to change the richTextBox text
i want form and button to not know each other how can i do it ?
i tries this one :
public partial class Form1 : Form
{
delegate void myfatherDelgate();
static int msgCounter = 0 ;
public Form1()
{
InitializeComponent();
button1 = new myButton();
myfatherDelgate += myMethod();
}
public void myMethod()
{
switch (msgCounter)
{
case 1:
{
richTextBox1.Text = "first click";
msgCounter++;
}
case 2:
{
richTextBox1.Text = "second click";
}
defult: this.Close;
}
}
}
public class mybutton : Button
{
static int myint;
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
this.Parent.Invoke(myfatherDelgate());
}
}
the easiest way is to do :
private void button1_Click(object sender, EventArgs e)
{
switch (msgCounter)
{
case 1:
{
richTextBox1.Text = "first click";
msgCounter++;
}
case 2:
{
richTextBox1.Text = "second click";
}
defult: this.Close;
}
}
in the father form ...
I think my all concept is crap can someone in light me ?
but i mistake here and it's circular can someone help me here ?...
So perhaps what you are looking for is more of an interface implementation:
public interface IMyInterface {
void MyAction();
}
public partial class form1 : Form, IMyInterface {
public void MyAction() {
richTextBox1.Text = "first click";
...
}
}
public class button1 : Button {
protected override void OnClick(EventArgs e) {
var parent = this.Parent as IMyInterface;
if( parent != null ) {
parent.MyAction();
}
}
}
Firstly your talking about child elements on a form, not actual sub classes of a form. Right?
So you want to remove the dependency between the form and the button. This could be solved with design patterns. You could have button implement an interface of say IButton. Then in form use either a Factory class to create the button and return an IButton reference instead of MyButton. Or, use dependency injection instead of a factory.
Either way i do not see an advantage to what you are doing, can you explain the problem in more detail?
In your example, the button knows that the parent Form has a delegate called myFartherDelegate. Why not just handle the Button.Click event on the parent Form?
Your code would look something like this
public partial class Form1 : Form
{
static int msgCounter = 1;
public Form1()
{
InitializeComponent();
button1.Click += new EventHandler(button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
switch (msgCounter)
{
case 1:
{
richTextBox1.Text = "first click";
msgCounter++;
}
break;
case 2:
{
richTextBox1.Text = "second click";
}
break;
default: this.Close(); break;
}
}
}
The button is not at all aware of the Parent form, just a normal button. Of course the parent registers it's interest in the Click event of the button. If you need a looser coupling than this, then it might help to explain the requirement in more detail.
If you want a child to do something to his father, the father has to at least know that A child exists. He doesn;t have to know the specifics, but if he's supposed to react to his child then he needs an event handler, callback, etc that the child will invoke.
This can be accomplished with a basic principle called the Dependency Inversion Principle. Classes that depend upon external classes should not depend upon concrete implementations, but upon abstractions of the implementation. Parent should not need a specific Child, just something that looks like one and acts like one. Children, by the same token, should not have to know their specific Parent, but if interaction is required, the Child must have some way to tell the Parent things even if it doesn't know the Parent's listening.
Try a Parent (your form) that contains an IChild reference (the button) and a public event handler. Then, create a Child that implements IChild and has an event it can raise. Then, you need a third class that creates (or is given) the Parent and Child, gives the Parent the Child (as an IChild), and hooks the Child's event to the Parent's event handler. Now you have a parent who only knows it has something resembling a child, and you have a child who has a flag he can wave when something important happens, but doesn't have to know who's listening.

Categories

Resources