The thing is that WPF Window doesn't implement IDisposable interface which led me to believe, that I don't have to manually dispose of it when I open it by calling ShowDialog() but the first comment on this MSDN page states differently. Does anybody know what's the truth?
Only if you open the window using Show() instead of ShowDialog().
From the documentation:
If a window, opened by calling ShowDialog, and with a Button with its IsCancel property set to true, will automatically close when the button is either clicked, or ESC is pressed. If the window was opened using Show, however, Close must be explicitly called, such as from Click event handler for the Button.
and:
Closing a window causes the Closing event to be raised. If the Closing event isn't canceled, the following occurs:
The Window is removed from Application.Windows (if an Application object exists).
The Window is removed from the owner Window if the owner/owned relationship was established before the owned Window was shown and after the owner Window was opened.
The Closed event is raised.
Unmanaged resources created by the Window are disposed.
If ShowDialog was called to show the Window, ShowDialog returns.
How about the code below? implementing IDisposable on your form and removing all event handlers.
However, Is Microsoft already doing that on Close()?
Also does manual GC.Collect help?
Some references and related posts:
What is the correct way to dispose of a WPF window?
What is the correct way to dispose of a WPF window?
/// <summary>
/// Interaction logic for MyForm.xaml
/// </summary>
public partial class MyForm: IDisposable
{
public MyForm()
{}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Dispose();
}
public void Dispose()
{
try{
_resourcescollection.Clear();
_resourcescoll = null;
//close other resources
}
catch(exception ex)
{}
EventHelper.RemoveAllEventHandlers(_resources);
EventHelper.RemoveAllEventHandlers(_timer);
EventHelper.RemoveAllEventHandlers(_etc);
EventHelper.RemoveAllEventHandlers(this);
}
~MyForm()
{
Dispose();
}
}
Related
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.
I was wondering if there was a way to close a window when a property in the view model changes. In my situation I have a login window with an Ok button bound to a LoginCommand so that the function Login executes when Ok is clicked. If the login is successful, I want the window to close.
Now I know I could do this by adding an event handler on my button, which calls a function like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
DatabaseCredentialsViewModel vm = (this.DataContext as DatabaseCredentialsViewModel);
vm.Login();
if (vm.LoginSuccessful)
{
this.Close();
}
}
But I was wondering if there was a way to close the window when LoginSuccessful property changes without having an event handler on my button (I like working only with command binding and not having event handlers on Click event).
Thank you
Here's a similar question, which filled my need.
Basically, you use an attached property for your window, which binds to a bool? property on your VM. When the VM property is set to something non-null, the attached property sets the Window's DialogResult, which will automatically close the window.
If you want you can try this different approach.
You can do this by associating the OK button with a command. Create an event such as LoginSuccess and when then add a window.Close() to the list of event callback. Then you have only to raise the LoginSuccess event to close the windows.
In my opinion, this respect the MVVM pattern defining an event that can be used for other trigger and not only for closing windows.
You could do this fairly easily by creating an attached property or Behavior (from Blend SDK) that hooked into your Window.
I posted a sample behavior to the Expression Code Gallery which does something similar (though definitely different) - it prevents a window from being closed via a property on the VM. You could very easily adapt the code (included in the download) to just close the window on a property change.
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.
I dynamically create UserControls using Reflection:
UserControl myConmtrol = (UserControl)Activator.CreateInstance(t);
The UserControl may handle a Closing event but I do not know the name of the handler.
When the Window hosting the UserControl closes I remove the UserControl from its parent Window and it disappears from the Window: Everything seems OK.
But if I open and close again the UserControl I can see in the debugger the Closing event is handled twice, one time by the current UserControl but also by the previous UserControl that is still alive.
Theorically the UserControl being no longer referenced should be GarbageCollected.
How can I force it to be Killed/Deleted/Disposed ? At least is there a way to forbid it handles events ?
Thanks
Not sure without more detail but i would start and check if you have any event handlers that isn't removed
Do I need to remove event subscriptions from objects before they are orphaned?
Answer about removing handlers without knowing their names:
public void RemoveHandlerOfUserControl(UserControl uc)
{
MulticastDelegate dlg = MyEvent;
Delegate[] handlers = dlg.GetInvocationList();
foreach (Delegate d in handlers)
{
if (d.Target == uc)
{
this.RemoveHandler(MyEvent, d);
}
}
}
This method must reside in the object where the event is declared.
I had to cope with the same situation in Winforms where I dynamically create a user control inside another user control (Let's say a "DynControl" inside "HostControl").
There is no Closing event in "HostControl". So I used the Disposed event of HostControl to release resources :
this.Disposed += (s, e1) =>
{
DynControl.Click -= += new EventHandler(MyClickHandler);
this.Controls.Remove(DynControl);
DynControl.Dispose();
};
I have a simple two forms, one that contains a grid and a button. When I click the button, my application starts doing a long operation. While it is working, I show another form that contains a progress bar
I open it like this:
_busyWindow.ShowDialog();
And defined
public partial class BusyWindow : DevExpress.XtraEditors.XtraForm
{
public BusyWindow()
{
InitializeComponent();
}
private void BusyWindow_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true; // this cancels the close event.
}
}
When the operation is finished, I hide the form like this
if (ended)
_busyWindow.Hide();
It works fine. The problem is that when I close the second form (same closing code), it also closes fine but my main GUI loses the focus. For example, if I have the Firefox opened behind the application, then the Firefox gets the focus.
This only happens when I close the second form when the busyWindow has been opened, and no when it hasn't (ie, if I open the form, I close it without clicking on the button, then the main GUI doesn't lose the focus).
Do you know what is happening or where could I try to search?
There could be two possible solutions to enable you to keep focus on your main window:
//Edited: Main Window in the below example would be the window with Grid and Button.
Since you are showing the busy window via ShowDialog() try setting the owner of the window by this: _busyWindow.ShowDialog(this);. I had earlier faced a similar problem and this worked for me. Since you specify the owner of the busyWindow, when it closes it would put the focus back on its owner,i.e. your main window
In case the above technique doesnt work (it should, as it worked for me), you could try to pass the reference of the main window to the busyWindow and then on its close set the focus of the main window. Sample:
_busyWindow.MyMainWindow = this; //MyMainWindow references mainWindow of your app
_busyWindow.ShowDialog();
And the following at the FormClosing of busyWindow:
private void BusyWindow_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true; // this cancels the close event.
MainWindow.Focus();
}
See if it works. The first solution should work.
Hope it helps.
Thanks & Happy Windowing!
Just set child's window Owner = null before closing it