Winforms add tabPage from child form to parent form - c#

I want to add new tabpage from other form in parent form.
My parent form is MainWindow and this form has TabControl.
I have child form ChildForm when i click on child form button i want to add new tabpage in TabControl from MainWindow.
I try to create constructor dependency in ChildForm
private MainWindow mainWindow;
public List(MainWindow form)
{
this.mainWindow = form;
}
private void createButton_Click(object sender, EventArgs e)
{
TabPage tabPage = new TabPage("ASD");
mainWindow.MainTabControl.TabPages.Add(tabPage);
}
This will throw System.NullReferenceException!
I also try to create in MainWindow accessors witch will return mainTabControl access in MainWindow but also not work.
public static TabControl MainTabControl
{
get {
MainWindow self = new MainWindow();
return self.mainTabControl;
}
}
This not work becouse i create new reference and that is problem.
I try 2 examples and both not work and i know whay not work!!!
Anyone know any other opetion how to slove this problem ?

A better approach is leaving the task to create new tabpages to the MainWindow and do not let the child forms know anything of the internal details of the MainWindow. The child forms exposes an event and they will raise it when they want to notify their parent that it is time to create a new tabpage (or whatever the MainWindow wants to do). The MainWindow subscribes to this event and start the creation of the new tab page when requested to do so....
public class ListForm: Form
{
public delegate void OnNewTabPage(string key);
public event OnNewTabPage NewTabPage;
public ListForm()
{
.....
}
private void createButton_Click(object sender, EventArgs e)
{
// Here we pass to the subscriber of the event just a string as
// the delegate requires, but, of course, you could change this
// to whatever data you wish to pass to the mainwindow
// Event a reference to an instance of a class with many fields...
NewTabPage?.Invoke("ASD");
}
}
Code in main form
ListForm f = new ListForm();
f.NewTab += CreateTabPage;
f.Show();
private void CreateTabPage(string key)
{
TabPage page = new TabPage(key);
this.TabControl.TabPages.Add(page);
}

Related

how to refresh parent winform from child winform?

The parent Window Forms button mouse move event is getting correctly into the status bar label of the child window form ... but the opposite of that is not working means "the child window form button mouse move event is not getting displayed into the parent window form status bar label, please help
One of the good ways to do it is to use events in your child class:
First, declare the event:
public partial class ChildForm: Form
{
public event EventHandler ButtonClicked;
public ChildForm()
{
InitializeComponent();
}
}
Then call it in the button onClick method of the child form:
...
ButtonClicked?.Invoke();
...
if your onclick event is button_onclick then it would look like:
private void button_onclick(object sender, EventArgs e)
{
ButtonClicked?.Invoke();
}
and add your refresh login to this event when you declare this child form from your parent form:
var childForm = new ChildForm();
childForm.ButtonClicked += (e,args)=>{
//put the logic here
}
childForm.Show();
You could use a reference like this:
public partial class MainForm : Form
{
YourChildForm ycf = new YourChildForm(this);
ycf.Show();
}
And in your child form:
public partial class YourChildForm : Form
{
MainForm mf_ref
public YourChildForm(MainForm mf)
{
InitializeComponent();
mf_ref = mf;
}
}
Now you can access to every pubblic method on your mainform just using
mf_ref.SomeMethod();

Passing a variable from Child Form to Parent Form

I'm using a container (mdi parent) to open up a main menu. The main menu allows the user to connect to a database and open other programs. I'm trying to display what database you are connected to on the container (parent form) but i'm having issues passing the string from main menu to the container. When the user clicks the connect button, I somehow need the container to have an event listener to listen for a button click from the child form. When the connect button is clicked on the child form, it will pass the variable to the parent. How would I go about doing this?
Maybe you can use an event. So each time the database name changes on the child form you can get a call back on the parent form
Child
public partial class Child : Form
{
public event DatabaseChangeHandler DatabaseChanged;
public delegate void DatabaseChangeHandler(string newDatabaseName);
public Child()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//When the database changes
if (this.DatabaseChanged != null)
{
this.DatabaseChanged("The New Name");
}
}
}
Parent
public partial class Parent : Form
{
private Child childForm;
public Parent()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Open the child form
childForm = new Child();
childForm.DatabaseChanged += childForm_DatabaseChanged;
childForm.ShowDialog();
}
void childForm_DatabaseChanged(string newDatabaseName)
{
// This will get called everytime you call "DatabaseChanged" on child
label1.Text = newDatabaseName;
}
}
Just declare a public variable Eg: var1 in Form2 and on selection of rows from Grid assign the selected value to the Form2 public variable var1.
Then Once you close the Form2. You can access the values in Form1 by say you have a textbox in Form1 which should get the selected value from grid of Form2 by mentioning as
Form2 f2=new Form2();
TextBox1.Text=f2.var1;
Hope this helps

Add/Remove panel controls by clicking button on dynamically added usercontrol

I am new to c# windows forms and I'm trying to make a GUI that has two panels. The left panel is used to display dynamically added user controls that contain buttons. The right panel is used to display dynamically added usercontrols that contain other controls: textboxes, labels, comboboxes, buttons, etc.
I've created a form1 that has the two panels. I can successfully load both panels with different UserControl.cs content by using a menu that I've added to the top of the form. When I click a menu option, form1 buttonPanel is loaded with the appropriate buttonPanel.cs content and form1 mainPanel is loaded with the appropriate mainPanel.cs content. However, when I click the button that exists on buttonPanel.cs, I can't get form1 mainPanel to change it's content.
ie: WelcomeMenu.cs has a button called btnPage2 that should change mainPanel controls to show Page2.cs usercontrol instead of Welcome.cs usercontrol.
I want to be able to use in the button click handler on UserControl.cs:
mainPanel.Controls.Clear();
UserControl usrCtl = new UserControl();
Form1.mainPanel.Controls.Add(usrCtl);
My problem seems to be that WelcomeMenu.cs cannot see or access Form1 mainPanel.
Is there a way to make this work? Or am I trying to do this the wrong way?
My reason for this method is so I can load a new buttonPanel.cs usercontrol and mainPanel.cs usercontrol for each department and then be able to change mainPanel content for each button I click in the current buttonPanel. I'm trying to avoid creating a bunch of panels on Form1 and then hiding them and only making them visible when I need them.
Update:
buttonMenu.cs
{
{
public partial class ucWelcomeMenu : UserControl
public ucWelcomeMenu()
{
InitializeComponent();
}
private void btnPage2_Click(object sender, EventArgs e)
{
Form1.mainPanel.Controls.Clear();
ucWelcome frm = new ucWelcome();
Form1.mainPanel.Controls.Add(frm);
}
}
}
Form1.mainPanel.Controls.Add(frm) generates an error on Form1.mainPanel that states:
"An object reference is required for the non-static field, method, or property 'Form1.mainPanel'
UPDATE 2:
Ok. I've searched several different links and found some helpful information. However, I am still unable to fire an event from a button click in a dynamically added UserControl.cs. I have 2 panels on Form1. menuPanel and mainPanel. They are both set to Modifiers = Public.
Here is my Form1:
namespace TestUserControl
public partial class Form1 : Form
{
private ucWelcomeMenu welc = new ucWelcomeMenu();
public Form1()
{
InitializeComponent();
ucWelcomeMenu welcomeMenu = new ucWelcomeMenu();
menuPanel.Controls.Add(welcomeMenu);
welc.ButtonClick += new EventHandler(this.CustomEvent_Handler);
}
private void CustomEvent_Handler(object sender, EventArgs e)
{
MessageBox.Show("Yes");
}
}
}
And Here is my UserControl:
namespace TestUserControl.UserControls
public partial class ucWelcomeMenu : UserControl
{
public event EventHandler ButtonClick;
public ucWelcomeMenu()
{
InitializeComponent();
}
private void btnPage2_Click(object sender, EventArgs e)
{
if (ButtonClick != null)
ButtonClick(sender, e);
}
}
}
Ok. I am definitely a little slow. I found my problem. I was Instantiating the ucWelcomeMenu twice. Once I removed the private instantiation above the constructor, the event fired just fine. Thanks for all the input. It sent me to some good links with some very helpful information.
Here is what I ended up with:
Form1 Menu Option Click Handler:
private void option1ToolStripMenuItem_Click(object sender, EventArgs e)
{
UserControl1 ctl1 = new UserControl1();
menuPanel.Controls.Add(ctl1);
ctl1.btn1Click += new EventHandler(btn1_Click);
UserControl2 ctl2 = new UserControl2();
mainPanel.Controls.Add(ctl2);
}
Button 1 Click Handler on Form1:
private void btn1_Click(object sender, EventArgs e)
{
mainPanel.Controls.Clear();
UserControl2 frm = new UserControl2();
mainPanel.Controls.Add(frm);
}
UserControl1.cs
public partial class UserControl1 : UserControl
{
public event EventHandler btn1Click;
public UserControl1()
{
InitializeComponent();
}
private void btn1_Click(object sender, EventArgs e)
{
if (btn1Click!= null)
btn1Click(sender, e);
}
}
Set the accessibility Modifiers property of mainPanel from private to internal public.

How to reach and set a control's property outside of a Form?

I am really new to programming and currently working on a C# Windows Forms application.
The problem is the following:
I have a Form with different objects and controls like: tabpages, textboxes, timers, etc .
I also have a UserControl form which I load into one of the main Form's tabpages.
I would like to write a code into the UserControl , how can I manipulate element properties of the main Form.
For example: when I click on a button on the UserControl form It sets the main Form's timer.Enabled control to true.
It is possible to do this, but having the user control access and manipulate the form isn't the cleanest way - it would be better to have the user control raise an event and have the hosting form deal with the event. (e.g. on handling the button click, the form could enable/disable the timer, etc.)
That way you could use the user control in different ways for different forms if need be; and it makes it more obvious what is going on.
Update:
Within your user control, you can declare an event - In the button click, you raise the event:
namespace WindowsFormsApplication1
{
public partial class UserControl1 : UserControl
{
public event EventHandler OnButtonClicked;
public UserControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = OnButtonClicked;
// if something is listening for this event, let let them know it has occurred
if (handler != null)
{
handler(this, new EventArgs());
}
}
}
}
Then within your form, add the user control. You can then hook into the event:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
userControl11.OnButtonClicked += userControl11_OnButtonClicked;
}
void userControl11_OnButtonClicked(object sender, EventArgs e)
{
MessageBox.Show("got here");
}
}
}
You may want to rethink what it is you are trying to accomplish. However, to answer your question, it can be done.
The best way to do it is to make a property in your UserControl called MainForm:
public Control MainForm {
get;
set;
}
Then, in your MainForm's Load event, set the property to itself:
userControl1.MainForm = this;
Finally, in your user control, set the MainForm's timer:
protected button_click(object sender, EventArgs e)
{
timerName = "timer1";
EnableTimer(timerName);
}
private void EnableTimer(timerName)
{
var timer = MainForm.Controls.FirstOrDefault(z => z.Name.ToLower().Equals(timerName.ToLower());
if (timer != null)
{
((Timer)timer).Enabled = true;
} else {
// Timer was not found
}
}
This is very simple. It's called events. On the user control you would expose an event with a EventHandler for the form to subscribe to.
public partial class MyUserControl : UserControl
{
/// You can name the event anything you want.
public event EventHandler ButtonSelected;
/// This bubbles the button selected event up to the form.
private void Button1_Clicked(object sender, EventArgs e)
{
if (this.ButtonSelected != null)
{
// You could pass your own custom arguments back to the form here.
this.ButtonSelected(this, e)
}
}
}
Now that we have the user control code we'll implement it in the form code. Probably in the constructor of the form you'll have some code like below.
MyUserControl ctrl = new MyUserControl();
ctrl.ButtonSelected += this.ButtonSelected_OnClick;
Finally in the form code you'll have a method that subscribed to the event like the below code that will set the Timer enabled to true.
private void ButtonSelected_OnClick(object sender, EventArgs e)
{
this.Timer1.Enabled = true;
}
And that's how you allow an event on a user control on a form set an object on the form.
You can set the timer1.Modifiers property to "internal" and access it with an instance to Form1:
form1.timer1.Enabled = true;
You need to have an instance of your class Form1, not the class itself. For example:
// INVALID
Form1.timer1.Enabled = true;
// VALID
var form1 = Form1.ActiveForm;
form1.timer1.Enabled = true;
But this is not a very clean way to do this, you would rather use events as described in NDJ's answer.
You need to put the below code,
(`userControl11.OnButtonClicked += userControl11_OnButtonClicked;`)
in a separate file in Visual Studio. The other file is called 'Form1.Designer.cs', and can be found in the Solution Explorer pane under
Form1 >> Form1.cs >> Form1.Designer.cs.
Hope this helps!

How to refresh datagridview when closing child form?

I've a dgv on my main form, there is a button that opens up another form to insert some data into the datasource bounded to the dgv. I want when child form closes the dgv auto refresh. I tried to add this in child form closing event, but it doesn't refresh:
private void frmNew_FormClosing(object sender, FormClosingEventArgs e)
{
frmMain frmm = new frmMain();
frmm.itemCategoryBindingSource.EndEdit();
frmm.itemsTableAdapter.Fill(myDatabaseDataSet.Items);
frmm.dataGridView1.Refresh();
}
However, when I add this code in a button on the parent form, it actually does the trick:
this.itemCategoryBindingSource.EndEdit();
this.itemsTableAdapter.Fill(myDatabaseDataSet.Items);
this.dataGridView1.Refresh();
There are many ways to do this, but the following is the simpliest and it will do what you want and get you started.
Create a public method on your main form.
Modified constructor of second form to take a main form.
Create an instance of the second form passing the main form object.
When closing second form, call the public method of the main form object.
Form1
public partial class Form1 : Form {
public Form1() {
//'add a label and a buttom to form
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
Form2 oForm = new Form2(this);
oForm.Show();
}
public void PerformRefresh() {
this.label1.Text = DateTime.Now.ToLongTimeString();
}
}
Form2
public class Form2 : Form {
Form1 _owner;
public Form2(Form1 owner) {
_owner = owner;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing);
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e) {
_owner.PerformRefresh();
}
}
We can also proceed this way:
We have form_1 and form_2
In form_1, create a public method. Inside this public method we put our stuff;
In form_2 we create a global form variable;
Still in form_2, pass form_1 into form_2 through form_2 constructor;
Still in form_2, make your global variable(the one we created in step 2) receive the new form_1 instance we created in form_2 constructor;
Inside the closing_event method we call the method which contains our stuff.
The method with our stuff is the method that will fill our form1 list, dataGridView, comboBox or whatever we want.
Form_1:
public fillComboBox()//Step 1. This is the method with your stuff in Form1
{
foreach(var item in collection myInfo)
{myComboBox.Items.Add(item)}
}
Form_2:
Form1 instanceForm1;//Step 2
public Form2(Form1 theTransporter)//Step 3. This the Form2 contructor.
{
InitializeComponent();
instanceForm1 = theTransporter;//Step 4
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
instanceForm1.fillComboBox();//Step 5 we call the method to execute the task updating the form1
}
I hope it helps...
You're creating a new instance of the main form which isn't effecting the actual main form instance. What you need to do is, call the code on the main form itself, just like the code you say works on the button click:
private void frmNew_FormClosing(object sender, FormClosingEventArgs e)
{
this.itemCategoryBindingSource.EndEdit();
this.itemsTableAdapter.Fill(myDatabaseDataSet.Items);
this.dataGridView1.Refresh();
}
Great answer there! The other method would have been:
Check if the form you want to update is open.
Call the method to refresh your gridVieW.
**inside your refreshMethod() in form1 make sure you set the datasource to null **
if (System.Windows.Forms.Application.OpenForms["Form1"]!=null)
{
(System.Windows.Forms.Application.OpenForms["Form1"] as Form1).refreshGridView("");
}

Categories