Events in MDIParents Forms and Childs - c#

How can I Handle MDIParent Form events in childs forms?
for example in Parent Form I Have a option "search on child grid" and when that button got clicked, in the child form one row on grid get focused.
Im using C# 3.5 Windows Forms Application
Thanks in Advance

I see two different way that I would choose between for this problem.
If you could think of hosting the command in a MenuStrip instead, and it is the same child form that lives in several instances in the MDI application, you could add the command(s) to a MenuStrip control in the child form instead. These menu commands will be automatically merged with the commands in the parent form, but any click events will be carried out in the active child form.
You can control where and how menu commands from the child form merges with the commands in the parent form through the MergeAction and MergeIndex properties. If using this approach you should probably set the Visible property of the MenuStrip in the child form to false to prevent it from taking up unnecessary space on the form.
The second option that I would suggest is to create an interface for defining the search functionality, implement that interface in the child forms that support it, and use the MdiChildActivate event of the MDI parent form to enable or disable the search function based on whether the current child supports it or not.
Simplified code sample of the second approach:
interface IGridSearch
{
void PerformSearch(string criteria);
}
public partial class MdiChildUI : Form, IGridSearch
{
public MdiChildUI()
{
InitializeComponent();
}
public void PerformSearch(string criteria)
{
// peform the search
}
}
public partial class MdiParentUI : Form
{
public MdiParentUI()
{
InitializeComponent();
}
private void MdiParentUI_MdiChildActivate(object sender, EventArgs e)
{
SetControlStates();
}
private void SetControlStates()
{
_searchCommand.Enabled = (this.ActiveMdiChild is IGridSearch);
}
private void _searchCommand_Click(object sender, EventArgs e)
{
IGridSearch child = (this.ActiveMdiChild as IGridSearch);
if (child != null)
{
child.PerformSearch("whatever to search for");
}
else
{
MessageBox.Show("Can't search in the active form");
}
}
}

It's not too complicated:
public partial class Form1 : Form
{
// other stuff...
// e.g. some button's click event handler
private void addChild_Click(object sender, EventArgs e)
{
Form2 child = new Form2();
child.MdiParent = this;
this.SomeEvent += child.SomeMethod();
// other init stuff...
}
}
Just make sure the signature of the handler method on the child Forms matches the signature of the event handler delegate of the parent.
One thing to note is if you want only the active child form to respond to the event. In that case you can create a helper extension method like this
public static bool IsActiveMDIChild(this Form child)
{
Form mdiParent = Form.ActiveForm;
Form activeChild = mdiParent.ActiveMdiChild;
return child == activeChild;
}
Then add code like this to the SomeMethod() handler:
public bool SomeMethod(*/ signature here /*)
{
if(!this.IsActiveMDIChild()) return;
//do stuff normally, we're in the active child form
}

In the child form, create a new event for the parent to call:
Friend Event search(ByVal token As String)
In the parent form, declare an instance of the child form withevents:
Private WithEvents _FChild As frmChild
In the parent form, when you want to call the child form, reference your declared variable. The event should appear in intellisense:
Private Sub searchChild_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearchChild.Click
_FChild.search(txtToken)

Have you some code so we can be more helpful?
In any case, you can create your custom events on the child forms, and get the Parent form to suscribe to these events

I'm doing the same kind of thing right now, and here's how I do it:
Since the parent is the one raising the event, the event needs to exist on the parent form
During the code on the parent that loads the child (you have code somewhere that instantiates the child form), after the child form exists, use AddHandler to tether the event on the MDI parent with a public sub on the child form
When the parent form fires the event, the instance of the child form will handle it.
Does this make sense? I'm using VB.NET, so the language may be slightly different, but that's the general technique I'm using.

Related

Set parent forms FormElement.TitleBar.BackColor from child form

I have a form FrmMain, which has a child form displayed within a PageView, FrmChild. I am trying to set the FrmMain's: this.FormElement.TitleBar.BackColor from FrmChild.
FrmChild
private void SetWarning() {
FrmMain.SetTitleBarColor(true);
}
FrmMain
public void SetTitleBarColor(bool warning) {
if (warning) {
this.FormElement.TitleBar.BackColor = Color.Red;
}
}
I tried setting FrmMain.SetTitleBarColor to static, but then I couldn't access the instance of the form.
The answer can be found here: answer
The correct way to update the parent form is through bubbling. Have the parent form listen for an event from the child form and have the parent update itself. Any parameters needed can be passed through the EventArgs.

C# Event driving between user controls on win forms

I have a main form (form1) which has a panel (panel1) -- see pic.
Form1 pic
Panel1 loads one of two different user controls based on which button is pressed (to simulate screen changes). I have a button on user control 1 which needs to act (change text) on user control 2.
The issue I have is the user controls are dynamically created with a button press on form 1 (see code below) which is causing me issues trying to link events-
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
panel1.Controls.Add(new Screens.UC1());
}
private void button1_Click(object sender, EventArgs e)
{
foreach (Control ctrl in panel1.Controls)
{
ctrl.Dispose();
}
panel1.Controls.Add(new Screens.UC1());
}
private void button2_Click(object sender, EventArgs e)
{
foreach (Control ctrl in panel1.Controls)
{
ctrl.Dispose();
}
panel1.Controls.Add(new Screens.UC2());
}
}
What is the best way to deal with linking these kinds of items with events when the instance of the objects are dynamically created. I also tried making instances of the screen and then referencing to those, but that ran into scope issues.
Code for UC1 (user control 1)
public partial class UC1 : UserControl
{
public UC1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Event to change text on UC2
}
}
Code for UC2 (user control 2)
public partial class UC2 : UserControl
{
public UC2()
{
InitializeComponent();
}
public void WriteText(object sender, EventArgs e)
{
label2.Text = "Text Changed...";
}
}
Any help greatly appreciated.
Why dispose and create all those controls when the operator presses a button?
Better is to create two UserControls. One with all the Controls you want to show when operator presses button 1 and one with all the Controls you want to show when operator presses button 2.
To create a user control use menu Project - Add User Control, or right click in solution explorer on your project and select add new item.
Layout your user controls with all the controls your want to show. Add event handlers etc.
Then in your form:
private readonly UserControl userControl!;
private readonly UserControl userControl2;
public MyForm()
{
InitializeComponent()
this.userControl1 = new UserControlA(...);
this.userControl2 = new UserControlB(...);
// make sure that the user controls are Disposed when this form is Disposed:
this.Components.Add(this.userControl1);
this.Components.Add(this.userControl2);
}
void OnButton1Clicked(object sender, ...)
{
// remove userControl2 from the panel
this.Panel1.Controls.Remove(this.userControl2);
// add userControl1 to the panel
this.Panel1.Controls.Add(this.userControl1);
}
This way all the overhead of creating / adding / positioning / add event handlers and all cleanup is only done once: during construction of your form. Switching the user controls will be done in a flash
I am not sure what you are trying to accomplish, but it looks like you are trying to change the state of objects from other objects that cannot have references to the objects they are trying to change.
In this case, I would create a type that functions as some kind of manager that subscribes to events of all of these controls. You can create your own events within a UC class, or just use the Windows Forms click event like you are already doing.
Since the handler of the events are defined in the manager, you can easily write logic that will work on the other user controls, as long as the manager has references to them.
Like this:
public class ClickTrafficer {
private UC target;
public void HandleClick(object sender, UCClickHandlerEventArgs ea) {
target.WriteText(ea.TextToWrite);
}
}
public Form1()
{
InitializeComponent();
var trafficer = new ClickTrafficer();
var screen1 = new Screens.UC1();
screen1.Click += trafficer.HandleClick;
panel1.Controls.Add(screen1);
}
This is a crude idea of what you could do. Missing here are the logic to set whatever the target field must be set to. You need to create logic that tells the trafficer which control sets which control's text.
Also, the ClickTrafficer I created uses a custom event with custom eventargs, you need to define those or find a way to pass the necessary information through the built in events. Creating events is really easy though so you can look that up online.

Triggering method(s) in parent forms from a child form

I have a problem with triggering a method in various parent forms from one child form. This child form is used to take user input and pass it to the parent form. Since this input is identical for various types of work (each type is realised in it's own form), I call this child form from various forms.
So far I've solved this problem like this:
In child form there is a piece of code:
private void button3_Click(object sender, EventArgs e)
{
if (Parent.GetType() == typeof(MyType))
{
if ((Parent as MyType).MyFunction()))
{
this.Close();
}
}
}
Parent is a property of type object. This child form is called from a parent form with this code:
MyChildForm IPU = new MyChildForm();
IPU.Parent = this;
IPU.ShowDialog();
The problem with this approach is that I might end up with tens of if-else blocks, one for each type of parent form that need's this child form for input. My question is - is there a way to shorten this code, so that it work's for every type that has a function named MyFunction?
I've tried something like this:
(Parent as typeof(Parent.GetType())).MyFunction()
But I get an error 'Parent is a property but is used like a type'
You can create interface
public interface IParent
{
bool MyFunction();
}
And make Parent property of type IParent. Then make your parent forms implement this interface. Usage will look like:
private void button3_Click(object sender, EventArgs e)
{
if (Parent.MyFunction())
this.Close();
}

How I send a data from child form to parent MDI form or parent MDI from to child form in C#?

I have a value(let CompanyId) in a child form. I want to pass this value in a level of the MDI parent form.
In child form I retrieve data from database in a datagrid view.
Now I select a value from datagrid view.
string SkillName = dataGridView1.CurrentRow.Cells["SHORTS"].Value.ToString();
Now I want to pass this SkillName value to MDI parent form.
How Can I do this?
there are literally countless ways to do it. it all depend on what you want to do and why.
#f0x way is good, but also use a public parameter, create an event and pop it when you want, set a flag(could be a global flag) and more.
if you want to pass simple data from parent to child you can do it by, as f0x said, in the constructor, or make the child register an event you execute, that send a string/int/etc., and then you can execute the event whenever you(the parent) want and the child immediately handle that data.
it can go the other way around: when the parent create the child, it register on an event the child fire...
here is an example:
public partial class Form1 : Form
{
public void RegisterSon()
{
ChildForm frm = new ChildForm();
frm.MyEventChild += new MyEvntHndler(frm_MyEventChild);
}
void frm_MyEventChild(string data)
{
}
}
public delegate void MyEvntHndler(string data);
public class ChildForm: Form
{
public event MyEvntHndler MyEventChild;
private void button1_Clicked(object sender, EventArgs e)
{
if (MyEventChild != null)
{
MyEventChild("This is my data");
}
}
}
The easiest way would be to pass the companyId as a parameter to the constructor of the form.
For example in the company form:
public partial class CompanyForm : Form
{
public CompanyForm(int companyId)
{
InitializeComponent();
}
}
When you call the new form simply pass the value from your calling form:
var form = new CompanyForm(10); // '10' the id
form.MdiParent = this;
form.Show();

Sending Data from child form to Parent Form TextBox

I have a Parent Form that holds a "HUD" with First Name, Last Name, etc. One of the child forms is a Search Form. When the user selects a member from the results that are displayed in a DataGrid I want the pertinent information to fill in the HUD. I created a HUD class with variables for each value and a method called UpdateHUD(). I am unsure how to get this working. I have a reference to the Search Form of the Parent form containing the HUD, like so:
public frmWWCModuleHost _frmWWCModuleHost;
This is the code I use to embed forms. I am not using MDI.
public static void ShowFormInContainerControl(Control ctl, Form frm)
{
frm.TopLevel = false;
frm.FormBorderStyle = FormBorderStyle.None;
frm.Dock = DockStyle.Fill;
frm.Visible = true;
ctl.Controls.Add(frm);
}
Here is the code I am running on Cell Click on the Search Form. This is from before I tried implementing the HUD class.
private void dgvSearchResults_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
_frmWWCModuleHost = new frmWWCModuleHost();
_frmWWCModuleHost.tbxHUD_LastName.Text = dgvSearchResults.CurrentRow.Cells[1].FormattedValue.ToString();
_frmWWCModuleHost.tbxHUD_LastName.Invalidate();
_frmWWCModuleHost.FormPaint();
}
Thanks in advance!
~ Patrick
EDIT
dgvSearchResults_CellContentClick is now current. When I step through this code it is getting the correct Value here but it is never updating the actual HUD.
EDIT 2
Is my problem that I am declaring a NEW frmWWCModuleHost instead of passing a ref to the existing? I am still pretty weak in my understanding of this.
EDIT 3
I have "solved" this by doing the following: On the Parent Form where I declare the Child Form I pass this as a param. Then in the constructor of the child form I added _frmWWCModuleHost = m_parent; I have a UpdateHUD() method on my Parent form and I call it from the _CellClick event on the child.
Now to rephrase my question; Is there anything glaringly wrong with doing it this way?
When the child form search completes, raise a "SearchCompleted" event. Then anything (including the parent form) can subscribe to that event and retrieve the details.
See the following NotepadCode for an example:
class ParentForm
{
private readonly ChildForm childForm;
public ParentForm()
{
InitializeComponent();
childForm = new ChildForm();
childForm.SearchCompleted += childForm_SearchCompleted;
}
private void childForm_SearchCompleted(object sender, SearchCompletedEventArgs e)
{
// Update the display
lblName.Text = e.DataToDisplay;
}
}
class ChildForm
{
public event EventHandler<SearchCompletedEventArgs> SearchCompleted;
private void Search(string query)
{
// Do the searching
OnSearchCompleted(new SearchCompletedEventArgs([arg values]));
}
public void OnSearchCompleted(SearchCompletedEventArgs args)
{
if (SearchCompleted != null)
{
SearchCompleted(this, args);
}
}
}
In .NET, Forms are objects like everything else, so you should think of the problem in those terms.
With that, the child form will need access to the parent form. You can provide that by passing the parent form reference to the child form through the constructor, a method, or a field/property (although the constructor makes the most sense).
Then, you can change the values in parent form from the child.
HOWEVER I would say this isn't the best idea. Rather, the child should expose an event indicating that the data changed (as well as the mechanism to get that data) and then the parent should subscribe to that event and update itself with the data when it is fired.
Sometimes in situations like this I'll create a delegate that matches the signature of the method I want to call in the parent class (I think that would be UpdateHUD in your case), and then pass an instance of that delegate (i.e. a reference to UpdateHUD) to the child form (the search form in this case). When the child form is finished accepting input, it invokes the delegate using the data collected on the form.
So, say UpdateHUD is a method in the parent form that looks something like this.
private void UpdateHUD(string firstName, string lastName) {
//...
}
You would create a delegate with the same signature, like this.
public delegate void HUDUpdateHandler(string firstName, string lastName);
Then you would add a HUDUpdateHandler parameter to the constructor of the child form and store it in a private field (for example, this.handler = handler). When your child form is ready to send its data back, you would invoke the child form's private field (this.handler.Invoke(firstNameTextBox.Text, lastNameTextBox.Text), for example). That will invoke UpdateHUD in your parent class using the values from the child class, and you won't have to expose anything.
I find this approach simpler to implement than raising and catching events, and it allows you to keep the internals of your parent class internal.

Categories

Resources