Reputation: 1197
I have a CustomControl and a list of view models for that control. Using ItemsControl I'm able to create a control for each view model dynamically. Now I use AvalonDock and I want to add one DockableContent for each generated UserControl. How can this be done dynamically?
Upvotes: 1
Views: 1541
Reputation: 7004
You want to bind your collection of ViewModels to the DocumentSource of the docking manager, and set up a template to bind to properties like title etc like this:
<dock:DockingManager DocumentsSource="{Binding Documents}" >
<dock:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type dockctrl:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}" />
<Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}" />
<Setter Property="CanClose" Value="{Binding Model.CanClose}" />
</Style>
</dock:DockingManager.LayoutItemContainerStyle>
</dock:DockingManager>
and add things dynamically using something like this:
Documents.Add(MyNewlyCreatedViewModel)
Edit: Things get more complex when you use static panes. You have to use a template selector to choose the correct template for your normal/static panes. The MVVM AvalonDock sample is pretty good. Here's how I've implemented it (Tools are static):
<avalonDock:DockingManager
AnchorablesSource="{Binding Tools}"
DocumentsSource="{Binding Documents}"
AllowMixedOrientation="True" >
<avalonDock:DockingManager.Theme>
<avalonDock:MetroTheme />
</avalonDock:DockingManager.Theme>
<avalonDock:DockingManager.LayoutUpdateStrategy>
<helpers:LayoutUpdateStrategy />
</avalonDock:DockingManager.LayoutUpdateStrategy>
<avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<helpers:AutobinderLayoutSelector>
<helpers:AutobinderLayoutSelector.DocumentStyle>
<Style TargetType="{x:Type avalonDock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}" />
</Style>
</helpers:AutobinderLayoutSelector.DocumentStyle>
<helpers:AutobinderLayoutSelector.ToolStyle>
<Style TargetType="{x:Type avalonDock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}" />
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
</Style>
</helpers:AutobinderLayoutSelector.ToolStyle>
</helpers:AutobinderLayoutSelector>
</avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<avalonDock:DockingManager.LayoutItemTemplateSelector>
<helpers:AutobinderTemplateSelector>
<helpers:AutobinderTemplateSelector.DocumentTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding . }" IsTabStop="False" />
</DataTemplate>
</helpers:AutobinderTemplateSelector.DocumentTemplate>
<helpers:AutobinderTemplateSelector.ToolTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding . }" IsTabStop="False" />
</DataTemplate>
</helpers:AutobinderTemplateSelector.ToolTemplate>
</helpers:AutobinderTemplateSelector>
</avalonDock:DockingManager.LayoutItemTemplateSelector>
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal">
<avalonDock:LayoutDocumentPane/>
<avalonDock:LayoutAnchorablePane Name="ToolsPane" DockWidth="240"/>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
with the custom class LayoutUpdateStrategy:
public class LayoutUpdateStrategy : ILayoutUpdateStrategy
{
public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
{}
public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown)
{}
public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
{
//AD wants to add the anchorable into destinationContainer
//just for test provide a new anchorablepane
//if the pane is floating let the manager go ahead
LayoutAnchorablePane destPane = destinationContainer as LayoutAnchorablePane;
if (destinationContainer != null &&
destinationContainer.FindParent<LayoutFloatingWindow>() != null)
return false;
var toolsPane = layout.Descendents().OfType<LayoutAnchorablePane>().FirstOrDefault(d => d.Name == "ToolsPane");
if (toolsPane != null)
{
toolsPane.Children.Add(anchorableToShow);
return true;
}
return false;
}
public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
{
return false;
}
}
Custom Layout Selector:
class AutobinderLayoutSelector : StyleSelector
{
public Style DocumentStyle { get; set; }
public Style ToolStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
//check if the item is an instance of TestViewModel
if (item is IDockToolBar)
return DocumentStyle;
else if (item is IDockDocument)
return ToolStyle;
//delegate the call to base class
return base.SelectStyle(item, container);
}
}
and custom TemplateSelector:
public class AutobinderTemplateSelector : DataTemplateSelector
{
public DataTemplate DocumentTemplate { get; set; }
public DataTemplate ToolTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
//check if the item is an instance of TestViewModel
if (item is IDockToolBar)
return DocumentTemplate;
else if (item is IDockDocument)
return ToolTemplate;
//delegate the call to base class
return base.SelectTemplate(item, container);
}
}
public class AutobinderTemplate : DataTemplate
{
}
public interface IDockToolBar {
bool IsVisible { get; set; }
}
public interface IDockDocument { }
Upvotes: 3