I Made an application. The Main form Name is Form1.
And the other Form is called PoP.
public partial class pops : Form
{
public pops()
{
InitializeComponent();
CenterToScreen();
}
private void pops_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Close();
}
private void lblAdminNo_Click(object sender, EventArgs e)
{
}
}
Make two public properties on popup form and retrieve them from parent form.
string username = string.Empty;
string password = string.Empty;
using (LoginForm form = new LoginForm ())
{
DialogResult result = form.ShowDialog();
if (result == DialogResult.Ok)
{
username = form.Username;
password = form.Password;
}
}
It all depends on from where are you calling the Pop form.
If it is called from the Form1 itself, then the Popform's object itself would provide you the value.
Pop popFrm = new Pop();
if(popFrm.ShowDialog() == Ok)
{
string userName = popFrm.TextBox1.Text;
}
If the Pop is invoked from a different area/part of application, you may have to store it somewhere common to both the forms.
This can be done through events. This approach is particularly useful when data to be posted even when the child form is kept open.
The technique is- From parent form, subscribe to a child from event. Fire the event when child form closes, to send data
----- SAMPLE CODE-----
Note: In the Parent Form add a Button:button1
namespace WindowsFormsApplication2
{
public delegate void PopSaveClickedHandler(String text);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Pops p = new Pops();
p.PopSaveClicked += new PopSaveClickedHandler(p_PopSaveClicked);//Subscribe
p.ShowDialog();
}
void p_PopSaveClicked(string text)
{
this.Text = text;//you have the value in parent form now, use it appropriately here.
}
}
Note: In the Pops Form add a TextBox:txtUserName and a Button:btnSave
namespace WindowsFormsApplication2
{
public partial class Pops : Form
{
public event PopSaveClickedHandler PopSaveClicked;
public Pops()
{
InitializeComponent();
}
private void btnSave_Click(object sender, EventArgs e)
{
if(PopSaveClicked!=null)
{
this.PopSaveClicked(txtUserName.Text);
}
}
}
}
Summary:
1.Add a delegate(place where it available to both parent and child form) :
public delegate void PopSaveClickedHandler(String text);
2.In form:Pops, Add an event:
public event PopSaveClickedHandler PopSaveClicked;
3.Subscribe to the event in Parent Form:
p.PopSaveClicked += new PopSaveClickedHandler(p_PopSaveClicked);
4.Invoke the event in form:Pops Save Button Click
if(PopSaveClicked!=null)
{
this.PopSaveClicked(txtUserName.Text);
}
You can send data to the form object before you display it. Create a method to call, send the info through the constructor... etc.
Related
In my program, I have two forms: public partial class Form1 : Form,
and a log-in form: public partial class Login : Form. Both within the same namespace
Login window is opened when a Log-in button is clicked on the main window:
public partial class Form1 : Form
{
private void LoginToolStripMenuItem_Click(object sender, EventArgs e) //Login button event
{
LoginWindow = new Login();
LoginWindow.ShowDialog();
LogOutToolStripMenuItem.Enabled = true;
}
}
When the password is entered, I want to enable additional controls for the user, on the main screen.
groupBox2 is invisible by default, now I would like to make it visible:
public partial class Login : Form
{
public Login()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e) //Confirm click event
{
if (textBox1.Text == Form1.password) //Here, no trouble accessing a string from the main screen
{
Form1.groupBox2.Visible = true; //********** Here is my problem **********
Form1.LoginWindow.Close();
}
else
{
textBox1.Text = "Incorrect password";
textBox1.SelectAll();
}
}
}
How do I overcome "An object reference is required for the non-static field, method or property 'Form1.groupBox2' problem?
All my controls are already set to public.
I'm reading and reading and can't figure it out, it's driving me mad now.
I'm not expecting a ready solution, just a good explanation.
You can just raise a event on your login form like this:
public partial class Login : Form
{
public EventHandler OnPasswordDone; // declare a event handler
public Login()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text == Form1.password)
{
// raise the event to notify main form
OnPasswordDone(this, new EventArgs());
}
else
{
textBox1.Text = "Incorrect password";
textBox1.SelectAll();
}
}
}
And in your main form:
public partial class Form1 : Form
{
private void LoginToolStripMenuItem_Click(object sender, EventArgs e) //Login button event
{
LoginWindow = new Login();
LoginWindow.OnPasswordDone += Login_PasswordDone; // regist your event here
LoginWindow.ShowDialog();
LogOutToolStripMenuItem.Enabled = true;
}
private void Login_PasswordDone(object sender, EventArgs e)
{
//Do what you need to do here like:
groupBox2.Visible = true;
}
}
Since Form1 is not static class , so you should create object of this class then set visible to true like as
Form1 formobj=new Form1();
formobj.groupBox2.Visible = true;
At first I thought that it won't be a problem for me, but now I can't figure it out. So,
when I click Button1 in main form, form2 opens. Form2 is simple numeric keyboard, that user can enter some data. On form2 is also Save. When user clicks it, entered value should pass to main form and from that moment some event must happen in main form, which contains data from form2. Could you please give me some example or any kind of help? Thanks!
// code from main form to create form2
private void button1_Click(object sender, EventArgs e)
{
// Create a new instance of the Form2 class
Form2 settingsForm = new Form2();
// Show the settings form
settingsForm.Show();
string val = settingsForm.ReturnValue1;
MessageBox.Show(val);
}
//button save on form2
private void button13_Click(object sender, EventArgs e)
{
this.ReturnValue1 = "Something";
this.ReturnValue2 = DateTime.Now.ToString(); //example
this.Close();
//after this, some event should happen in main form !
}
There is a lot of solutions to do what you want; but I think one of these will resolve your problem.
1- Simple and easy: use public properties in Form2, initialize them when buttonSave get clicked, and access them in Form1:
Form2:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e){
YourDate = "something";
Close();
}
public object YourDate { get; private set; }
}
Form1:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e){
var f2 = new Form2();
f2.ShowDialog();
var data = f2.YourDate;
}
}
2- A better way, is using events which is more flexible and professional programming friendly:
Form2:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
// create an event of Action<T> which T is your data-type. e.g. in this example I use an object.
public event Action<object> SaveClicked;
// create an event invocator, to invoke event whenever you want
protected virtual void OnSaveClicked(object data){
var handler = SaveClicked;
if (handler != null)
handler(data);
}
private void button1_Click(object sender, EventArgs e){
// prepare your data here, -object, or string, or int, or whatever it is
var data = PrepareYourDataHere;
// invoke the event
OnSaveClicked(data);
Close();
}
}
Form1:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e){
// create an instance of Form2
var f2 = new Form2();
// add an event listener to SaveClicked event -which we have declared it in Form2
f2.SaveClicked += f2_SaveClicked;
f2.Show();
// or: f2.ShowDialog();
}
void f2_SaveClicked(object obj) {
// get data and use it here...
// any data which you pass in Form2.OnSaveClicked method, will be accessible here
}
}
UPDATE:
If you want to fire some events in form1, just after form2 closed, you can simply add a listener to Form2.FormClosed event:
// code from main form to create form2
private void button1_Click(object sender, EventArgs e) {
// Create a new instance of the Form2 class
Form2 settingsForm = new Form2();
settingsForm.FormClosed += SettingFormClosed;
// Show the settings form
settingsForm.Show();
string val = settingsForm.ReturnValue1;
MessageBox.Show(val);
}
void SettingFormClosed(object sender, FormClosedEventArgs e) {
// this method will be called automatically when form2 closed
}
here a sample how you can achieve this
//here I suppose that form1 is the mainform
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void UpdateMainForm(string updatedString)
{
//here you can update and invoke methods
//Once called you could raise events in your mainform
}
private void button1_Click(object sender, EventArgs e)
{
using (Form2 form2 = new Form2(this))
{
form2.ShowDialog();
}
}
}
Form2
public partial class Form2 : Form
{
private Form1 _mainForm1;
public Form2(Form1 mainForm1)
{
InitializeComponent();
_mainForm1 = mainForm1;
}
private void button1_Click(object sender, EventArgs e)
{
_mainForm1.UpdateMainForm( DateTime.Now.ToString());
}
}
I have two child forms. The first form (Employee) has all the textboxes and a button to open another child form called Search. The Search form has a combobox. After user selects data from combobox then the data from combobox will display in Employee form.
Employee Form:
public string s;
protected override void OnShown(EventArgs e)
{
txtName.Text = s;
base.OnShown(e);
}
Search Form:
private void cbFind_SelectedValueChanged(object sender, EventArgs e)
{
if (cbFind.SelectedItem != null)
{
emp em = new emp();
em.s = cbFind.SelectedItem.ToString();
em.ShowDialog();
}
}
I do not want another Employee form to open after user selects data from combobox. I want it to appear on the Employee Form that is already opened..
EDIT:
Employee Form
namespace Master
{
public partial class Employee : Form
{
public Employee()
{
InitializeComponent();
searchForm.ItemSelected += ItemSelected;
}
private SearchForm searchForm = new SearchForm();
private void ItemSelected(object sender, ItemSelectedEventArgs e)
{
txtName.Text = e.SelectedItem.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
SearchForm searchForm = new SearchForm();
searchForm.Show();
}
}
}
Search Form
namespace Master
{
public partial class SearchForm : Form
{
public SearchForm()
{
InitializeComponent();
}
private void SearchForm_Load(object sender, EventArgs e)
{
}
private void cbFind_SelectedValueChanged(object sender, EventArgs e)
{
if (cbFind.SelectedItem != null)
{
if(ItemSelected != null)
ItemSelected(this, new ItemSelectedEventArgs(cbFind.SelectedItem));
}
}
public delegate void ItemSelectedEventHandler(object sender, ItemSelectedEventArgs e);
public event ItemSelectedEventHandler ItemSelected;
}
public class ItemSelectedEventArgs : EventArgs
{
public object SelectedItem { get; set; }
public ItemSelectedEventArgs(object selectedItem)
{
SelectedItem = selectedItem;
}
}
}
There are many many ways to achieve what you want, the most favorite I like is using some kind of event, yes event is one of the most interesting things in modern programming languages like C# (in .NET environment). However you can choose another solution simply like this:
//in your Search form
public string ShowSearch(){
if(ShowDialog() == DialogResult.OK){
return cbFind.SelectedItem == null ? "" : cbFind.SelectedItem.ToString();
}
return "";
}
//returning "" means some kind of cancel action which will result no search performed.
Search form should be one element in your Employee form, you can show your search form using the method above and get the returned selected item value.
That's not a decent way in some cases, here I introduce you the way using event, you have to declare some event to notify the selecting from user and show the selected item on your Employee form:
//your Employee form
public class Employee : Form {
public Employee(){
InitializeComponent();
searchForm.ItemSelected += ItemSelected;
}
//Search form
private SearchForm searchForm = new SearchForm();
//your ItemSelected handler
private void ItemSelected(object sender, ItemSelectedEventArgs e){
txtName.Text = e.SelectedItem.ToString();
}
}
//your Search form
public class SearchForm : Form {
public SearchForm(){
InitializeComponent();
}
//handler for your combobox SelectedValueChanged event.
private void cbFind_SelectedValueChanged(object sender, EventArgs e)
{
if (cbFind.SelectedItem != null)
{
if(ItemSelected != null) ItemSelected(this, new ItemSelectedEventArgs(cbFind.SelectedItem);
}
}
public delegate void ItemSelectedEventHandler(object sender, ItemSelectedEventArgs e);
//your own event
public event ItemSelectedEventHandler ItemSelected;
}
public class ItemSelectedEventArgs : EventArgs {
public object SelectedItem {get;set;}
public ItemSelectedEventArgs(object selectedItem){
SelectedItem = selectedItem;
}
}
You can use traditional ways which pass values between classes... but I recommend using event (as the code above shows) or at least some kind of delegate. Programming in .NET environment requires you to make familiar with events and delegates much more...
on your parent form you should do this
private void button1_Click(object sender, EventArgs e)
{
Form1 searchForm = new Form1();
if (searchForm.ShowDialog() == DialogResult.OK)
{
string selectedRecord = searchForm.SelectedRecord;
}
}
where button1 is your button to open the search form. Form1 is your search form. and selectedRecord is your property that you set before closing the search form. I have assumed that it is a string though it can be any object.
I've got two forms, with subForm being called/created by a buttonClick in Form1. Right now I can initiate subForm, hide Form1, and then unhide Form1 when subForm is closed. What I'd like to be able to do is:
If user clicks changeform button, check to see if subForm is active but hidden
If no, then initiate subForm, else hide Form1, unhide subForm and pass control to it
If user clicks subForm's changeform button, hide subForm, unhide Form1 and pass control to it
If user clicks the "X" in the upper right corner of the form, then close the application, regardless of which form is active. (Right now, selecting the "X" closes the subForm and opens/unhides Form1.)
I can find solutions that do part of the requirements (and maybe all, I'm just too noob to know). To repeat from my previous question here, the code I have so far is:
Form1
private void countClick(object sender, EventArgs e)
{
this.Hide();
subForm myNewForm = new subForm();
myNewForm.ShowDialog();
this.Show();
countSelect.Checked = false;
}
and subForm
private void totalClick(object sender, EventArgs e)
{
this.Close();
}
This works, but it's not really elegant.
I think the best way to do this is to roll your own ApplicationContext. This allows you full control over the application lifetime without having it being tied to a specific Window. See http://msdn.microsoft.com/en-us/library/ms157901.aspx for more information.
Here's an example:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApplicationContext());
}
}
public class MyApplicationContext : ApplicationContext
{
public MyApplicationContext()
{
ShowForm1();
}
public void ShowForm1()
{
if (_form2 != null)
_form2.Hide();
if (_form1 == null)
{
_form1 = new Form1(this);
_form1.FormClosed += OnFormClosed;
}
_form1.Show();
MainForm = _form1;
}
public void ShowForm2()
{
if (_form1 != null)
_form1.Hide();
if (_form2 == null)
{
_form2 = new Form2(this);
_form2.FormClosed += OnFormClosed;
}
_form2.Show();
MainForm = _form2;
}
private void OnFormClosed(object sender, FormClosedEventArgs e)
{
if (_form1 != null)
{
_form1.Dispose();
_form1 = null;
}
if (_form2 != null)
{
_form2.Dispose();
_form2 = null;
}
ExitThread();
}
private Form1 _form1;
private Form2 _form2;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Form1(MyApplicationContext context)
: this()
{
_context = context;
}
private void button1_Click(object sender, EventArgs e)
{
if (_context != null)
_context.ShowForm2();
}
private readonly MyApplicationContext _context;
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public Form2(MyApplicationContext context)
: this()
{
_context = context;
}
private void button1_Click(object sender, EventArgs e)
{
if (_context != null)
_context.ShowForm1();
}
private readonly MyApplicationContext _context;
}
So we'll start out by going to the child form and creating a new event that can be used to notify the parent when it wants to change forms:
public event Action ChangeForm;
Then we fire the event and hide the child form when it wants to change forms:
private void ChangeForm_Click(object sender, EventArgs e)
{
Hide();
if (ChangeForm != null)
ChangeForm();
}
The parent form needs an instance of the child form as an instance field:
private subForm child = new subForm();
And it needs to initialize it in it's constructor, both adding handlers to the ChangeForm event to show the parent, and to the closed event to close itself:
public Form1()
{
InitializeComponent();
child.ChangeForm += () => Show();
child.FormClosed += (s, args) => Close();
}
Then all that's left is for the parent form to hide itself and show the child when it wants to change forms:
private void ChangeForm_Click(object sender, EventArgs e)
{
Hide();
child.Show();
}
Why not simply setting them to foreground, topmost, and so on ?
And setting them back vice versa ?
---added as comment as proposed
To access MainForm fromsubForm:
Create a constructor in your subForm and a field:
MainForm MainFormRef_Field;
subForm(MainForm MainFormRef)
{
this.MainFormRef_Field = MainFormRef;
}
Now you can access your MainForm using this reference. Like this:
MainFormRef_Field.Show();
MainFormRef_Field.Hide(); //or how ever you want to handle it
To access subForm fromMainForm:
To handle your subForm use the object you created for it. Here:
subForm myNewForm = new subForm();
To close whole application if any of the form closes:
Set a Form_Closing event for both forms:
private void MainForm_Closing(object sender, EventArgs e)
{
Application.Exit();
}
private void subForm_Closing(object sender, EventArgs e)
{
Application.Exit();
}
Note:
I am not writing the whole code for all of your cases. Set the variables, check the conditions. Its all up to you that how code it. All the main points you needed I've provided you the solution of them.
I have 2 WinForms where one is parent and passing parameter to it's chilf form. The code goes something like this:
public class FormMain : Form {
private User user;
public FormMain (User user) {
InitializeComponent();
this.user = user;
}
private void btnUpdateAccount_Click(object sender, EventArgs e)
{
updateUser = new FormUsersUpdate(user);
updateUser.Show();
}
}
and this:
public class FormUsersUpdate(User user){
//Update user in database
}
User class have some usual properties like Name, surname, etc. So my question is how to inform parent class about this update without need to again retrieve user from database?
Thanks.
You can invoke a callback delegate after the update. In FormMain:
private void btnUpdateAccount_Click(object sender, EventArgs e)
{
updateUser = new FormUsersUpdate(user, new Action<User>(OnUserUpdated));
updateUser.Show();
}
private void OnUserUpdated(User user)
{
// Whatever you wanted to do with the updated user.
}
In FormUsersUpdate:
public class FormUsersUpdate(User user, Action<User> callback)
{
// Update user, then invoke the callback using the updated user instance,
// which will call the OnUserUpdated method of the FormMain:
callback.Invoke(user);
}
ShowDialog is mostly a better choice but I never tried it on an mdi child:
private void btnUpdateAccount_Click(object sender, EventArgs e)
{
updateUser = new FormUsersUpdate(user);
updateUser.ShowDialog();
// Will wait until the user closes the dialog box.
// FormUserUpdate keeps the updated user in a property called User:
OnUserUpdated(updateUser.User);
}
Some options:
Define an event UserUpdated on your second form, and fire the event when any changes occur in the User instance.
Implement INotifyPropertyChanged on the User class, and handle this event in your main form when fired.
If you are simply wanting to pass the values back then expose them as public static variables in the parent and set them in the child window.
Parent:
public static User CurrentUser {get; set;}
Child:
FormMain.CurrentUser = user;
FormMain.CurrentUser.LastName = "Menefee";
Here is the working sample for the above issue using delegate and event:
public partial class FormUsersUpdate : Form
{
private readonly User user;
public delegate void UserChangedEventHandler(object sender, EventArgs e);
public event UserChangedEventHandler UsrChanged;
private void InvokeUsrChanged()
{
var args = new EventArgs();
if (UsrChanged != null) UsrChanged(this, args);
}
public FormUsersUpdate()
{
InitializeComponent();
}
public FormUsersUpdate(User usr)
{
InitializeComponent();
this.user = usr;
this.user.name = "Kishore";
}
private void FormUsersUpdate_Load(object sender, EventArgs e)
{
InvokeUsrChanged();
}
}
public partial class Form1 : Form
{
private User user;
FormUsersUpdate _frmusrUpdate;
public Form1()
{
InitializeComponent();
this.user = new User { name = "Test" };
}
private void button1_Click(object sender, EventArgs e)
{
_frmusrUpdate = new FormUsersUpdate(this.user);
_frmusrUpdate.UsrChanged += new FormUsersUpdate.UserChangedEventHandler(_frmusrUpdate_UsrChanged);
_frmusrUpdate.Show();
}
void _frmusrUpdate_UsrChanged(object sender, EventArgs e)
{
MessageBox.Show("User Details Changed");
}
}