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.
Related
I have WPF application where I have changed the default entry point.
<Application x:Class="FrazerClient.App" Startup="AppStartup">
public void AppStartup(object sender, StartupEventArgs e)
{
// Does some minor work before an application window opens.
}
The minor work calls this a couple of times:
App.Current.Dispatcher.Invoke((Action)delegate
{
// Custom dialog window is opened
});
The second time this is called, App.Current becomes null. I am almost positive is has to do with the custom dialog window closing, but not really sure how to prevent the closing of the dialog window from nulling out App.Current when the last window closes.
This also prevents App.Current.Shutdown() from working.
Set ShutDownMode to OnExplicitShutdown so that closing the window does not automatically shutdown the application.
You usually do that in the Xaml of the application object
<Application x:Class="FrazerClient.App"
Startup="AppStartup"
ShutdownMode="OnExplicitShutdown">
Resolved with this code:
Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
I've got another Window besides my MainWindow in my Application and I override the closing-method like this because I don't want the Window to be fully closed:
private void Window_Closing(object sender, CancelEventArgs e)
{
e.Cancel = true;
this.Visibility = Visibility.Hidden;
}
then in the constructor:
public Inputwindow()
{
InitializeComponent();
this.Closing += Window_Closing;
}
But now if I want to close my MainWindow, it only hides the MainWindow.
Can't figure out, how to get it to work.
Every WPF application has a property called Application.ShutdownMode, which determines when the application actually ends. By default, it is set to OnLastWindowClose, which means that the application won't end until all windows are closed (even if the main window closes). It sounds like you want your application to end when the main window closes even if other windows are not closed, just hidden, which would correspond to the OnMainWindowClose mode. Here is the relevant MSDN documentation: https://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode(v=vs.110).aspx
To set the property in your xaml, open the App.xaml file and add the ShutdownMode property like this:
<Application x:Class="TestClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ShutdownMode="OnMainWindowClose">
</Application>
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
}
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
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?