User input in subform - c#

I am trying to get values back from a form.
I have been trying this: How to return a value from a Form in C#?
It does not work for me, maybe I'm doing something wrong but at the second part.
using (var form = new frmImportContact())
{
var result = form.ShowDialog();
if (result == DialogResult.OK)
{
string val = form.ReturnValue1; //ReturnValue1 is not an option...
string dateString = form.ReturnValue2;
//Do something here with these values
//for example
this.txtSomething.Text = val;
}
}
I am unable to get "ReturnValue1" to show up. It is declared public, what else do I need to do?
Here is what I have written. My sub-form:
namespace ASPE.GUI.SensorWizard
{
public partial class PortsSensitivity : Form
{
public int ReturnValue1 { get; set; }
public PortsSensitivity()
{
InitializeComponent();
}
private void PortsBox_ValueChanged(object sender, EventArgs e, KeyPressEventArgs m)
{
this.ReturnValue1 = Convert.ToInt16(PortsBox.Value);
}
private void PortsSensitivity_Load(object sender, EventArgs e)
{
}
}
}
And my main form:
//Show Form (Number of Ports, Sensitivity)
Form Part3 = new ASPE.GUI.SensorWizard.PortsSensitivity();
DialogResult dr3 = new DialogResult();
dr3 = Part3.ShowDialog();
//Write Variables
int numofports = Part3.ReturnValue1; //Not an option.
//Close Form

Your Part3 variable is defined as type Form which does not declare the ReturnValue1 property. (the ReturnValue1 property is declared on your PortSensitivity class).
Change
Form Part3 = new ASPE.GUI.SensorWizard.PortsSensitivity();
to
PortSensitivity Part3 = new ASPE.GUI.SensorWizard.PortsSensitivity();
Your first example is also instantiating something of type frmImportContact in the using statement but you have not shown the implementation of this. Check you have declared the property on this type (or that you aren't meant to be creating an instance of the PortSensitivity type).

Related

All values become the same when assigning value to array

Have in mind that this problem probably is the consequence of a beginners-mistake.
There are there 4 classes in my program relevant for this problem.
Main form: Declares and initiates the object currentRecipe (uses class recipe) and recipeMngr (uses class recipeManager) directly in the class.
currentRecipe(Recipe) have a couple of fields that is collected from user input, the fields include the array ingredients[] that is collected from a property in another form that opens when a button is pressed. currentRecipe is used later when "add recipe button" is pressed and because it is used in both these methods the object currentRecipe needs to be initialized outside these methods as i understand it.
RecipeManager: Hold an array that stores the recipes. And method that that manages the adding of the recipe into the array. this method takes currentRecipe as a property from the main form.
Recipe: Holds the template for Recipe.
FormIngredients: collect ingredients from user and stores them in property.
However, the problem. When storing an recipe in the array in recipeManager the latest stored array just copies so all earlier assigned items in the list gets the new value. As an result
recipe[0] = Waffles
recipe[1] =
...
when adding a new it becomes
recipe[0] = pie
recipe[1] = pie
...
When it should become
recipe[0] = Waffles
recipe[1] = pie
...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeGUI();
}
private const int maxRecipe = 20;
private const int maxIngredients = 50;
private static Recipe currentRecipe = new Recipe(maxIngredients);
private static RecipeManager recipeMngr = new RecipeManager(maxRecipe);
private void btnAddIngredients_Click(object sender, EventArgs e)
{
FormIngredients FormI = new FormIngredients(currentRecipe);
var result = FormI.ShowDialog();//show ingredient form
if (result == DialogResult.OK) {
currentRecipe = FormI.recipe;
lblIngredAmount.Text = "Ingredients: " + currentRecipe.ingredientsAmounts().ToString();
}
}
private void AddRecipe(Recipe scurrentRecipe) {
scurrentRecipe.rName = tbxName.Text;
scurrentRecipe.rDescription = tbxDescription.Text;
scurrentRecipe.rCategory = (FoodCategories)cbxCategory.SelectedIndex;
bool valid = checkIfValid();
if (valid)
{
recipeMngr.Add(scurrentRecipe);
updateGUI();
SimpleInitializeGUI();
}
else
{
MessageBox.Show("Please fill all the fields (or add atleast one ingredient)", "Stop");
}
}
I've added the most important parts from main form, where is know the problem is from.
I want to add that the problem disappears when moving the initialization of currentRecipe into the "addRecipe click"-method. But this creates alot of new problems and the code is supposed to be structured like this.
I do not use any loop to fill the array.
Explanation:
Classes are reference types. If you go through the original code you've posted, the currentRecipe is instantiated only once. Everytime you are changing the value of scurrentRecipe / currentRecipe variables, you are just changing that object only. If you need multiple objects, you've to create them by multiple times by using the new keyword.
Updated code to make it clear for you:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeGUI();
}
private const int maxRecipe = 20;
private const int maxIngredients = 50;
private static Recipe currentRecipe = new Recipe(maxIngredients);
private static RecipeManager recipeMngr = new RecipeManager(maxRecipe);
private void btnAddIngredients_Click(object sender, EventArgs e)
{
FormIngredients FormI = new FormIngredients(currentRecipe);
var result = FormI.ShowDialog();//show ingredient form
if (result == DialogResult.OK) {
currentRecipe = FormI.recipe;
lblIngredAmount.Text = "Ingredients: " + currentRecipe.ingredientsAmounts().ToString();
}
}
private void AddRecipe() {
scurrentRecipe = new Recipe(maxIngredients);
scurrentRecipe.rName = tbxName.Text;
scurrentRecipe.rDescription = tbxDescription.Text;
scurrentRecipe.rCategory = (FoodCategories)cbxCategory.SelectedIndex;
bool valid = checkIfValid();
if (valid)
{
recipeMngr.Add(scurrentRecipe);
updateGUI();
SimpleInitializeGUI();
currentRecipe = scurrentRecipe();
}
else
{
MessageBox.Show("Please fill all the fields (or add atleast one ingredient)", "Stop");
}
}

How do I retrieve a custom list from another form in a using block? [duplicate]

I have a main form (let's call it frmHireQuote) that is a child of a main MDI form (frmMainMDI), that shows another form (frmImportContact) via ShowDialog() when a button is clicked.
When the user clicks the 'OK' on frmImportContact, I want to pass a few string variables back to some text boxes on frmHireQuote.
Note that there could be multiple instances of frmHireQuote, it's obviously important that I get back to the instance that called this instance of frmImportContact.
What's the best method of doing this?
Create some public Properties on your sub-form like so
public string ReturnValue1 {get;set;}
public string ReturnValue2 {get;set;}
then set this inside your sub-form ok button click handler
private void btnOk_Click(object sender,EventArgs e)
{
this.ReturnValue1 = "Something";
this.ReturnValue2 = DateTime.Now.ToString(); //example
this.DialogResult = DialogResult.OK;
this.Close();
}
Then in your frmHireQuote form, when you open the sub-form
using (var form = new frmImportContact())
{
var result = form.ShowDialog();
if (result == DialogResult.OK)
{
string val = form.ReturnValue1; //values preserved after close
string dateString = form.ReturnValue2;
//Do something here with these values
//for example
this.txtSomething.Text = val;
}
}
Additionaly if you wish to cancel out of the sub-form you can just add a button to the form and set its DialogResult to Cancel and you can also set the CancelButton property of the form to said button - this will enable the escape key to cancel out of the form.
I normally create a static method on form/dialog, that I can call. This returns the success (OK-button) or failure, along with the values that needs to be filled in.
public class ResultFromFrmMain {
public DialogResult Result { get; set; }
public string Field1 { get; set; }
}
And on the form:
public static ResultFromFrmMain Execute() {
using (var f = new frmMain()) {
var result = new ResultFromFrmMain();
result.Result = f.ShowDialog();
if (result.Result == DialogResult.OK) {
// fill other values
}
return result;
}
}
To call your form;
public void MyEventToCallForm() {
var result = frmMain.Execute();
if (result.Result == DialogResult.OK) {
myTextBox.Text = result.Field1; // or something like that
}
}
Found another small problem with this code... or at least it was problematic when I tried to implement it.
The buttons in frmMain do not return a compatible value, using VS2010 I added the following and everything started working fine.
public static ResultFromFrmMain Execute() {
using (var f = new frmMain()) {
f.buttonOK.DialogResult = DialogResult.OK;
f.buttonCancel.DialogResult = DialogResult.Cancel;
var result = new ResultFromFrmMain();
result.Result = f.ShowDialog();
if (result.Result == DialogResult.OK) {
// fill other values
}
return result;
}
}
After adding the two button values, the dialog worked great!
Thanks for the example, it really helped.
delegates are the best option for sending data from one form to another.
public partial class frmImportContact : Form
{
public delegate void callback_data(string someData);
public event callback_data getData_CallBack;
private void button_Click(object sender, EventArgs e)
{
string myData = "Top Secret Data To Share";
getData_CallBack(myData);
}
}
public partial class frmHireQuote : Form
{
private void Button_Click(object sender, EventArgs e)
{
frmImportContact obj = new frmImportContact();
obj.getData_CallBack += getData;
}
private void getData(string someData)
{
MessageBox.Show("someData");
}
}
I just put into constructor something by reference, so the subform can change its value and main form can get new or modified object from subform.
If you want to pass data to form2 from form1 without passing like new form(sting "data");
Do like that
in form 1
using (Form2 form2= new Form2())
{
form2.ReturnValue1 = "lalala";
form2.ShowDialog();
}
in form 2 add
public string ReturnValue1 { get; set; }
private void form2_Load(object sender, EventArgs e)
{
MessageBox.Show(ReturnValue1);
}
Also you can use value in form1 like this if you want to swap something in form1
just in form1
textbox.Text =form2.ReturnValue1
I use MDI quite a lot, I like it much more (where it can be used) than multiple floating forms.
But to get the best from it you need to get to grips with your own events. It makes life so much easier for you.
A skeletal example.
Have your own interupt types,
//Clock, Stock and Accoubts represent the actual forms in
//the MDI application. When I have multiple copies of a form
//I also give them an ID, at the time they are created, then
//include that ID in the Args class.
public enum InteruptSource
{
IS_CLOCK = 0, IS_STOCKS, IS_ACCOUNTS
}
//This particular event type is time based,
//but you can add others to it, such as document
//based.
public enum EVInterupts
{
CI_NEWDAY = 0, CI_NEWMONTH, CI_NEWYEAR, CI_PAYDAY, CI_STOCKPAYOUT,
CI_STOCKIN, DO_NEWEMAIL, DO_SAVETOARCHIVE
}
Then your own Args type
public class ControlArgs
{
//MDI form source
public InteruptSource source { get; set; }
//Interrupt type
public EVInterupts clockInt { get; set; }
//in this case only a date is needed
//but normally I include optional data (as if a C UNION type)
//the form that responds to the event decides if
//the data is for it.
public DateTime date { get; set; }
//CI_STOCKIN
public StockClass inStock { get; set; }
}
Then use the delegate within your namespace, but outside of a class
namespace MyApplication
{
public delegate void StoreHandler(object sender, ControlArgs e);
public partial class Form1 : Form
{
//your main form
}
Now either manually or using the GUI, have the MDIparent respond to the events of the child forms.
But with your owr Args, you can reduce this to a single function. and you can have provision to interupt the interupts, good for debugging, but can be usefull in other ways too.
Just have al of your mdiparent event codes point to the one function,
calendar.Friday += new StoreHandler(MyEvents);
calendar.Saturday += new StoreHandler(MyEvents);
calendar.Sunday += new StoreHandler(MyEvents);
calendar.PayDay += new StoreHandler(MyEvents);
calendar.NewYear += new StoreHandler(MyEvents);
A simple switch mechanism is usually enough to pass events on to appropriate forms.
First you have to define attribute in form2(child) you will update this attribute in form2 and also from form1(parent) :
public string Response { get; set; }
private void OkButton_Click(object sender, EventArgs e)
{
Response = "ok";
}
private void CancelButton_Click(object sender, EventArgs e)
{
Response = "Cancel";
}
Calling of form2(child) from form1(parent):
using (Form2 formObject= new Form2() )
{
formObject.ShowDialog();
string result = formObject.Response;
//to update response of form2 after saving in result
formObject.Response="";
// do what ever with result...
MessageBox.Show("Response from form2: "+result);
}
I raise an event in the the form setting the value and subscribe to that event in the form(s) that need to deal with the value change.

Passing value between form and class winforms

I'm traying to pass a value from a form to a class to determinate the level in which the game will be, but it keeps passing with 0 value.
I need to pass "nivelElegido" with the values 1 or 2
int nivelElegido;
private void pictureBox1_Click(object sender, EventArgs e)
{
nivelElegido = 1;
Form1 frm = new Form1();
frm.Show();
this.Hide();
}
private void pictureBox2_Click(object sender, EventArgs e)
{
nivelElegido = 2;
Form1 frm = new Form1();
frm.Show();
}
public int niveEle
{
get { return nivelElegido; }
}
I change the value and in the other form try to use it.
using (var nivelarmando = new NivelArmando())
{
niveleleg = nivelarmando.niveEle;
}
pala.nivo = niveleleg;
pala.Traelo();
pala.traelo brings data from a class and pala.nivo is the level.
public void Traelo()
{
if (nivo==1)
{
}
else if (nivo==2)
{
}
But nivo comes with a 0 instead of 1 or 2. How can I do?
It looks like the top code is from the NivelArmando class. If so, this code
using (var nivelarmando = new NivelArmando())
{
niveleleg = nivelarmando.niveEle;
}
is creating a new instance of NivelArmando, and in that case, nivelElegido will be initialized to 0. niveleleg will then be set to zero and not see the value that you modified elsewhere.
You should create a property on Form1 or pass the value of nivelElegido to the constructor of Form1 and then use that value in Traelo() function.
Get and set the variable with variables.nivelElegido = 1
Read with variables.nivelElegido
Public Class variables
Public Shared Property nivelElegido() As Integer
Get
Return m_nivelElegido
End Get
Set(value As Integer)
m_nivelElegido = value
End Set
End Property
Private Shared m_nivelElegido As Integer
End Class

Why is my pseudo dialog form hiding its "charms" and ignoring its own properties?

I've created a pseudo dialog (form with FormBorderStyle property set to FixedDialog) that contains a label, a DatetimePicker, and an OK button. The OK button's DialogResult property is "OK"
Adapted from this post: How to return a value from a Form in C#?, I'm trying to create a way to prompt the user to select a date when my app can't suss out the date by the filename (sometimes it can, sometimes it can't, depending on whether the filename is "well formed."
The code is below.
The problem is that the form does not display its controls when it is invoked; AND, it does not display in the center of the screen, although its StartPosition = CenterScreen...???
public partial class ReturnDate : Form {
public DateTime ReturnVal { get; set; }
private String _lblCaption;
public ReturnDate() {
InitializeComponent();
}
public ReturnDate(String lblCaption) {
_lblCaption = lblCaption; // "Object not set to an instance of an object" if I try to set the Label here directly
}
private void buttonOK_Click(object sender, EventArgs e)
{
this.ReturnVal = dateTimePicker1.Value.Date;
this.Close();
}
private void ReturnDate_Shown(object sender, EventArgs e) {
labelCaption.Text = _lblCaption;
}
}
...and I conditionally invoke it like so:
public static DateTime getDateTimeFromFileName(String SelectedFileName) {
// Expecting selected files to be valid pilsner files, which are expected
// to be of the format "duckbilledPlatypus.YYYY-MM-DD.pil" such as:
// "duckbilledPlatypus.2011-06-11.pil"
const int DATE_BEGIN_POS = 19;
const int DATE_LENGTH = 10;
String substr = string.Empty;
if (SelectedFileName.Length >= DATE_BEGIN_POS + DATE_LENGTH) {
substr = SelectedFileName.Substring(DATE_BEGIN_POS, DATE_LENGTH);
}
DateTime dt = DateTime.Now;
if (!(DateTime.TryParse(substr, out dt))) {
using (var dtpDlgForm = new ReturnDate("Please select the Date that the file was created:")) {
DialogResult dr = dtpDlgForm.ShowDialog();
if (dr == DialogResult.OK) {
dt = dtpDlgForm.ReturnVal;
}
}
}
return dt;
}
If you add a new constructor overload to a Form (or any derived Control), you need to make sure that the designer-generated code in InitializeComponent() gets called.
Make your new constructor call the default constructor first via : this():
public ReturnDate(String lblCaption) : this()
{
_lblCaption = lblCaption;
}

How to return a value from a Form in C#?

I have a main form (let's call it frmHireQuote) that is a child of a main MDI form (frmMainMDI), that shows another form (frmImportContact) via ShowDialog() when a button is clicked.
When the user clicks the 'OK' on frmImportContact, I want to pass a few string variables back to some text boxes on frmHireQuote.
Note that there could be multiple instances of frmHireQuote, it's obviously important that I get back to the instance that called this instance of frmImportContact.
What's the best method of doing this?
Create some public Properties on your sub-form like so
public string ReturnValue1 {get;set;}
public string ReturnValue2 {get;set;}
then set this inside your sub-form ok button click handler
private void btnOk_Click(object sender,EventArgs e)
{
this.ReturnValue1 = "Something";
this.ReturnValue2 = DateTime.Now.ToString(); //example
this.DialogResult = DialogResult.OK;
this.Close();
}
Then in your frmHireQuote form, when you open the sub-form
using (var form = new frmImportContact())
{
var result = form.ShowDialog();
if (result == DialogResult.OK)
{
string val = form.ReturnValue1; //values preserved after close
string dateString = form.ReturnValue2;
//Do something here with these values
//for example
this.txtSomething.Text = val;
}
}
Additionaly if you wish to cancel out of the sub-form you can just add a button to the form and set its DialogResult to Cancel and you can also set the CancelButton property of the form to said button - this will enable the escape key to cancel out of the form.
I normally create a static method on form/dialog, that I can call. This returns the success (OK-button) or failure, along with the values that needs to be filled in.
public class ResultFromFrmMain {
public DialogResult Result { get; set; }
public string Field1 { get; set; }
}
And on the form:
public static ResultFromFrmMain Execute() {
using (var f = new frmMain()) {
var result = new ResultFromFrmMain();
result.Result = f.ShowDialog();
if (result.Result == DialogResult.OK) {
// fill other values
}
return result;
}
}
To call your form;
public void MyEventToCallForm() {
var result = frmMain.Execute();
if (result.Result == DialogResult.OK) {
myTextBox.Text = result.Field1; // or something like that
}
}
Found another small problem with this code... or at least it was problematic when I tried to implement it.
The buttons in frmMain do not return a compatible value, using VS2010 I added the following and everything started working fine.
public static ResultFromFrmMain Execute() {
using (var f = new frmMain()) {
f.buttonOK.DialogResult = DialogResult.OK;
f.buttonCancel.DialogResult = DialogResult.Cancel;
var result = new ResultFromFrmMain();
result.Result = f.ShowDialog();
if (result.Result == DialogResult.OK) {
// fill other values
}
return result;
}
}
After adding the two button values, the dialog worked great!
Thanks for the example, it really helped.
delegates are the best option for sending data from one form to another.
public partial class frmImportContact : Form
{
public delegate void callback_data(string someData);
public event callback_data getData_CallBack;
private void button_Click(object sender, EventArgs e)
{
string myData = "Top Secret Data To Share";
getData_CallBack(myData);
}
}
public partial class frmHireQuote : Form
{
private void Button_Click(object sender, EventArgs e)
{
frmImportContact obj = new frmImportContact();
obj.getData_CallBack += getData;
}
private void getData(string someData)
{
MessageBox.Show("someData");
}
}
I just put into constructor something by reference, so the subform can change its value and main form can get new or modified object from subform.
If you want to pass data to form2 from form1 without passing like new form(sting "data");
Do like that
in form 1
using (Form2 form2= new Form2())
{
form2.ReturnValue1 = "lalala";
form2.ShowDialog();
}
in form 2 add
public string ReturnValue1 { get; set; }
private void form2_Load(object sender, EventArgs e)
{
MessageBox.Show(ReturnValue1);
}
Also you can use value in form1 like this if you want to swap something in form1
just in form1
textbox.Text =form2.ReturnValue1
I use MDI quite a lot, I like it much more (where it can be used) than multiple floating forms.
But to get the best from it you need to get to grips with your own events. It makes life so much easier for you.
A skeletal example.
Have your own interupt types,
//Clock, Stock and Accoubts represent the actual forms in
//the MDI application. When I have multiple copies of a form
//I also give them an ID, at the time they are created, then
//include that ID in the Args class.
public enum InteruptSource
{
IS_CLOCK = 0, IS_STOCKS, IS_ACCOUNTS
}
//This particular event type is time based,
//but you can add others to it, such as document
//based.
public enum EVInterupts
{
CI_NEWDAY = 0, CI_NEWMONTH, CI_NEWYEAR, CI_PAYDAY, CI_STOCKPAYOUT,
CI_STOCKIN, DO_NEWEMAIL, DO_SAVETOARCHIVE
}
Then your own Args type
public class ControlArgs
{
//MDI form source
public InteruptSource source { get; set; }
//Interrupt type
public EVInterupts clockInt { get; set; }
//in this case only a date is needed
//but normally I include optional data (as if a C UNION type)
//the form that responds to the event decides if
//the data is for it.
public DateTime date { get; set; }
//CI_STOCKIN
public StockClass inStock { get; set; }
}
Then use the delegate within your namespace, but outside of a class
namespace MyApplication
{
public delegate void StoreHandler(object sender, ControlArgs e);
public partial class Form1 : Form
{
//your main form
}
Now either manually or using the GUI, have the MDIparent respond to the events of the child forms.
But with your owr Args, you can reduce this to a single function. and you can have provision to interupt the interupts, good for debugging, but can be usefull in other ways too.
Just have al of your mdiparent event codes point to the one function,
calendar.Friday += new StoreHandler(MyEvents);
calendar.Saturday += new StoreHandler(MyEvents);
calendar.Sunday += new StoreHandler(MyEvents);
calendar.PayDay += new StoreHandler(MyEvents);
calendar.NewYear += new StoreHandler(MyEvents);
A simple switch mechanism is usually enough to pass events on to appropriate forms.
First you have to define attribute in form2(child) you will update this attribute in form2 and also from form1(parent) :
public string Response { get; set; }
private void OkButton_Click(object sender, EventArgs e)
{
Response = "ok";
}
private void CancelButton_Click(object sender, EventArgs e)
{
Response = "Cancel";
}
Calling of form2(child) from form1(parent):
using (Form2 formObject= new Form2() )
{
formObject.ShowDialog();
string result = formObject.Response;
//to update response of form2 after saving in result
formObject.Response="";
// do what ever with result...
MessageBox.Show("Response from form2: "+result);
}
I raise an event in the the form setting the value and subscribe to that event in the form(s) that need to deal with the value change.

Categories

Resources