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

C# 使用AvalonDock+Caliburn Micro在WPF应用程序中正确处理文档关闭和工具隐藏,c#,wpf,caliburn.micro,avalondock,C#,Wpf,Caliburn.micro,Avalondock,我正在尝试在我的WPF应用程序中同时使用MVVM兼容和。除了一些与关闭文档窗格或隐藏工具窗格有关的问题外,所有这些都可以正常工作 My main viewmodel派生自Conductor.Collection.OneActive,并为工具和文档公开两个BindableCollection的屏幕派生viewmodels;相应的XAML如下所示: <xcad:DockingManager Grid.Row="1" AnchorablesSource="{

我正在尝试在我的WPF应用程序中同时使用MVVM兼容和。除了一些与关闭文档窗格或隐藏工具窗格有关的问题外,所有这些都可以正常工作

My main viewmodel派生自Conductor.Collection.OneActive,并为工具和文档公开两个BindableCollection的屏幕派生viewmodels;相应的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>
1.结案文件 第一个问题出现在处理文档窗格关闭时。AD有自己的文档处理机制,应该与CM的同步。CM基于屏幕导体;当需要关闭屏幕时,如果可能,使用方法TryClose将其关闭,即,除非guard方法告诉框架无法关闭屏幕,例如,因为文档脏了。为了让AD使用CM,我使用了一种类似于中所述的解决方法,其中主视图代码直接调用此方法来处理docking manager关闭事件:当AD关闭文档时,调用底层VM guard方法,并在需要时取消;如果未取消,则AD继续关闭,从而触发DocumentClosed事件

为了验证这是否可行,我首先在文档viewmodel库中创建了一个公共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文档关闭和文档关闭处理程序中调用的方法:

请注意,我不能在OnDocumentClosing中直接调用TryClose,因为这会导致AD中出现空对象引用错误。这确实很难看,但它可以工作。我现在可以关闭文档,并在继续之前适当地调用我的保护方法。不管怎么说,如果能在这里找到一个不那么老套的解决方案,那就太好了

2.隐藏工具 另一个问题是隐藏“工具”窗格。在这种情况下,广告应该只是隐藏它们。AD控件可见性可以使用Booleant可见性转换器绑定到我的viewmodels实现工具窗格中的IsVisible布尔属性。为此,我只需在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,然后恢复布局。如果我错过了这两个步骤中的任何一个,窗格将保持隐藏状态。很明显,我没有遵循预期的实施策略。谁能给我指出正确的方向吗?

看看双子座。。。我知道有一些丑陋的黑客在那里处理阿瓦隆码头的问题。谢谢这是个不错的主意!不幸的是,Gemini看起来像是一个相当大的框架,因此挖掘其代码并不比试图挖掘AD/CM源代码寻找提示更容易。无论如何,考虑到这似乎是一个相当常见的问题,而且我没有找到完整的指导,我为此创建了一个公共GitHub:请随意查看并贡献:最后记住一点。再次感谢,除非我错了,否则这似乎与Gemini选择如何处理CM和AD之间的文档同步有关,使用从CM ActiveItem到AD ActiveContent的数据绑定。就我而言,我没有遇到这样的问题;相反,文档处理似乎还可以,但工具处理却不行,除非我再次遇到一些难看的问题,比如在更改工具可见性后在docking manager中强制更新布局。感兴趣的读者可以在上面提到的github项目的自述文件中找到更多信息。似乎通过更多的谷歌搜索和实验,我至少解决了最明显的问题。一个关键的帖子是,即使我不得不稍微修改它的解决方案。我现在已经更新了我的GitHub回购协议,但我仍然愿意接受任何改进它或修复其他一些烦恼的建议。更多信息,请阅读回购协议中更新的自述文件。多谢大家
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();
}
<xcad:DockingManager.LayoutItemContainerStyle>
    <Style TargetType="{x:Type xcad:LayoutItem}">
        ...
        <Setter Property="Visibility" 
                Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityCvt}}"/>
        ...