views:

737

answers:

2

I have a WinForms usercontrol hosting a WPF custom Listbox in it. After the WinForms user control gets disabled and then re-enabled the WPF control in the WinForms usercontrol is unresponsive. Has anyone else experienced this?

We had to hack a soultion into remove and re-add the element host each time the control gets disable / enabled to fix the issue.

WinForms

wpfControl.Enabled = false;
...
wpfControl.Enabled = true;

Hack for fixing it in the WinForms EnabledChanged method for the usercontrol

if ( Enabled ) 
{
  ElementHost oldEh = ctlElementHost;
  ElementHost eh = new ElementHost();
  eh.Name = oldEh.Name;
  oldEh.Child = null;
  eh.Child = wpfControl;
  this.Controls.Remove( ctlElementHost );
  this.Controls.Add( eh );
  eh.Dock = DockStyle.Fill;

  oldEh.Dispose();
  ctlElementHost = eh;
}

There seems to be a memory leak where the disposed element hosts are still sticking around until the parent form that was hosting the WinForms usercontrol gets closed.

+1  A: 

Does the element host subscribe to events from the WPF user control? If so, and the events aren't unwired before trying to dispose the element host, it will hang around in memory until the WPF control is disposed (and since it looks like you're using the same instance of the control throughout, that isn't until the form is closed.)

Lee Roth
Nope, there aren't any events that I'm hooking into on the element host. I'm aware, that I would need to unhook those, from the memory profile, it looks like .NET is hooking in events that are getting unhooked.
Mark Boltuc
+3  A: 

A co-worker (thanks KwB) of mine managed to find a fix for this issue: http://support.microsoft.com/kb/955753

It involves inheriting from ElementHost and manually telling the window region to enable:

public class MyElementHost : ElementHost
{
    protected override void OnEnabledChanged(EventArgs e)
    {
        SynchChildEnableState(); 

        base.OnEnabledChanged(e);
    } 

    private void SynchChildEnableState()
    {
        IntPtr childHandle = GetWindow(Handle, GW_CHILD);
        if (childHandle != IntPtr.Zero)
        {
            EnableWindow(childHandle, Enabled);
        }
    } 

    private const uint GW_CHILD = 5; 

    [DllImport("user32.dll")]
    private extern static IntPtr GetWindow(IntPtr hWnd, uint uCmd); 

    [DllImport("user32.dll")]
    private extern static bool EnableWindow(IntPtr hWnd, bool bEnable);
}
Mark Boltuc