我试图在我的WPF应用程序中同时使用AvalonDock 2.0(符合MVVM)和Caliburn Micro。一切正常,除了与关闭文档窗格或隐藏工具窗格相关的几个问题。
我的主视图模型源自Conductor<IScreen>.Collection.OneActive
,并为BindableCollection
和Screen
提供了两个Tools
Documents
个派生的视图模型。相应的相关XAML如:
<xcad:DockingManager Grid.Row="1"
AnchorablesSource="{Binding Path=Tools}"
DocumentsSource="{Binding Path=Documents}"
ActiveContent="{Binding Path=ActiveItem, Mode=TwoWay}">
<xcad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type xcad:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.DisplayName}" />
</Style>
</xcad:DockingManager.LayoutItemContainerStyle>
<xcad:DockingManager.LayoutItemTemplateSelector>
<views:AutobinderTemplateSelector>
<views:AutobinderTemplateSelector.Template>
<DataTemplate>
<ContentControl cal:View.Model="{Binding . }" IsTabStop="False" />
</DataTemplate>
</views:AutobinderTemplateSelector.Template>
</views:AutobinderTemplateSelector>
</xcad:DockingManager.LayoutItemTemplateSelector>
<xcad:LayoutRoot>
<xcad:LayoutPanel Orientation="Horizontal">
<xcad:LayoutAnchorablePane DockHeight="150" DockMinWidth="200">
</xcad:LayoutAnchorablePane>
<xcad:LayoutDocumentPane/>
</xcad:LayoutPanel>
</xcad:LayoutRoot>
</xcad:DockingManager>
模板选择器就像那样简单:
public class AutobinderTemplateSelector : DataTemplateSelector
{
public DataTemplate Template { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return Template;
}
}
处理文档窗格关闭时出现第一个问题。 AD有其文档处理机制,应该与CM的机制同步。 CM基于屏幕导体;当需要关闭屏幕时,方法TryClose
用于在可能的情况下关闭它(即,除非保护方法告诉框架屏幕不能被关闭,例如因为文档是脏的)。要让AD与CM一起使用类似于Prevent document from closing in DockingManager中描述的解决方法,其中主视图代码直接调用此方法来处理停靠管理器关闭事件:当AD关闭文档时,调用底层VM保护方法,如果需要取消;如果没有取消,则AD继续关闭,从而触发DocumentClosed
事件。
要查看这是否可行,我首先在文档视图模型库中创建了一个公共TryClose
方法,基本上复制了CM TryClose
覆盖中的代码,如(IsDirty
是一个受后代viewmodels覆盖的受保护虚拟方法):
public bool CanClose()
{
if (!IsDirty()) return true;
MessageBoxAction prompt = new MessageBoxAction
{ ...prompt message here... };
bool bResult = true;
prompt.Completed += (sender, args) =>
{
bResult = prompt.Result == MessageBoxResult.Yes;
};
prompt.Execute(null);
return bResult;
}
这是AD 文档关闭和文档关闭处理程序后面的主视图代码调用的方法:
private void OnDocumentClosing(object sender, DocumentClosingEventArgs e)
{
DocumentBase doc = e.Document.Content as DocumentBase;
if (doc == null) return;
e.Cancel = !doc.CanClose();
}
private void OnDocumentClosed(object sender, DocumentClosedEventArgs e)
{
DocumentBase editor = e.Document.Content as DocumentBase;
if (doc != null) doc.TryClose();
}
请注意,我无法直接调用TryClose
中的OnDocumentClosing
,因为这会导致AD中的空对象引用错误。这真的很丑,但它确实有效。我现在可以关闭文档,并在继续之前适当调用我的防护方法。无论如何,在这里获得一个不太苛刻的解决方案的建议会很好。
隐藏工具窗格会产生另一个问题。在这种情况下,AD应该隐藏它们。可以使用IsVisible
转换器将AD控件可见性绑定到实现工具窗格的viewmodels中的BooleanToVisibility
布尔属性。为此,我只需在XAML中添加绑定:
<xcad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type xcad:LayoutItem}">
...
<Setter Property="Visibility"
Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityCvt}}"/>
...
现在,如果我通过单击其X按钮隐藏工具窗格,我可以看到我的VM IsVisible
属性按预期设置为false
,并且窗格被隐藏。然后,如果我以编程方式将此属性设置回true
,则不会显示该窗格。甚至恢复布局也不起作用:我可以看到,当应用程序启动并且与隐藏VM相对应的对象被添加到Tools
集合时,其IsVisible
已经是false
。要将其恢复,我必须将其设置为true
和,然后恢复布局。如果我错过了这两个步骤中的任何一个,则该窗格仍然隐藏。显然,我并没有遵循预期的实施策略。有人能指出我正确的方向吗?