views:

2374

answers:

4

The WPF control WindowsFormsHost inherits from IDisposable.

If I have a complex WPF visual tree containing some of the above controls what event or method can I use to call IDispose during shutdown?

A: 

You don't need to dispose controls when closing a form, the API will do it for you automatically if the control is in the visual tree of the form ( as a child of the form or other control in the form)

Pop Catalin
My WFH is a child of another WPF control in a tree that includes the main wpf window. Dispose on the WFH is never called.
morechilli
When Dispose is called on the main wpf window, all of its children will be disposed of (and so on). Your WFH control should be disposed of at that time without any extra work on your part.
Sean Reilly
Given that neither the wpf application class nor the wpf window class inherits from IDisposable that seems unlikely - I believe wpf is immune from the need to dispose until you pull in winforms.
morechilli
+3  A: 

In the case of application shutdown there is nothing you need to do to properly dispose of the WindowsFormsHost. Since it derives from HwndHost disposing is handled when the Dispatcher is shutdown. If you use Reflector you will see that when HwndHost is initialized it creates a WeakEventDispatcherShutdown.

If you are using it in a dialog the best I can suggest is to override OnClosed and dispose of your Host then, otherwise the HwndHost will hang around until until the Dispatcher is shutdown.

public partial class Dialog : Window
{
    public Dialog()
    {
     InitializeComponent();
    }

    protected override void OnClosed(EventArgs e)
    {
     if (host != null)
         host.Dispose();

     base.OnClosed(e);
    }
}

A simple way to test when dispose gets called is to derive a custom class from WindowsFormsHost and play around with different situations. Put a break point in dispose and see when it gets called.

public class CustomWindowsFormsHost : WindowsFormsHost
{
    protected override void Dispose(bool disposing)
    {
     base.Dispose(disposing);
    }
}
Todd White
Thx sounds good.So for a windowsformshost control with app. lifetime I can rely on hwdhost hooking to the dispatcher shutdown event,for a dialog I could write a similar hook in my control to the onclosed event of the dialog window and I can copy both these patterns for a generic IDisposable control.
morechilli
A: 

Building from Todd's answer I came up with this generic solution for any WPF control that is hosted by a Window and want's to guarantee disposal when that window is closed.

(Obviously if you can avoid inheriting from IDisposable do, but sometimes you just can't)

Dispose is called when the the first parent window in the hierarchy is closed.

(Possible improvement - change the event handling to use the weak pattern)

public partial class MyCustomControl : IDisposable
    {

        public MyCustomControl() {
            InitializeComponent();

            Loaded += delegate(object sender, RoutedEventArgs e) {
                System.Windows.Window parent_window = Window.GetWindow(this);
                if (parent_window != null) {
                    parent_window.Closed += delegate(object sender2, EventArgs e2) {
                        Dispose();
                    };
                }
            };

            ...

        }

        ...
    }
morechilli
Question: what do you do in the dispose method?
Pop Catalin
depends on the control - normally you don't have anything but unfortunately there are special cases see my comment on your answer
morechilli
This will fail for those who are hosting WPF within a Windows Forms app. There are more compatible ways to also alternatively hook up to the associated WinForms close events for the main Form but as you have it this would not be sufficient for a widely reusable WPF control library. Also cleaning up only when the main window is closed is probably not exactly what most developers would want. Instead it is probably more desirable to do clean up when the first window/page up the tree is out of scope (not necessarily when it is closed).
jpierson
Thanks - Sounds like you have some useful ideas - if you fancy submitting an answer describing a better and more general solution then I'll happily deselect this answer and consider yours.
morechilli
A: 

WPF Controls don't implement the IDisposable interface, because they have nothing to dispose (No handles to clean up, no unmanaged memory to release). All you need to do is make sure that you don't have any references to the controls and the GC will clean them.

Therefore WPF employs weak event patterns to ensure that controls can be garbage collected. This is the pattern you need to implement to ensure clean-up, not IDisposable.

Pop Catalin
Normally you are correct - however there are exceptions - as an example WindowsFormsHost is a WPF control and does implement IDisposable. It does have an hwnd to dispose as it hosts winforms controls.
morechilli
If you have something to dispose then implement IDisposable, if you don't then don't. But don't implement it until you do.
Pop Catalin
It seems that the weak event pattern could still pose a problem in situations where you swap out an existing control and want to make sure that all events on that old control and handeled by that control to be unhooked so that they stop processing events. In our experiments it seems that these events continue to fire. Calling Dispose used to serve this event cleanup purpose as well in WinForms.
jpierson