动态添加 DockablePanes
Dynamically add DockablePanes
我有一个 CustomControl 和该控件的视图模型列表。使用 ItemsControl 我能够为每个视图模型动态创建一个控件。现在我使用 AvalonDock,我想为每个生成的 UserControl 添加一个 DockableContent。这如何动态完成?
您想将 collection 的 ViewModels 绑定到停靠管理器的 DocumentSource,并设置模板绑定到标题等属性,如下所示:
<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>
并使用如下方式动态添加内容:
Documents.Add(MyNewlyCreatedViewModel)
编辑: 当您使用静态窗格时,事情会变得更加复杂。您必须使用模板选择器为 normal/static 窗格选择正确的模板。 MVVM AvalonDock 示例非常好。以下是我的实现方式(工具是静态的):
<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>
使用自定义 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;
}
}
自定义布局选择器:
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);
}
}
和自定义模板选择器:
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 { }
我有一个 CustomControl 和该控件的视图模型列表。使用 ItemsControl 我能够为每个视图模型动态创建一个控件。现在我使用 AvalonDock,我想为每个生成的 UserControl 添加一个 DockableContent。这如何动态完成?
您想将 collection 的 ViewModels 绑定到停靠管理器的 DocumentSource,并设置模板绑定到标题等属性,如下所示:
<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>
并使用如下方式动态添加内容:
Documents.Add(MyNewlyCreatedViewModel)
编辑: 当您使用静态窗格时,事情会变得更加复杂。您必须使用模板选择器为 normal/static 窗格选择正确的模板。 MVVM AvalonDock 示例非常好。以下是我的实现方式(工具是静态的):
<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>
使用自定义 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;
}
}
自定义布局选择器:
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);
}
}
和自定义模板选择器:
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 { }