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.DocumentsSource
或 DockingManager.AnchorablesSource
时,都会调用此策略。您可以在添加内容之前或之后处理布局细节。
请注意,每个文档模型仍然需要一个单独的 DataTemplate
(请参阅 examples)。 ILayoutUpdateStrategy
只处理布局,不处理内容渲染。
您必须将所有不同类型的文档添加到一个公共源集合中。
我建议引入一个接口,例如 IDocument
,每个文档类型都需要实现该接口。这允许将它们存储在类型 IDocument
的公共集合中,并在迭代集合时启用多态性。
然后,您可以将 ObservableCollection<IDocument>
绑定到 DockingManager.DocumentsSource
.
以下示例还创建了所需的布局(由于分组约束)。因为它会将错误的布局元素添加到 DockingManager.Layout
的 LayoutPanel
,所以在添加内容之前 处理布局。因此,对于分组文档,无需预定义 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>
我有一个基于 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.DocumentsSource
或 DockingManager.AnchorablesSource
时,都会调用此策略。您可以在添加内容之前或之后处理布局细节。
请注意,每个文档模型仍然需要一个单独的 DataTemplate
(请参阅 examples)。 ILayoutUpdateStrategy
只处理布局,不处理内容渲染。
您必须将所有不同类型的文档添加到一个公共源集合中。
我建议引入一个接口,例如 IDocument
,每个文档类型都需要实现该接口。这允许将它们存储在类型 IDocument
的公共集合中,并在迭代集合时启用多态性。
然后,您可以将 ObservableCollection<IDocument>
绑定到 DockingManager.DocumentsSource
.
以下示例还创建了所需的布局(由于分组约束)。因为它会将错误的布局元素添加到 DockingManager.Layout
的 LayoutPanel
,所以在添加内容之前 处理布局。因此,对于分组文档,无需预定义 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>