Remove regions from module when window is closed - wpf

I have prism module which I loading in separate application window.
When I closing it and opening again, getting error that some region is already registered. It is child region from one of my views. To make it more clear, I have next hierarchy:
Shell
--RegionA
--View
--RegionB
--RegionC
So when I try to navigate to RegionA with View, I getting error that RegionB is already registered. I cannot complain, it is really registered on previous window load and regions wasn't removed.
I tried to add event handler to Closing event of window but at this moment IRegionManager.Regions collection is empty for some reason.
So I need a way to handle window close event and clear regions.

Related

Opening a dialog when all regions are loaded in Shell

I have a WPF application using Prism framework. It has three regions that gets loaded in shell. Now, I have a requirement for which have to display a dialog once the main window(all the regions) is loaded. i.e. dialog should display on top of main window. I tried to publish an event during shell initialization,however dialog display only when I close main window or if publish the event in one of region's usercontrol constructor, it displays the dialog first and when dialog is closed main window loads. Now, am thinking if there is any way I can find if all the regions are loaded through an event then I can publish the event there.
Questions:
1. Is there any event that I can use to detect if all the regions are loaded?
2. Is there any other approach that you can point me to to achieve this requirement?
Put this in the constructor of the parent control
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => {code that should be executed after all children are loaded} ));
Is there any event that I can use to detect if all the regions are loaded?
Override PrismApplicationBase.OnInitialized and call the IDialogService from there.

Trying to understand closed widgets or Where "closed" widgets goes?

I'm trying to archive a closable Composite custom widget. I'm studying the Window, Page and TabView classes.
The close() method from Window basically just hide the widget, The TabView listen for close Page event, then call to remove(page) method, this remove the page from the internal pane, but i don't found a kind of page.close(). So, what happened with closed widows and Pages? Still exist?
My own close() method must just call to hide() method and fire a close event just like Window does? This do not carry some memory leaks?
Widgets stay usable until you call widget.destroy(), but until then you are free to either hide them or remove them from their parent container. Once they have been removed from one container, you can reuse them and add them to another container altogether - in the days of IE6 this was a common requirement because it was faster to move unused widgets into a pool and reuse them than to create a new one from scratch (the widget will retain it's DOM elements until it is destroyed).
The close() method in Window is really just part of the semantics of using a Window - all it really does is remove or hide the Window widget and fire an event, so close() and open() are (almost) nothing more than nice API sugar to make life easy for the user.
OTOH Page doesn't need a close() method because adding and removing pages from the TabView is the entire concept.

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

Why isn't my WPF closing event being fired for system closes?

I have the following line in my Window stanza in the XAML file:
Closing="Window_Closing"
I originally thought that the web page here assured me that this event fires when you use the big X close method, Alt-F4 or close from the system menu yet that doesn't appear to be the case since my breakpoint on the Window_Closing() function isn't being hit.
It does hit the breakpoint when I do the File, Exit method of exiting so that's working okay.
Re-reading that linked page leads me to believe that it may not trigger the closing event.
My questions are:
How do you catch the three methods listed in order to detect if your file is dirty and needs saving? I have all the 'dirty' and file saving code done, I just need to know how to trap the events.
Can you stop the exit from taking place with that method (as you can by intercepting the closing event)? In other words, if the user says they don't want to exit because the accidentally used Alt-F4 on the wrong window, can it be done?
According to the documentation page for the Closing event:
If a session ends because a user logs
off or shuts down, Closing is not
raised; handle SessionEnding to
implement code that cancels
application closure.
Therefore you'll want to make sure you handle the SessionEnding event as well as the Closing event. The SessionEnding event could be used to automatically save the current state to a temporary file that will be loaded again the next time the application starts. But if you do want to prompt the user, you can do so with a modal dialog box in SessionEnding but they will likely see the Windows screen that warns about unresponsive applications, giving them the chance to kill the process without responding to your dialog.
Try the Closed event instead: Closed="Window_Closing"

WPF parent-child window: binding reference problem

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.

Resources