您可以在 DataTemplate 中使用 CollectionViewSource 吗?

发布于 2024-09-28 00:28:15 字数 1482 浏览 8 评论 0原文

是否可以在数据模板中显式使用 CollectionViewSource?通常我们会将 CollectionViewSource 与模板一起放入资源中,但我们的模型不允许这样做,因为 collectionviewsource 的“源”是树中此级别的 DataContext 的属性,这意味着需要有一个实例在这个级别。将其放在资源的根目录中意味着只有一个实例。我们也不能简单地在外层使用分组,因为这些项目只有在层次结构的最底层才存在,而且并非所有兄弟姐妹都具有此属性。因此,我们在 DataTemplate 中实例化 CollectionViewSource(在本例中是 HierarchicalDataTemplate,但这无关紧要)在逻辑上是有意义的。

具体来说,我们试图允许在此特定节点级别进行特定排序。我们唯一的其他选择是在 ViewModel 本身中进行排序,但这变得很痛苦,因为我们使用的 ObservableCollections 本身不支持排序。实际上,我们在该主题上看到的每一篇文章都指出您应该正是出于这个原因使用 CollectionViewSource,因此出现了这个问题。

例如,这有效……

<HierarchicalDataTemplate x:Key="CategoryTemplate"
    ItemTemplate="{StaticResource TreeViewSymbolTemplate}"
    ItemsSource="{Binding Symbols}">

    <TextBlock Text="{Binding Name}" FontWeight="Bold" />

</HierarchicalDataTemplate>

但这不起作用……

<HierarchicalDataTemplate x:Key="CategoryTemplate"
    ItemTemplate="{StaticResource TreeViewSymbolTemplate}">

    <HierarchicalDataTemplate.ItemsSource>
        <Binding>
            <Binding.Source>
                <CollectionViewSource Source="{Binding Symbols}" />
            </Binding.Source>
        </Binding>
    </HierarchicalDataTemplate.ItemsSource>

    <TextBlock Text="{Binding Name}" FontWeight="Bold" />

</HierarchicalDataTemplate>

在我看来,它会,但事实并非如此。同样,我们不能将 CollectionViewSource 放在与数据模板相同的级别,因为每个模板需要一个实例,因为每个模板都有自己的一组项目(尽管它们都共享排序标准。)

M

Is it possible to explicitly use a CollectionViewSource inside a data template? Normally we'd put the CollectionViewSource in the resources alongside the template, but our model doesn't allow that because the 'source' of the collectionviewsource is a property of the DataContext at this level in the tree, meaning there needs to be an instance at this level. Putting it out in the root of the resources would mean there was only one instance. We also can't simply use grouping on the outer level as these items don't exist until you're this far down the hierarchy, and not all siblings even have this property. So it makes sense logically that we instantiate the CollectionViewSource within the DataTemplate (in this instance a HierarchicalDataTemplate, but that's irrelevant.)

Specifically, we're trying to allow a specific sorting at this particular node level. Our only other choice is to sort in the ViewModel itself but that becomes a pain since we're using ObservableCollections which don't themselves support sorting. Actually, every article we've seen on the topic all state you should be using a CollectionViewSource precisely for that reason, hence this question.

For example, this works…

<HierarchicalDataTemplate x:Key="CategoryTemplate"
    ItemTemplate="{StaticResource TreeViewSymbolTemplate}"
    ItemsSource="{Binding Symbols}">

    <TextBlock Text="{Binding Name}" FontWeight="Bold" />

</HierarchicalDataTemplate>

But this doesn’t…

<HierarchicalDataTemplate x:Key="CategoryTemplate"
    ItemTemplate="{StaticResource TreeViewSymbolTemplate}">

    <HierarchicalDataTemplate.ItemsSource>
        <Binding>
            <Binding.Source>
                <CollectionViewSource Source="{Binding Symbols}" />
            </Binding.Source>
        </Binding>
    </HierarchicalDataTemplate.ItemsSource>

    <TextBlock Text="{Binding Name}" FontWeight="Bold" />

</HierarchicalDataTemplate>

Seems to me like it would, but it doesn’t. Again, we can't put the CollectionViewSource out at the same level as the data template as there needs to be one instance per template since each has its own set of items (although they will all share sorting criteria.)

M

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

似最初 2024-10-05 00:28:15

好吧......所以这不完全是我想做的,但结果是完全相同的,甚至没有人发表评论,更不用说回答了,因此我把它作为一个。

我们需要这样做的最初原因是进行特定于节点的排序。虽然我们从未让 CollectionViewSource 工作,但我们确实设法将排序直接应用于节点。诀窍是在节点创建时执行此操作,或者像我们正在执行的那样,在节点展开时执行此操作(我们使用绑定,因此我们不会手动创建节点。)

请注意,我们的实际代码确实会跟踪我们是否已经将排序应用于有问题的节点,因此不会对每个“扩展”事件执行排序,但该代码与此问题无关,因此为了简洁起见,我省略了它。不过,您应该添加类似的内容。

无论如何,这就是如何进行每个节点排序...

private void tvSymbols_Expanded(object sender, RoutedEventArgs e) {

    TreeViewItem node = e.OriginalSource as TreeViewItem;
    if(node==null) return;
    node.Items.SortDescriptions.Clear();
    node.Items.SortDescriptions.Add(new SortDescription("SomeField",      ListSortDirection.Ascending));
    node.Items.SortDescriptions.Add(new SortDescription("SomeOtherField", ListSortDirection.Descending));

}

当然,如果有人仍然弄清楚为什么原始问题的代码不起作用,请让我知道!

标记

Ok... so this isn't exactly what I wanted to do, but the outcome is exactly the same, and nobody even commented, let alone answered, hence my putting this as one.

The original reason for us needing to do this was to have node-specific sorting. While we never did get the CollectionViewSource to work, we did manage to apply sorting directly to the nodes. The trick is to do it either at node creation time, or like we're doing it, when the node expands (we're using binding so we don't manually create the nodes.)

Note that our actual code does track if we've already applied the sort to the node in question so it isn't performed on each 'Expanded' event, but that code is irrelevant to this question so I omitted it for brevity. Still, you should add something similar.

Anyway, here's how you can do per-node sorting...

private void tvSymbols_Expanded(object sender, RoutedEventArgs e) {

    TreeViewItem node = e.OriginalSource as TreeViewItem;
    if(node==null) return;
    node.Items.SortDescriptions.Clear();
    node.Items.SortDescriptions.Add(new SortDescription("SomeField",      ListSortDirection.Ascending));
    node.Items.SortDescriptions.Add(new SortDescription("SomeOtherField", ListSortDirection.Descending));

}

Of course if anyone still figures out why the original question's code didn't work, lemme know!

Mark

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文