使用AvalonDock + Caliburn Micro在WPF应用程序中正确处理文档关闭和工具隐藏

时间:2015-01-28 13:56:33

标签: c# wpf caliburn.micro avalondock

我试图在我的WPF应用程序中同时使用AvalonDock 2.0(符合MVVM)和Caliburn Micro。一切正常,除了与关闭文档窗格或隐藏工具窗格相关的几个问题。

我的主视图模型源自Conductor<IScreen>.Collection.OneActive,并为BindableCollectionScreen提供了两个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;
    }
}

1。结账文件

处理文档窗格关闭时出现第一个问题。 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中的空对象引用错误。这真的很丑,但它确实有效。我现在可以关闭文档,并在继续之前适当调用我的防护方法。无论如何,在这里获得一个不太苛刻的解决方案的建议会很好。

2。隐藏工具

隐藏工具窗格会产生另一个问题。在这种情况下,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 ,然后恢复布局。如果我错过了这两个步骤中的任何一个,则该窗格仍然隐藏。显然,我并没有遵循预期的实施策略。有人能指出我正确的方向吗?

0 个答案:

没有答案