如何在WPF中过滤TreeView? [英] How to filter a TreeView in WPF?

查看:87
本文介绍了如何在WPF中过滤TreeView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在WPF TreeView上进行过滤时遇到麻烦。

I'm having troubles doing filtering on a WPF TreeView.

这是我的TreeView XAML:

Here is my TreeView XAML:

<TreeView x:Name="ResourcesTreeView" ItemsSource="{Binding Path=FilteredResources}">
<TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type models:HierarchicalResource}" ItemsSource="{Binding ContainedResources}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{Binding ResourceIdentifier.ResourceType, Converter={StaticResource ResourceTypeToIconConverter}}" 
                Stretch="Uniform" Height="23" VerticalAlignment="Center"/>
            <TextBlock Text="{Binding Path=Name}" Style="{StaticResource ResourceName}" VerticalAlignment="Center"/>
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.Resources>
<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectedItemChanged">
        <i:InvokeCommandAction Command="{Binding OnSelectedResourceChangedCommand}"
        CommandParameter="{Binding ElementName=ResourcesTreeView, Path=SelectedItem}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

这是HierarchicalResource类:

Here is the HierarchicalResource class:

public class HierarchicalResource
{
    public HierarchicalResource(ResourceIdentifier resourceIdentifier, List<HierarchicalResource> containedResources, string name)
    {
        this.ResourceIdentifier = resourceIdentifier;
        this.ContainedResources = containedResources;
        this.Name = name;
    }

    public ResourceIdentifier ResourceIdentifier { get; }

    public List<HierarchicalResource> ContainedResources { get; set; }

    public string Name { get; }
}

这是我初始化CollectionViewProperty的方式:

This is how Im initializing the CollectionViewProperty:

this.FilteredResources = CollectionViewSource.GetDefaultView(resourcesTree);

resourcesTree是一个包含一个根元素的列表,该根元素的ContainedResources属性包含多个子元素。
它看起来很棒。唯一的问题是,尝试进行过滤时无法正常工作。
当我尝试使用this.FilteredResources.Filter = obj => {...}时,它仅在根节点上发生一次。我如何真正使Filter委托在每个现有的树节点上执行?

the resourcesTree is a list that contain one root element, that contain several children in its ContainedResources property. It works an looks great. Only problem is that when trying to filter it is not working. When I am trying to use this.FilteredResources.Filter = obj => { ... } it is happening only once on the root node. How can I really make the Filter delegate to be executed on each of the existing tree nodes??

谢谢,
Guy

Thanks, Guy

推荐答案

这将不适合一堆评论,因此我将尝试在一个答案中进行解释。 (我没有时间写一个完整的示例。)

This isn't going to fit into a bunch of comments so I'll try and explain in an answer. (I don't have the time to write a complete sample.)

从基础开始,这样您就可以完全理解我的意思。
树视图中的内容由treeviewitems组成。

treeviewitem是带标题的项目控件。
这就是为什么您看到的文本是页眉属性的原因。
在层次结构模板中,您有一个itemssource绑定。

这是itemscontrol的itemssource,位于父树viewitem的内部。

这就是问题的原因.br

如果是treeviewitems,则过滤的只是顶层。

您没有过滤其中的itemscontrol。

或每个对象中的itemscontrol其中...等等。

Start from basics so you can definitely understand what I'm on about. The stuff in a treeview is composed of treeviewitems.
A treeviewitem is a headered items control. That's why the text you see is a "Header" property. In a hierarchical template you have an itemssource binding.
This is the itemssource for the itemscontrol which is INSIDE the parent treeviewitem.
And this is the cause of your issue.
What you're filtering is just that top level if treeviewitems.
You're not filtering the itemscontrols within them.
Or the itemscontrols within each of them... and so on.

与此相关的路线有两条。

There are two routes to go with this.

您可以在视图中进行过滤。



您可以在视图模型中进行过滤。

You can filter in the view.
or
You can filter in the viewmodel.

首先讨论 ViewModel

绑定到列表。

何时您可以执行此操作,并且会自动生成一个collectionview。

您可以获取对此的引用并对其应用过滤器。几乎就像他们设计了这个一样,您可以轻松地进行绑定,但是要进行更多的工作,并且可以对+进行排序。

Let's talk about the ViewModel first.
You bind to a list.
When you do that, there is a collectionview automatically generated.
You could get a reference to that and apply a filter to that. Almost as if they designed this so you can easily bind but put in a bit more work and you can sort + filter.

您应该对此进行一下搜索,但是粗略地说,这就像:

You should google up on this a bit, but loosely speaking this is like:

var view1 = CollectionViewSource.GetDefaultView(source);

您可能必须强制转换为collectionview或listcollectionview。
这些具有谓词过滤功能。
像这样:

https://social.technet.microsoft.com/wiki/contents/articles/26673.wpf-collectionview-tips.aspx#Filtering

有一个示例关联使用该文章,您可以基于列表绑定到显式collectionview。

You might have to cast to a collectionview or listcollectionview. These have filtering with predicates. Like this:
https://social.technet.microsoft.com/wiki/contents/articles/26673.wpf-collectionview-tips.aspx#Filtering
There's a sample associated with that article and you could bind to an explicit collectionview based on your list.

或者。

您可以在视图中执行此操作。

我建议您看看一下,但是视图模型过滤。

Alternatively.
You could do this in the view.
I suggest you take a look at this but go with the viewmodel filtering.

这比较困难,但是这意味着您的过滤器可以在XAML中使用。
我这样做的方法是使用转换器,但这也是一个框架元素。
像这样 http://drwpf.com/blog/category/value-converters /

This is more difficult but would mean your filter could go in XAML. The way I'd do this is with a converter, but one which is also a frameworkelement. Like this http://drwpf.com/blog/category/value-converters/

上面还可以具有转换器可以使用的一个或多个属性。

这是除数转换器:

This can also have a property (or properties) on it which the converter can use.
Here's a divisor converter:

public class DivideByConverter : MarkupExtension, IValueConverter
{
    public double Divisor { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double bound = System.Convert.ToDouble(value);
        return bound / Divisor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

已使用:

<ScaleTransform ScaleX="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType=Button}
    , Converter={local:DivideByConverter Divisor=480}
    }" 

为什么需要财产?

您想要某种方式来传递谓词,以便转换器可以为您过滤列表。

在WPF中,您可以过滤不带代码的CollectionViewSource吗?

您甚至可以列出谓词。

向转换器添加属性的技术非常有用。

You could even have a list of predicates.
The technique of adding a property to a converter is quite useful.

这篇关于如何在WPF中过滤TreeView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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