I know this might sound basic, but as a beginner, I've been confused about the following:
I have two forms, the first one is where all connections and calculations are made, and the second one is where I want to display all the results.
FORM 1, Where I call to open the second form.
private void button_Click1(object sender, EventArgs e)
{
Button selected = sender as Button;
openClientForm(new Form2());
}
private Form activeForm = null;
private void openClientForm( Form clientForm)
{
if (activeForm != null)
activeForm.Close();
activeForm = clientForm;
clientForm.TopLevel = false;
clientForm.FormBorderStyle = FormBorderStyle.None;
clientForm.Dock = DockStyle.Fill;
panelClientForm.Controls.Add(clientForm);
panelClientForm.Tag = clientForm;
clientForm.BringToFront();
clientForm.Show();
}
FORM 2)
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
//Form2_Load();
updateText(txtCmdConsole, Form1.cmdres);
}
private void updateText(TextBox text, string strdata)
{
text.AppendText(strdata);
}
}
I have 1 question.
When I open the second form, How can I run the Method updateText from form 1 and display the result in the second form?
The reason I ask is that form1 should still be running in the background, and if a certain condition is met, I want the update text to be run in form 1(to get values from there) and update the second form.
First, your activeForm should be of type Form2, not just Form, otherwise you cannot call specific methods from it (at least not easily). The code should look like this:
private Form2 activeForm = null;
private void openClientForm(Form2 clientForm)
{
if (activeForm != null)
activeForm.Close();
activeForm = clientForm;
//...
Form2 can then offer a public interface to update certain text from the outside, with methods which don't expect internal controls as parameters. Something along the lines of
// inside Form2
public void UpdateCmdText(string strdata)
{
updateText(txtCmdConsole, strdata);
}
Now you can call this method inside Form1 whereever you like:
activeForm.UpdateCmdText(someNewResult)
Hope this helps.
Related
I have been struggling with this for a week now and I don't see any other questions about it. I need to do something such as at Accessing Forms data from another form but I need to access a variable that is in the first form's code FROM the second form, and the click event happens during the second form.
Here is some of the first form's (mainForm's) code:
namespace Sudoku
{
public partial class mainForm : Form
{
public mainForm()
{
InitializeComponent();
}
difficultyForm difForm = new difficultyForm();
public string difficulty = "";
private void generateNewPuzzleMenuItem_Click(object sender, EventArgs e)
{
generateBegin();
}
private void generateBegin()
{
difForm.Show();
difForm.difficultyTextBox.Text = "";
difForm.difficultyTextBox.Focus();
And here is some of the second form's (difficultyForm's) code:
namespace Sudoku
{
public partial class difficultyForm : Form
{
string difficulty = "";
public difficultyForm()
{
InitializeComponent();
}
private void enterButton_Click(object sender, EventArgs e)
{
difficulty = difficultyTextBox.Text;
if (difficulty != "1" && difficulty != "2" && difficulty != "3" && difficulty != "4" && difficulty != "5")
MessageBox.Show("The difficulty must be an integer from 1 to 5.", "Difficulty Error", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
else
{
this.Hide();
}
Also I am a noob at C# so if you have any other tips that would be great, thanks.
Note: I am using a string for difficulty because of something further down in the code, so please don't tell me to use an integer, thanks.
To push information from your second form to your main form you should use an event. Create the event on the second form and fire it when your button is clicked:
public partial class difficultyForm : Form
{
string difficulty = "";
public difficultyForm()
{
InitializeComponent();
}
public event Action<string> DifficultySubmitted;
private void enterButton_Click(object sender, EventArgs e)
{
difficulty = difficultyTextBox.Text;
if (DifficultySubmitted != null)
DifficultySubmitted(difficulty);
//...
}
}
Then subscribe to that event on the main form:
private void generateBegin()
{
difForm.Show();
difForm.difficultyTextBox.Text = "";
difForm.difficultyTextBox.Focus();
difForm.DifficultySubmitted += newDifficulty => difficulty = newDifficulty;
}
If I understand your difficulty correctly, you might want to look at event handling.
Define a custom event args class (eg: DifficultyEventArgs or something). Define a delegate with one param as your event args
Declare an event with the delegate in the class..
Invoke the delegate in the setter method of the property which you'd like to observe.
In the other form, you can subscribe to this event, to monitor any changes made to it. This is just one way.
Also, you should better use an enum for DifficultyLevel, instead of a string.
you can pass the Form1 in a constructor param of DificultForm, and so access the controls of Form1
If what you're trying to do is simply getting the value of your second forms's TextBox at an specific circunstance, you can create a public method in the second form's code
public string GetTxtBoxValue()
{
return difficultyTextBox.Text;
}
and then call it from the first form.
But, if you want a better control upon it, I'd recommend using an event.
In my project I have a Settings form and a Main form.
I'm trying to call the Main form's MasterReset function from the Setting form, but nothing happens.
The Master form's Masterreset function looks like this.
public void MasterReset()
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to perform master reset? All settings will be set to default.", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (dialogResult == DialogResult.Yes)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string phonebook_path = path + "\\Phonebook\\Contacts.xml";
XmlDocument xDoc = new XmlDocument();
xDoc.Load(phonebook_path);
XmlNode xNode = xDoc.SelectSingleNode("People");
xNode.InnerXml = "";
xDoc.Save(phonebook_path);
listView1.Clear();
people.Clear();
}
else if (dialogResult == DialogResult.No)
{
return;
}
}
And I'm accessing it from the Settings form like this
private void btn_MasterReset_Click(object sender, EventArgs e)
{
Main f1 = new Main();
f1.MasterReset();
}
Why am I not seeing any results?
Do you know what composition over inheritance is?
In the form where you have MasterReset you should do something like this:
Llet's suppose that in your second form you have something like this, and let's suppose your "mainform" will be called "MasterForm".
public partial class Form1 : Form
{
private MasterForm _masterForm;
public Form1(MasterForm masterForm )
{
InitializeComponent();
_masterForm = masterForm;
}
}
Here's the code in your masterForm Class:
private void button2_Click(object sender, EventArgs e)
{
Form1 form1 = new Form1(this);
}
Here's in your form1:
private void btn_MasterReset_Click(object sender, EventArgs e)
{
_masterForm.MasterReset();
}
Hope this helps!
This worked for me: In your Program class, declare a static instance of Main (The class, that is) called Form. Then, at the beginning of the Main method, use Form = new Main(); So now, when starting your app, use
Application.Run(Form);
public static Main Form;
static void Main() {
Form = new Main();
Application.Run(Form)
}
Now, calling a function from another form is simple.
Program.Form.MasterReset(); //Make sure MasterReset is a public void
namespace F1
{
// Method defined in this class
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//This method I would like to call in other form
public void function()
{
MessageBox.Show("Invoked");
}
// opening the new form using button click
private void OpenNewForm_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.ShowDialog();
}
}
// This is second form
public partial class Form2: Form
{
public Form2()
{
InitializeComponent();
}
// on button click Form1 method will be called
private void button1_Click(object sender, EventArgs e)
{
var mainForm = Application.OpenForms.OfType<Form1>().Single();
mainForm.function();
}
}
}
There are multiple solutions possible. But the problem itself arise from the bad design. If you need something to be accessed by many, then why should it belong to someone? If, however, you want to inform something about anything, then use events.
Your mistake is what you are creating another instance of form1, thus MasterReset is operating with form, which is not even shown.
What you can do:
Make (as Ravshanjon suggest) a separate class to handle that MasterReset (and maybe something else). But also add to it an event. form1 and form2 can both subscribe to it and whenever either of them call MasterReset - both will react.
Create form dependency (as BRAHIM Kamel suggested): when you create form2, then pass to it form1 instance (as constructor parameter or by setting public property), to be able to call public non-static methods of form1.
As a quick, but relatively legimate solution, make this method static:
private static Form1 _instance;
public Form1()
{
InitializeComponents();
_instance = this;
}
public static void MasterReset()
{
// alot of code
_instance.listView1.Clear();
// alot of code
}
this way you can call MasterReset from any other form like this Form1.MasterReset(). Disadvantage of this method is what you can not have more than one instance of form2 (which is more likely anyway).
I understand your problem, you can declare your function as public static void(also listView1 and people should be static too). Then when you want to call to like this:
private void btn_MasterReset_Click(object sender, EventArgs e)
{
Main.MasterReset();
}
I am working on a game that utilizes Windows Forms in C#. I want to be able to use the first form to call a second form. I have this working. Then I would like for the second form to send data back to the first form rather than creating a new instance of the first form. Can this be done? I know I need to have my properties set up so that I can set the variables from one form to the other. I am just not sure how to go about calling the first form without creating a new instance of it.
Is there a way that this can be done?
For example if I have Form A create an instance of Form B, can I have Form B do some work and send the data back to the original Form A without creating a new instance of Form A?
If you don't use the Data sent back Form A right away then you could use the Form_Closing event handler Form B and then a public property in Form B also.
In your Form A it could look like this:
public partial class FormA : Form
{
FormB frmB = new FormB(); // Instantiate FormB so that you could create an event handler in the constructor
public FormA()
{
InitializeComponent();
// Event Handler for Form Closing
frmB.FormClosing += new FormClosingEventHandler(frmB_FormClosing);
}
void frmB_FormClosing(object sender, FormClosingEventArgs e)
{
String fromFormB = frm2.FormBData; // Get Data from Form B when form is about to close
}
private void button1_Click(object sender, EventArgs e)
{
frmB.ShowDialog(); // Showing Form B
}
}
And in your Form B it could look like this:
private void button1_Click(object sender, EventArgs e)
{
// Let just say that the data is sent back once you click a button
FormBData = "Hello World!";
Close();
}
public String FormBData { get; set; }
It's hard to say without knowing your full requirements. But generally I go like this (Somewhat psuedo code).
Form2 dialogForm = new Form2();
if(dialogForm.ShowDialog() == DialogResult.OK)
{
this.PropertyOnForm1 = dialogForm.PropertyOnForm2
}
This ofcourse relies that your second form is a dialog. You will need to set the dialogresult buttons on Form2, and have a public property that will be accessed from Form1 once the dialog has been completed.
Let me know if this doesn't work and I'll write up a different answer.
Since you are creating Form2 in Form1, you can create a custom event in Form2 and subscribe to it in Form1 at the time that you create Form2, if you are returning information from Form2 when you are closing it then Edper's or MindingData's answers will work.
Here is a quick and dirty example using EventHandler<TEventArgs>
Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.myCustomEvent += frm2_myCustomEvent;
frm2.Show();
}
void frm2_myCustomEvent(object sender, string e)
{
this.Text = e;
}
}
Form2
public partial class Form2 : Form
{
public event EventHandler<string> myCustomEvent;
int count;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
count +=1;
myCustomEvent(sender, count.ToString());
}
}
I have a MainForm and AnotherForm. AnotherForm is accessed via MainForm's menuItem.
AnotherForm has listView. When user clicks on an item it I want to get the string element and pass it to MainForm's textbox, so the element shows there and AnotherForm is closed. So far AnotherForm closes but nothing shows in the textbox in MainForm. Any suggestions?
private void listView1_ItemActivate(object sender, EventArgs e)
{
string input = listView1.SelectedItem[0].ToString();
MainForm mainF = new MainForm(input);// called the constructor
this.Close(); //close this form and pass the input to MainForm
mainF.inputTextBox.Text = input;
mainF.loadThis(input);
}
I assume you have an instance of MainForm already, and that's what creates an instance of AnotherForm.
Inside the event you posted, you're actually creating an entirely new instance of MainForm, never showing it, and then it's destroyed anyway when AnotherForm closes.
The reason you see nothing in the text box is because you're looking at the original instance of MainForm, which you haven't actually changed.
One quickie way of fixing this would be passing a reference to the original MainForm into AnotherForm:
public class AnotherForm
{
private MainForm mainF;
public AnotherForm(MainForm mainF)
{
this.mainF = mainF;
}
...
...
private void listView1_ItemActivate(object sender, EventArgs e)
{
...
mainF.inputTextBox.Text = input;
...
}
}
Note: Instead of having AnotherForm aware of MainForm, you might want to switch it around and create a public property in AnotherForm like this:
public class AnotherForm
{
public InputValue { get; private set; }
private void listView1_ItemActivate(object sender, EventArgs e)
{
...
InputValue = input;
...
}
}
Which you can then access from MainForm when the other form is closed:
private void SomeMethodInMainForm()
{
var newAnotherForm = new AnotherForm();
newAnotherForm.ShowDialog();
var inputValueFromAnotherForm = newAnotherForm.InputValue;
// do something with the input value from "AnotherForm"
}
If your MainForm has already been created you cannot just create another one in order to access it and set properties. You've created two separate MainForms (though the 2nd one is hidden because you never showed it).
It sounds like what you want to do is a modal dialog pattern. Your MainForm is the main window in your application. You want to have a 2nd form pop up when you click on a menu link. This is called a dialog. Then when you close that dialog you want your MainForm to retrieve a value as a returned result of the dialog.
In your MainForm the event handler which handles the menu item click should look something like this:
private void pickSomethingMenuItem_Click(object sender, EventArgs e)
{
using (var picker = new PickerDialog())
{
if (picker.ShowDialog(this) == DialogResult.OK)
{
LoadSomething(picker.SomethingPicked);
}
}
}
Then the following code would be inside your dialog form:
public string SomethingPicked { get; private set; }
private void somethingListView_ItemActivate(object sender, EventArgs e)
{
SomethingPicked = somethingListView.SelectedItem[0].ToString();
DialogResult = DialogResult.OK;
}
Notice how I named all of the objects with meaningful names. Well, except for "Something". It was impossible to tell from your code what you were actually using the dialog to pick. You should always use meaningful names for your objects and variables. Your code is almost completely nonsensical.
And you should almost never make a control on a Form public like you have with your inputTextBox. You should always expose values you want to share as public properties.
On this presented solution, you could do five main things in order to achieve what you want to do, namely:
1) Declare a global object for AnotherForm in MainForm
2) Initiate a FromClosing event handler for AnotherForm in MainForm
3) Make a public property or field in AnotherForm
4) Before closing in AnotherForm you save it the public property mentioned above
5) In the MainForm get the public property from AnotherForm
Here is the code:
MainForm
public partial class MainForm : Form
{
AnotherForm anotherForm; // Declare a global object for AnotherForm
public MainForm()
{
InitializeComponent();
}
private void showToolStripMenuItem_Click(object sender, EventArgs e)
{
anotherForm = new AnotherForm(); // when Menu Item is clicked instantiate the Form
anotherForm.FormClosing += new FormClosingEventHandler(anotherForm_FormClosing); // Add a FormClosing event Handler
anotherForm.ShowDialog();
}
void anotherForm_FormClosing(object sender, FormClosingEventArgs e)
{
inputTextBox.Text = anotherForm.listViewValue; // get the Value from public property in AnotherForm
}
}
AnotherForm
void listView1_ItemActivate(object sender, EventArgs e)
{
listViewValue = listView1.SelectedItems[0].Text; // Get the listViewItem value and save to public property
this.Close(); // Close
}
public String listViewValue { get; set; } // public property to store the ListView value
One thing to note here in comparison to your code I didn't use ToString() in ListView.SelectedItems:
listView1.SelectedItems[0].ToString();
But instead use the Text Property:
listView1.SelectedItems[0].Text;
I have a form1 (that runs the program) and form2 (that is a form for user to input). Form2 has a function that clears the user input (textboxes, checkboxes, combo boxes, it clears them).
The function looks like this:
public void CleartheForm(Control groupofcontrols)
{
foreach (Control c in groupofcontrols.Controls)
{
if (c is TextBox)
{
((TextBox)c).Clear();
}
if (c.HasChildren)
{
CleartheForm(c);
}
if (c is CheckBox)
{
((CheckBox)c).Checked = false;
}
label3.Text = "";
comboBox1.SelectedIndex = -1;
comboBox2.SelectedIndex = -1;
}
}
This works on its own. On my main form, I need to call this function, it should look like this:
I make a instance of form2 call Inputform and then:
private void Addrecord_Click(object sender, EventArgs e)
{
Inputform.ShowDialog();
if(Inputform.Addedrecord == true)
{
Inputform.Addrecord();
Inputform.CleartheForm(WHAT DO I PUT IN HERE??);
}
}
So that once a record has been added, the input form clears itself and ready for another record to be added.
The question is as above, what do I put in there? How do I call the groupofcontrols that is in the Inputform.CleartheForm() that is located in form2 from form1?? I tried to make a public Control groupofcontrols on the top of form2 and then leave my form1 as Inputform.CleartheForm(Control groupofcontorls), but then it saids I don't have object reference. If I leave it blank it saids Inputform.CleartheForm(); does not take 0 arguement.
Well, if you wanted to clear all the controls in the InputForm you could write another version of CleartheForm() without a parameter, and call the version with a parameter from it, like so:
public void CleartheForm()
{
ClearTheForm(this); // Passes all the controls in the Form.
}
Or you can just call the original ClearTheForm(Control) passing a reference to the InputForm as an argument: InputForm.ClearTheForm(InputForm).
If you always want to clear all the controls, I'd write a separate parameterless method for clarity.
However, this is only useful if you want to clear all the controls in InputForm.
Because Form is inherited from Control, you can call your method with form as an argument - it will clear all the TextBoxes and CheckBoxes in it:
Inputform.CleartheForm(Inputform);
However, probably, you can simply create new (and empty!) Inputform each time.
And, for your method - you should put
label3.Text = "";
comboBox1.SelectedIndex = -1;
comboBox2.SelectedIndex = -1;
away from the loop.
From what you've said (i.e. you put the groupofcontrols as public on form2), this should work:
Inputform.CleartheForm(Inputform.groupofcontrols);
(This is considering that Inputform is a property or a field on your main form - which I observed it is as you're calling ShowDialog on it.)
I don't understand your program's workflow.
If it is:
Form1 opens Form2
User input data into Form2
User press OK button on Form2
Form2 closes
Form1 reflect changes which was made by the user in Form2
User can repeat from the step 1
You should use new instance of the Form2 for the each iteration
To do that you should remove any clear code from your Form2 and change your code to the next one:
private void Addrecord_Click(object sender, EventArgs e)
{
var inputForm = new Form2();
inputForm.ShowDialog();
if(inputForm.Addedrecord == true)
{
...Reflect changes here...
}
}
But if you need a Form2 should stay opened while a Form1 adds new record each time when user click "Ok" button on the Form2
You should call Form1 from the Form2, the next design will be nice
interface IDataTarget
{
void Update(int id, string name); // you should reflect here all of your data
}
class Form1
: Form, IDataTarget
{
public void Update(int id, string name)
{
// add new record here
}
private void AddButton_Click(...)
{
using(var form2 = new Form2(this))
{
form.ShowDialog(this);
}
}
}
class Form2
: Form
{
private readobly IDataTarget dataTarget;
public Form2(IDatatarget dataTarget)
{
this.dataTarget = dataTarget;
}
private OK_Click(...)
{
dataTarget.Update(textBox1.Text, textBox2.Text);
ClearTheControls();
}
}
Personally I would move this method into a class library. You can make it static class and then just call
FromControls.CleartheForm(Inputform.groupOfControls)
So, your new class in a class library is (and nothing has been tested here, so mistakes are likely!)
public static class FormControls
{
public static void CleartheForm(Control groupofcontrols)
{
foreach (Control c in groupofcontrols.Controls)
{
if (c is TextBox)
((TextBox)c).Clear();
if (c.HasChildren)
CleartheForm(c);
if (c is CheckBox)
((CheckBox)c).Checked = false;
}
}
}
I would remove the following code:
label3.Text = "";
comboBox1.SelectedIndex = -1;
comboBox2.SelectedIndex = -1;
...as the CleartheForm code above will clear it.
So, your code would be (remembering to add a reference to your class library)
private void Addrecord_Click(object sender, EventArgs e)
{
AddRecord();
}
private void AddRecord()
{
Inputform.ShowDialog();
if(Inputform.Addedrecord)
{
Inputform.Addrecord();
FromControls.CleartheForm(GetControlOnPage())
}
}
private control GetControlOnPage()
{
//logic to return control if needed although it may just be this:
return Inputform.groupofcontrols
}