c# - how does child and parent comuncate - c#

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.

Related

How to get the value from a listBox1_SelectedIndexChanged event from another class?

I have a main form with a listbox, I also have a listBox1_SelectedIndexChanged event and more code going on for each item when it changes.
Is there a simple way to make this event in another class and not on the main form?
If not, as I meant, I don't want all this code on my main form's code so I want to move it to another class where it is more related.
what is the "best practice" way to notify Class B when listBox1_SelectedIndexChanged occurs? is it by a delegate? I tried to figure it out but didn't really understand. Help will be much appreciated.
Thanks.
I am not sure how both classes are linked to each other and their types but using following code you can get idea to solve your problem
public class A
{
public delegate void ItemSelectedHandler(string title);
public event ItemSelectedHandler OnItemSelected;
public void listBox1_SelectedIndexChanged(object sender, EventArg, e)
{
//other code
if(OnItemSelected!=null)
{
OnItemSelected("Something");
}
}
public void LaunchB()
{
var b = new B(this);
b.ShowDialog();
}
}
public class B
{
private A _parent;
public B(A parent)
{
_parent = parent;
_parent.OnItemSelected += onItemSelected;
}
public void onItemSelected(string title)
{
//will fire when selected index changed;
}
}
I think I solved my question in a simpler way.
I set the listbox1 access modifier to Internal
I created properties for the main form.
In Class B, I subscribed to the listBox1.SelectedIndexChanged event and created an event handler like this:
form1Properties.listBox1.SelectedIndexChanged+=listBox1_SelectedIndexChangedforClassB;
Then I've implemented the event handler in Class B like this:
private void listBox1_SelectedIndexChangedforClassB(object sender, EventArgs e)
{
MessageBox.Show("listbox1 selected item has changed!");
}
I hope I am using all the right terms, please correct me if I'm wrong, and please tell me if you find my solution is flawed in any way. Thanks.

User Control to pass event back to parent form

I have a main form with 3 User Controls attached to it. How can I have events inside a specific User Control reach out and modify the UI of the other two User Controls without creating spaghetti code?
Main Form (Form1.cs)
public partial class Form1 : Form
{
private UserControl1 userControl11;
private UserControl2 userControl21;
private UserControl3 userControl31;
public Form1()
{
InitializeComponent();
}
}
UserControl1.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Change buttons around and fill in some data on user control 2 and 3
}
private void button2_Click(object sender, EventArgs e)
{
// Remove certain elements from control2 and 3
}
// .. So forth
}
I will have many events that do many different things on the other two user controls. I am creating a basic interface that's similar to Visual Studio where I can open projects, close them, add files, etc. These actions on one form should load up different windows and such in the other controls. What's the best method to achieve this? Creating custom events and parsing each event in the main form? Or accessing each user control directly from the first one? Or...?
The general pattern for events is:
public class MyClass{
public static EventHanlder<ofSomeType> MyEventHandler;
public void MyClass{
MyEventHandler = _MyEventHandler;
}
public void _MyEventHandler(object sender, OfSomeType args){
//do something with passed in args.
}
}
Other classes would use these eventhandlers like this...
public class myOtherClass{
public void doSomething(){
//do something here and signal the other class
var ofSomeTypeData = GetData();
MyClass.MyEventHandler(ofSomeTypeData);
}
}
Some will argue this style is too closely coupled but it works flawlessly and is a good start.
Create an event inside each UserControl. Form1 should subscribe to events on those controls.
So suppose that UserControl1 allows the user to sort the data. Then you might write this:
public Form1()
{
InitializeComponent();
// I assume UserControl1 was created by this point
userControl1.OnDataSorted = DataSorted;
}
// This will be called when the user wants to sort the data
private void DataSorted(UserControl1 sender, EventArgs e)
{
// Change buttons around and fill in some data on user control 2 and 3
}
Then you will create an event and a delegate in the UserControl.
public class UserControl1 {
public delegate void DataSortedDelegate(UserControl1 sender, EventArgs e);
public event DataSorted OnDataSorted;
private void button1_Click(object sender, EventArgs e)
{
if (OnDataSorted != null)
OnDataSorted(this, EventArgs.Empty);
// Replace EventArgs.Empty above with whatever data Form1 needs
}
This approach creates a separation of concerns between Usercontrol1 and Form1. The control does not need to actually modify the private controls inside Form1. It merely notifies Form1 that something has happened, and allows Form1 to make the changes.

Delegates and Events with multiple classes

This has taken me quite a few days to develop a demo of communicating between classes with delegates and events. I would like to know if this is the best practices way of accomplishing this passing of data between classes or not. If there is a better method please let me know. Specifically, if something happens in a subclass how do you get it back to the main class. This would be particularly useful when doing n-tier architecture by separating out the User Interface from the Business Logic Level, and the Data Access Level.
I have a form that has 3 text boxes: tb1, tb2, and tbAnswer.
I also have a button that says "Add" and it is just button1.
The main form is:
namespace DelegateTest
{
public delegate void ShowMessage(object sender, Form1.AnswerEventArgs e);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void a_OnShowMessage(object sender, AnswerEventArgs e)
{
tbAnswer.Text = e.answer;
}
public class AnswerEventArgs :EventArgs
{
public string answer { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
AddClass a = new AddClass();
a.OnShowMessage += new ShowMessage(a_OnShowMessage);
a.AddMe(Convert.ToInt16(tb1.Text), Convert.ToInt16(tb2.Text));
}
}
}
and the subform called AddClass.cs is:
namespace DelegateTest
{
class AddClass
{
public event ShowMessage OnShowMessage;
public void AddMe(int a, int b)
{
Form1.AnswerEventArgs e = new Form1.AnswerEventArgs();
e.answer = (a+b).ToString();
OnShowMessage(this, e);
}
}
}
Your approach is sound except for two details.
First, a NullPointerException will occur if your event is raised before any handlers are added. You can get around this in one of two ways.
1) Make a local copy (to avoid race condition) and check it for null:
var showMessage = OnShowMessage;
if (showMessage != null)
{
showMessage(this, e);
}
2) Initialize your event to an empty delegate:
public event ShowMessage OnShowMessage = delegate { };
Second, you do not need to declare your own delegate in this case. You can simply create a standard EventHandler with your own event args:
public event EventHandler<Form1.AnswerEventArgs> OnShowMessage = delegate { };
See How to: Publish Events that Conform to .NET Framework Guidelines for more information.

Child/Parent event raising

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
}
}

Performing an event at the base form level

This seems fairly simple, but I haven't been able to accomplish it. I have a BaseForm class that every form in my application inherits.
I simply want to execute a line of code every time a key is pressed in any form inheriting the BaseForm. In my BaseForm I've attempted the following with no luck:
public class BaseForm : Form
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
//Perform action
}
}
public class MainForm : BaseForm
{
//All of my main form code goes here.
}
Any help would be greatly appreciated! Thanks in advance
Probably you need to set KeyPreview of your base form to true for it to be able catch all the key presses from any control. Consider doing this in the form designer or in the base class constructor. I guess you've got some editors (a textbox, for example) on your derived forms, so you need the KeyPreview to be set to true for the base form to be able to catch those key presses.
You can either override the OnKeyPress method (as in your question) or add an event handler for the KeyPress event in the base form.
public class BaseForm : Form
{
public BaseForm()
{
this.KeyPreview = true; //it's necessary!!
//or just override the OnKeyPress method instead
this.KeyPress += new KeyPressEventHandler(BaseForm_KeyPress);
}
private void BaseForm_KeyPress(object sender, KeyPressEventArgs e)
{
//do your action
}
}
What you have done so far is correct. If your OnKeyPress is not being executed then you have something wrong - do you have an OnKeyDown that is interfering?
What you do next is to have the same override in your derived forms:
public class MainForm : BaseForm
{
//All of my main form code goes here.
protected override void OnKeyPress(KeyPressEventArgs e)
{
//do whatever action this form needs to, if any
base.OnKeyPress(e);
}
}
See that call to the base.OnKeyPress? That executes that line of code you have in the base. Note that you can put that call anywhere within the function, it might be more appropriate to have it at the start before the form specific code.

Categories

Resources