What is UserPreferenceChangedEventHandler in C# winform applications? - winforms

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.

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.

VisualState Binding threading issue

I have an audio recording app in Windows Phone 7.
The app allows a user to play the recorded sounds.
I try to stick to MVVM guidelines where it is possible.
I have a play/stop button in a list of all recordings. Each recording has its own ViewModel, which, besides all, also controls the look of the corresponding play/stop button.
The button has a custom visual state defined in its' style.
The Visual State is bound to the ViewModel's property using the approach, shown here:
http://tdanemar.wordpress.com/2009/11/15/using-the-visualstatemanager-with-the-model-view-viewmodel-pattern-in-wpf-or-silverlight/
Having implemented this approach, whenever I want to change the look of the play/stop button, I need to set the public string property (named "PlayStopVisualState") in my ViewModel to either "PlayingState" or "Normal", and that will assign an appropriate visual state to my button.
The problem is that when user presses the play button, a SoundEffectInstance is created in a background thread, which plays the sound. The thread then waits for the playing to end. When the recording playing is over (I have to track it in the same background thread, or create another for just tracking SoundEffectInstance.State) I set the PlayStopVisualState property back to "Normal", but I get a cross-thread reference exception. Isn't MVVM specifically designed to allow developers to manipulate logical variables in a view model, and not having to worry about how the changes to them are reflected in a View?
I know that I need to do the adjustment of the PlayStopVisualState property in a Dispatcher thread in order for the problem to disappear, but this is just no right. It, from my point of view, defeats the whole purpose of MVVM, leaving only the organizational advantage.
Or am I doing something wrong? Thanks.
UPDATE:
I have worked around the problem by using
Deployment.Current.Dispatcher
but it seems to me as a very "ugly" solution, given that I almost all over have MVVM pattern followed.
Using the Dispatcher to reflect a UI-bound value is the correct way to do it, yes.
What you're forgetting is that your ViewModel is created on the UI thread. So any change to the ViewModel from a background thread, would a cross-thread operation.
You should consider if a background thread is really needed. , or if you could just schedule your action on the UI thread directly.

Events routing in WPF

I have implemented a UserControl. Then I would like to handle an event that is originally handled by Window (keyboard press). What is the best way to route the event caught by another component (higher in the components' tree)?
Thanks in advance for the replies and hints!
Cheers
It depends on the event you're trying to access. If it's a Preview event and the Window is setting e.Handled to true you'll need to use the method Alex suggests to circumvent the Window's handling of the tunneling. If it is a bubbling event (i.e. KeyDown) you don't need to do anything special since bubbling events hit the handlers on child elements first and go up the visual tree so the Window handler won't occur until after your UC's.
One thing you need to be careful with using Key events is that the event is only going to get picked up by your UC in the first place if the Focus is on or inside of it. This isn't something you need to worry about with things like Mouse events since they start at a specific location in the tree.
I believe you cannot gurantee that.
Window class is wrapping Win32 message-based event model and this will be the only WPF entity which will have access to those information.
I suggest that you create an attached property (which will be used by the Window) and implement the routing of the events yourself so that controls could subscribe to.
You can attach the routed handler specifying that you want to handle handled messages as well:
this.AddHandler(routedEvent, handler, true);
where this is an UIElement or derived class.
However there may still be events (key presses in this case) which don't make it past the window, not sure.

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