Search code examples
c#wpfuser-controlsdispose

WPF Control Disposal


In WinForms, for all controls there is the .OnDisposed override, the Disposed event, and the IsDisposed property.

WPF seems to have no equivalent.

How can I listen for the disposal of a UserControl in a WPF application?

To be more clear; I need to know when the control is removed. The reason being that for some controls I want to keep a static reference to the control for easier access to it, and when the control is no longer in scope, I need to set that reference to null.

To be even more clear :

public class Foo : UserControl{
    private static Foo _Instance;
    //For ease of access. I do not want to have to call Control.Control.Control.Control.FooVar.DoSomething() when I can call Foo.Instance.DoSomething()
    public static Foo Instance { get { return Foo._Instance ?? new Foo() } }

    public Foo(){
        this.InitializeComponents();
        /*Other Initialization Stuff*/
        Foo._Instance = this; /*<---- This needs to be set to null when Foo is closed/disposed/removed/out of scope etc.*/
    }        
}

Solution

  • If you want to statically reference objects, but without keeping them in-memory, you could always elect for a WeakReference<T>

    public partial class MyControl : UserControl
    {
        private readonly static WeakReference<MyControl> _instance
            = new WeakReference<T>(null);
    
        public static MyControl Instance
        {
            get
            {
                UserControl result;
                if(!_instance.TryGetTarget(out result))
                    _instance.SetTarget(result = new MyControl());
    
                return result;
            }
        }
    }
    

    This, however, introduces the possibility that, depending on the whims of the GC, you may get the same control after quickly closing and refreshing a page. In such case, you should make sure the Unloaded event triggers a nullification of the instance

    // Ensure the instance is cleared when unloading
    public void OnUnloaded(object sender, RoutedEventArgs args)
    {
        _instance.SetTarget(null);
    }
    

    and then in your XAML...

    <UserControl ...
                 Unloaded="OnUnloaded">