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();
}
Related
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.
I have 2 windows Forms, a parent and a child. The parent is the main form. The child is a dialog where the user can edit their details.
When a button is clicked on the parent form, it loads the child form. Like so:
private void add_account_Click(object sender, EventArgs e)
{
this.account_add_edit = new Form2();
account_add_edit.test();
account_add_edit.ShowDialog();
}
As you can see I've created a new form, tried to call a function from the new form, and then showed the form. The problem is the method from the form is not being called. I am getting an error on the IDE that says Windows.Forms.Form does not contain a method test.
I've created the method in the child form:
public static string test(string val)
{
this.username = val;
}
Any ideas as to what I'm doing wrong?
your method is defined as static , so its not posiible to call it on an instace.
you should eaither not make it static, or call it from as static:
Form2.test();
Use:
Form2.test();
static members are associated directly to the class not to its instances. Than means if you need to access a static member you have to access it using it is container type.
More than that, you can not access normal members from static ones. You can only access staticmembers from their peers.
You cannot do the following inside a static method:
this.Member ...
I want to access the list box and add the item into it for my Custom control which is dynamically created on run time. I want to add the Item when I press the button place in the custom control, but it does not work. I have use the following code to work:
private void button1_Click(object sender, EventArgs e)
{
Form1 frm = new Form1();
frm.ABC = "HI";
}
the 'ABC' is the Public string on the form ie:
public string ABC
{
set { listBox1.Items.Add (value); }
}
the above string works fine when I use it form the Button on the form and it adds the value in the lsitbox but whent I use it form the custom control's button the text of the 'value' changes but it does not add the item in list box.I have also try it on tabel but does not help. I change the Modifires of the ListBox1 from Private to Public but it does not works. The above function works well in the form but cannot work from the custom control.
Thanks.
Expose an event ("ItemAdded" or whatever) in the child form that your main form can handle. Pass the data to any event subscribers through an EventArgs derived object. Now your mainform can update the UI as it please with no tight coupling between the two classes. One class should not know about the UI layout of another, it's a bad habit to get into (one that everyone seems to suggest when this question crops up).
What I think you should use is
this.ParentForm
So in your case it should be:
public string ABC
{
set { this.ParentForm.listBox1.Items.Add (value); }
}
The easiest way would be to pass the form down into your custom control as a parameter in the constructor that way you could access it from the custom control.
EX:
public class CustomControl
{
private Form1 _form;
public CustomControl(Form1 form)
{
_form = form;
}
private void button1_Click(object sender, EventArgs e)
{
_form.ABC = "HI";
}
}
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.
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.