4

I've been using the DockManager with LayoutRoot, LayoutAnchorablePane and LayoutDocumentPane.

<ad:DockingManager x:Name="dockManager" >
  <adLayout:LayoutRoot>
    <adLayout:LayoutPanel x:Name="myLayoutPanel" Orientation="Horizontal">
      <adLayout:LayoutAnchorablePane x:Name="myLayoutAnchorablePane" DockWidth="400"/>
      <adLayout:LayoutDocumentPane x:Name="myDocumentPane" ChildrenCollectionChanged="myDocumentPane_ChildrenCollectionChanged"/>
    </adLayout:LayoutPanel>
  </adLayout:LayoutRoot>
</ad:DockingManager>

However, one problem I've encounted is that in DockManager.LogicalChildren, the ContentPresenter and my UserControl that went into the LayoutDocument never gets removed when I close the window and keeps building up more and more LogicalChildren until it starts to slow down the application.

How do I, when I detect ChildrenCollectionChanged, remove the ContentPresenter and UserControl that were associated with that LayoutDocument?

Edit 1: Okay, so LogicalChildren is System.Linq.Enumerable.WhereSelectListIterator<System.WeakReference,object>, so I won't be able to remove anything from that list (also it only has a get, and no set).

The LayoutDocumentPane.RemoveChild() method doesn't do anything to the DockingManager.LogicalChildren, so I can't figure out where the LogicalChildren is pulling the iteration date from.

Edit 2: So, I tried adding an event to the DocumentClosing event handler for DockManager and it still doesn't seem to remove the unused LogicalChildren from DockManager.

void dockManager_DocumentClosing(object sender, Xceed.Wpf.AvalonDock.DocumentClosingEventArgs e) {
    UserControl uc = e.Document.Content as UserControl;
    e.Cancel = true;
    e.Document.IsActive = false;
    if(uc != null) {
        var u = myDocumentPane.Children.Where(a => a.Content.Equals(uc)).FirstOrDefault();
        u.IsActive = false;
        u.Close();
        myDocumentPane.Children.Remove(u);
        myDocumentPane.RemoveChild(u);

        var oldLogicalParentPaneControl = 
            LogicalTreeHelper.GetParent(u.Content as UIElement) as Xceed.Wpf.AvalonDock.DockingManager;
        oldLogicalParentPaneControl.Layout.RemoveChild(u);
        oldLogicalParentPaneControl.Layout.CollectGarbage();
        dockManager.UpdateLayout();
    }
}

Edit 3: After looking at what remains in LayoutDocumentPane after the DocumentClosed without any modification (instead of DocumentClosing), it seems that the User Control is removed from LayoutDocumentPane, but not from LogicalChildren still.

Bob.
  • 3,894
  • 4
  • 44
  • 76
  • what version of avalondock are you using? – Jehof Oct 18 '13 at 06:54
  • I had this before also. My own work-around was to ditch the AnchorablePane (plus anything else with Anchorable in it) and use 'LayoutDocumentPane' as the factory site. I also hooked the closing event like you did. – Gayot Fow Oct 18 '13 at 12:07
  • @Jehof I'm using v2.0.2000 – Bob. Oct 18 '13 at 12:45
  • @GarryVass I tried changing my `LayoutAnchorablePane` to a `LayoutDocumentPane` and I still have the same memory issue. – Bob. Oct 18 '13 at 13:31
  • @Bob. Then you'll have to include your factory code in the question... I.e., the code that adds children. – Gayot Fow Oct 19 '13 at 12:10

3 Answers3

0

Its hard to understand your problem properly since you are in Xceed and AvalonDock world and not standard microsoft controls. I guess only few of us here know xceed's controls in details. Futhermore I would suggest you to post this on xceeds forum.

Still I would like to mention few things to you which apply to every wpf control that might help you solve your issue.

Whenever you using a Panel, Pane or whatsoever UIElement for layouting in WPF you end up at some point adding/removing children to/from visual and logical tree.

Therefore I suggest you to check out following link:

http://msdn.microsoft.com/en-us/library/ms753391.aspx

That will explain you wpf trees in detail.

Also check out the link to Panel.Children:

http://msdn.microsoft.com/en-us/library/system.windows.controls.panel.internalchildren.aspx

I dont know if your LayoutPanel there inherits from "Microsoft" Panel but if so then how about you try something like this:

layoutPanel.Children.Remove(..)

Children is a UIElementCollection and every UIElementCollection calls inside Remove() the RemoveVisualVisual() and the RemoveLogicalChild() methods internally.

http://msdn.microsoft.com/en-us/library/system.windows.controls.uielementcollection.aspx

In the end I came up with two alternative solutions. If nothing of this above helps you how about you simply find the FrameworkElement that is the parent of the control you wish to be removed and by using FrameworkElement.RemoveLogicalChild you remove the child from logical tree.

Check this link out:

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.removelogicalchild.aspx

Second alternative solution would be overriding LogicalChildren property of your layouting panel.

This link explains you how to: http://msdn.microsoft.com/en-us/library/ms742244.aspx

I hope you let me know if this was anyhow helpful to you or others who might stumble upon this. In case though I didnt understand your issue at all just let me know and I will remove this post.

dev hedgehog
  • 8,698
  • 3
  • 28
  • 55
  • Thanks for your effort, but none of those are an option, and if I want to use `FrameworkElement.RemoveLogicalChild`, I'd have to write my own custom class since it's an `internal` function. – Bob. Oct 21 '13 at 11:49
  • Well those are the only methods available in wpf to remove a child. It is not possible that you cant use any of those. Yes, remove logical child method can only be execute in protected scope as so can also logicalchildren property be overriden. Are you sure you are doing everything correct? Are you sure the child is stuck in logical tree? – dev hedgehog Oct 21 '13 at 12:36
  • Have you tried snooping logical tree? Check out the Tool Snoop available on codeplex.com or something like that... – dev hedgehog Oct 21 '13 at 12:42
0

I think it's a memory leak issue. did you try to look into memory profiler to know what's happened? Also, I've found this link maybe it's your situation? http://avalondock.codeplex.com/workitem/16060

Lonli-Lokli
  • 3,357
  • 1
  • 24
  • 40
0

I've had this problem when using DockingManager's serialization when used on LayoutDocumentPane. After the LayoutAnchorablePane was loaded from xml, I was not able to close it.

Fixed it by removing loading LayoutAnchorablePane's properties if it's parent is LayoutDocumentPane.

Michal Pokluda
  • 390
  • 4
  • 11