I have an application that shows data from a MySQL table. Basically, my application consists of two forms: the main form, and a form for adding stuff to the database.
The main form shows all the entries in the database and relevant information. When the user wants to add a new entry to the database, a secondary form is opened that prompts for information. Once the information is filled out, the user presses a Submit button and the form closes. My problem is that when the secondary form closes, the listBox in the main form doesn’t update to reflect the newly-added entry.
Here is the code that is executed when the user submits the secondary form:
private void closeWindow()
{
mainForm parent = new mainForm();
parent.listParts.Refresh();
this.Close();
}
Is there a reason when I call the listBox to be refreshed, it doesn’t show my newly-added information? Perhaps I am calling something in the wrong order? Or does the Refresh() method not even work like that?
Any help would be appreciated! Alternatively, if you know of a better way to do this, I’d love to hear it!
The problem is that you're refreshing the wrong form:
private void closeWindow()
{
mainForm parent = new mainForm();
parent.listParts.Refresh();
this.Close();
}
Since you use: new mainForm(), you're allocating a completely separate instance of the "mainForm", and refreshing it's content. This will not effect the existing, opened form.
I would recommend passing a reference to the mainForm to the constructor of the secondary form. It then would know which instance of mainForm it needs to use to call Refresh().
Reed has given an answer with why what you did din't work, here's one possible solution for how to actually fix it:
in some event handler for MainForm:
var otherForm = new SomeOtherForm();
otherForm.Closed += (sender, args) =>
{
//update the listbox in MainForm here
};
If you need information from the second form to update the listbox, then make a public property in SomeOtherForm that exposes the data needed by MainForm.
I think you should reload the data again. fetch it again set the datasource
Have a Parent Property to your child form which is of type of your First form.
some thing like this.
Your Parent form
public partial class KitTypes : Form
{
public void ReloadData()
{
// Get the data and Set as datasource of control
}
}
And the Child form
public partial class Kit : Form
{
private int _KitId=0;
private KitTypes _parentForm = null;
public Kit(KitTypes parentForm)
{
_parentForm =parentForm;
}
}
And from your First form, when you create an object of this, pass the parent form as the parameter
Kit objChild=new kit(this);
objChild.Show();
Now in your child, form you can call the public method of parent form like this
this._parentForm.ReloadData();
Related
It's probably a silly question, but I really don't know how to handle it.
My main form default class looks like this:
public partial class MainForm : Form
{
public MainForm(bool version)
{
InitializeComponent();
if(version == true)
{
items_checkedListBox.Items.Add("aa".ToString());
}
else
{
Controls.Remove(items_checkedListBox);
}
}
}
By default, my WinForm app starts with Application.Run(new MainForm(true)); and everything is ok. But I want to update the checkedListBox from another class and for that I need to instantiate my main form object and I call the new object with MainForm mainForm = new MainForm(false); but the problem is that the checkedList control remains, even though Controls.Remove(items_checkedListBox); gets executed.
How could I manipulate a control from another class when I instantiate the main form? :(
By doing this:
MainForm mainForm = new MainForm(false);
you create a new second form of the type MainForm and delete it's control items_checkedListBox, but that's not the control which you see on your first form of MainForm. Furthermore you don't see the second form you created, because you didn't make it show up, so don't wonder that you don't see anything happening like the removal of the other control on the second form.
So in order to manipulate your control items_checkedListBox you need to pass the reference of this control to your class in which you wish to manipulate it.
Imagine you would have another form (which is your other class), which you use to manipulate your control items_checkedListBox.
public partial class FmManipulateControl : Form
{
public FmManipulateControl()
{
InitializeComponent();
}
}
In order to be able to do this, pass a reference of this control as method parameter to the constructor:
public FmManipulateControl(Control myControl) { ... }
So that we can manipulate it we store this reference of our control in a field, so e.g. a button click event can access the control to change/remove/... it.
Control controlToChange;
public FmManipulateControl(Control myControl)
{
InitializeComponent();
controlToChange = myControl;
}
Let's imagine we bind to a button click event in our form FmManipulateControl:
private void button1_Click(object sender, EventArgs e)
{
//diposes the control, so it does not exist anymore, but you can apply
//any change to the control you wish to do
controlToChange.Dispose();
}
Now all you have to do is to create an instance of FmManipulateControl and pass it a reference of the control items_checkedListBox and show the new form object.
FmManipulateControl fmChangeAControl = new FmManipulateControl( items_checkedListBox);
fmChangeAControl.Show();
Further explaination about the reference type:
I am talking about passing a reference of the control and I think you might wonder about what I mean by that. I suggest you to read about value and reference types.
I try to keep it short and simple.
Imagine a value type contains the value directly itself: e.g. an int. The object contains the value directly.
int a = 3;
a contains the value 3.
Now let's have a look at our control. This ListBox control items_checkedListBox does not contain our object control, but a reference to it's location in memory. That's why it is called reference type.
So when we pass items_checkedListBox as a method parameter, we don't pass an object, but the memory location of our items_checkedListBox control. So we point to the same object, so we are abel to manipulate it.
Note:
Method parameters are just a copy of the inputted object, so when we do:
FmManipulateControl fmChangeAControl = new FmManipulateControl( items_checkedListBox);
In our form fmChangeAControl we got an object(myControl) which is a copy of items_checkedListBox. But since we did not pass the object, but a reference it does not matter if we have a copy or not, we still point to the same memory location so we still manipulate the same object.
In my program I have two forms. The main form and a form where you fill in extra information. What I'm trying to do is to write out the information given on the second form on a list box when the 'ok' button is pressed.
Currently this is what I have:
Main form:
public void writeLine()
{
foreach (var item in VarClass.listItems[VarClass.count - 1])
{
listBox1.Items.Add(item.ToString());
}
}
Second form:
Form1.writeLine();
As it, I get the following error at 'Form1.writeLine();'
"An object reference is required for the non-static field, method or property..."
I can kinda fix this by making 'writeLine()' static in the main form, but then I get the same error on 'listBox1' in the main form. How do I fix this?
You should pass the reference of your main form to the second form and call the method on that reference. For example you can create a property on the second form like private Form _mainForm; and create a constructor of the second form to receive that reference and set to that field. After that you will be able to call _mainForm.writeLine() in your second form.
Create an instance of Form1 and call the method. Here is the code:
new Form1().writeLine();
There are a couple ways to handle this. One is for form2 to have a reference back to the calling form ideally through an interface rather than a reference to the concrete class.
Another option would be for Form2 to have an event that form1 could subscribe to that would inform form1 that form2 has some output.
Keep a reference to the second form from the first:
public MyFirstForm
{
...
public MyFunction()
{
MySecondForm secondForm = new MySecondForm();
// ... Open your form etc, look for when it's complete and then ...
// Read the values from the second form into the first
var MyValues = secondForm.getValues();
// Now populate the list-box with the information returned.
//for (my listbox)
}
}
If I were to navigate between 2 forms (or more), it would be like this:
Main Menu to second form:
Form2 form2 = new Form2(this) // Instantiate form and pass form data to next form
Hide();
Second form:
Form1 form;
public Form2(Form1 form1)
{
this.form1 = form1; //Take in previous form's data
}
Navigating forward will Hide() the current form while navigating backwards will Close() the current form.
But what if I am in the 3rd, 4th... nth form and I wish to go back to the main menu? Is there some kind of way to close all of my hidden forms?
Or is there a proper method to navigate between forms?
In my opinion you should use Interfaces to change data between forms. This let's you stay more independent and your Form2 just get the data it needs. For example:
public interface IForm1 //You should find better naming
{
void Edit(); //Method for edit some data
List<T> DataList {get;} //List with some relevant data
}
public Form Form1 : IForm1
{
public void Edit(){ //Your edit logic}
public List<T> DataList {get{return myGrid.DataSource as List<T>;}}
}
public Form Form2
{
private IForm1 formData;
public Form2(IForm1 formData)
{
formData = formData;
}
}
Further i would think about your idea to have so much forms. I think one MainForm with a TabControl as first element is better way to go in many cases. You can create a UserControl for each TabPage and just switch the TabPage instead of poping up Forms all the time.
UPDATE
This Picture maybe clarify what i mean. The TabPageHeader are all invisible (in image i make it visible for clarification). If Login succeed you just switch the TabPage.
TabControl.SelectedTabPage = tabPageMainScreen;
So it feels more fluent to the user and you don't have the problem you describe. But i would recommend to separate the Form by different UserControls to keep it simple.
UPDATE 2
On Winforms you can hide the TabHeader as suggested in this post.
Example:
tabControl.ItemSize = new Size(0, 1);
tabControl.SizeMode = TabSizeMode.Fixed;
It's a bit ugly that the default TabControl don't has regular way but it works fine.
I would create a view model from the data in the first form and then supply it in a method on the second form.
public class Form1ViewModel {
public int Age {get; set;}
public string Name {get; set;}
}
//method on Form1
public void NavigateToForm2()
{
var vm = new Form1ViewModel{ Age = 32, Name = "Test name"};
var form2 = new Form2();
form2.SetViewModel(vm);
form2.Show();
}
Also to close the forms take a look at this link.
I would recommend taking a look into MVVM pattern because that handles the navigation, instantiation of the forms (views). A library to start with is mvvmfx. There are also other libraries for MVVM.
While Sebi and Mihail has given great ways for a proper navigation, I have did some practice on my own and found several solutions.
As what Sebi mentioned, a TabControl with one main form is the better way to go in many cases as it is more fluent, does not have forms popping up all the time.
Another way is to only preserve the instance of your parent(main) form:
Navigating from a child form to another will pass the parent form and values of your data (if required), before closing the form (Once closed, all resources created is disposed).
However in some cases where you need to maintain the values for a previous child form (So that all user input does not need to be re-entered again), You have to also pass the child form and hide it instead of closing it.
One thing that confused me when I opened the question was that I had initially thought that navigating forward in forms should always use Hide();, and not Close();.
To close all forms except the main form (Might be useful for those who have a similar design concept as mine):
List<string> currentform = new List<string>();
foreach (Form form in Application.OpenForms)
{
if (form.Name != "Form1")
{
currentform.Add(form.Name);
}
}
foreach (string formName in currentform)
{
Application.OpenForms[formName].Close();
}
I'm fairly new to Visual C# and I'm writing an GUI app with multiple forms. One form is main window, and the rest are some kind of option windows. When showing an option window, I need to load some data to it (for example a string to window's editbox), then edit it and return back to main window when closing option window. Is there any simple way I can achieve it?
I've found some solutions like, or c# event handling between two forms, but I can't really conform it to my needs. I was thinking about passing data in constructor, but how to get it back? I've found something about ShowDialog, but as I said I'm new to C# (started yesterday ^^) and don't know if I can use it.
Any ideas, please?
I found the following previous answer which outlines sending specific properties from the one form to another:
Send values from one form to another form
The using keyword will also ensure that the form is cleaned-up properly, here's a link to it's usage (pardon the pun...) : http://msdn.microsoft.com/en-us/library/vstudio/yh598w02.aspx
I've run into the same issue to be honest, and I have to say that prior to this discussion I would just pass the parent form itself to the child and alter it in that way. Such as:
ChildForm child = new ChildForm(this); //from the parent
and
public ChildForm(ParentForm parent)
{
this.parent = parent;
}
Probably not the best convention though, as you probably don't need to access that much from the parent as the child.
Thanks guys, I think I finally get it. Idle_Mind, your idea was the easiest in my point of view, so I decided to use it. If someone else has a problem like this, here's what I've coded:
In main window form: when button is clicked, a new form appears; after closing it, label1 shows the text typed in that form
private void Button1_Click(object sender, EventArgs e)
{
LoadDataForm loaddata = new LoadDataForm("initial value");
if (loaddata.ShowDialog() == DialogResult.OK)
{
label1.Text = loaddata.textBox1.Text;
}
}
In load data form: argument passed in form's constructor appears in textBox1; textBox1's Modifiers property has to be modified to "public"
public LoadDataForm(string initvalue)
{
InitializeComponent();
textBox1.Text = initvalue;
}
private void ApplyButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
Regards,
mopsiok
I once read a tutorial about how to create a new form and make it above all other windows so you can click only it - like in internet explorer for example when you click on browse for a file you can't click the main window until you finish using the browse window.
Also what is the best way to get values from a form back, for exmpale on my second form I have a listbox and when a user clicks on one of the values the first form (mainform) should get the event - is this possible?
It sounds like you want:
using (MyCustomForm form = new MyCustomForm(...))
{
if (form.ShowDialog() == DialogResult.OK) {
// Now use the values in form
// (e.g. through properties of the form)
}
}
Just use a modal form, which is done by calling .ShowDialog() after you've made an instance of it.
To get the values back, just store them in properties of the form, and then read those properties from the parent window/code before it goes out of scope. You'd handle the SelectionChanged event in the code-behind of your new form and set a property with the value.
What you are looking for is to show the form as a modal dialog box. Form.ShowDialog() Here you can read more about this topic.
You can access parent form (back form) in couple ways:
Make modal form constructor to accept parent from as parameter
Put parent form reference into some global variable that can be accessed from modal form
...
To get an event from child form you can do something like this:
form.myListBox.SelectedIndexChanged += new System.EventHandler(this.myListBox_SelectedIndexChanged);
form.ShowDialog();
You need to make myListBox control public in order to access it from parent (caller) form.
try this:
Create your form and
In your calling code do the following:
MyForm form = new MyForm();
form.ShowDialog();
To get the values back, simply create properties on your form that map to the values of your controls (make sure you don't dispose your form before you access the properties!):
public class MyForm
{
//...
public string FirstName
{
get
{
return firstNameTextBox.Text;
}
}
}
Then call the properties from your calling code after the dialog is done:
MyForm form = new MyForm();
if(form.ShowDialog() == DialogResult.OK)
{
string myFirstName = form.FirstName;
// etc
}