[c#] Disposing WPF User Controls

I have created a custom WPF user control which is intended to be used by a third party. My control has a private member which is disposable, and I would like to ensure that its dispose method will always get called once the containing window/application is closed. However, UserControl is not disposable.

I tried implementing the IDisposable interface and subscribing to the Unloaded event but neither get called when the host application closes. MSDN says that the Unloaded event may not be raised at all. And it might also be triggered more than once, that is when user changes theme.

If at all possible, I don't want to rely on consumers of my control remembering to call a specific Dispose method.

 public partial class MyWpfControl : UserControl
 {
     SomeDisposableObject x;

     // where does this code go?
     void Somewhere() 
     {
         if (x != null)
         {
             x.Dispose();
             x = null;
         }

     }
 }

The only solution I have found so far is to subscribe to the Dispatcher's ShutdownStarted event. Is this a reasonable approach?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

This question is related to c# .net wpf user-controls dispose

The answer is


Interesting blog post here:

http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx

It mentions subscribing to Dispatcher.ShutdownStarted to dispose of your resources.


Dispatcher.ShutdownStarted event is fired only at the end of application. It's worth to call the disposing logic just when control gets out of use. In particular it frees resources when control is used many times during application runtime. So ioWint's solution is preferable. Here's the code:

public MyWpfControl()
{
     InitializeComponent();
     Loaded += (s, e) => { // only at this point the control is ready
         Window.GetWindow(this) // get the parent window
               .Closing += (s1, e1) => Somewhere(); //disposing logic here
     };
}

I use the following Interactivity Behavior to provide an unloading event to WPF UserControls. You can include the behavior in the UserControls XAML. So you can have the functionality without placing the logic it in every single UserControl.

XAML declaration:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<i:Interaction.Behaviors>
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" />
</i:Interaction.Behaviors>

CodeBehind handler:

private void UserControlClosingHandler(object sender, EventArgs e)
{
    // to unloading stuff here
}

Behavior Code:

/// <summary>
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing.
/// </summary>
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += UserControlLoadedHandler;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Loaded -= UserControlLoadedHandler;
        var window = Window.GetWindow(AssociatedObject);
        if (window != null)
            window.Closing -= WindowClosingHandler;
    }

    /// <summary>
    /// Registers to the containing windows Closing event when the UserControl is loaded.
    /// </summary>
    private void UserControlLoadedHandler(object sender, RoutedEventArgs e)
    {
        var window = Window.GetWindow(AssociatedObject);
        if (window == null)
            throw new Exception(
                "The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used."
                    .FormatWith(AssociatedObject.GetType().Name));

        window.Closing += WindowClosingHandler;
    }

    /// <summary>
    /// The containing window is closing, raise the UserControlClosing event.
    /// </summary>
    private void WindowClosingHandler(object sender, CancelEventArgs e)
    {
        OnUserControlClosing();
    }

    /// <summary>
    /// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing.
    /// </summary>
    public event EventHandler UserControlClosing;

    protected virtual void OnUserControlClosing()
    {
        var handler = UserControlClosing;
        if (handler != null) 
            handler(this, EventArgs.Empty);
    }
}

An UserControl has a Destructor, why don't you use that?

~MyWpfControl()
    {
        // Dispose of any Disposable items here
    }

My scenario is little different, but the intent is same i would like to know when the parent window hosting my user control is closing/closed as The view(i.e my usercontrol) should invoke the presenters oncloseView to execute some functionality and perform clean up. ( well we are implementing a MVP pattern on a WPF PRISM application).

I just figured that in the Loaded event of the usercontrol, i can hook up my ParentWindowClosing method to the Parent windows Closing event. This way my Usercontrol can be aware when the Parent window is being closed and act accordingly!


I use the following Interactivity Behavior to provide an unloading event to WPF UserControls. You can include the behavior in the UserControls XAML. So you can have the functionality without placing the logic it in every single UserControl.

XAML declaration:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<i:Interaction.Behaviors>
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" />
</i:Interaction.Behaviors>

CodeBehind handler:

private void UserControlClosingHandler(object sender, EventArgs e)
{
    // to unloading stuff here
}

Behavior Code:

/// <summary>
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing.
/// </summary>
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += UserControlLoadedHandler;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Loaded -= UserControlLoadedHandler;
        var window = Window.GetWindow(AssociatedObject);
        if (window != null)
            window.Closing -= WindowClosingHandler;
    }

    /// <summary>
    /// Registers to the containing windows Closing event when the UserControl is loaded.
    /// </summary>
    private void UserControlLoadedHandler(object sender, RoutedEventArgs e)
    {
        var window = Window.GetWindow(AssociatedObject);
        if (window == null)
            throw new Exception(
                "The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used."
                    .FormatWith(AssociatedObject.GetType().Name));

        window.Closing += WindowClosingHandler;
    }

    /// <summary>
    /// The containing window is closing, raise the UserControlClosing event.
    /// </summary>
    private void WindowClosingHandler(object sender, CancelEventArgs e)
    {
        OnUserControlClosing();
    }

    /// <summary>
    /// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing.
    /// </summary>
    public event EventHandler UserControlClosing;

    protected virtual void OnUserControlClosing()
    {
        var handler = UserControlClosing;
        if (handler != null) 
            handler(this, EventArgs.Empty);
    }
}

I'm thinking unload is called all but at hard exist in 4.7. But, if you are playing around with older versions of .Net, try doing this in your loading method:

e.Handled = true;

I don't think older versions will unload until loading is handled. Just posting because I see others still asking this question, and haven't seen this proposed as a solution. I only touch .Net a few times a year, and ran into this a few years back. But, I wonder if it's as simple as unload not being called until loading has finished. Seems like it works for me, but again in newer .Net it seems to always call unload even if loading isn't marked as handled.


An UserControl has a Destructor, why don't you use that?

~MyWpfControl()
    {
        // Dispose of any Disposable items here
    }

You have to be careful using the destructor. This will get called on the GC Finalizer thread. In some cases the resources that your freeing may not like being released on a different thread from the one they were created on.


My scenario is little different, but the intent is same i would like to know when the parent window hosting my user control is closing/closed as The view(i.e my usercontrol) should invoke the presenters oncloseView to execute some functionality and perform clean up. ( well we are implementing a MVP pattern on a WPF PRISM application).

I just figured that in the Loaded event of the usercontrol, i can hook up my ParentWindowClosing method to the Parent windows Closing event. This way my Usercontrol can be aware when the Parent window is being closed and act accordingly!


An UserControl has a Destructor, why don't you use that?

~MyWpfControl()
    {
        // Dispose of any Disposable items here
    }

I'm thinking unload is called all but at hard exist in 4.7. But, if you are playing around with older versions of .Net, try doing this in your loading method:

e.Handled = true;

I don't think older versions will unload until loading is handled. Just posting because I see others still asking this question, and haven't seen this proposed as a solution. I only touch .Net a few times a year, and ran into this a few years back. But, I wonder if it's as simple as unload not being called until loading has finished. Seems like it works for me, but again in newer .Net it seems to always call unload even if loading isn't marked as handled.


Dispatcher.ShutdownStarted event is fired only at the end of application. It's worth to call the disposing logic just when control gets out of use. In particular it frees resources when control is used many times during application runtime. So ioWint's solution is preferable. Here's the code:

public MyWpfControl()
{
     InitializeComponent();
     Loaded += (s, e) => { // only at this point the control is ready
         Window.GetWindow(this) // get the parent window
               .Closing += (s1, e1) => Somewhere(); //disposing logic here
     };
}

You have to be careful using the destructor. This will get called on the GC Finalizer thread. In some cases the resources that your freeing may not like being released on a different thread from the one they were created on.


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to .net

You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to use Bootstrap 4 in ASP.NET Core No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Update .NET web service to use TLS 1.2 EF Core add-migration Build Failed What is the difference between .NET Core and .NET Standard Class Library project types? Visual Studio 2017 - Could not load file or assembly 'System.Runtime, Version=4.1.0.0' or one of its dependencies Nuget connection attempt failed "Unable to load the service index for source" Token based authentication in Web API without any user interface

Examples related to wpf

Error: the entity type requires a primary key Reportviewer tool missing in visual studio 2017 RC Pass command parameter to method in ViewModel in WPF? Calling async method on button click Setting DataContext in XAML in WPF How to resolve this System.IO.FileNotFoundException System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll? Binding an Image in WPF MVVM How to bind DataTable to Datagrid Setting cursor at the end of any text of a textbox

Examples related to user-controls

How do I add my new User Control to the Toolbox or a new Winform? Get access to parent control from user control - C# How do I make an Event in the Usercontrol and have it handled in the Main Form? How to calculate the sum of the datatable column in asp.net? User Control - Custom Properties Add a user control to a wpf window "The Controls collection cannot be modified because the control contains code blocks" Disposing WPF User Controls How do I get the full url of the page I am on in C#

Examples related to dispose

How to check if object has been disposed in C# Do you need to dispose of objects and set them to null? Should I Dispose() DataSet and DataTable? Finalize vs Dispose Disposing WPF User Controls