How to close an activeMidForm and open another? - c#

I have a method that I use the open a Mid Child.
Lets say I am on a form called "InventoryAdd" on this form I have a drop down menu. When a user selects a value "-1" from the menu, I want to open another (ie. DepartmentsAdd().) Then after DepartmentAdd open I want to close InventoryAdd form.
this is the code behind the menu on InventoryAdd form
private void InputDepartment_SelectedValueChanged(object sender, EventArgs e) {
//InputDepartment.ValueMember = "ID";
int selectedDept = Convert.ToInt32(InputDepartment.SelectedValue);
if (selectedDept == -1) {
Form myForm = this.ActiveMdiChild;
Common.OpenMyForm("Vendors", new string[] { "add" }, new DepartmentsAdd());
if (myForm != null) {
myForm.Close();
}
}
}
This method what opens the new Mid form
public static void OpenMyForm(string sectionName, string[] keys, Form myform) {
//make sure there are no other forms of the ame type open
foreach (Form form in Application.OpenForms) {
if (form.GetType() == myform.GetType()) {
form.Activate();
return;
}
}
if (Settings._AuthenticationMode == "Thumbprint") {
var newMDIChild = myform;
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = AppContext.CurrentContext.MainForm;
// Display the new form.
newMDIChild.Show();
}
if (Settings._AuthenticationMode == "Single" && UserInfo.Autherized == true) {
var role = new Roles();
if (role.hasAccess(sectionName, keys)) {
var newMDIChild = myform;
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = AppContext.CurrentContext.MainForm;
// Display the new form.
newMDIChild.Show();
}
else {
Common.Alert("You do not have a permissions to perform this action!");
}
}
}
}
My code open the Mid form with no issues. However, the "InventoryAdd" form never close. "myForm" is always null to it never close it.
How can I properly close the Mid form?
Thanks

If you set an event listener for shown on the newly opened form in the calling context you can have the existing form close itself once its child is opened.
Form myForm=new Form();
myForm.shown += closeForm;
...
void closeForm(object sender, EventArgs e){
this.Dispose(); // as long as within the previous forms context.
}

myForm.Close();
is closing the program try to use
myForm.Hide();

Related

How to refresh contextmenustrip items or refreshing form's items

Basically, i am creating a raw-based web browser application. Bookmarks are added in contextmenu toolstripitem either from using "star" button or via another form. When added using another form, it is not refreshing the contextmenu items which are added from another form in the main form.
MainForm View:
mainform
Favourites/Bookmarks View:
bookmarks
updatebookmarks
This is how it is added via another form:
addbookmark
addbookmark2
Code Preview:
Star Button:
private void favButton_Click(object sender, EventArgs e)
{
if(inputUrlBox.Text != "")
{
var item = inputUrlBox.Text.ToString();
if(!favouritesToolStripMenuItem.DropDownItems.Cast<ToolStripMenuItem>().Any(x => x.Text == item))
{
try {
Properties.Settings.Default.BookmarksList.Add(item + ",null");
Properties.Settings.Default.Save();
foreach (var bookmark in Properties.Settings.Default.BookmarksList) {
var link = bookmark.Split(',')[0].ToString();
favouritesToolStripMenuItem.DropDownItems.Add(link);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show("Bookmark already exists!");
}
}
}
Moving directly to "Add" in another form's button (this is written in BookmarkWindow Form):
private void addButton_Click(object sender, EventArgs e)
{
AddBookmarkWindow form = new AddBookmarkWindow();
form.ShowDialog(this);
}
In AddBookMark's Form (AddBookmkarkWindow.cs):
if ((isUri) && (linkinput != null && linkinput.Length > 0) && (nameinput != null && nameinput.Length > 0))
{
Properties.Settings.Default.BookmarksList.Add(linkinput + "," + nameinput);
Properties.Settings.Default.Save();
MainWindow mw = new MainWindow();
mw.updatebookmarkstab(linkinput);
this.Close();
MessageBox.Show("Added!");
}
This "updatebookmarkstab" function is in mainwindow/mainform:
public void updatebookmarkstab(string item)
{
menuStrip1.Refresh();
contextMenuStrip1.Refresh();
favouritesToolStripMenuItem.DropDownItems.Add(item);
}
What I expect is, once i add bookmark(s) from another form, I want it to be showed in main form's contextmenustrip item just like how "star" works.
Anyone has any idea on how to refresh menuitems from another form or has a better solution to provide this view.

The FormClosing event seems to run after a different Form is started

I did a lot of research about this problem and tried methods but none of them worked. First I will show you what is in my application and what I want it to be with some pictures.
Picture 1
As you can see in the first picture, I open new childForms using the buttons on the main form. One of them is the form named "Price". This form saves the prices entered by the user to the json file. I do the saving process in the FormClosing event. (Yes i know but I don't want to use the "Save" button.)
Picture 2
As you can see in the second picture, the "Result" form did some mathematical operations by reading the values entered by the user in the "Price" form over json.
Now let's come to the problem, I open the "Price" form, change the values and press the result button. Results are coming, everything is great! But the results are not correct because when the "Result" Form was run it didn't wait for the current values to be saved in json. So it didn't wait for the "Price" form to close (i.e. it didn't wait for the Price.FormClosing event to complete).
To avoid this error, I open the results form after opening a different form, but this is amateurish.
I hope I was able to explain my problem clearly.
Thanks in advance for your answers and thoughts.
Code to Write Current Values to JSON File:
private void ProductPricesForm_FormClosing(object sender, FormClosingEventArgs e)
{
string jsonString = JSONOperations.getItemsAsString(products);
File.WriteAllText(JSONOperations.productsJSONPath, jsonString);
}
Code to Read JSON File:
private static void getItems()
{
using (StreamReader r = new StreamReader(JSONOperations.productsJSONPath))
{
string json = r.ReadToEnd();
products = JSONOperations.getItemsAsClass<Product>(json);
}
}
Form Opening Code:
private void buttonResult_Click(object sender, EventArgs e)
{
openChildForm(new ResultForm());
}
private void buttonProductPrices_Click(object sender, EventArgs e)
{
openChildForm(new ProductPricesForm());
}
private Form activeForm;
private void openChildForm(Form childForm)
{
if (activeForm == null)
{
startChildForm(childForm);
}
else
{
if (String.Equals(activeForm.Name, childForm.Name))
{
return;
}
else if (!String.Equals(activeForm.Name, childForm.Name))
{
activeForm.Close();
startChildForm(childForm);
}
}
}
private void startChildForm(Form childForm)
{
childForm.TopLevel = false;
childForm.FormBorderStyle = FormBorderStyle.None;
childForm.Dock = DockStyle.Fill;
panelChildForm.Controls.Add(childForm);
panelChildForm.Tag = childForm;
childForm.BringToFront();
childForm.Show();
activeForm = childForm;
}
You can simply Hide the dialog instead of close.
First, create your childs types:
private enum FormType
{
Result = 0,
Products = 1,
//...
}
An a method to create each form:
private Form CreateChildForm(FormType formType)
{
switch (formType)
{
case FormType.Result:
return new ResultForm();
case FormType.Products:
return new ProductPricesForm();
default:
return null;
}
}
Now, in your form, add this fields:
private int _activeChildIndex = -1;
private readonly Form[] _childsForms = new Form[Enum.GetNames(typeof(FormType)).Length];
_childsForms will store each type of ChildWindow that you create. _activeChildIndex indicates the _childsForms which is active now.
private void ShowChildWindow(FormType formType)
{
var index = (int)formType;
if (this._activeChildIndex == index)
{
return;
}
if (this._activeChildIndex >= 0)
{
var activeChild = this._childsForms[this._activeChildIndex];
// TODO: Hide form
this.OnHideForm(this._activeChildIndex);
}
this._activeChildIndex = index;
if (this._childsForms[index] != null)
{
// TODO: Reset to default (or leave with last state, as you prefer)
// TODO: And show
}
else
{
// TODO: Create child form
var childForm = this.CreateChildForm(formType);
if (childForm != null)
{
this._childsForms[index] = childForm;
}
}
this.OnShowForm(this._activeChildIndex);
}
This method create a child form if not exists and show when was previously created.
In your ProductsForm, add a method to get the JSON:
public string GetProductsJson()
{
return JSONOperations.getItemsAsString(products);
}
Now, you can use OnShowForm in this way:
private void OnShowForm(int index)
{
var formType = (FormType)index;
if (formType == FormType.Result)
{
var productsForm = this._childsForms[(int)FormType.Products];
if (productsForm != null)
{
var json = productsForm.GetProductsJson();
}
}
}
When you activate your result form, search your products form. If was previously created, get the Json. You don't need save to file the json to use here. Save it if you need for other reason.
Do some changes in FormClosing:
private void ProductPricesForm_FormClosing(object sender, FormClosingEventArgs e)
{
// Do this if you need
string jsonString = GetProductsJson();
File.WriteAllText(JSONOperations.productsJSONPath, jsonString);
// TODO: You need a flag to know when are you closing the app.
// In that case, don't cancel
e.Cancel = true;
}
UPDATE
I don't like this solution but may be that you are waiting for:
First, add a method to get the Json in your Product form:
public string GetJson()
{
return JSONOperations.getItemsAsString(products);
}
And a field in your main form:
private string _productsJson;
Instead of a file, use this string. You also can save to file if you need for other purposes.
Change this other method:
private void buttonProductPrices_Click(object sender, EventArgs e)
{
var form = new ProductPricesForm();
form.FormClosing += (sender2, e2) => this.OnProductsPrices(form.GetJson());
openChildForm(form);
}
It do the same as you was doing and also get the closing event to get the Json and invoke to OnProductsPrices with that string.
private void OnProductsPrices(string json)
{
if (_productsJson != json)
{
_productsJson = json;
var form = activeForm as ResultForm;
if (form != null)
{
form.DoSomethingWithTheJson(json);
}
}
}
If the Json doesn't change, you don't need to do anything. When it's changed, you update your _productsJson and check if current form is ResultForm. In this case, you load the Json or do whatever you do with the Json in that Form.
Also, you must use _productsJson when you create the ResultForm, like know, that I suppose you get from file. In this way, you use the json always when you create ResultForm or later, when the ProductsForm is closed.
private void buttonResult_Click(object sender, EventArgs e)
{
var form = new ResultForm();
openChildForm(form);
if (!string.IsNullOrEmpty(_productsJson))
form.DoSomethingWithTheJson(_productsJson);
// Or do the same in the constructor and manage inside the form, calling to DoSomethingWithTheJson
//var form = new ResultForm(_productsJson);
}

Single instance of all WinForm forms

I am developing a C# Windows Forms application. I would like to have a single instance of all the forms.
So, when the user clicks on the Contact button, for instance, twice, instead of having two contact forms, I would to bring the single instance contact form to the front.
How can I achieve this?
Check if the form exists in collection of open forms before creating and showing the form using Application.OpenForms
if (System.Windows.Forms.Application.OpenForms["Form1"] as Form1 != null)
MessageBox.Show("Form1 is opened");
else
MessageBox.Show("Form1 is not opened");
public static Form GetOpenedForm<T>() where T: Form {
foreach (Form openForm in Application.OpenForms) {
if (openForm.GetType() == typeof(T)) {
return openForm;
}
}
return null;
}
And in your code, where you create the ContactForm:
ContactForm form = (ContactForm) GetOpenedForm<ContactForm>();
if (form == null) {
form = new ContactForm();
form.Show();
} else {
form.Select();
}
Simple as that:
Form fc = Application.OpenForms["Form1"];
if (fc != null)
{
fc.Focus();
}
else
{
Form1 f1 = new Form1();
f1.Show();
}
You can disable the contactButton when it is clicked and open the contactForm-
private void contactButton_Click(object sender, EventArgs e)
{
contactButton.Enabled=false;
//code to open the contactForm
}
When the contactForm is closed, you can re-enable the button-
contactButton.Enabled=true;
Try this combo
First make contact form a global object
private ContactForm contactForm;
Then your contact button handler:
private void contactButton_Click(object sender, EventArgs e)
{
if (contactForm == null)
{
contactForm = new ContactForm();
contactForm.FormClosing += new FormClosingEventHandler(contactForm_FormClosing);
}
contactForm.Show();
}
Then handle the FormClosing event of the ContactForm to hide it rather than close it:
private void contactForm_FormClosing(object sender, FormClosingEventArgs e)
{
contactForm.Hide();
e.Cancel = true;
}
Or if you want the contact form to close, and open as new next time, handle the FormClosed instead:
private void contactForm_FormClosed(object sender, FormClosedEventArgs e)
{
contactForm = null;
}
Then next time the button is clicked, the null if clause will be caught and the form will be set to a new instance and opened.
Form2 form2 = null;
private void button1_Click(object sender, EventArgs e)
{
bool isFormExists = false;
foreach (Form openForm in Application.OpenForms)
{
if (openForm == form2 && openForm!=null)
{
openForm.Focus();
isFormExists = true;
break;
}
}
if (!isFormExists)
{
form2 = new Form2();
form2.Show();
}
}
I'd go with Otiel's answer. Also you can add a WindowState, because if the form is minimized it won't be shown. this answer can be used to get the restore method.
ContactForm form = (ContactForm) GetOpenedForm<ContactForm>();
if (form == null) {
form = new ContactForm();
form.Show();
} else {
//use this (if you want it to be restored to normal and focused)
//no need of extension method
//form.WindowState = FormWindowState.Normal;
//form.Select();
//or use this if you want it to be restored as previous state and focused
//You need a Restore extension method that can be found in the link above
form.Focus();
form.Restore();
}

How to hide a WinForms form without losing it's data

i implement a wizard in c#, in this manner:
private static void MyInitialization()
{
WizardData wData = new WizardData();
wData.FormToShow = WizardData.wizardForms.FirstStep;
Form step1 = new FirstStep(wData);
Form step2 = new SecondStep(wData);
Form step3 = new ThirdStep(wData);
while (wData.FormToShow != WizardData.wizardForms.Cancel)
{
switch (wData.FormToShow)
{
case WizardData.wizardForms.FirstStep:
{
step1.ShowDialog();
break;
}
case WizardData.wizardForms.SecondStep:
{
step2.ShowDialog();
break;
}
case WizardData.wizardForms.ThirdStep:
{
step3.ShowDialog();
break;
}
}
when i want to move to another form i need to close the currnet(this.close), but i want make the current visibility=false and not lose the data in the current form when i go to other form?
private void btnNext_Click(object sender, EventArgs e)
{
// to show the SecondStep form
wData.FormToShow = WizardData.wizardForms.SecondStep;
this.Close();
}
any idea?
Use the Hide() method
Form1.Hide();
This way, the Form won't be visible, and the data will be saved until you Dispose() of the form.

Get list of open windows form instance that are excuted from different assembly

I have a 'loader app' that loads a menu and when user clicks the menu image button a list view opens based on the text
(if text = employee)
(Go to class A)
(Go to class B)
...
...
(Show List View Window)
if he clicks again on the same button it opens again, I would like to prevent this.
i.e but this for a WPF application
If you want a list of the open forms, that is Application.OpenForms. You could iterate over this, using GetType() and checking the .Assembly to find those from a different assembly. Beyond that, I'm not entire clear on the question...
Assembly currentAssembly = Assembly.GetExecutingAssembly();
List<Form> formsFromOtherAssemblies = new List<Form>();
foreach (Form form in Application.OpenForms) {
if (form.GetType().Assembly != currentAssembly) {
formsFromOtherAssemblies.Add(form);
}
}
If you just want to track forms you have opened yourself, then cache that instance. Or if you use "owned forms", you can just check by name:
private void button1_Click(object sender, EventArgs e) {
foreach (Form form in OwnedForms) {
if (form.Name == "Whatever") {
form.Activate();
return;
}
}
Form child = new Form();
child.Name = "Whatever";
child.Owner = this;
child.Show(this);
}
NewProduct newproduct;
private void button1_Click(object sender, EventArgs e)
{
if(!isOpened())
{
newproduct = new NewProduct();
newproduct.Show();
}
}
private bool isOpened()
{
foreach (Form f in Application.OpenForms)
{
if (f == newproduct)
{
return true;
}
}
return false;
}
Another simple example
private Boolean FindForm(String formName)
{
foreach (Form f in Application.OpenForms)
{
if (f.Name.Equals(formName))
{
f.Location = new Point(POINT.X, POINT.Y + 22);
return true;
}
}
return false;
}
You can use a Command pattern. The loader assembly will search for commands in loaded assemblies.
For every command the loader create menu item ( or anything else, you want ), and click event will run the concrete command.
The command must know if should be created new form or used some already existing.
Mark Garvell's answer helped me to figure out what I should do, but it needed adjusting for WPF.
(In my case I wanted to close any windows not owned by the main one when it closes, but the principle is the same.)
private void EmployeeMenuItemClick(object sender, RoutedEventArgs e)
{
bool found = false;
foreach(Window w in Application.Current.Windows)
{
if(w.GetType() == typeof(EmployeeListViewWindow)
{
found = true;
break;
}
}
if(!found)
{
EmployeeListViewWindow ew = new EmployeeListViewWindow();
ew.Show();
}
}

Categories

Resources