C# AvalonDock multiple LayoutDocumentPane具有不同的ObservableCollection,其中包含动态创建的用户控件
我有一个基于AvalonDock的UI,其中至少有三个静态布局文档窗格。如何用不同的UserControl集合动态填充这些窗格? 我发现,我可以为整个DockingManager设置一个C# AvalonDock multiple LayoutDocumentPane具有不同的ObservableCollection,其中包含动态创建的用户控件,c#,wpf,xaml,data-binding,avalondock,C#,Wpf,Xaml,Data Binding,Avalondock,我有一个基于AvalonDock的UI,其中至少有三个静态布局文档窗格。如何用不同的UserControl集合动态填充这些窗格? 我发现,我可以为整个DockingManager设置一个DocumentSource,然后可以使用这个集合为所有窗格生成元素 我可以使用多个源集合还是可以为每个LayoutDocumentPane筛选集合 <xcad:DockingManager DocumentsSource="{Binding MyUserControl
DocumentSource
,然后可以使用这个集合为所有窗格生成元素
我可以使用多个源集合还是可以为每个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.anchorablesource
添加项目时,将调用此策略。可以在添加内容之前或之后处理布局详细信息
请注意,每个文档模型仍然需要一个单独的DataTemplate
(请参阅)<代码>ILAyoutUpdateStregy仅处理布局,而不处理内容呈现
您必须将所有不同类型的文档添加到公共源集合。我建议引入一个接口,例如,
I文档
,每个文档类型都需要实现该接口。这允许将它们存储在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
}
公共类LayoutUpdateStrategy:ILayoutUpdateStrategy
{
#ILAOutUpdateStrategy的区域实现
插入之前的公共bool可插入(
LayoutRoot布局,
LayoutAnchorableThow,
ILAOUT集装箱目的地(集装箱)
{
返回false;
}
插入式锚具后的公共空隙(所示为LayoutRoot布局、LayoutChorable锚具)
{
}
//为每个文档模型类型创建新的LayoutDocumentPane。
//所有分组文档将驻留在公共布局DocumentPaneGroup中。
插入文档之前的公共bool(
LayoutRoot布局,
布局文档文档显示,
ILAOUT集装箱目的地(集装箱)
{
if(destinationContainer?.FindParent()!=null)
{
//由于策略未执行任何操作,因此返回“false”
返回false;
}
LayoutDocumentPane existingDocumentsPane=layout.degents().OfType().FirstOrDefault(
pane=>pane.Children.Any(
layoutDocument=>layoutDocument.Content.GetType()==documentToShow.Content.GetType());
如果(现有文档span!=null)
{
现有文档span.Children.Add(documentToShow);
}
其他的
{
//获取现有的LayoutDocumentPaneGroup
LayoutDocumentPaneGroup paneGroup=layout.degents()。of type().FirstOrDefault();
//如果当前布局中没有布局,请创建新的布局DocumentPaneGroup
if(paneGroup==null)
{
paneGroup=新布局文档paneGroup();
layout.RootPanel.Children.Add(paneGroup);
}
//为新文档类型创建新的LayoutDocumentPane
变量窗格=新布局文档窗格(documentToShow);
paneGroup.Children.Add(窗格);
}
//当策略已执行任何操作时,返回“true”
返回true;
}
插入文档后公共无效(LayoutRoot布局,LayoutDocumentToShow文档)
{
}
#端区
}
main window.xaml
<Window>
<DockingManager DocumentsSource="{Binding MyDocuments}">
<DockingManager.LayoutUpdateStrategy>
<LayoutUpdateStrategy />
</DockingManager.LayoutUpdateStrategy>
</DockingManager>
</Window>
再次感谢您的回答-这是一个很好的起点。在我的xaml中,我想直接处理我现有的LayoutDocumentPanes。是否可以使用x:Name属性选择LayoutUpdateStregy类中的元素?类似于:layout.degents().OfType().FirstOrDefault(d=>d.Name==“ToolsPane”)代码>否。x:Name
指令将创建一个受保护的字段,以引用元素名称范围所有者(例如main窗口
)中的命名元素。由于访问修饰符,此字段不可访问。此外,如果没有对所有者的引用,则无法访问名称范围。可以引入自定义附着特性,以便按名称标识布局元素。知道其父窗格组集合中窗格的顺序与标记中定义的顺序相等可能会有所帮助。标记中的第一个窗格是子体集合中的第一个窗格。您可以通过索引访问它们,例如layout.degents().OfType().ElementAt(0).Children.Add(documentToShow)
x:Name
是一个纯XAML指令。显然,阿瓦隆托克有其局限性。它本可以得到更好的实施。如前所述,您可以创建一个自定义附加属性,并将其应用于XAML中的窗格。这很快