AvalonDock 多个 LayoutDocumentPane 与不同的 ObservableCollection 包含动态创建的 UserControls

AvalonDock multiple LayoutDocumentPane with different ObservableCollection containing dynamic created UserControls

我有一个基于 AvalonDock 的 UI,至少有三个静态 LayoutDocumentPanes。我怎样才能用不同的 UserControl 集合动态填充这些窗格? 我想通了,我可以为整个 DockingManager 设置一个 DocumentSource,然后这个 Collection 可用于为所有窗格生成元素。

我可以使用多个源集合还是可以为每个 LayoutDocumentPane 过滤我的集合?

<xcad:DockingManager  
            DocumentsSource="{Binding MyUserControls1}">
          
            <xcad:DockingManager.Resources>
                <DataTemplate DataType="{x:Type local:MyUserControl}">
                        <local:MyUserControl/>   
                </DataTemplate>
            </xcad:DockingManager.Resources>

    <xcad:LayoutRoot>
        <xcad:LayoutPanel Orientation="Horizontal" >
            <xcad:LayoutPanel Orientation="Vertical" DockWidth="6*">
                <xcad:LayoutPanel Orientation="Horizontal">
                            <xcad:LayoutDocumentPaneGroup>
                                <xcad:LayoutDocumentPane>
                                <!-- UserControls from ObservableCollection 1-->
                                </xcad:LayoutDocumentPane>
                            </xcad:LayoutDocumentPaneGroup >
                            <xcad:LayoutDocumentPaneGroup>
                                <xcad:LayoutDocumentPane >
                                <!-- UserControls from ObservableCollection 2-->
                                </xcad:LayoutDocumentPane>
                            </xcad:LayoutDocumentPaneGroup >
                            <xcad:LayoutDocumentPaneGroup>
                                <xcad:LayoutDocumentPane >
                                <!-- UserControls from ObservableCollection 3-->
                                </xcad:LayoutDocumentPane>
                            </xcad:LayoutDocumentPaneGroup >
                </xcad:LayoutPanel>
            </xcad:LayoutPanel>
        </xcad:LayoutPanel>
     </xcad:LayoutRoot>

要动态控制布局,您必须实现 ILayoutUpdateStrategy 并将其分配给 DockingManager.LayoutUpdateStrategy。每当您将项目添加到 DockingManager.DocumentsSourceDockingManager.AnchorablesSource 时,都会调用此策略。您可以在添加内容之前或之后处理布局细节。

请注意,每个文档模型仍然需要一个单独的 DataTemplate(请参阅 examples)。 ILayoutUpdateStrategy 只处理布局,不处理内容渲染。

您必须将所有不同类型的文档添加到一个公共源集合中。
我建议引入一个接口,例如 IDocument,每个文档类型都需要实现该接口。这允许将它们存储在类型 IDocument 的公共集合中,并在迭代集合时启用多态性。
然后,您可以将 ObservableCollection<IDocument> 绑定到 DockingManager.DocumentsSource.

以下示例还创建了所需的布局(由于分组约束)。因为它会将错误的布局元素添加到 DockingManager.LayoutLayoutPanel,所以在添加内容之前 处理布局。因此,对于分组文档,无需预定义 LayoutRoot:

LayoutUpdateStrategy.cs

public class LayoutUpdateStrategy : ILayoutUpdateStrategy
{
  #region Implementation of ILayoutUpdateStrategy

  public bool BeforeInsertAnchorable(
    LayoutRoot layout,
    LayoutAnchorable anchorableToShow,
    ILayoutContainer destinationContainer)
  {
    return false;
  }

  public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
  {
  }

  // Creates a new LayoutDocumentPane for each document model type.
  // All grouped documents will reside in a common LayoutDocumentPaneGroup.
  public bool BeforeInsertDocument(
    LayoutRoot layout,
    LayoutDocument documentToShow,
    ILayoutContainer destinationContainer)
  {
    if (destinationContainer?.FindParent<LayoutFloatingWindow>() != null)
    {
      // Return 'false' as the strategy hasn't performed any action
      return false;
    }

    LayoutDocumentPane existingDocumentsPane = layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault(
      pane => pane.Children.Any(
        layoutDocument => layoutDocument.Content.GetType() == documentToShow.Content.GetType()));

    if (existingDocumentsPane != null)
    {
      existingDocumentsPane.Children.Add(documentToShow);
    }
    else
    {
      // Get the existing LayoutDocumentPaneGroup
      LayoutDocumentPaneGroup paneGroup = layout.Descendents().OfType<LayoutDocumentPaneGroup>().FirstOrDefault();

      // Create a new LayoutDocumentPaneGroup if there is none in the current layout
      if (paneGroup == null)
      {
        paneGroup = new LayoutDocumentPaneGroup();
        layout.RootPanel.Children.Add(paneGroup);
      }

      // Create a new LayoutDocumentPane for the new document type
      var pane = new LayoutDocumentPane(documentToShow);
      paneGroup.Children.Add(pane);
    }

    // Return 'true' as the strategy has performed any action
    return true;
  }

  public void AfterInsertDocument(LayoutRoot layout, LayoutDocument documentToShow)
  {
  }

  #endregion
}

MainWindow.xaml

<Window>
  <DockingManager DocumentsSource="{Binding MyDocuments}">
    <DockingManager.LayoutUpdateStrategy>
        <LayoutUpdateStrategy />
      </DockingManager.LayoutUpdateStrategy>
  </DockingManager>
</Window>