Passing string between two forms - c#

I have a problem in passing a string value between two forms.
First I created public string sanacode which I assign the value passed in form 2
Form 1 code
AnalysisEdit ae = new AnalysisEdit();
int Row = dataGridView1.CurrentRow.Index;
ae.sanacode = dataGridView1[0, Row].Value.ToString();
ae.Show();
Form 2 constructor code
public AnalysisEdit()
{
InitializeComponent();
MessageBox.Show(sanacode,);
}
it shows me nothing

Change you constructor from
public AnalysisEdit()
{
InitializeComponent();
MessageBox.Show(sanacode);
}
to
public AnalysisEdit(string sanacode)
{
InitializeComponent();
MessageBox.Show(sanacode);
}
form call
int Row = dataGridView1.CurrentRow.Index;
AnalysisEdit ae = new AnalysisEdit(dataGridView1[0, Row].Value.ToString());
ae.Show();

The issue is that you're not calling things in the correct order. The form 2 constructor code will be called on line 1 of the form code, or AnalysisEdit ae = new AnalysisEdit(); However, this is before the assignment that takes place on line 3: ae.sanacode = dataGridView1[0, Row].Value.ToString(); So when you show the messagebox in the form 2 constructor, sanacode has not yet been assigned to.
There are two ways to fix this. Firstly, you can pass the value in via the constructor as per #kostas ch.'s answer, or you can override the form's OnShown event in form 2:
protected override void OnShown(EventArgs e)
{
MessageBox.Show(sanacode);
}

I wouldn't put your code
MessageBox.Show(sanacode,);
in the constructor. I would use the "Load"-Event.
If you use the "Load"-Event your MessageBox will Show, when you use
ae.Show();
Like this
private void AnalysisEdit_Load(object sender, EventArgs e)
{
MessageBox.Show(sanacode);
}

Perhaps you'd like some ideas for the various ways to pass data between forms. I have written two blog posts on the subject:
http://geek-goddess-bonnie.blogspot.com/2011/01/passing-data-between-forms.html
http://geek-goddess-bonnie.blogspot.com/2012/12/passing-data-between-forms-redux_31.html

You could temporarily add MessageBox.Show() to your setter:
// In Form2
public sanacode
{
set
{
_sanacode = value;
MessageBox.Show(_sanacode);
}
get
{
return _sanacode;
}
}

Related

C# Get variable from popup form that will be closed

I have a form populated with an array of userControls that is created from the main form. I need to be able to access this array of userControls from the main form once the popup has been closed when a button is pressed. If I fill out the forms and then press the button on the main form without closing the popup, the values are present. However, if I close the popup window, the values are not present. My main form is static so I can use it's variables in other forms.
Code for the popup:
public ScanChannel[] controls;
public ScanListSetup()
{
InitializeComponent();
int numChans = Convert.ToInt32(Form1.Self.numChannels.Text);
controls = new ScanChannel[numChans];
// Create the UserControls
for(int i = 0; i < numChans; i++)
{
controls[i] = new ScanChannel();
}
// Place them
for (int i = 0; i < numChans; i++)
{
controls[i].Location = new Point(13,(35+25*(i)));
this.Controls.Add(controls[i]);
}
doneButton.Location = new Point(82, 35 + (25 * (numChans + 1)));
this.Size =new Size(280, 110 + (25 * (numChans + 1)));
}
private void doneButton_Click(object sender, EventArgs e)
{
Form1.Self.setChannelsToScan(controls);
}
I need to access the controls array in the main form. The code for the main form is as follows:
private ScanChannel[] channelsToScan;
private void configureScanListButton_Click(object sender, EventArgs e)
{
var form = new ScanListSetup();
form.Show(this);
scanListConfigured = true;
this.channelsToScan = new ScanChannel[Convert.ToInt32(numChannels.Text)];
}
public void setChannelsToScan(ScanChannel[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
this.channelsToScan[i] = arr[i];
}
}
private void scanButton_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Test: " + this.channelsToScan[0].getDeviceType());
// THIS PRINTS AN EMPTY STRING
}
So, the Debug writeLine outputs the correct value if I click the scanButton while the popup form is still open. However, if I close the form after clicking the doneButton on the popup form, the Debug writeLine outputs Test: with nothing else.
Any help with this would be greatly appreciated. Thanks.
Your problem essentially boils down to sending data from a secondary window (your 'pop-up' window) to the main window from where it was created. It doesn't matter whether you're working with Windows Control objects or simple data types like string, so I'm going to use a simple example to illustrate how to handle such a situation.
Let's assume you have a Main form that looks like this. It has an OPEN button and a TextBox.
When you click OPEN, it opens up this secondary input window (your pop-up) which looks like this:
Now the idea is this. You click OPEN and opens the Input form, and lets the user enter some text into the TextBox there. Once you click the OK button, it should close the Input window, and display the text entered by the user in the Main window. Remember that at this point the Input window is closed, which is equivalent to your situation.
So I'd make use of Delegates to accomplish this goal. A delegate lets you transfer data between windows which is what you want.
In my Main I'd declare a public delegate with a signature like this:
public delegate void DataTransfer(string data);
That is, this delegate represents a method that takes in a single string parameter, and has void return type. The idea is to let the secondary Input window 'call' a method in the Main, and that method takes in a string parameter. So, if there was a way for us to call a method that resides in the Main from Input, and pass a string, we can then take the user input text in the Input window, and pass it to the Main window. With me so far?
Now, if I write a method like this in the Main, and let it be called from Input, that should accomplish our goal. Here, txtDisplay is the TextBox in the Main form.
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
To accomplish this, I would define a delegate of type DataTransfer in the Main form like below, and register the ReceiveInput() method to it. Your Main form code behind should look like this:
public delegate void DataTransfer(string data);
public partial class MainForm : Form
{
public DataTransfer transferDelegate;
InputForm inputForm = null;
public MainForm()
{
InitializeComponent();
transferDelegate += new DataTransfer(ReceiveInput);
}
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
private void BtnOpen_Click(object sender, EventArgs e)
{
inputForm = new InputForm(transferDelegate);
inputForm.Show();
}
}
BtnOpen is the OPEN button in the Main form, and when it's clicked, it passes the delegate to the Input form, then opens it. So, accordingly, we need to now modify our Input form:
public partial class InputForm : Form
{
DataTransfer transferDel;
public InputForm(DataTransfer del)
{
InitializeComponent();
transferDel = del;
}
private void BtnOK_Click(object sender, EventArgs e)
{
string data = txtInput.Text;
transferDel.Invoke(data);
Close();
}
}
Here, we modify the constructor so that it takes in a delegate of type DataTransfer, and sets it to the local instance of the same type. Then, at the click of BtnOK on the Input form, we take in the text input by user, and pass that text to the said delegate and invoke it. 'Invoking' is the same as calling the method in the Main form. At this point, you can Clsoe() the Input window as shown above, and you'd still have access to the user input string data from your Main form.
You can use this same approach, and instead of strings you can pass around Controls. However, it's not the best approach to pass around a bunch of controls back and forth, so ideally you would extract the data you need from those controls in your pop-up, and pass only the said data instead of the whole controls.
EDIT: After OP posted the erroneous code.
OK, so here's your issue. The testUserControl class is not a regular class but a control element derived from UserControl. In otherwise, a GUI element. You shouldn't use GUI elements to pass data around. Because, when you do your controlArr[i].getText();, it tries to get the text from the textItem, but textItem is a TextBox Control which doesn't exist at this point because you closed your window. Remember, you do the delegate.Invoke() only once, and at that point *you must send ALL the data back to your main window*.
What you should do is, simply define a class to hold ALL the data you want to pass to your main. For example something like this:
public class DataToPass
{
public string TextBoxText { get; set; }
public string SomeOtherData { get; set; }
// Other stuff you want...
}
Now, instead of passing an array of testUserControl, pass an array of DataToPass. That way, at the Main form you don't have to do the following:
controlArr[i].getText();
Instead you'd simply do something like:
controlArr[i].TextBoxText;
where controlArr now is an array of type DataToPass.
Simply, passing a control derived from UserControl is not a good idea. Just create one class that is capable of holding ALL the data you want to pass and pass it back to the main once.

changing textlabel in form1 using different class

having a bit of a problem changing the label text when a button is pressed. my code looks like this. i searched a bit in this forum and tried this solution in form1 i have this code.
public string info
{
get
{
return label11.Text;
}
set
{
label11.Text = value;
}
}
in class search i have this
public void fighting()
{
character tom = new character();
Form1 f = new Form1();
Random explore = new Random();
int exploration = explore.Next(0, 3);
if (character.location == "Forest" || character.location == "Dungeon")
{
switch (exploration)
{
case 0:
f.info = "You didnt find anything";
f.Refresh();
f.herodamage = exploration.ToString();
break;
...
the button has this
public void button8_Click(object sender, EventArgs e)
{
Search find = new Search();
find.fighting();
}
what am i doing wrong? everytime i press the button the text wont change but it works because it does change a buttons text.
Fighting method is creating a new instance of Form1, different from your UI.
While it is updating label1.Text, it refers to different Form1.
My suggestion is for refactoring of your code to make responsibilities more clear.
Something like
var info = find.fighting(); // Where fighting returns string, instead of creating new Form1 and setting value, just return the value.
this.info = info;
If you still insist to update UI from search method, which is not correct way to approach this problem, you can pass around Form1 from the parameter.
Search find = new Search(this); // Store it as instance of Search class.
find.fighting(); // fighting should never create new instance of Form1 (reason of problem you are facing)
Instead of creating a new instance of Form1 you need to get a reference to the already existing instance of this form.
One simple way to do this is to use the Application.OpenForms property:
character tom = new character();
Form1 f = Application.OpenForms.OfType<Form1>().FirstOrDefault();
Random explore = new Random();
...

C# Take combobox item from one form and add its name as text to another

Ok so I'm attempting to create a simple game. In a nutshell it's a resource management game where the player will attempt to manage a thieves guild. In regards to running missions I've created a Thief class, a new instance of which is created when a new thief is recruited. I have coded within the thief class the ability to gain experience and level up.
Here's my specific problem:
I want the player to be able to select which thief/thieves to send on a mission. I have thought about it and figured that opening a new form and populating it with checkboxes is the easiest way to allow this. These checkboxes will be related to a List<thief> of thieves, the player then checks the thieves s/he wants to send and these are then stored in another List<thief> and passed on to the run mission function.
I've built a separate project with the intention of testing and playing around with this before putting it into the main program. The test project consists of two forms: The first (frmMain) with a textbox to hold the selected options and a button to open the second form (frmSelect). Currently I can open and populate the second form (frmSelect) but when I try to add the checked options to the textbox I simply...well can't.
So far I have tried directly accessing the textbox by typing frmMain.txtOptionsDisplay in the cs file of frmSelect but it causes the following error:
An object reference is required for the non-static field, method or
property
I tried to create a new form in frmSelect and make it equal to the active instance of frmMain with: Form frmTemp = frmMain.ActiveForm; and then alter the textbox using frmTemp as a go-between but that produced the error:
'System.Windows.Forms.Form' does not contain a definition for
'txtOptionsDisplay'.
Having searched both google and stackoverflow forums I've encountered answers that I either have never heard of (Threading) or answers that I kind've recognise but can't interpret the code pasted to make it relevant to my problem (delegates).
Any advice or pointers would be fantastic.
EDIT:
frmMain code:
public frmMain()
{
InitializeComponent();
selections.Add("Option 1");
selections.Add("Option 2");
}
private void btnClick_Click(object sender, EventArgs e)
{
frmSelectOptions.Show();
int length = selections.Count();
for (int i = 0; i < length; i++)
{
CheckBox box = new CheckBox();
box.Text = selections[i];
box.AutoSize = true;
box.Location = new Point(50, 50*(i+1));
frmSelectOptions.grpControls.Controls.Add(box);
}
}
public void updateText(string option)
{
txtOptionsDisplay.Text += option;
}
}
frmSelect code:
public List<CheckBox> selectedOptions = new List<CheckBox>();
Form frmTemp = frmMain.ActiveForm;
public frmSelect()
{
InitializeComponent();
}
private void btnSelect_Click(object sender, EventArgs e)
{
foreach (CheckBox box in grpControls.Controls)
{
if (box.Checked == true)
selectedOptions.Add(box);
}
this.Hide();
}
}
I hope this formats correctly... I'm kinda new and don't know how to indent. Oh look there's a preview...
Does this help?
Your problem is that controls defined within a form by default receive the private access identifier. Hence you could just add a property along the lines of
public ControlType ProxyProperty {
get {
return txtOptionsDisplay;
}
}
Besides from that you should think about wether what you're trying is actually a good solution. Manipulating forms from one to another will become a huge clusterfuck in terms of maintenance later on.
I'd suggest using the Singleton pattern for your frmMain. This will help safeguard you from accidentally launching another instance of frmMain and at the same time, will give you access to frmMain's objects. From there, you can either write accessors to Get your txtOptionsDisplay or you can make it public. Below is an example:
public class frmMain
{
private static frmMain Instance = null;
private static object LockObj = new object();
public static frmMain GetMain()
{
// Thread-safe singleton
lock(LockObj)
{
if(Instance == null)
Instance = new frmMain();
return Instance;
}
}
public string GetOptionsDisplayText()
{
return txtOptionsDisplay.Text;
}
}
public class frmSelect
{
private void frmSelect_Load(object sender, EventArgs e)
{
// Set whatever text you want to frmMain's txtOptionsDisplay text
txtDisplay.Text = frmMain.GetMain().GetOptionsDisplayText();
}
}
If you do go this route, don't forget to update Program.cs to use frmMain's singleton.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new frmMain()); - Old method
Application.Run(frmMain.GetMain());
}

Get data from user control since Webpage

I have a simple question in asp.net.
I want to know if it is possible to get data from controls in my user control directly . I want to do it without using Session variable,Viewstate ...
EDIT: I now use the method of declaring public variables in the UC.
Here is a part of Page_load from my parent page:
this.plan_action = (UCPlan)Page.LoadControl("~/Association/UCPlan.ascx");
PlaceHolder1.Controls.Add(this.plan_action);
if (this.plan_action.Validate == true)
{
CheckBox1.Checked = true;
//String référence = Session["liste_action"].ToString();
for (int i = 0; i < this.plan_action.List1.Count; i++)
{
Label8.Text += this.plan_action.List1[i].Référence + "/";
//Label8.Text += "/";
}
}
but my variable validate stay to false.
Here is the code where I change the value of the validate variable with it declaration:
private bool validate;
public bool Validate
{
get { return validate; }
set { validate = value; }
}
protected void Button2_Click(object sender, EventArgs e)
{
//myCommand.Connection = myConnection;
//Session["liste_action"] = this.List;
this.Validate = true;
//Response.Redirect("../Risques_folder/AjouterRisque.aspx");
}
Thank you for your help,
Quentin
UPDATE due to new information
You need to learn about the sequence of events in ASP.NET.
The Load of the page happens a long time before the Click handler of Button2 in your UserControl... so the Validate property is always going to be set to false.
You have two obvious options (as I see it)...
Keep the creation of the UserControl in your Page_Load (or preferably, move it to your Page_Init, as this is normally the most appropriate place for it). Then place your check for the Validate property in a Page_PreRender.
Or, create an Event in your UserControl, Raise that event on the click of Button2, and handle the event in the Page.
ANOTHER UPDATE
For the 2nd of the two options above, in your UserControl class have the following...
public delegate void ButtonClickedDelegate(object sender, EventArgs e);
public event ButtonClickedDelegate ButtonClicked;
In the Button2_Click method of the UserControl (after setting the this.Validate = true;) call...
ButtonClickedDelegate(sender, e);
In the Page_Init of the Page, put something like...
ctrl1.ButtonClicked += new UCPlan.ButtonClickedDelegate(ctrl1_ButtonClicked);
And then have a new method called something like
void ctrl1_ButtonClicked(object sender, EventArgs e)
{
if (ctrl1.Validate)
{
...
}
}
Remember, as you control the delegate you can pass whatever information you want, including an entire class. So instead of calling the Validate property, create a new instance of the class you want, and pass that as a delegate parameter.
You can find more information on delegates and events on MSDN.
ORIGINAL ANSWER
Unless I've missed something, this is a very simple ASP.NET concept...
You can create properties and/or methods.
For example, as a property...
public string MyProperty
{
get { return "My Property Value"; }
}
Or as a method
public string MyMethod()
{
return "My Method Value";
}
If you're talking about passing the values between the UserControl and the ASP.NET Page that contains it, then in your Page, you can simply call the property or method. If your control was called (for example) myCtrl, then you can something like...
string prop = myCtrl.MyProperty;
string meth = myCtrl.MyMethod();
(On the back of the great comment from AHMED EL-HAROUNY)
If you're talking about passing the values to the client side page, then you can use the same properties / methods directly in the HTML markup. However, in this case, the properties / method can be declared as protected rather than public
For instance, to display the value...
<%=MyProperty%>
Or
<%=MyMethod()%>
Or if you're going to use the value in javascript, something like...
var myProp = "<%=MyProperty%>";
Yes That is possible, But exposing the controls in the UserControl as Public.

passing values between forms (winforms)

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

Categories