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");
}
}
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;
Recently picked up C# in university, trying to work out how to pass the variable "name" in MainWindow.xaml to ThirdWindow.xaml?
The below code is for the main window where the data is assigned to the variable "name"
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void NameBox_TextChanged(object sender, TextChangedEventArgs e)
{
string name = NameBox.Text;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondWindow newWin = new SecondWindow();
newWin.Show();
this.Close();
}
}
The below code is for the third window
public partial class ThirdWindow : Window
{
public ThirdWindow()
{
InitializeComponent();
}
public void LstThanks_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LstThanks.Items.Add(name);
}
}
You can simply pass that string name variable in the constructor as an argument to the ThirdWindow on Button_Click event.
private void Button_Click(object sender, RoutedEventArgs e)
{
var name = "your name";
var newWin = new ThirdWindow(name);
newWin.Show();
this.Close();
}
That string text will be available in the constructor of ThirdWindow.
public partial class ThirdWindow: Window
{
public ThirdWindow(string name)
{
InitializeComponent();
}
public void LstThanks_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LstThanks.Items.Add(name);
}
}
You can pass the variable through the constructor of the new window
var win = new ThirdWindow(name);
public ThirdWindow(string name)
{
InitializeComponent();
}
Another method is to pass it through an event message. This will require you to write a new message and add an event listener to your constructor in the ThirdWindow class. If you google this there are a variety of examples out there on how to do such a thing.
Here you are defining a local variable name. This variable is visible only inside the {} block. So we cannot use it anywhere else.
public void NameBox_TextChanged(object sender, TextChangedEventArgs e)
{
string name = NameBox.Text;
}
You could add a new string property into second window and pass value through that to all the way into third form.
So, add new property into your two windows (SecondWindow, ThirdWindow)
public string Name { get; set; }
These properties are holding the data for whole their lifetime (until they are closed).
Remove NameBox_TextChanged event handling, because we don't need it.
Add property setting inside your buttons click event
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondWindow newWin = new SecondWindow();
newWin.Name = NameBox.Text; //Store value into SecondWindow variable
newWin.Show();
this.Close();
}
Now when SecondWindow is visible (Show is called), you have name value available in Name variable and you should be able to copy this behavior for ThirdWindow.
If the ThirdWindow window is dependent on the name value then you can pass it through the constructor:
public partial class ThirdWindow : Window
{
public string Name { get; set; }
public ThirdWindow(string name)
{
InitializeComponent();
Name = name;
}
}
or if not then make a method on the ThridWindow to set the name:
public partial class ThirdWindow : Window
{
public string Name { get; set; }
public void SetName(string name)
{
Name = name;
}
}
I have seen a few links on attempts at this but I haven't found a solution. I am attempting to access my form textbox and update it with text from another class. I can update the text within my DataOrganizerForm class directly but when I pass text back to the DataOrganizerForm class then it doesn't update on the GUI. Here is what I have:
public partial class DataOrganizerForm : Form
{
//Default constructor
public DataOrganizerForm()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
//Handle a Start/Stop button click
private void start_stop_button_Click(object sender, EventArgs e)
{
SerialNumberSearcher snsearch = new SerialNumberSearcher();
snsearch.searchSN();
}
//Allow simple access to update to notification textbox
public void setNotificationText(string text)
{
notification_textbox.Text = text;
}
}
public class SerialNumberSearcher
{
public void searchSN()
{
DataOrganizerForm formAccess = new DataOrganizerForm();
formAccess.setNotificationText("Updated text from different class");
}
}
Well, it won't update the textbox 'cause you're instantiating another object of the DataOrganizerForm class. What you could do is passing a reference of the form object to the SerialNumberSearcher, like this:
public class SerialNumberSearcher
{
private readonly DataOrganizerForm _form;
public SerialNumberSearcher(DataOrganizerForm form)
{
_form = form;
}
public void searchSN()
{
_form.setNotificationText("Updated text from different class");
}
}
You need to understand at which instance you operate. When you use the new-eperator you create a new instance, like a new copy of that type.
DataOrganizerForm formAccess = new DataOrganizerForm();
The original Form is a different instance then the one you create in the searchSN method.
You need to pass that instance into the method to manipulate it:
public void searchSN(DataOrganizerForm formAccess )
{
formAccess.setNotificationText("Updated text from different class");
}
When you want to call this method you need to use this to reference the current object :
private void start_stop_button_Click(object sender, EventArgs e)
{
SerialNumberSearcher snsearch = new SerialNumberSearcher();
snsearch.searchSN(this);
}
this will access the current instance of the Form, thereby allowing you to manipulate the textbox that you are interested in.
When do you use the “this” keyword? might also be helpfull
Thanks for the help. This is what I was able to do to make my application work. I passed the Textbox object by reference to my other class and was able to display my information that way. Also, I had issues getting my text box to continuously update. I had to add
public partial class DataOrganizerForm : Form
{
//Default constructor
public DataOrganizerForm()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
//Handle a Start/Stop button click
private void start_stop_button_Click(object sender, EventArgs e)
{
SerialNumberSearcher snsearch = new SerialNumberSearcher();
snsearch.searchSN(notification_textbox);
}
//Allow simple access to update to notification textbox
public void setNotificationText(string text)
{
notification_textbox.Text = text;
notification_textbox.Update();
}
}
public class SerialNumberSearcher
{
public void searchSN(Textbox notifyTextbox)
{
notifyTextbox.setNotificationText = "Updated text from different class";
notifyTextbox.Update();
}
}
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 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.