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.
Related
This question already has answers here:
Change a textbox's text value on a UserControl from a Window in WPF
(2 answers)
Closed 3 years ago.
Ok, I have two windows in my WPF app. I want to change the text of a textbox, from a second window. This should also happen parallel.
I know, this is about multithreadin, but I know very little about it.
This is what my current code looks like, but this is for copying textbox text.
private void copyButton_Click(object sender, RoutedEventArgs e)
{
secondWindow = new SecondWindow();
secondWindow.textBoxS.Text = textBox.Text;
secondWindow.Show();
}
But, I want to change textbox texts dynamically between the MainWindow and the Second window.
So I tried something like this:
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
Task t = Task.Run(() =>
{
secondWindow = new SecondWindow();
secondWindow.textBoxS.Text = textBox.Text;
secondWindow.Show();
});
t.Start();
}
There are several ways to do this. I put two way in below:
Method 1
You can create a public method (e.g. SetTextBoxValue) and
pass the window that contains the TextBox to other window. Then change the TextBox value using that method. like this:
MainWindow
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
public void SetTextBoxValue(string value)
{
SampleTextBox.Text = value;
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var otherWindow = new AnotherWindow(this);
otherWindow.Show();
}
}
Other Window
public partial class AnotherWindow
{
private readonly MainWindow _mainWindow;
public AnotherWindow(MainWindow mainWindow)
{
_mainWindow = mainWindow;
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
_mainWindow.SetTextBoxValue("New value from other window");
}
}
Method 2
You can create a event for other window and subscribe to it in main window. like this:
MainWindow
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var otherWindow = new AnotherWindow();
otherWindow.TextBoxValueChanged += OtherWindowOnTextBoxValueChanged;
otherWindow.Show();
}
private void OtherWindowOnTextBoxValueChanged(object sender, TextBoxValueEventArgs e)
{
SampleTextBox.Text = e.NewValue;
}
}
Other Window
public partial class AnotherWindow
{
public event EventHandler<TextBoxValueEventArgs> TextBoxValueChanged;
public AnotherWindow()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var newValue = "New value from other window";
OnTextBoxValueChanged(new TextBoxValueEventArgs(newValue));
}
protected virtual void OnTextBoxValueChanged(TextBoxValueEventArgs e)
{
TextBoxValueChanged?.Invoke(this, e);
}
}
public class TextBoxValueEventArgs : EventArgs
{
public string NewValue { get; set; }
public TextBoxValueEventArgs(string newValue)
{
NewValue = newValue;
}
}
OUTPUT
try this, initialize the second window in first window constructor
private SecondWindow _secondWindow;
public FirstWindow()
{
_secondWindow = new SecondWindow();
}
and your second form before constructor
private string text;
public string Text
{
get
{
return text;
}
set
{
textBoxOfSecondWindow.Text = value;
text = value;
}
}
then in the copybutton function
private void copyButton_Click(object sender, RoutedEventArgs e)
{
_secondWindow.Text= textBox.Text;
_secondWindow.Show();
}
in the textchange of the first window
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
_secondwindow.Text = textBox.Text;
}
in your second window, place this code in the textBox_TextChanged method.
((MainWindow)Application.Current.MainWindow).txtFirstWindow.Text = txtSecondWindow.Text;
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 am struggling in adding a dynamic and removing a user control into the form. I have a form and inside my form I have a panel which it has a static control.
What I am trying to achieved is to add the user control into the panel. Though it was easy to add but I know there is a better way out there to do this.
Adding a user control to my panel by clicking a button in the form.
private void btnadd_Click(object sender, EventArgs e)
{
UserControl1 usr = new UserControl1
pnlUI.SuspendLayout();
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
pnlUI.ResumeLayout(false);
}
// This one adds it and clearing the control that was already in the panel of the form.
Now, I get stacked here in removing the user control that was added and trying to display again the control that was in the panel that was been removed or cleared.
On my user control there is a back button on that back button I am trying to dispose the user control. But after that the original control is no longer there and the panel is empty already.
Any suggestions?
You could add an instance variable to your form to keep track of the previous control. This assumes that there will only ever be one control in the panel.
In your class:
private Control _previousPanelContent;
then in your method:
private void btnadd_Click(object sender, EventArgs e)
{
UserControl1 usr = new UserControl1();
pnlUI.SuspendLayout();
// check if there's already content in the panel, if so, keep a reference.
if (pnlUI.Controls.Count > 0)
{
_previousPanelContent = pnlUI.Controls[0];
pnlUI.Controls.Clear();
}
pnlUI.Controls.Add(usr);
pnlUI.ResumeLayout(false);
}
then later when you want to go back:
pnlUI.SuspendLayout();
pnlUI.Controls.Clear();
// if the previous content was set, add it back to the panel
if (_previousPanelContent != null)
{
pnlUI.Controls.Add(_previousPanelContent);
}
pnlUI.ResumeLayout(false);
Here's a simple example of the Event approach mentioned in the Comments above.
The UserControl with a "Back" event:
public partial class UserControl1 : UserControl
{
public event dlgBack Back;
private UserControl1 _previous = null;
public delegate void dlgBack(UserControl1 sender, UserControl1 previous);
public UserControl1(UserControl1 previous)
{
InitializeComponent();
this._previous = previous;
}
private void btnBack_Click(object sender, EventArgs e)
{
if (Back != null)
{
Back(this, _previous);
}
}
}
The Form then creates the UserControl and subscribes to the Event:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
UserControl1 prevUsr = pnlUI.Controls.OfType<UserControl1>().FirstOrDefault();
UserControl1 usr = new UserControl1(prevUsr);
usr.Back += usr_Back;
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
}
void usr_Back(UserControl1 sender, UserControl1 previous)
{
pnlUI.Controls.Remove(sender);
if (previous != null)
{
pnlUI.Controls.Add(previous);
}
}
}
You are declaring your user control inside your button callback function (callback function is a function called at runtime when an event occurs, such as a button click etc.).
This means that the variable holding your user control is inaccessible outside it, and therefore you are not able to use it from another callback function.
Instead of doing this:
private void btnadd_Click(object sender, EventArgs e)
{
//This is not accessible outside the callback function.
UserControl1 usr = new UserControl1();
pnlUI.SuspendLayout();
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
pnlUI.ResumeLayout(false);
}
Try declaring a property that will hold the user control, in order to use it elsewhere:
//Declare a private property - you can adjust the access level of course,
//depending on what you need.
//You can even declare a field variable for the same cause,such as
//private UserControl _myUserControl;
//This declaration is in the class body.
private UserControl MyUserControl { get; set; }
//Your addition callback function.
private void btnadd_Click(object sender, EventArgs e)
{
//The user control is now assigned to the property.
MyUserControl = new UserControl1();
pnlUI.SuspendLayout();
pnlUI.Controls.Clear();
pnlUI.Controls.Add(MyUserControl);
pnlUI.ResumeLayout(false);
}
//Your removal callback function.
private void btnremove_Click(object sender, EventArgs e)
{
//...
//Use the property value here.
pnlUI.Controls.Remove(MyUserControl);
//...
}
I collected the solutions above (mostly the first of #Idle_Mind) I just added and adjusted some lines ; I will use his sentences:
Here's a simple example of the Event approach mentioned in the Comments above.
The UserControl with a "Back" event:
No Change here
public partial class UserControl1 : UserControl
{
public event dlgBack Back;
private UserControl1 _previous = null;
public delegate void dlgBack(UserControl1 sender, UserControl1 previous);
public UserControl1(UserControl1 previous)
{
InitializeComponent();
this._previous = previous;
}
private void btnBack_Click(object sender, EventArgs e)
{
if (Back != null)
{
Back(this, _previous);
}
}
}
The Form then creates the UserControl and subscribes to the Event:
Let take a look at commented lines
public partial class Form1 : Form
{
//prevUsr is global instead
private UserControl1 prevUsr = null;
public Form1()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
//prevUsr is removed from here
//UserControl1 prevUsr = pnlUI.Controls.OfType<UserControl1>().FirstOrDefault();
UserControl1 usr = new UserControl1(prevUsr);
usr.Back += usr_Back;
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
//prevUsr is updated
prevUsr = usr;
}
void usr_Back(UserControl1 sender, UserControl1 previous)
{
pnlUI.Controls.Remove(sender);
//prevUsr is updated
prevUsr = previous;
if (previous != null)
{
pnlUI.Controls.Add(previous);
}
}
}
And, don't forget to set btnBack_Click for click of the UserControl's back button.
I hope this is helpful, it worked perfectly at my side ; I can send or share the full VS project (VS2012).
I hope it works for you,
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int count = 0;
private LinkedList<UserControl1> lstControls = new LinkedList<UserControl1>();
private void btnAdd_Click(object sender, EventArgs e)
{
var c = new UserControl1();
if (pnlUI.Controls.Count > 0)
{
lstControls.AddLast(pnlUI.Controls[0] as UserControl1);
pnlUI.Controls.Clear();
}
c.lblTitle.Text = "Control #" + (++count).ToString();
pnlUI.Controls.Add(c);
}
private void btnBack_Click(object sender, EventArgs e)
{
if (lstControls.Last != null)
{
var lastControl = lstControls.Last.Value;
pnlUI.Controls.Clear();
pnlUI.Controls.Add(lastControl);
lstControls.RemoveLast();
}
}
}
I combine the answers of idle_mind,rdavisau and fabrice. I used rdavisau code in getting back the controls and idle_mind for the back event in the usercontrol and fabrice for his some modifications in the form.. I wish i can split the bounty into three,so I give it to idle mind..thanks all
I created a class:
class GetControls
{
private Control[] cntrl;
public Control[] Previous
{
get
{
return cntrl;
}
set
{
cntrl = value;
}
}
}
on my main form here is the revised code.
GetControls help = new GetControls();
private void btnpay_Click(object sender, EventArgs e)
{
TenderUI usr = new TenderUI(prevUsr);
usr.Back += usr_Back;
help.Previous = pnlUI.Controls.OfType<Control>().ToArray();
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
}
and to retrieve the controls
void usr_Back(TenderUI sender, TenderUI previous)
{
pnlUI.Controls.Remove(sender);
if (help.Previous != null)
{
foreach (Control ctr in help.Previous)
{
pnlUI.Controls.Add(ctr);
}
}
}
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");
}
}
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.