WPF parent-child window: binding reference problem - wpf

I have a WPF Window that open a modal child window to load some data. Both window have a own viewmodel, now I have this problem: after I close the child window it seems still running in background!
To close the child window I set DialogResult from viewmodel command; now, if I create a new data and then I edit it from parent window (with the child window closed before), the child window still capture the property changed event for the properties previously bind.
How can avoid this?
I would clear every reference with data when I close modal window. Which is the best practise to do it?

Ensure that you don't keep any references to your window, even an indirect one. One of the most common cause of leaks are events. If a window B is adding an event handler to an event of window A, B won't be released until A is also.
For example, if you're directly listening to property changes, you should use the Weak Event Pattern and replace all your += with a call to PropertyChangedEventManager.AddListener. In general, every strong handler you add to an event should be removed to avoid leaking.
More information about leaks in .NET in this MSDN article.
You can use a memory profiler like Scitech's mem profiler or Jetbrains dotTrace to see what ojects are keeping your windows in memory.
Edit: In response to your comments, your case is really simpler than I first thought: the Garbage Collector simply didn't collect the window yet. Adding GC.Collect on Test_Click for testing purposes solves the issue.
Here, remove the SelectionChanged event from the ComboBox when the form is closing so you can let the GC do its job and reclaim the form later without having problems. If you really need the whole form to get released right now, you might consider calling GC.Collect although you should avoid it when you can.
Edit 2: In response to your third comment, it should only matters for objects that are shared between views, and where the changes in the view will change something back in a shared object. In your test project the SelectionChanged does nothing on the original list so it doesn't really matter if the event is raised or not. The form will get collected eventually.

Related

How to dispose of dynamically loaded usercontrols/viewmodels when parent window is closed

We have a main window that launches a child window. That child window dynamically loads custom usercontrols. In the contructor of these usercontrols, I pass a master object which, from this master object, a usercontrol specific viewmodel is generated and assigned as its datacontext.
All of this is working quite well. However, I jst discovered that when I close the child window at least some of my custom usercontrols are still active. How am I supposed to clean up my controls/viewmodels? Nothing seems to get called until the main window is closed. No destructor, no Dispatcher.ShutdownStarted, no dispose is available, no closing event, nothing I can find.
Anyone know what is supposed to be done to properly clean up after the window is closed?
I believe you need to think precisely about what is responsible for creating your views and your viewmodels, and what is responsible for determining whether or not something can close or not, etc.
It is usually a good idea for whatever that created something to destroy it. Therefore, if your child window is creating custom user controls it perhaps should be responsible for removing them. However, I believe if none of your objects has a reference (or strong event subscription) it should be eventually garbage collected. You could implement a finalizer/destructor and output a Debug.String to the output window to see when this might eventually happen. A good memory profiler could also be a good idea. However, it is also likely that you need more precise control of telling your ViewModel when it has been closed.
It's hard to say exactly what should happen in your scenario because it really depends on your exact and specific setup. Let me describe to you a scenario I had in my application. I had several views that were being displayed in tab pages. The tab pages had an X button to close the tab, and my View contained a hosted Windows Forms control that needed to have .Dispose() called to clean up resources as well as it needed to be informed of when to unsubscribe from composite commands in the file menu system. So, initially, I had a problem... how does my ViewModel unsubscribe from commands when the tab pages remove's the view? How does the View which is contained in a WPF control know when it has been removed? here's what I came up with
The tab page itself should not be telling my program if a view can or can not be closed
I needed the ability to cancel the closing event in case of program logic (File saved? Yes/no/cancel)
I needed the ability to detect when it was closed so I could cleanup/unregister at that exact moment
My solution was to implement an interface in my viewmodel called IRemovable which exposed a Removable boolean and a Remove() method which returns a boolean (was removed or not). My tab control only displayed the X button if Removable was true, Tab Control's Closing fired the Remove() of the IRemovable ViewModel and if it returned false it set the event args Canceled property to true if the ViewModel's Remove returned false.
Therefore, the remove of the view model could prompt the user for confirmation, unregister from commands, etc. The view could handle Closed event and call Dispose on any Windows Forms components etc. (of course I had to check if my View.DataContext is IRemovable).
Anyway, I know this isn't an exact answer but hopefully it helps you come up with some thoughts on how to solve your own problem

Exiting an App or Closing a Control When Using MVVM

In my WPF application, I am using the ViewModelLocator without IoC. I am calling the static ViewModelLocator.Cleanup() method provided by the MVVM-Light framework from my own button which is tied to a "close window command". This Command calls the static ViewModelLocator.Cleanup(), which calls an instance Cleanup() method on my MainWindowViewModel instance. The instance Cleanup() method then sets the property to which the MainWindow binds its DataContext, to null. The setter on the property raises a PropertyChanged event. Curiously, setting this property to null does not cause the window to close.
I am trying to understand why this is the case? If I set the MainWindow's DataContext to null, should that not be the same as Window.Close()? In my case, the Window and all of its elements remain on the screen. However, if I attempt further actions, I get null pointer exceptions, indicating the DataContext binding Property has indeed been set to null; this has also been confirmed in the debugger.
I have created a workaround by hooking the Application.Exit event and issuing a Window.Close() in the event handler in order to create my own "Close Window" button (ie, to create same functionality for my own Button / Command as clicking the X button in the upper right of a Window). Since calling a UI element (ie, the Window instance) from MVVM directly is not MVVM friendly, I used a ViewService to implement the Window.Close() functionality in order to keep the workaround MVVM friendly. I am a big fan of the ViewService idiom (or pattern), but I just don't think it should be necessary here; except, I could see how exiting the app is a special case that perhaps should tie-in with the application lifecycle, and .Net seems to only allow exiting a WPF app by issuing the Window.Close() method.
Thoughts appreciated.
I believe I have found the answer to my original question, in addition to the one raised in my comments discussion with flq.
First, the answer to the original question is that the proper way to close the Window is along the lines of what I did in my described "workaround". Closing an app is a View-initiated process, as it is the Window control that has the bits for how to do it. You can of course hook the Application.Exit event so that you can perform cleanup on your ViewModels, prompt the user to save data, etc..
The question raised by me after some interesting discussion with flq is, if I don't just set a control's DataContext (ie, ViewModel) to null in order to release the View and ViewModel resources, how should I do it?
An interesting discussion with some nuances can be found here, but the basic answer is that you find the parent control and remove the control you want to close from its Children list. Note, this is a different technique with a different goal than just making the control not visible by setting is Visibility property to Collapsed. In the following example, "this" is the control to be removed (ie, "Closed"):
Panel p = (Panel) this.Parent;
p.Children.Remove(this);
I am not sure if you still need to then set the child (ie, "this") to null to re-claim its resources, or, if just removing it from the visual tree will cause WPF to re-claim the resources; the above linked discussion makes no mention. As mentioned in the original discussion, the above technique can be supplemented by hooking it to certain events, or using other application specific logic.

MDI WinForm application and duplicate child form memory leak [duplicate]

This question already has answers here:
About PropertyStore and MDI child form
(2 answers)
Closed 2 years ago.
This is a WinForm MDI application problem (.net framework 3.0). It will be described in C#. Sorry it is a bit long because I try to make things as clear as possible.
I have a MDI application. At some point I find that one MDI child form is never released. There is a menu that creates the MDI child form and show it. When the MDI child form is closed, it is supposed to be destroyed and the memory taken by it should be given back to .net. But to my surprise, this is not true. All the MDI child form instances are kept in memory. This is obviously a "memory leak". Well, it is not a real leak in .net. It is just that I think the closed form should be dead but somehow there is at least one unknown reference from outside world that still connect with the closed form.
I read some articles on the Web. Some says that when the MDI child form is closing, I should unwire all the event handlers, otherwise some event handlers may keep my form alive. Some says that DataBindings should be cleaned before the form is closing otherwise the DataBindings will add references to some global Hashtable and thus keep my form alive.
My form contains quite a lot things. Many event handlers and many DataBindings and many BindingSources and few suspected controls containing user control and HelpProvider. I create a big method that unwires all the event handlers from all the relevant controls, clear all the DataBindings and DataSources. The HelpProvider and user controls are disposed carefully.
At the end, I find that, I don't have to clear DataBindings and DataSources. Event handlers are definitely causing the problem. And MDI form structure also contributes to something.
During my experiments, I find that, if you create a MDI child form, even if you close it, there will still be one instance in the memory. The reference is from PropertyStore of the main form. This means, unless the main form is closed (application ends), there will always be one instance of MDI child form in the memory. The good news is that, no matter how many times you open and close the child form, there will be only one instance, not a big "leak".
When it comes to event handlers, things become more tricky. I have to address that, all the event handlers on my form are anonymous event handlers. Here is an example code:
//On MDI child form's design code...
Button btnSave = new Button();
btnSave.Click += new System.EventHandler(btnSave_Click);
Where btnSave_Click is also a method in MDI child form. The above is always the case for various controls and various types of event. To me, this is a bi-directional circular reference. btnSave keeps a reference of MDI child form via the event handler. MDI child form keeps a reference of btnSave instance. To me again, such bi-directional circular reference should not cause any problem for .net's garbage collector. This means that I do not have to explicitly unwire the event when the form is being disposed:
btnSave.Click -= btnSave_Click;
But the truth is not so. For some event handlers, they are safe. Ignoring them do not cause any duplicate instance. For some other event handlers, they will cause one instance remaining in the memory (similar effect as the MDI form structure, but this time caused by the hanging event handlers). For some other event handlers, they will cause every instance opened in the memory. I am totally confused about the differences between these three types of event handlers. The controls are created in the same way and the event is attached in the same way. What is the difference? (Don't tell me it is the event handle methods that make difference.) Anyone has experience of this wired scenario and has an answer for me? Thanks a lot.
So now, for safety issue, I will have to unwire all the event handlers when the form is being disposed. That will be a long list of similar code for each control. Is there a general way of removing events from controls in recursive way using reflection? What about performance issue?
That's the end of my story and I am still in the middle of my problem. For any help, I thank you.
As long as the object that the event handler is wired to is declared in the child form you donĀ“t have to remove the event handler when the child form is disposed, but when the object that the event handler is wired to is declared outside the child form you must remove the event handler when the child form is disposed.
If this code is executed several times (and btnSave is an object not declared in the child form)
btnSave.Click += btnSave_Click;
This code has to be executed the same number of times
btnSave.Click -= btnSave_Click;
It might be that you are referencing the child form somewhere in the application, this reference must be removed before the garbage collector will remove the child form object.

What is UserPreferenceChangedEventHandler in C# winform applications?

I found some of my winform application controls, such as DataGridView and ToolStrips, are referred to by UserPreferenceChangedEventHandlers. I have no idea what setting of the controls will generate such references and why such references keep my control alive in memory. How can I remove such references from that event? Thanks.
It is the delegate type for the SystemEvents.UserPreferenceChanged event. This event fires when Windows broadcasts the WM_SETTINGCHANGE message. Which typically happens when the user uses a control panel applet and changes a system setting.
Several controls register an event handler for this event, DataGridView, DateTimePicker, MonthCalendar, ProgressBar, PropertyGrid, RichTextBox, ToolStrip, NumericUpDown. They typically are interested in font or cue changes and anything that would affect the layout.
SystemEvents.UserPreferenceChanged is a static event. Registering a handler and forgetting to unregister it causes a memory leak, it prevents the control from being garbage collected. The listed controls ensure this doesn't happen, they unregister the event handler in either the OnHandleDestroyed() or the Dispose() method.
You'll get in trouble when neither of those two methods run. That will happen when you remove the control from the container's Controls collection and forget to Dispose() it. While forgetting to call Dispose() is not normally a problem, it is a hard requirement for controls. It is easy to forget too, controls are normally automatically disposed by the Form. But that only happens for controls in the Controls collection.
Also be sure to call Dispose() on forms that you display with the ShowDialog() method, after you obtained the dialog results. The using statement is the best way to handle that.
One more excruciating detail is important about the UserPreferenceChanged event, it is often the one that deadlocks your app when you create controls on a worker thread. Typically when the workstation is locked (press Win+L). Which cannot come to a good end when you use the controls I listed, the SystemEvents class tries to raise the event on the UI thread but of course cannot do this correctly when more than one thread has created them.
Also the kind of bug that can have a lasting effect, a splash screen for example can get the SystemEvents class to guess wrong about which thread is your UI thread. After which it then permanently raises the event on the wrong thread. Very ugly to diagnose, the deadlock is well hidden.

WPF RichTextBox tab selection eating up system memory!

I have a TabControl in WPF / MVVM that is bound to an ItemsSource on top of an ObservableCollection. Each tab has its own collections and bindings with components such as Images, Richtextboxes, and user input boxes, and everything seems to work well.
However, I have noticed that each time I switch a tab, it uses about 100k of system memory which never gets reclaimed! If I hold ctrl-tab down to cycle through all tabs, I can use up 200 megs of memory within a minute.
Now - I created a blank WPF app with just a tab control, and it also uses memory for each tab switch (albiet MUCH less). Is this just some .NET bug, or a feature? Maybe it stores a breadcrumb trail, maybe its used for debugging (although I compiled in release mode).
How do I reclaim my memory? Or better yet, not lose memory to tab switchings?
This fixed the issue to me:
http://blingcode.blogspot.com/2010/10/memory-leak-with-wpfs-richtextbox.html
Basically add two attributes to each RichTextBox :) :)
IsUndoEnabled="False" UndoLimit="0"
You might want to check if there are any event handlers left behind.
In the case where you registered an event in other control, the garbage collector will not collect the objects that are no longer needed, because the event is still attached so to speak.
So if you registered Loaded somewhere in code behind
public ParentEditor()
{
InitializeComponents();
control.Loaded += OnControlLoaded;
}
or in XAML or the ParentControl
<Control Loaded="OnControlLoaded" />
You basically have two solutions to tackle this problem:
Solution 1 - Remove event handlers when they are no longer needed:
You might want to remove this handler in the unloaded of the parent control like so:
public ParentEditor()
{
InitializeComponents();
control.Loaded += OnControlLoaded;
this.Unloaded += OnParentUnloaded;
}
void OnParentUnloaded(object sender, RoutedEventArgs e)
{
//Remove unloaded event
this.Unloaded -= OnParentUnloaded;
//Remove event from child control
control.Loaded -= OnControlLoaded;
}
You can also use the Unloaded event of the child control of course.. that is up to you..
Solution 2 - Using the WeakEvent pattern:
Another solution for events would be the WeakEvent pattern, which bypasses this problem.
Why Implement the WeakEvent Pattern?
Listening for events can lead to
memory leaks. The typical technique
for listening to an event is to use
the language-specific syntax that
attaches a handler to an event on a
source. For instance, in C#, that
syntax is: source.SomeEvent += new
SomeEventHandler(MyEventHandler).
This technique creates a strong
reference from the event source to the
event listener. Ordinarily, attaching
an event handler for a listener causes
the listener to have an object
lifetime that influenced by the object
lifetime for the source (unless the
event handler is explicitly removed).
But in certain circumstances you might
want the object lifetime of the
listener to be controlled only by
other factors, such as whether it
currently belongs to the visual tree
of the application, and not by the
lifetime of the source. Whenever the
source object lifetime extends beyond
the object lifetime of the listener,
the normal event pattern leads to a
memory leak: the listener is kept
alive longer than intended.
In either case, good luck.. its quite hard to find leaks like the one you are experiencing!
Good advice, but in the end I decided a bindable textblock was more useful and simpler than a richtextbox. I never found out what was causing the leak - but it was definitely in the bindablerichtextbox code (OnInitialized was being called each time a tab switched, which was beyond my control).
The leaks are gone, and my app runs quicker because of the use of the simpler bindable textblock.

Resources