I have a main form that has most of the functionality in it. I was just wondering how would I pass on a variable from say a pop up form, to that main form.
Like for instance:
I have a main form that needs some connection info. So when you click the button "Enter Connection Info", it opens up a new form that the user can type in the IP Address he wants to use for his connection.
On this new form, I have a textbox and a button and once you enter the information it should close and pass on the string that contains the ip back to the original form.
Any suggestions? Do you think there is a better method of accomplishing this than using a windows form, and just going ahead and using a windows form or something? I'm quite perplexed on this issue at the moment.
Expose the textbox text as a public read only property. Show the connection form as a dialog and when it closes, get the connection from the property and then dispose the form:
in open form handler (button click, menu, whatever)
string connectionString = null;
using (ConnectionForm form = new ConnectionForm())
{
DialogResult result = form.ShowDialog();
if (result == DialogResult.Ok)
connectionString = form.ConnectionString
}
In you connection form:
public class ConnectionForm: Form
{
....
public string ConnectionString { get { return textBox1.Text; } }
}
You can create a public property in your main form and pass main form instance in pop-up constructor. In this way you can change the main form property.
You can also create an event in your pop-up form and hook it in your main form.
I like to use a pattern sort of like this (bear with me, c# is not my first language):
public class ValueForm: Form
{
public static string GetFromUser(string originalValue)
{
using (ConnectionForm form = new ConnectionForm())
{
form.TheValue = originalValue;
var result = form.ShowDialog();
if (result == DialogResult.Ok)
return form.TheValue;
else
return originalValue;
}
}
public string TheValue {
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
/* also some code behind your OK & cancel buttons to set
DialogResult appropriately,
and do any validation that you need to do
*/
}
and then you would use this like:
string newValue = ValueForm.GetFromUser(oldValue);
Reference Bind the controls on the dialog Form to properties of the Parent Form.
public dlgDbConnProps ( Form Owner )
{
// TODO: Complete member initialization
InitializeComponent ( );
owner = Owner;
}
private void cbo_ProviderLst_SelectedIndexChanged ( object sender, EventArgs e )
{
owner.Provider = cboLst.Text;
}
Here is another method that I have implemented:
... pass a Func to the child form constructor:
public dlgRequestLogin ( Func<string, string, bool> LoginMethod )
{
InitializeComponent ( );
p_loginMethod = LoginMethod;
}
... then handle on button click (or other appropriate event):
private void cmd_SendLoginCredentials_Click ( object sender, EventArgs e )
{
bool res = p_loginMethod.Invoke ( txt_UserID.Text, txt_UserPassword.Text );
}
Related
Wierd behaviour when passing values to and from second form.
ParameterForm pf = new ParameterForm(testString);
works
ParameterForm pf = new ParameterForm();
pf.testString="test";
doesn't (testString defined as public string)
maybe i'm missing something? Anyway I'd like to make 2nd variant work properly, as for now - it returns null object reference error.
Thanks for help.
Posting more code here:
calling
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(doc.GetElementById(ParametersButton.Tag.ToString()));
pf.ShowDialog(this);
pf.test = "test";
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
};
definition and use
public partial class ParameterForm : Form
{
public string test;
public XmlElement node;
public delegate void ParameterSubmitResult(object sender, XmlElement e);
public event ParameterSubmitResult Submit;
public void SubmitButton_Click(object sender, EventArgs e)
{
Submit(this,this.node);
Debug.WriteLine(test);
}
}
result:
Submit - null object reference
test - null object reference
pf.ShowDialog(this); is a blocking call, so pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit); is never reached: switch the order.
Submit(this,this.node); throws a null object reference because no event is assigned to it (see above). Generally, you should always check first: if (Submit != null) Submit(this,this.node);
You should change ``pf.ShowDialog(this);topf.Show(this);` so that your main form isn't disabled while your dialog box is open, if that's what you want, or use the model below (typical for dialog boxes.)
I'm not sure what pf_Submit is supposed to do, so this might not be the best way to go about it in your application, but it's how general "Proceed? Yes/No" questions work.
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(testString);
pf.ShowDialog(this); // Blocks until user submits
// Do whatever pf_Submit did here.
};
public partial class ParameterForm : Form
{
public string test; // Generally, encapsulate these
public XmlElement node; // in properties
public void SubmitButton_Click(object sender, EventArgs e)
{
Debug.WriteLine(test);
this.Close(); // Returns from ShowDialog()
}
}
When you want to use your second variant, you have to use a getString()-Method, where you can put the e.g. "testString". The way you wrote it, "testString" should be a method (and got brackets).
EDIT (a bit more precise):
You could write:
pf.getString(testString);
, if "pf" is an instance of your own class, otherwise you had to look up, whether you can retrieve a String in this class.
the thing was in line order :)
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
and
pf.Test = "test";
should have been set before
pf.ShowDialog(this);
my mistake thingking that parameter can be passed after 2nd form was displayed
thnx for answers
How to Close background Forms whenever a new form is opened in Windows Forms C#?
It should not be the specific form to be closed.
It should close all the background forms whenever a form is opened.
Two approaches.
First is using Application.OpenForms like this:
foreach (Form form in Application.OpenForms)
{
if(Form is YourMainFormClassName) //Check if current form is your main form and do not close it since your app would close. You can use .Hide() if you want
return;
form.Close();
}
Other approach is using List but you cannot do List<Form> because when removing you will have problem if you want to remove specific form and you go like yourList.Remove(this) it will remove all items with class of that form. Of course it will happen only if you open one form multiple times but to avoid that we will use Form.Tag property.
An Object that contains data about the control. The default is null
So we will use it to store our Id of the form.
So now when we prepared system let's write it:
First we need List<Form> that is accessible from all classes so we will create it like public static property.
public static class Settings //Class is also static
{
public static List<Form> OpenedForms = new List<Form>();
public static int MaxIdOfOpenedForm() //With this method we check max ID of opened form. We will use it later
{
int max = -1;
foreach(Form f in OpenedForms)
{
if(Convert.ToInt32(f.Tag) > max)
max = Convert.ToInt32(f.Tag);
}
return max;
}
public static void RemoveSpecificForm(Form form) //Remove specific form from list
{
for(int i = 0; i < OpenedForms.Count; i++)
{
if((OpenedForms[i] as Form).Tag == form.Tag)
{
OpenedForms.Remove(form);
return;
}
}
}
public static void CloseAllOpenedForms()
{
for(int i = 0; i < OpenedForms.Count; i++)
{
OpenedForms.Remove(OpenedForms[i]);
}
}
}
Now we have list but need to populate it every time we open new form so we will do it like this:
public partial class YourForm
{
public YourForm()
{
InitializeComponents();
this.Tag = Settings.MaxIdOfOpenedForm() + 1; //We are setting Tag of newly opened form
Settings.OpenedForms.Add(this); //Adding new form to opened forms.
}
}
And when we close form we need to remove form from list:
private void YourFormClosed(object sender, EventArgs e)
{
RemoveSpecificForm(this);
}
and when we set this up just call CloseAllOpenedForms().
This method could have some improvements in performance but this is basic and you expand it further.
well as only one form can be active and in the foreground, so when openening a new form you can close the previous one:
In your main form:
Form previous_form = null;
and when creating any form:
if( previous_form != null)
previous_form.Close();
SomeForm someform = new SomeForm();
previsous_form = some_form;
someform.Show();
i have this WPF application in which i am trying to make popup window. well window is created and working fine, but what i want to do. that if i press OK/Update button in that popup, The selected values should be passed the the parent window and that popup should be closed.
i have seen this problem solution here..
C# - Return variable from child window to parent window in WPF
But i do not understand how this delegates works..
I have done it like this..
When click on button this method will opens the popup window.
private void btnAddBeneficiaryPopup_Click(object sender, RoutedEventArgs e)
{
try
{
AddBeneficiaryPopup addBen = new AddBeneficiaryPopup(refCustId);
addBen.selectedBeneID += value => selectedBeneficiaryID = value;
addBen.Show();
}
catch (Exception ex)
{ this.MyErrorMessage(ex); }
}
In Popup window in the constructor i have code like this.
public AddBeneficiaryPopup(int id)
{
InitializeComponent();
refCustId = id;
this.LoadReferenceBeneficiary();
}
Now this below Method i am working on and want to change it mostly..
private void cmbRefBene_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string beneId = null;
if (cmbRefBene.SelectedIndex >= 0)
{
try
{
beneId = ((DataRowView)cmbRefBene.SelectedItem).Row.ItemArray[0].ToString();
selectedBeneID = beneId;
bene.OpenConnection(str);
SqlDataReader reader = bene.LookUpSingleBene(int.Parse(beneId));
if (reader.Read())
{
tbName.Text = reader["Name"].ToString();
tbContactNo.Text = reader["ContactNo"].ToString();
btnUpdate.IsEnabled = true;
}
reader.Close();
bene.CloseConnnection();
}
catch (Exception ex)
{
MyErrorMessage(ex);
}
finally
{
bene.CloseConnnection();
}
}
}
As you can see in above code selectedBeneID = beneId; this beneId gives error. as i am trying to assign it selectedBeneID, as i think its a delegate to there must be another way to assigning values to it and passing it to the Parent Window..
But really am not sure how to work with this delegate and what to write to assign value to it.
i am getting error
"cannot implicitly convert type string to "System.Action<string>"
Solution A (getting your one working)
To get your solution running, change the following line in your cmbRefBene_SelectionChanged function:
selectedBeneID = beneId;
to
selectedBeneID(beneId);
Now you should not get the error message and the value should be set correctly.
Solution B
The following solution isn'n the most elegant but it always works:
Give your Popup Window a public Property (selectedBeneID).
public partial class AddBeneficiaryPopup : Window {
public string selectedBeneID;
.....
}
}
Set this property in your cmbRefBene_SelectionChanged function.
MainWindow:
change addBen.Show(); in your Main Window
to
addBen.ShowDialog();
idreturned = addBen.selectedBeneID;
Now The program will wait until you close the Popup.
After that you can access the property of your popup Window and read it out.
I'm writing an application that uses a wizard-like series of 5 simple forms. The first form, NewProfile, is opened from a menu item on the main application, MainForm, so is a subform of MainForm. The second form, TwoProfile, is opened from a button on NewProfile. The third form, ThreeProfile is opened from a button on TwoProfile, and so on for all 5 forms. Here is the sequence:
MainForm --> NewProfile <--> TwoProfile <--> ThreeProfile <--> FourProfile <--> FiveProfile. My problem is that when any form (NewProfile, TwoProfile, ThreeProfile, FourProfile or FiveProfile) is open, I don't want a user to be able to create an instance of NewProfile.
I started out by implementing a Singleton pattern, which half-way works. It works if NewProfile is open and I go to MainForm and try to create another instance of NewProfile. It does not work if NewProfile has been destroyed, by advancing to the next form and one of TwoProfile, ThreeProfile, FourProfile or FiveProfile is open. It tells me that NewProfile.IsDisposed is true, giving me a bad reference to the Singleton instance.
What I can't figure out is how to do my logic so that NewProfile won't be created if one of TwoProfile, ThreeProfile, FourProfile or FiveProfile is open or if NewProfile itself is open.
I hope this made sense. I don't really have much code to post, except what I did for my Singleton.
private static NewProfile _instance = null;
public static NewProfile Instance
{
get
{
if (_instance == null)
{
_instance = new NewProfile();
}
return _instance
}
}
Thank you :)
As suggested in the comments, each "form" could actually be a usercontrol you swap. That way, you only have one form and multiple pages. Alternatively, you can hide the form.
If you want multiple forms instead, then you could loop through all the open forms and see if the the ones you want to check are open. If not, you can open NewProfile.
bool shouldOpenNewDialog = true;
foreach (Form f in Application.OpenForms)
{
//give each dialog a Tag value of "opened" (or whatever name)
if (f.Tag.ToString() == "opened")
shouldOpenNewDialog = false;
}
if(shouldOpenNewDialog)
np = new NewProfile();
It's untested, but it should loop through all open forms and look for any that has a Tag saying opened. If it comes across one, then it set the shouldOpenNewDialog flag to false and NewProfile won't be called.
The way that we handle this is to have a static window manager class that keeps track of the open form instances. When the user performs an action that would cause a new window to open, we first check the window manager to see if the form is already open. If it is, we set focus on it rather than creating a new instance.
Every form that is opened inherits from a base form implementation that automatically registers itself with the window manager when it is opened and removes its registration when it is closed.
Here is a rough outline of the WindowManager class:
public class WindowManager
{
private static Dictionary<string, Form> m_cOpenForms = new Dictionary<string, Form>();
public static Form GetOpenForm(string sKey)
{
if (m_cOpenForms.ContainsKey(sKey))
{
return m_cOpenForms[sKey];
}
else
{
return null;
}
}
public static void RegisterForm(Form oForm)
{
m_cOpenForms.Add(GetFormKey(oForm), oForm);
oForm.FormClosed += FormClosed;
}
private static void FormClosed(object sender, FormClosedEventArgs e)
{
Form oForm = (Form)sender;
oForm.FormClosed -= FormClosed;
m_cOpenForms.Remove(GetFormKey(oForm);
}
private static string GetFormKey(Form oForm)
{
return oForm.Name;
}
}
And you can use it as follows:
Form oForm = WindowManager.GetOpenForm("Form1");
if (oForm != null)
{
oForm.Focus();
oForm.BringToFront();
}
else
{
oForm = new Form1();
WindowManager.RegisterForm(oForm);
// Open the form, etc
}
I have a windows form application. On the main form a user will enter a number of item, etc and then click a button which will open a new form (either a small form or a large form depending on a checkbox). Now on my main application I have a file menu - under which is settings - change background colour. This opens the colordialog. If a user does not pick anything the background colours will stay default. However if they change it on the main entry form i change the background of a few textboxes - code below.
private void warning1ToolStripMenuItem_Click(object sender, EventArgs e)
{
colorDialog1.ShowDialog();
Warn1Color = colorDialog1.Color.ToString();
if (Warn1Color != null)
{
tbWarn1Hrs.BackColor = colorDialog1.Color;
tbWarn1Mins.BackColor = colorDialog1.Color;
tbWarn1Secs.BackColor = colorDialog1.Color;
tbWarn1Msg.BackColor = colorDialog1.Color;
}
}
Now my problem is how to I get this to then change the background in the other form that opens. I was hoping I could pass the string across in the new form constructor as i do with a number of other values.
i.e - here is my code in the new form....(note - string Warn1Color was passed across in constructor and then made = to the string _Warn1Color. If it is null then background will be default yellow but it cant convert type string to system.drawing.color. Does anyone see an easy solution to this or what I could do to get this working easily.
if (_Warn1Color == null)
{
this.BackColor = System.Drawing.Color.Yellow;
}
else
this.BackColor = _Warn1Color;
Pass the Color on via the Constructor not a string. If this is not possibly for whatever reason, you could create a ColorConfigClass that holds the required Color and you can set it when used.
You should create a static class to store your configuration data such as this colour style. You can then set this value once you have prompted the user for the change and you can also call the Color value from any other form when you need to use it.
Your static class should look something like this...
public static class StyleSettings{
private static Color _warn1Color = Color.FromArgb(255, 0, 0);//default colour
public static Color Warn1Color {
get { return _warn1Color; }
set { _warn1Color = value; }
}
}
Then you can use this in your example method like...
private void warning1ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
{
StyleSettings.Warn1Color = colorDialog1.Color;
tbWarn1Hrs.BackColor = StyleSettings.Warn1Color;
tbWarn1Mins.BackColor = StyleSettings.Warn1Color;
tbWarn1Secs.BackColor = StyleSettings.Warn1Color;
tbWarn1Msg.BackColor = StyleSettings.Warn1Color;
}
}
I assume you used a string because you wanted to be able to pass null, and System.Drawing.Color being a struct can not be null.
In which case either use Nullable ( http://msdn.microsoft.com/en-us/library/b3h38hb0%28v=vs.80%29.aspx ) which can be null or you can consider some other value as "default", say alpha=0.
To pass a value in your constructor simply go to the code file for the form (the one where you code the stuff for the events) and find the constructor function (has the same name as the form) e.g.:
namespace MyApp
{
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
}
...
And add the parameters to it:
namespace MyApp
{
public partial class MyForm : Form
{
public MyForm(System.drawing.color background)
{
InitializeComponent();
...do whatever you want with background...
}
...
Of course you also need to edit the places you create this form, e.g. change
form = new MyForm();
form.Show();
to
form = new MyForm(backgroundColour);
form.Show();