如何将ObservableCollection绑定到AvalonDock DocumentPaneGroup? [英] How do I bind an ObservableCollection to an AvalonDock DocumentPaneGroup?

查看:110
本文介绍了如何将ObservableCollection绑定到AvalonDock DocumentPaneGroup?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在AvalonDock 2.0中将一组项目加载为文档.这些对象继承自一个抽象类,我想根据其子类在文档内部渲染一个框架.

I need to load a collection of items as documents in AvalonDock 2.0. These objects inherit from an abstract class, for which I want to render a frame inside the document depending on which subclass are.

这是我的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集合中的项目一样多的文档,但是我似乎无法在每个文档中显示任何内容.

So far I've achieved to show as many documents as items are in the OpenProjects collection, but I can't seem to show anything inside each document.

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

Plus, I don't know if I'm using ActiveContent properly: I want to assign to CurrentProject the ViewModel assigned on the current active document.

谢谢您的时间.

推荐答案

之所以看不到任何内容,是因为您定义了LayoutItem模板.这行不通.
还可以考虑使用自定义控件代替Frame. Frame非常重.除非不需要显示HTML,否则请避免使用此控件.内容导航非常容易实现,以防您想要显示可导航的内容.只需将文档内容包装到UserControl.

The reason why you are not able to see any content is of the way you defined your LayoutItem templates. This can't work.
Also consider to use a custom control instead of the Frame. The Frame is very heavy. Unless you don't need to display HTML, avoid this control. Content navigation is very easy to implement, in case you want to show navigable content. Just wrap your document content into a UserControl.

您正在正确使用ActiveContent属性.

要解决您的问题,您有三种推荐的解决方案,其中第一种不能完全满足您的要求.由于您定义了DockingManager.LayoutItemTemplate错误,因此无论如何我都会显示它.

To fix your problem you have three recommended solutions, where the first doesn't exactly meet your requirements. Since you defined the DockingManager.LayoutItemTemplate wrong, I will show it anyway.

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

In case you only need a single template for all LayoutDocument and LayoutAnchorable containers, you can use the DockingManager.LayoutItemTemplate property. This property accepts a single DataTemplate. Nested DataTemplate definitions, like in your code, are generally not supported by WPF.

<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定义.


Solution 2: Implicit DataTemplate

In more advanced scenarios you display different views based on different models. If the displayed content depends on the data type of the model alone (like in your case), the recommended approach is to provide implicit DataTemplate definitions.

WPF将自动将隐式DataTemplate应用于与该模板的DataTemplate.TargetType匹配的每种数据类型.
如果未分配x:Key值,则DataTemplate是隐式的.为了确保实际上可以自动应用DataTemplate,还必须在与目标类型相同的资源范围内定义DataTemplate.例如,在 App.xaml Application.Resources中定义DataTemplate,将使模板自动应用于应用范围.

WPF will automatically apply an implicit DataTemplate to every data type that matches the DataTemplate.TargetType of this template.
The DataTemplate is implicit, if it has no explicit x:Key value assigned. To ensure that the DataTemplate can actually be applied automatically, the DataTemplate must also be defined in the same resource scope as the target type. E.g., defining the DataTemplate in Application.Resources of App.xaml, would make the template to be applied automatically in the application scope.

<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定义的先前解决方案可以替换为DataTemplateSelector. DataTemplateSelector是另一个WPF概念,用于选择性地应用DataTemplate.
如果选择DataTemplate可能比单独模型的数据类型更复杂的约束,建议使用DataTemplateSelector.它允许例如对数据项进行评估,并根据特定条件选择合适的模板.


Solution 3: DataTemplateSelector

The previous solution, which uses implicit DataTemplate definitions, can be replaced with a DataTemplateSelector. DataTemplateSelector is another WPF concept to apply a DataTemplate selectively.
A DataTemplateSelector is the recommended choice, if selecting a DataTemplate may depend on more complex constraints, than the model's data type alone. It allows to e.g. evaluate the data item and chose the appropriate template based on certain criteria.

要定义模板选择器,必须扩展DataTemplateSelector,它应返回DataTemplate.
最简单的方法是使用x:Key App.xaml 资源字典中定义模板,然后根据条件从模板中进行选择.
DockingManger通过分配DockingManager.LayoutItemTemplateSelector属性来接受模板选择器:

To define a template selector, you have to extend DataTemplateSelector, which is expected to return a DataTemplate.
The easiest way is to define the templates in App.xaml resource dictionary using an x:Key and then select from them based on the condition.
DockingManger accepts a template selector by assigning the DockingManager.LayoutItemTemplateSelector property:

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

App.xaml
Define the explicit DataTemplate using x:Key:

<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
以下代码使用Switch表达式,该表达式自C#8.0起可用.可以用switch语句或级联的if语句代替它.

DocumentManagerTemplateSelector.cs
The following code uses the Switch Expression, which is available since C# 8.0. It can be replaced with a switch statement or cascaded if-statements.

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>

这篇关于如何将ObservableCollection绑定到AvalonDock DocumentPaneGroup?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆