【问题标题】:How do I bind an ObservableCollection to an AvalonDock DocumentPaneGroup?如何将 ObservableCollection 绑定到 AvalonDock DocumentPaneGroup?
【发布时间】:2014-11-19 12:15:29
【问题描述】:

我需要在 AvalonDock 2.0 中加载一组项目作为文档。这些对象继承自一个抽象类,我想根据哪个子类在文档中呈现一个框架。

这是我的 XAML:

<ad:DockingManager Background="Gray" DocumentsSource="{Binding Path=OpenProjects}" 
        ActiveContent="{Binding Path=CurrentProject, Mode=TwoWay}">
    <ad:DockingManager.DocumentHeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=OpenProjects/Name}" />
        </DataTemplate>
    </ad:DockingManager.DocumentHeaderTemplate>
    <ad:DockingManager.LayoutItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.Resources>
                    <DataTemplate DataType="{x:Type vm:SubclassAViewModel}">
                        <Frame Source="Pages/SubclassAProject.xaml" />
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type vm:SubclassBViewModel}">
                        <Frame Source="Pages/SubclassBProject.xaml" />
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type vm:SubclassCViewModel}">
                        <Frame Source="Pages/SubclassCProject.xaml" />
                    </DataTemplate>
                </Grid.Resources>
            </Grid>
        </DataTemplate>
    </ad:DockingManager.LayoutItemTemplate>
    <ad:LayoutRoot>
        <ad:LayoutPanel>
            <ad:LayoutDocumentPaneGroup>
                <ad:LayoutDocumentPane>

                </ad:LayoutDocumentPane>
            </ad:LayoutDocumentPaneGroup>
        </ad:LayoutPanel>
    </ad:LayoutRoot>
</ad:DockingManager>

到目前为止,我已经实现了显示与 OpenProjects 集合中的项目一样多的文档,但我似乎无法在每个文档中显示任何内容。

另外,我不知道我是否正确使用了ActiveContent:我想将分配给当前活动文档的 ViewModel 分配给 CurrentProject

感谢您的宝贵时间。

【问题讨论】:

    标签: c# wpf mvvm binding avalondock


    【解决方案1】:

    您看不到任何内容的原因是您定义LayoutItem 模板的方式。这行不通。
    还可以考虑使用自定义控件而不是 FrameFrame 很重。除非您不需要显示 HTML,否则请避免使用此控件。内容导航很容易实现,以防您想显示可导航的内容。只需将您的文档内容包装成UserControl

    您正在正确使用ActiveContent 属性。

    要解决您的问题,您有三个推荐的解决方案,其中第一个不完全符合您的要求。既然你把DockingManager.LayoutItemTemplate定义错了,那我还是给大家看看吧。

    解决方案1:本地LayoutItemTemplate

    如果您只需要一个模板用于所有 LayoutDocumentLayoutAnchorable 容器,则可以使用 DockingManager.LayoutItemTemplate 属性。此属性接受单个 DataTemplate。 WPF 通常不支持嵌套的DataTemplate 定义,就像在您的代码中一样。

    <ad:DockingManager>
        <ad:DockingManager.LayoutItemTemplate>
            <DataTemplate>
                <Frame Source="Pages/SubclassAProject.xaml" />
            </DataTemplate>
        </ad:DockingManager.LayoutItemTemplate>
    
        <ad:LayoutRoot>
            <ad:LayoutPanel>
                <ad:LayoutDocumentPaneGroup>
                    <ad:LayoutDocumentPane />
                </ad:LayoutDocumentPaneGroup>
            </ad:LayoutPanel>
        </ad:LayoutRoot>
    </ad:DockingManager>
    

    解决方案 2:隐式 DataTemplate

    在更高级的场景中,您会根据不同的模型显示不同的视图。如果显示的内容仅取决于模型的数据类型(如您的情况),推荐的方法是提供隐式 DataTemplate 定义。

    WPF 将自动将隐式 DataTemplate 应用于与此模板的 DataTemplate.TargetType 匹配的每个数据类型。
    DataTemplate 是隐式的,如果它没有明确分配 x:Key 值。为确保DataTemplate 实际上可以自动应用,DataTemplate 还必须在与目标类型相同的资源范围内定义。例如,在 App.xamlApplication.Resources 中定义 DataTemplate,将使模板在应用程序范围内自动应用。

    <ad:DockingManager>
        <ad:DockingManager.Resources>
            <DataTemplate DataType="{x:Type vm:SubclassAViewModel}">
                <Frame Source="Pages/SubclassAProject.xaml" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type vm:SubclassBViewModel}">
                <Frame Source="Pages/SubclassBProject.xaml" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type vm:SubclassCViewModel}">
                <Frame Source="Pages/SubclassCProject.xaml" />
            </DataTemplate>
        </ad:DockingManager.Resources>
    
        <ad:LayoutRoot>
            <ad:LayoutPanel>
                <ad:LayoutDocumentPaneGroup>
                    <ad:LayoutDocumentPane>
    
                    </ad:LayoutDocumentPane>
                </ad:LayoutDocumentPaneGroup>
            </ad:LayoutPanel>
        </ad:LayoutRoot>
    </ad:DockingManager>
    

    解决方案 3:DataTemplateSelector

    之前使用隐式DataTemplate 定义的解决方案可以替换为DataTemplateSelectorDataTemplateSelector 是另一个 WPF 概念,可以选择性地应用 DataTemplate
    DataTemplateSelector 是推荐的选择,如果选择 DataTemplate 可能取决于比模型的数据类型更复杂的约束条件。它允许例如评估数据项并根据某些标准选择适当的模板。

    要定义一个模板选择器,你必须扩展DataTemplateSelector,它应该返回一个DataTemplate
    最简单的方法是使用x:KeyApp.xaml 资源字典中定义模板,然后根据条件从它们中进行选择。
    DockingManger 通过分配@ 来接受模板选择器987654357@财产:

    App.xaml
    使用x:Key 定义显式DataTemplate

    <Application.Resources>
        <DataTemplate x:Key="SubclassAViewModelTemplate" DataType="{x:Type vm:SubclassAViewModel}">
            <Frame Source="Pages/SubclassAProject.xaml" />
        </DataTemplate>
        <DataTemplate x:Key="SubclassBViewModelTemplate" DataType="{x:Type vm:SubclassBViewModel}">
            <Frame Source="Pages/SubclassBProject.xaml" />
        </DataTemplate>
        <DataTemplate x:Key="SubclassCViewModelTemplate" DataType="{x:Type vm:SubclassCViewModel}">
            <Frame Source="Pages/SubclassCProject.xaml" />
        </DataTemplate>
    </Application.Resources>
    

    DocumentManagerTemplateSelector.cs
    以下代码使用自 C# 8.0 起可用的 Switch 表达式。它可以用 switch 语句或级联 if 语句替换。

    class DocumentManagerTemplateSelector : DataTemplateSelector
    {
      #region Overrides of DataTemplateSelector
    
      public override DataTemplate SelectTemplate(object item, DependencyObject container)
      {
        return item switch
        {
          SubclassAViewModel _ => Application.Current.Resources["SubclassAViewModelTemplate"] as DataTemplate,
          SubclassBViewModel _ => Application.Current.Resources["SubclassBViewModelTemplate"] as DataTemplate,
          SubclassCViewModel _ => Application.Current.Resources["SubclassCViewModelTemplate"] as DataTemplate,
          _ => base.SelectTemplate(item, container)
        };
      }
    
      #endregion
    }
    

    MainWindow.xaml

    <ad:DockingManager>
        <xcad:DockingManager.LayoutItemTemplateSelector>
          <local:DocumentManagerTemplateSelector />
        </xcad:DockingManager.LayoutItemTemplateSelector>
    
        <ad:LayoutRoot>
            <ad:LayoutPanel>
                <ad:LayoutDocumentPaneGroup>
                    <ad:LayoutDocumentPane>
    
                    </ad:LayoutDocumentPane>
                </ad:LayoutDocumentPaneGroup>
            </ad:LayoutPanel>
        </ad:LayoutRoot>
    </ad:DockingManager>
    

    【讨论】:

    • 非常感谢您的回答。是否也可以有多个 'LayoutDocumentPane' - 每个 DataType 一个?以及如何将正确的对象寻址到“LayoutPane”? stackoverflow.com/questions/63630628/…
    • 我已经发布了对您的链接问题的答案。
    猜你喜欢
    • 1970-01-01
    • 2014-01-12
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 2014-08-23
    • 1970-01-01
    • 2013-09-07
    相关资源
    最近更新 更多