Lock menu item when window open, unlock when closing - c#

I have a window that I want to allow only one instance of it to be open at a time. They can open / close the window, but can't have multiple copies of the same window open at a time.
I have a menu with an option that when clicked, opens the ProductSelection window. ListProductList is my button:
private void ListProductListCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = _productListCanExecute;
//_productListCanExecute = !_productListCanExecute;
}
private void ListProductList(object sender, ExecutedRoutedEventArgs e)
{
_productListCanExecute = false;
ProductSelection pl = new ProductSelection(productCategoryList, productStyleList, productList);
pl.Show();
}
Notice that I set the e.CanExecute of the ListProductList button to false to ensure that the event handler doesn't run and therefore doesn't open more windows.
Now, how can I detect that the ProductSelection window has closed in order to set the _productListCanExecute back to true? It's not a modal window, because I want to allow them to do other things.

Probably the easiest solution here is to make the pl variable a global.
Whenever the button is clicked, just "show" that existing window.

Related

Do actions AFTER a window (not the Main Window) is closed in C# WPF

In my program, I have a button that opens a new window called CreateNewLabelGroup. This is the click event written in the MainWindow:
private void ButtonCreateNewLabelGroup_Click(object sender, RoutedEventArgs e)
{
new CreateNewLabelGroup(out write_to_import_textbox).Show(); //Line 1
ImportedPathTextbox.Text = write_to_import_textbox; //Line 2
LoadComboboxItems(); //Line 3
}
Line 1 opens the new window.
What I need to happen is that after the user is finshed working in CreateNewLabelGroup, the window will be closed, and only then would Lines 2 and 3 be called. What happens is that Lines 1-3 happen simultaneously.
Line 2 takes a variable created from the CreateNewLabelGroup window and writes it on a textbox in the MainWindow.
Line 3 follows through by loading the array from write_to_import_textbox and lists them in a combobox. LoadComboboxItems() is a method in the MainWindow.
I tried the Closing event (Closing="CreateNewLabelGroup_Closing") but I can only create the event within the CreateNewLabelGroup window.
TIA.
You can attach a close handler outside the window, something like this:
private void ButtonCreateNewLabelGroup_Click(object sender, RoutedEventArgs e)
{
var labelGroupWindow = new CreateNewLabelGroup(out write_to_import_textbox);
// Adding a handler for the closing event
labelGroupWindow.Closing += LabelGroupWindow_Closing
// Show Window
labelGroupWindow.Show()
}
private void LabelGroupWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Your code here
ImportedPathTextbox.Text = write_to_import_textbox;
LoadComboboxItems();
// Don't forget to delete it after processing the event!
(sender as Window).Closing -= LabelGroupWindow_Closing;
}
If you need the user to do things in CreateNewLabelGroup before your code continues then you could open the window as a modal dialog. This blocks processing in your main window until the dialog window is closed.
private void ButtonCreateNewLabelGroup_Click(object sender, RoutedEventArgs e)
{
new CreateNewLabelGroup(out write_to_import_textbox).**ShowDialog**(); //Line 1
ImportedPathTextbox.Text = write_to_import_textbox; //Line 2
LoadComboboxItems(); //Line 3
}
You should really make the calling window "owner" of the dialog as well but that would require some more changes to your code.
See open as modal:
"WPF restricts interaction to the modal window, and the code that opened the window pauses until the window closes. This mechanism provides an easy way for you to prompt the user with data and wait for their response."
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/windows/how-to-open-window-dialog-box?view=netdesktop-6.0
As you can probably see, this is a simpler approach without necessitating subscribing to an event in a separate window.

Enable/Disable Buttons On Owner Form When Owned Form Is Closed

I am working on a WinForms Desktop application in C# .NET. The target framework is .NET Framework 4.8. When the application is started, the main form is displayed with several buttons. Each button hides the main form when clicked and opens another form that displays data with which the user interacts. The main form is the owner of the new form.One button opens a form that presents a list of files from a network share folder in a data grid view. The user selects a row in the data grid and clicks a button to import the information in the file to various tables in a SQL Server database. When the import is complete, the selected row is removed from the data grid. When the user closes this form, there is code in the Form Closed event to show the owner. This all works well.My problem is that when the main form is unhidden, I need to disable the button that opens the form to list files to import if there are not any files in the network share folder to be imported. There is also a line of code to change the button's text property informing the user there are not any files to import.I realize I can place the code to disable the button and change button text in the VisibleChanged event. But, I only want the code to run after the owned form's closed event shows the owner form. How do I enclose the code in the main form's VisibleChanged event to disable the file import button only after the owned form is closed. Or, is it possible to edit the properties of the button on the owner form in the Form Closed event prior to the Owner.Show();I found a similar question WinForm Form Closed Event. But when I follow the suggestion
private void LoadChildForm_Click(object sender, EventArgs e)
{
ChildForm form = new ChildForm();
form.FormClosed += new FormClosedEventHandler(ChildFormClosed);
form.Show();
}
substituting my names
private void btnImportHFR_Click(object sender, EventArgs e)
{
Form form = new frmHFRFiles();
form.FormClosed += new FormClosedEventHandler(frmHFRFiles_FormClosed);
form.Show(this);
Hide();
}
Visual Studio flags frmHFRFiles_FormClosed as an error for the name does not exist in the current context.
ChildForm form = new ChildForm(this);
Then in ChildForm constructor:
MainForm m_MainForm;
Public ChildForm (MainForm mainForm)
{
m_MainForm = mainForm;
}
Then in closing event:
m_MainForm.button1.Enabled = false;
Ensure button1 is public
Here is what I did. I created a boolean variable in the main form and set the initial value to false.
private bool updateButtons = false;
The main form's constructor executes the search for files in the network folder.
public frmMainMenu()
{
InitializeComponent();
Shared.FilesForImport = GetHFRFiles();
}
The form's load event calls the EnableButtons() method
public void EnableButtons()
{
btnImportHFR.Enabled = Convert.ToBoolean(Shared.FilesForImport.Count);
btnImportHFR.Text = btnImportHFR.Enabled ? "Find Available HFR" : "No HFR For Import";
btnGetFacilityStatus.Enabled = Shared.sqlWrap.GetDataForFacStat(Shared.DsFacStat);
updateButtons = false;
}
The main form's visible changed event fires after the form load event. The network folder is not searched again because the updateButtons value is set to false.
private void frmMainMenu_VisibleChanged(object sender, EventArgs e)
{
if(updateButtons)
{
EnableButtons();
}
}
In the button click event, the updateButtons value is set to true after the main form is hidden.
private void btnImportHFR_Click(object sender, EventArgs e)
{
frmHFRFiles form = new frmHFRFiles();
form.Show(this);
Hide();
updateButtons = true;
}
The child form's closed event calls the Owner.Show() method
private void frmHFRFiles_FormClosed(object sender, FormClosedEventArgs e)
{
Owner.Show();
}
This causes the main form's visible changed event to fire. Only this time the EnableButtons() method will run because the updateButtons value is true.
private void frmMainMenu_VisibleChanged(object sender, EventArgs e)
{
if(updateButtons)
{
EnableButtons();
}
}
public void EnableButtons()
{
btnImportHFR.Enabled = Convert.ToBoolean(Shared.FilesForImport.Count);
btnImportHFR.Text = btnImportHFR.Enabled ? "Find Available HFR" : "No HFR For Import";
btnGetFacilityStatus.Enabled = Shared.sqlWrap.GetDataForFacStat(Shared.DsFacStat);
updateButtons = false;
}
Finally, the EnableButtons() method sets the updateButtons value to false.
It seems rudimentary to me, but it works. Thank you everyone for your feedback.
My problem is that when the main form is unhidden, I need to disable the button that opens the form to list files to import if there are not any files in the network share folder to be imported. There is also a line of code to change the button's text property informing the user there are not any files to import.
So your main form has a button X. If this button is clicked a method is called. This method will first hide the form, then show the subform until the subform is closed. The method should disable button X, change the button's text and unhide the form.
To make this flexible, we won't do everything in one procedure, we make several procedures with the intention of the procedure: "Inform operator there are no files to import" "Disable opening the subform", and of course their counterparts "Enable opening the subform", "Inform operator there are files to import"
TODO: invent proper method names
private void ShowNoFilesToImport()
{
this.buttonX.Text = ...;
}
private void DisableOpeningSubForm()
{
this.buttonX.Text.Enabled = false;
}
The advantage of this, is that if you later want to change the way that you want to inform the operator, for instance if you want to use an information field at the bottom of you screen, you will only have to change this in one place.
Furthermore, you can reuse the procedures, for instance you can add a menu item that will do the same as button X, this menu item can call the same methods
private void PerformActionsButtonX() // TODO: invent proper name
{
// Hide this form, and show the Subform until it is closed
this.Visible = false;
using (var dlg = new SubForm())
{
// if needed, set properties of the subForm:
dlg.Text = ...
dlg.Position = ...
// show the form until it is closed
var dlgResult = dlg.ShowDialog();
this.ProcessDlgResult(dlgResult, dlg);
}
// Show that there are no files to Import and disable OpeningSubform
this.ShowNoFilesToImport();
this.DisableOpeningSubform();
// Finally: show this form:
this.Visible = true;
}
And of course call this method when ButtonX or menu item Y are clicked:
private void OnButtonX_Clicked(object sender, ...)
{
this.PerformActionsButtonX();
}
private void OnMenyItemYClicked(object sender, ...)
{
this.PerformActionsButtonX();
}

Quitting WPF Application after Window Closed

I have a method in class where I call loginWindow.ShowDialog(); which brings up a Window, however when you press Close (X in top right) it doesn't Quit the application, rather continues to run whatever is below loginWindow.ShowDialog(); in that method.
How am I able to quit the application entirely if that Window is closed?
I tried to use:
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
System.Windows.Application.Current.Shutdown();
base.OnClosing(e);
}
Although this didn't shut the application down, which confuses me. When I was using loginWindow.Show(); this wasn't a problem.
I don't know how your application runs, based on your sample code I have two solutions.
Solution 1:- Every window has DialogResult property. Inside the OnClosing event assign DialogResult = true; and call the Shutdown method. The windows who is responsible to call will get the result from return value of ShowDialog() method
For example:-
private void SecondWindow_OnClosing(object sender, CancelEventArgs e)
{
DialogResult = true;
System.Windows.Application.Current.Shutdown();
}
Below event, is from the First screen, calling the Second Window.
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondWindow secondWindow = new SecondWindow();
var dialogResult = secondWindow.ShowDialog();
if (dialogResult.HasValue && dialogResult.Value == false)
{
// any code of yours which must not be executed after the second
// window has closed the process
}
}
Once, the DialogResult is assigned true, the first window will check only if it is false execute the below code or else ignore.
Solution 2:- We will get the Current Application Running Process and Kill the whole process that is your whole application.
private void SecondWindow_OnClosing(object sender, CancelEventArgs e)
{
Process.GetCurrentProcess().Kill();
}
There is a shutdown mode that you can define in the App.Xaml
The default option is OnLastWindowClosed. If it is OnExplicitShutdown than the application wants you to call Application.Shutdown(). What this means is, if you close all windows the application is still running because it is expecting a Application.Shutdown() to be called. This is an explicit shutdown.
Other two options are implicit meaning the Application.Shutdown() method will be called when the last window is closed or when the main window is closed.
Can you check what option you have defined?

Click button and open same window again

In my WPF application, I have one main window (Window.xaml). Which has a button, if user click the button we want to open same window again(Window.xaml). Once again the user clicks the same button we want to open the same window again.
so how do I open the same window again?
You can create new instance of your current window in button click event and achieve it.
Code snippet:
private void button_Click(object sender, RoutedEventArgs e)
{
var currentWindow = new Window();
currentWindow.Show();
}
You have to create a new instance of the window (e.g. MainWindow class) and call the show method.
Just some pseudo code:
void Button_clicked()
{
new MainWindow().Show();
}

Prevent to close parent window if child windows are active

I am developing multiple instance WPF application. Application has a grid in a main screen and on double click of grid row, it opens child window. It has also functionality to open multiple child windows on double click of grid row from main screen.
Can anybody help me to prevent parent window to be close if child windows are active? So user can not able to close main window if child windows are active.
Set Owner property for those childs to Main Windows:
private void Button_Click(object sender, RoutedEventArgs e)
{
var wnd = new Window();
wnd.Owner = this;
wnd.Show();
}
Then in Main Window closing event handler:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (this.OwnedWindows.Count > 0)
{
MessageBox.Show("Child windows exists, you have to close'em first");
e.Cancel = true;
}
}
As a final point it could be helpful for you to know that you can get from anywhere in your code the app main windows with this:
System.Windows.Application.Current.MainWindow
So if you are using MVVM the above will help you in setting the Owner property.
You have two options:
1- You can use ShowDialog() to open the child window, but user can't interact with the parent window till the child is closed.
2- You can check all windows that are currently opened by checking
Application.Current.Windows
and then you can determine whether you want to close your window or not
Edit:
add the following event handler to your Parent.Closing event
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
foreach (var item in Application.Current.Windows)
{
Window window = item as Window;
if (window.Title == "YourChildWindowTitle")
{
// show some message for user to close childWindows
e.Cancel = true;
break;
}
}
}
In window closing command pass that if the child window is open disable closing functionality.
Or
you what you can do is make canexecute = false when a pop up is open and closing command is triggered.
Attach a function to the main window's 'Closing' event, and check to see if the child window is open. if it is, set
e.cancel = true;

Categories