It appears that second windows are not closing. Here is what I am doing....
I have created a new WPF project.
I placed a button in the main window.
I put the following code in the button to launch a second window and hide the main.
private void button1_Click(object sender, RoutedEventArgs e)
{
var projectWindow = new NewProjectInfo();
this.Hide();
projectWindow.Show();
}
-The new window is a blank window with nothing on it.
-In the "close" event of the new window I put the code to show the main window again.
private void Window_Closed(object sender, EventArgs e)
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
If I run the program and close the main window without opening the second window, the programs ends like I would like it to.
If I click the button on the main window, taking me to the second window, then close that window, taking me back to the main window, then close the main window the program does not end. (meaning I have to hit the stop button in visual studio to get it to end)
It's like visiting the second window leaves some kind of process running.
So, when I close the main window I can just run the:
Application.Current.Close();
But is that safe? Do I run the chance of leaving something hanging? Or is there a better way to close that second window so when I close the main the program will end?
These lines
var mainWindow = new MainWindow();
mainWindow.Show();
create a new MainWindow and show it. The original MainWindow is still hidden.
To resolve your problem, you need a reference to the original MainWindow instance.
Perhaps you could pass this reference when you build your secondary window
// Create a NewProjectInfo instance and pass this
var projectWindow = new NewProjectInfo(this);
this.Hide();
projectWindow.Show();
And in the constructor of the projectWindow, save the reference passed in a global var
var MainWindow _originalReference;
public NewProjectInfo(MainWindow original)
{
_originalReference = original;
}
now the window close event could use the referenced window
private void Window_Closed(object sender, EventArgs e)
{
_originalReference.Show();
}
Instead of creating a new Main window, can you simply call Application.Current.MainWindow.Show(); in your closed event handler?
Related
I have an issue that I am trying to resolve. I have two WPF windows. Those windows house the pages with content. My problem is not navigating page to page but rather window to window. here is an example of the code:
LoginPortal Design
<Grid>
<Frame x:Name="MainFrame" NavigationUIVisibility="Hidden"/>
</Grid>
LoginPortal Code
public LoginPortalMain()
{
InitializeComponent();
MainFrame.Navigate(new Uri("/Pages/LoginPortal.xaml", UriKind.RelativeOrAbsolute));
}
This is my Login portal that houses 4 buttons. Each button opens the second window which is houses several pages.
private void BtnSales_Click(object sender, RoutedEventArgs e)
{
var w = Application.Current.Windows[0];
w.Hide();
MainWindow mn = new MainWindow();
mn.Content = new SalesPage();
mn.Show();
}
When this button is clicked it opens the second WPF Window which is where several pages are housed. There is no problem with navigation. The problem starts when I wire the Closing event from the MainWindow to go back to the LoginPortalMain
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
LoginPortalMain lgm = Application.Current.MainWindow as LoginPortalMain;
lgm.Show();
}
It then goes back to the start again. Now my problem is if I click on the same button again. It just duplicates everything. Then on closing anything it just adds new windows. If I then exit out of any window, it throws an error in picture below. My question is, is there a way to either dispose of the navigation once the MainWindow is closed. So there is no duplicate windows once you close the mainWindow a second time. I have used navigation before on a single window but not on multiple windows.
I may have to rethink this whole structure and use custom UserControls and figure out the animation sequence from Pages to UserControls. However, any help would be greatly appreciated.
enter image description here
enter image description here
enter image description here
enter image description here
enter image description here
If you only want to be able to open one instance of the new window try showing and hiding a single window instance.
When the open window button is pressed create the window if need and show it.
private OtherWindow mOtherWindow;
private void OpenWindowButtonClick(object sender, RoutedEventArgs e)
{
mOtherWindow ??= new OtherWindow(); //initialize child window on first call
mOtherWindow.Show();
}
When the other window is closed hide it and cancel the close request. You could also reset the other window state here for the next time it is shown.
private void OtherWindowClosingEvent(object sender, System.ComponentModel.CancelEventArgs e)
{
((Window)sender).Hide();
Application.Current.MainWindow.Activate();
e.Cancel = true;
}
I ran into a weird case where Close event of the child window propagate to the parent window and causes it to close as well.
I made a minimum example as shown below
For TestWindow there is nothing but the default WPF window generated by VS
and in App.xaml.cs I override the OnStartup event and use it as a custom Main function
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
TestWindow t = new TestWindow();
t.ShowDialog();
}
Now if you click on the X button to close TestWindow, the application shuts down instead of showing the MainWindow. If you comment out t.ShowDialog then the MainWindow will show just fine. Next if you listen to the Closing event of MainWindow you will find that it will trigger after the TestWindow closes which doesn't seem right to me
It's not actually propagating, WPF runs your first dialog and upon closing notices that the process has no further windows present. WPF posts an application quit message for later processing. In the meantime your code has proceeded to display a further window which when processing the message pump encounters the quit message and so closes the window and terminates your app.
Debug log:
Information: 0 : App OnStartup
Information: 0 : new MainWindow
Information: 0 : MainWindow closing
Information: 0 : App exiting
To resolve, you need to remove the StartupUri and instead handle the Startup event.
Change:
<Application x:Class="WpfCloseProblem.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCloseProblem"
StartupUri="MainWindow.xaml"> ...
...to:
<Application x:Class="WpfCloseProblem.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCloseProblem"
Startup="Application_Startup">
Then discard the code on OnStartup and instead define a handler for Startup:
//protected override void OnStartup(StartupEventArgs e)
//{
// base.OnStartup(e);
//
// TestWindow t = new TestWindow();
// t.ShowDialog();
//}
private void Application_Startup(object sender, StartupEventArgs e)
{
var main = new MainWindow();
TestWindow t = new TestWindow();
t.ShowDialog();
main.Show();
}
Previously I was able to confirm that after the dialog closed, MainWindow was created; loaded and closed in quick succession.
The way App works here is it chooses the first started window as the main window. So in your case, the TestWindow will be chosen as the main window. The ShutdownMode in your code is somehow set to OnMainWindowClose. So after closing TestWindow, all child windows (including your MainWindow) have their Closing fired.
So the problem here is not propagating up, but propagating down the closing event.
You should not create any window before your main window actually being started first. Or if you want, you can set ShutdownMode to OnLastWindowClose.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose;
TestWindow t = new TestWindow();
t.ShowDialog();
}
Or you can set the MainWindow explicitly in the constructor of your main window:
public MainWindow(){
InitializeComponent();
Application.Current.MainWindow = this;
}
However if using ShowDialog(), there is no way for you to set the MainWindow explicitly. Because right after closing the TestWindow (at that time it's still main window), the whole app will be shutdown.
Edit:
I don't find any reference about this but it can be checked and we can be sure about that, here is the debugging:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new TestWindow();//not even need to be shown
var wm = Application.Current.MainWindow;// points to the new TestWindow
//If there is not any Window init here, the MainWindow is just null
}
I have a WPF project were I am using multiple WPF windows.
My WPF Windows are:
MainWindow
Window1
Login
I have to case scenarios, in the first one everything works fine but in the second I get a null reference exception.
First Scenario:
App.xaml is configured so as startup window to be MainWindow.
When user clicks on Button on MainWindow he is forwarded in Window1 were I have the following code:
MainWindow obj=(MainWindow)Application.Current.MainWindow;
private void button1_Click(object sender, RoutedEventArgs e)
{
obj.checkBox1.IsChecked = false;
}
2.Second Scenario:
App.xaml is configured so as startup window to be Login Window.
Code in Login:
private void button1_Click(object sender, RoutedEventArgs e)
{
var window=new MainWindow();
window.Show();
this.Close();
}
In this scenario when I click on button in Window1 a null reference exception is thrown for obj.
What is the difference in the initialization of MainWindow in these 2 cases that causes the exception in the 2nd case and how can I overcome it?
Well, the first Window being opened when you start the application, will become the window you get back when calling Application.Current.MainWindow.
In your case, that is Login, but in Window1 you expect it to be MainWindow, which is wrong. Since Login has been closed, you get null back, and the app crashes.
To fix this you have to make MainWindow the MainWindow :-)
You can do that in Login like so:
var window = new MainWindow();
Application.Current.MainWindow = window;
window.Show();
this.Close();
The this.Close() on your Login window in scenario 2 will close the application as this is the window being pointed to in your app.xaml file as the startup window. See the MainWindow property
MainWindow is automatically set with a reference to the first Window object to be instantiated in the AppDomain.
In the first scenario you don't close the MainWindow so the application continues. In the second one you close the Login window so the application exits.
In the first scenario you don't show where the user is forwarded to window1. It would be helpful to see that code as well.
My application is of such a nature that I need to jump around many windows consecutively. From my menu window I need to open another window (from the selection) and the disable or close the menu window.
What I'm currently using is window.show and then this.close() method to close the menu window.
Ex:
private void MainMenuControl_Link1MouseDown(object sender, RoutedEventArgs e)
{
// Utilities
UtilitiesMenyWindow UtilitiesMenyWindow = new UtilitiesMenyWindow(); // Assign Variable to window
UtilitiesMenyWindow.Show(); // Open window
this.Close(); // close current window
}
Then from within the new windows I just reopen the MainMenu window using the same method.
private void Utilities_Link3MouseDown(object sender, RoutedEventArgs e)
{
// Return to Main
MainMenuWindow MainMenu = new MainMenuWindow(); // Assign Variable to window
MainMenu.Show(); // Open Main window
this.Close(); // close login window
}
I then also keep a public variable class with static variables to store all the variables that are generic to all the windows.
All this is working fine for me except for one snag. If I were to call the UtilitiesMenyWindow from another window (not MainWindow) it's going to return to the MainMenu instead of the window I opened it from.
Is there a easier more generic way to return to the window that opened the secondary window without having to tell it to close itself and open a specific window (in this case it's "hardcoded" to MainMenu) (Obviously I first open and then close)
I was looking at the Unloaded event but how do I get the original window to stay hidden until this event occurs without it having to sit there and wait in a loop which is not a good idea.
Maybe somebody can guide me in a way to set it up as an automatic event that "fires" the event-handler, which in turn then activates the previous window?
Rather than closing windows, you could consider hiding them. That way, you could pass a reference to the calling window whenever you create a new window.
i.e.
UtilitiesMenyWindow UtilitiesMenyWindow = new UtilitiesMenyWindow();
UtilitiesMenyWindow.CallingWindow = this;
UtilitiesMenyWindow.Show();
this.Hide();
then, when you want to close the new window and return:
this.Hide();
this.CallingWindow.Show();
You could just close the original window - since all your windows are probably inheriting from Window class you just need to store the current window in a 'Window' typed variable on the utilities menu
This way you can continue doing what you are doing:
e.g.
private void MainMenuControl_Link1MouseDown(object sender, RoutedEventArgs e)
{
// Utilities
UtilitiesMenyWindow UtilitiesMenyWindow = new UtilitiesMenyWindow(); // Assign Variable to window
UtilitiesMenyWindow.ReturnWindow = this;
UtilitiesMenyWindow.Show(); // Open window
this.Hide(); // hide current window
}
And add
Window _returnWindow;
on your utility window class
Then in that class on the close method you can call the original window type:
private void Utilities_Link3MouseDown(object sender, RoutedEventArgs e)
{
// Return to original
_returnWindow.Show();
this.Close(); // close login window
}
This is of course assuming you don't kill the original window
What I need is such an event handler in my window class.
void someEventHandler(object sender, RoutedEventArgs e)
{
MyNewWindow mnw = new MyNewWindow();
mnw.Owner = Window.GetWindow(this);
mnw.ShowDialog();
this.Close();
}
Window.GetWindow(this) returns the parent window of the current window.
I had thought when the owner of the new window is the parent window of the current one, it would wait for the parent; and not the current one. But it did not work that way. Current window waits for the execution of the new and closes only after.
If I use Show() instead of ShowDialog() for some reason the window is not shown at all.
Probably I need some delegate methods but I am not sure where to start.
Edit: I guess I need to improve the question for future references:
The new window should be a dialog to the parent window. If I use Show() the parent window becomes accesible and I dont want that. If I use ShowDialog() it becomes a dialog to the current window, meaning that the current window does not close until the new window is closed, and I dont want that either.
Closing a window causes any windows that it owns to be closed.
If you just want the owner window to not be visible, try this;
void someEventHandler(object sender, RoutedEventArgs e)
{
MyNewWindow mnw = new MyNewWindow();
mnw.Owner = this;
this.Hide(); // not required if using the child events below
mnw.ShowDialog();
}
You'll likely want to hook up some event in the parent window that acts accordingly when you close the child window depending on your requirements.
EDIT
You could perhaps control the hiding of the (multiple parents) from the child;
void OnLoad(object sender, RoutedEventArgs e)
{
this.Owner.Hide();
}
void Closed(object sender, RoutedEventArgs e)
{
this.Owner.Show();
}
If I understand what you're trying to do you want to close the current window and replace it with a MyNewWindow that is a child of the window that was the original window's parent (probably the app's main window).
To do that you should be using:
mnw.Owner = this.Owner;
instead of calling GetWindow, which gives you back the current Window instance. The purpose of GetWindow is to obtain the Window which contains some other UIElement, like a Button farther down the tree. When passing in a Window instance, you just get back what you passed in.
Calling ShowDialog() blocks. That means, the method returns only when mnw is closed and only then is the original window closed.
If you change that to Show(), mnw is closed as soon as you call Close() on the original window. because Window.GetWindow(this) returns this. Thus, you set the owner to this and when you close this, mnw gets closed too. That leaves us with:
MyNewWindow mnw = new MyNewWindow();
mnw.Owner = this.Owner; // may not be necessary
mnw.Show();
this.Close();
This code seems to work for me.