AvalonDock Multiple LayoutDocumentPane com ObservableCollection diferente contendo UserControls dinâmicos criados
Eu tenho uma IU baseada em AvalonDock com pelo menos três LayoutDocumentPanes estáticos. Como posso preencher dinamicamente esses painéis com diferentes coleções de UserControl? Eu descobri que posso definir um DocumentSourcepara todo o DockingManager e essa coleção, em seguida, pode ser usado para gerar elementos para todos os painéis.
Posso usar várias coleções de origem ou posso filtrar minha coleção para cada 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>
Respostas
Para controlar o layout dinamicamente, você deve implementá ILayoutUpdateStrategy-lo e atribuí-lo a DockingManager.LayoutUpdateStrategy. Esta estratégia é invocada sempre que você adiciona um item a DockingManager.DocumentsSourceou DockingManager.AnchorablesSource. Você pode lidar com os detalhes do layout antes ou depois da adição do conteúdo.
Observe que um indivíduo DataTemplatepara cada modelo de documento ainda é necessário (ver exemplos ). ILayoutUpdateStrategylida apenas com o layout, mas não com a renderização de conteúdo.
Você deve adicionar todos os documentos de tipos diferentes a uma coleção de origem comum.
Recomendo a introdução de uma interface, por exemplo, IDocumentque deve ser implementada por cada tipo de documento. Isso permite armazená-los em uma coleção comum do tipo IDocumente ativa o polimorfismo ao iterar a coleção.
Você pode então vincular ObservableCollection<IDocument>a ao DockingManager.DocumentsSource.
O exemplo a seguir também cria o layout necessário (devido à restrição de agrupamento). Como ele adicionará elementos de layout mising ao LayoutPanelde DockingManager.Layout, o layout é tratado antes de o conteúdo ser adicionado. Portanto, no caso de documentos agrupados, não há necessidade de predefinir 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>