如何在关闭选项卡后从DockManager中移除LogicalChildren?

5

我一直在使用 DockManagerLayoutRoot, LayoutAnchorablePaneLayoutDocumentPane.

<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>

然而,我遇到的一个问题是,在 DockManager.LogicalChildren 中,ContentPresenter 和进入 LayoutDocument 的 UserControl 在关闭窗口时从未被移除,并且会不断地建立更多的 LogicalChildren,直到开始拖慢应用程序。当我检测到 ChildrenCollectionChanged 时,如何删除与该 LayoutDocument 关联的 ContentPresenter 和 UserControl 呢?
编辑1:好吧,LogicalChildren 是 System.Linq.Enumerable.WhereSelectListIterator,所以我无法从该列表中删除任何内容(它只有一个 get,没有 set)。
LayoutDocumentPane.RemoveChild() 方法对 DockingManager.LogicalChildren 不起作用,因此我无法弄清楚 LogicalChildren 从哪里获取迭代数据。
编辑2:所以,我尝试在 DockManager 的 DocumentClosing 事件处理程序中添加了一个事件,但似乎仍然无法从 DockManager 中删除未使用的 LogicalChildren。
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();
    }
}

编辑3: 在查看了没有任何修改的 DocumentClosed 后,我发现在 LayoutDocumentPane 中仍然存在 User Control,但仍未从 LogicalChildren 中移除。


你使用的 AvalonDock 版本是什么? - Jehof
我以前也遇到过这个问题。我的解决方法是放弃AnchorablePane(以及任何带有Anchorable的东西),改用“LayoutDocumentPane”作为工厂站点。我还像你一样挂钩了关闭事件。 - Gayot Fow
@Jehof 我正在使用 v2.0.2000 版本。 - Bob.
@GarryVass 我尝试将我的 LayoutAnchorablePane 更改为 LayoutDocumentPane,但我仍然遇到同样的内存问题。 - Bob.
@Bob。那么您需要在问题中包含您的工厂代码,即添加子项的代码。 - Gayot Fow
3个回答

0

在使用DockingManager的序列化功能时,我遇到了一个问题,当它用于LayoutDocumentPane时。在从xml中加载LayoutAnchorablePane后,我无法关闭它。

通过删除加载LayoutAnchorablePane的属性,如果其父级是LayoutDocumentPane,则解决了这个问题。


0

0

由于您使用的是 XceedAvalonDock 而不是标准的 Microsoft 控件,所以很难正确理解您的问题。我猜这里只有少数人详细了解 Xceed 的控件。此外,我建议您在 Xceed 的论坛上发布此问题。

尽管如此,我仍然想向您提及一些适用于每个 wpf 控件 的事情,这可能有助于您解决问题。

每当您在 WPF 中使用 PanelPane 或任何其他 UIElement 进行布局时,最终都会将子元素添加/删除到/从可视和逻辑树中。

因此,我建议您查看以下链接:

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

这将详细解释 WPF 树的内容。

同时,请查看 Panel.Children 的链接:

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

我不知道你的LayoutPanel是否继承自“Microsoft”Panel,但如果是的话,你可以试试这样做:

layoutPanel.Children.Remove(..)

Children是一个UIElementCollection,每个UIElementCollection在Remove()内部调用RemoveVisualVisual()和RemoveLogicalChild()方法。

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

最终,我想出了两个备选方案。如果上述任何方法都无法帮助您,那么您可以简单地找到包含要删除的控件的父级FrameworkElement,并使用FrameworkElement.RemoveLogicalChild从逻辑树中移除该子项。
请查看此链接:

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

第二种替代方案是覆盖您的布局面板的LogicalChildren属性。

此链接将向您解释如何操作: http://msdn.microsoft.com/en-us/library/ms742244.aspx

我希望您能让我知道这对您或其他可能遇到此问题的人是否有所帮助。如果我完全没有理解您的问题,请告诉我,我会删除此帖子。


感谢您的努力,但这些都不是选项。如果我想使用FrameworkElement.RemoveLogicalChild,我必须编写自己的自定义类,因为它是一个internal函数。 - Bob.
这些是WPF中唯一可用的删除子元素的方法。你不能不使用它们。是的,删除逻辑子元素的方法只能在受保护的范围内执行,因此逻辑子元素属性也可以被重写。你确定你做的一切都正确吗?你确定子元素被卡在逻辑树中了吗? - dev hedgehog
你尝试过窥视逻辑树吗?可以去codeplex.com上查看Tool Snoop这个工具,或者类似的东西... - dev hedgehog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接