How do I show windows sequentially in WPF? - wpf

I have the following code in App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
var window = new WelcomeWindow();
if (window.ShowDialog() == true)
{
var mainWindow = new MainWindow();
mainWindow.ShowDialog();
}
}
The second window never shows. Instead, the application simply closes when the Welcome window is closed. How do I ensure a second window can be shown after a first one is closed?

This is because default value of Application.ShutdownMode is OnLastWindowClose. This means when your WelcomeWindow is closed the application shuts down and you see nothing more.
To solve this set ShutdownMode to OnExplicitShutdown and call Shutdown explicitly if you want to exit your app.
public App()
{
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
}

What about to show WelcomeWindow on Initialized event of MainWindow and close last if Dialog is not true. This was you let MainWindow to stay the MainWindow of Application.
private void Window_Initialized(object sender, EventArgs e)
{
// at this moment MainWindow is Initialized but still nonvisible
if ((new WelcomeWindow()).ShowDialog()!=true)
{
this.Close();
}
}
When you load any window Application_Startup it become The MainWindow of application. And it will closed on this window closing.
I've checked that even if you have StartupUri="MainWindow.xaml" in you app.xaml it have no effect if some else window have been shown on Application StartUp event.
You may do it yourself. Just make breakpoint on your firstloaded window Loaded event handler and look in debuger on "Aplication.Current.MainWindow == this" expression result. It will be true.

Related

(WPF) Does .Close() method releases the window instance?

I'm creating a new window in On_Click method. First I tried this;
public partial class MainWindow : Window
{
CustomerOperations customerOperationsWindow;
public MainWindow()
{
customerOperationsWindow = new CustomerOperations();
InitializeComponent();
}
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
customerOperationsWindow.Owner = this;
customerOperationsWindow.Show();
}
}
It's not working so I started creating the window instance every time the user clicks on the Customers button. And I used the following codes.
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
CustomerOperations customerOperationsWindow = new CustomerOperations();
customerOperationsWindow.Owner = this;
customerOperationsWindow.Show();
}
In the new window, If user clicks to Main button, I want to navigate to main window.
private void btnMain_Click(object sender, RoutedEventArgs e)
{
this.Close();
this.Owner.Show();
}
First question: Does this.Close() releases the window instance?
Second question: Is this usage correct?
What do you think is the best practice?
Thank you all.
Window.Close() will dispose all resources allocated by the instance. That's why you cannot show it again once it was closed.
If you want to reuse the same Window instance, you should cancel the closing procedure to prevent disposal of internal resources and collapse the Window instead (by setting Window.Visibility to Visibility.Collapsed - Visibility.Collapsed is also the default value of an instantiated Window before Window.Show() is called).
Alternatively hide the Window by calling Window.Hide() (which will set the Visibility to Visibility.Hidden) instead of Window.Close().
Calling Window.Show will also set the window's visibility to Visibility.Visible.
As a matter of fact, showing a Window by setting Window.Visibility is the asynchronous version of Window.Show().
Generally, you switch between Window instances by using the Window.Activate method. Calling Window.Show on a Window that is currently showing/visible, does nothing.
public partial class MainWindow : Window
{
CustomerOperations CustomerOperationsWindow { get; }
public MainWindow()
{
InitializeComponent();
this.CustomerOperationsWindow = new CustomerOperations();
// Consider to move this logic to CustomerOperations class,
// where you can override the OnClosing method instead of subscribing to the event
this.CustomerOperationsWindow.Closing += CollapseWindow_OnClosing;
}
// Cancel close to prevent disposal and collapse Window instead
private void CollapseWindow_OnClosing(object sender, CancelEventArgs e)
{
e.Cancel = true;
this.CustomerOperationsWindow.Visibility = Visibility.Collapsed;
this.CustomerOperationsWindow.Owner.Activate();
}
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
this.CustomerOperationsWindow.Owner = this;
// Calling Show will set the Visibility to Visibility.Visible
this.CustomerOperationsWindow.Show();
}
}
Creating a Window instance allocates unmanaged resources. If this happens very frequently, you will keep the garbage collector busy. From a performance point of view you may want to avoid it and prefer to reuse the same instance.
In a common scenario this is not necessary. But since Window exposes a Hide() method, you may consider to use it instead of Close().
If you want to switch to the parent window, you can use the code this.Owner.Activate(); and if you want to close the current window, first this.Owner.Activate(); and then this.Close();.
When you enter this.Close(), the compiler does not execute the following lines after reaching it. And when a sample window still exists there is no need to recreate it
private void btnMain_Click(object sender, RoutedEventArgs e)
{
this.Owner.Activate();
this.Close();
}

Show() window wait for a button to be pressed and mainWindow active (WPF)

InteractiveWindow contain YES and NO button. The current solution is displaying the InteractiveWindow on MainWIndow without having access to MainWindow. InteractiveWindow is also a Window (not a UserControl). How is possible to transform my dialog window in order to have my InteractiveWindow on top of my MainWindow and be able to access MainWindow until one of the two buttons are pressed?
internal async Task<bool> Test()
{
// some code
var test= new InteractiveWindow();
test.Owner = this;
test.ShowDialog();
// some other code
return true;
}
Old code for one of the button:
private void YES_Click(object sender, RoutedEventArgs e)
{
GetWindow(this).DialogResult = true;
this.Close();
}
You should use
test.Show()
instead of test.ShowDialog(), because ShowDialog() is blocking. Even though your method is async, it executes synchronously until it needs to await an incomplete Task, so your Test method is blocking because there is no such await statement. I suggest you remove this async modifier if you don't use it.

How to enable button on Main Window when secondary window is closing or get closed? - WPF VB.NET

I have two windows. Main Window & Window1.
On Main Window, there is a button1. When it is clicked, it gets disabled and open Window1. But i want to enable button1 on Main Window when Window1 is closing or get closed.
Create A Public Button in Window1
public Button mainBtn ;
on mainWindow in the button click event
private void button_click(object sender , RoutedEventArgs e){
Window1 win = new Window1();
this.button.IsEnabled = false;
win.mainBtn = this.button;
win.Show();
}
add on closing event to Window1
private void Window_closing(object sender , CancelEventArgs e){
mainBtn.IsEnabled = true;
}
the idea is to pass the MainWindow Button to the Window1 Button
then you can control it as like you want .
I guess you are using WinForms. In that case you have an event handler for the click on button1:
private void OnButton1Clicked(object sender, ...)
{
// show window 1
}
Now there are two methods to show a Form. You can show it as a modeless dialog box or as a modal dialog box.
Modal dialog boxes, which require the user to respond before continuing the program
Modeless dialog boxes, which stay on the screen and are available for use at any time but permit other user activities
Most dialog boxes you see are Modal: If you press file save, you'll have to finish the Save-File-Dialog box before you can continue editing.
The modal dialog box is the easiest
- Show them using using Form.ShowDialog.
- ShowDialog returns when the form is closed.
If you use a modal dialog box your code would look sequential:
private void OnButton1Clicked(object sender, ...)
{
using (Window1 window1 = new Window1())
{
// if needed window1.SetValues...
var dlgResult = window1.ShowDialog(this);
// if here, window 1 is closed
if (dlgResult = DialogResult.OK)
{ // ok button pressed
// if needed: window1 read resulting values
}
} // because of using window 1 automatically disposed
}
However if window1 is shown as a modeless dialog box, window1 will have to tell others that it is closed. Use event Form.Closed:
private Window1 window1 = null;
private void OnButton1Clicked(object sender, ...)
{
if (this.window1 != null) return; // window1 already shown
this.window1 = new Window1())
this.window1.Closing += this.OnFormClosed;
}
private void OnFormClosed(object sender, FormClosedEventArgs e)
{
Debug.WriteLine("window1 closed");
if (this.window1.DialogResult = DialogResult.OK)
{
// process dialog results
}
this.window1.Dispose();
this.window1 = null;
}
Data Binding is the strongest tool in WPF:
Add the button and bind the IsEnabled property to a public property in your view model or code behind. In the secondary window - when closing - update the property to reflect the new state.
Do not forget to implement INotifyPropertyChanged

App xaml assumes the first window instantiated is the main window (showdialog is ignored), I need to show multiple windows

I have the following code in my App.xaml.cs
private void App_Start(object sender, StartupEventArgs e)
{
if ( CompletedInstall())
{
//using show to allow for pacifier if loading is slow
var manager = new WINServiceConfig();
MainWindow = manager;
manager.ShowDialog();
}
}
private bool CompletedInstall()
{
var window = new Initialize();
window.ShowDialog();
return window.DoLaunchManager;
}
and the following in the App.xaml
<Application x:Class="Manager.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_Start">
When i comment out the line that checks CompletedInstall() the manager.ShowDialog() works fine, and my configuration window shows.
When CompletedInstall() is called the call to manager.ShowDialog() returns right away without displaying the window. I added the main window on the assumption that somewhere along the line someone decided an app should only show one window.
I found a workaround by setting the main window before calling CompletedInstall
private void App_Start(object sender, StartupEventArgs e)
{
var manager = new WINServiceConfig();
MainWindow = manager;
if (CompletedInstall())
{
manager.ShowDialog();
}
but this forces me to develop WINServiceConfig (specifically the constructor) based on its use, because it cannot count on the prerequisites being completed. This is bad form. What else can i do to get around this problem?
Dummy window? That can't be the best answer. Can it??
You should set the ShutdownMode to OnExplicitShutdown (at least while showing the initial dialog).

WPF usercontrol showdialog problem

There is a MainWindow, a usercontrol which is located in my MainWindow and a OtherForm which I am going to show from usercontrol. I sent OtherForm as parameter from MainWindow to usercontrol. And in usercontrol I am calling OtherForm.showdialog. When I show it the second time, I am getting "Cannot set Visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after a Window has closed" problem.
Code
In MainWindow class
void Example()
{
usercontrol.Load(new Otherform{ variable= 1 });
}
In Usercontrol class
private Window _form;
public void Load(window form)
{
_form=form;
}
void ExampleInUSerControl
{
_form.VerifyAccess();
_form.Activate();
_form.ShowActivated = true;
_form.ShowDialog();
}
The error message in this case is pretty accurate: once a Window is closed, it's closed for good. Since ShowDialog() always closes the window, you need to create a new instance of the window every time you call ShowDialog().
One fairly simple way to accomplish this in your example is to have the Load event take an argument of type Func<Window>:
In the MainWindow:
private Window MakeWindow()
{
return new MyWindow();
}
private void Example()
{
usercontrol.Load(MakeWindow);
}
In the user control:
public void Load(Func<T> makeWindow)
{
_form = makeWindow();
...
}
Note, by the way, that there should be no reason to call Activate or set ShowActivated - ShowDialog will do all that. And I don't know why you'd call VerifyAccess either.

Resources