在WPF中,您可以在没有代码的情况下过滤CollectionViewSource吗?

Jer*_*xon 12 c# wpf xaml filter collectionviewsource

真的是这个主题说的一切.

<CollectionViewSource x:Key="MyData"
    Source="{Binding}" Filter="{ SomethingMagicInXaml? }" />
Run Code Online (Sandbox Code Playgroud)

并不是说我不能拥有代码.它只是唠叨我.

H.B*_*.B. 20

如果你"努力学习",你可以在XAML中做任何事情,直到在其中编写整个程序.

你永远不会忘记代码(好吧,如果你使用库,你不必编写任何代码,但应用程序当然仍然依赖它),这里有一个例子,你可以在这个特定情况下做些什么:

<CollectionViewSource x:Key="Filtered" Source="{Binding DpData}"
                      xmlns:me="clr-namespace:Test.MarkupExtensions">
    <CollectionViewSource.Filter>
        <me:Filter>
            <me:PropertyFilter PropertyName="Name" Value="Skeet" />
        </me:Filter>
    </CollectionViewSource.Filter>
</CollectionViewSource>
Run Code Online (Sandbox Code Playgroud)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Markup;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Windows;
using System.Text.RegularExpressions;

namespace Test.MarkupExtensions
{
    [ContentProperty("Filters")]
    class FilterExtension : MarkupExtension
    {
        private readonly Collection<IFilter> _filters = new Collection<IFilter>();
        public ICollection<IFilter> Filters { get { return _filters; } }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new FilterEventHandler((s, e) =>
                {
                    foreach (var filter in Filters)
                    {
                        var res = filter.Filter(e.Item);
                        if (!res)
                        {
                            e.Accepted = false;
                            return;
                        }
                    }
                    e.Accepted = true;
                });
        }
    }

    public interface IFilter
    {
        bool Filter(object item);
    }
Run Code Online (Sandbox Code Playgroud)
    // Sketchy Example Filter
    public class PropertyFilter : DependencyObject, IFilter
    {
        public static readonly DependencyProperty PropertyNameProperty =
            DependencyProperty.Register("PropertyName", typeof(string), typeof(PropertyFilter), new UIPropertyMetadata(null));
        public string PropertyName
        {
            get { return (string)GetValue(PropertyNameProperty); }
            set { SetValue(PropertyNameProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(PropertyFilter), new UIPropertyMetadata(null));
        public object Value
        {
            get { return (object)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty RegexPatternProperty =
            DependencyProperty.Register("RegexPattern", typeof(string), typeof(PropertyFilter), new UIPropertyMetadata(null));
        public string RegexPattern
        {
            get { return (string)GetValue(RegexPatternProperty); }
            set { SetValue(RegexPatternProperty, value); }
        }

        public bool Filter(object item)
        {
            var type = item.GetType();
            var itemValue = type.GetProperty(PropertyName).GetValue(item, null);
            if (RegexPattern == null)
            {
                return (object.Equals(itemValue, Value));
            }
            else
            {
                if (itemValue is string == false)
                {
                    throw new Exception("Cannot match non-string with regex.");
                }
                else
                {
                    return Regex.Match((string)itemValue, RegexPattern).Success;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想在XAML中执行某些操作,标记扩展名是您的朋友.

(您可能要拼出扩展的名称,即me:FilterExtension作为上即时在Visual Studio检查没有理由可以抱怨,但它仍然编译,当然会走动,但警告可能是恼人的.
也不要指望CollectionViewSource.Filter,以出现在IntelliSense中,它不希望您通过XML-element-notation设置该处理程序)


Tho*_*que 16

实际上你甚至不需要访问CollectionViewSource实例,你可以直接在ViewModel中过滤源集合:

ICollectionView view = CollectionViewSource.GetDefaultView(collection);
view.Filter = predicate;
Run Code Online (Sandbox Code Playgroud)

(注意,这ICollectionView.Filter不是类似的事件CollectionViewSource.Filter,它是类型的属性Predicate<object>)

  • @Jerry Nixon,这不是*代码支持; 这是ViewModel的代码.当然,除非您将任何C#代码视为代码隐藏... (4认同)
  • +1因为你的答案不是代码隐藏的,所以它在ViewModel中. (2认同)

Gle*_*den 8

每当您将任何 - 派生源数据绑定到属性时,WPF 都会自动创建CollectionView- 或其派生类型之一,例如ListCollectionView,或。您获得哪种类型取决于您提供的数据源在运行时检测到的功能。BindingListCollectionViewIEnumerableItemsControl.ItemsSourceCollectionView

有时,即使您尝试将自己的特定CollectionView派生类型显式绑定到ItemsSource,WPF 数据绑定引擎也可能对其进行包装(使用内部类型CollectionViewProxy)。

自动提供的CollectionView实例由系统在每个集合的基础上创建和维护(注意:不是 每个UI 控件或每个绑定目标)。换句话说,每个s?o?u?r?c?e?将有一个全球共享的“默认”视图您绑定到的集合,并且CollectionView可以随时通过将相同的“原始”IEnumerable实例CollectionViewSource.?GetDefaultView()再次传递回静态方法来检索(或按需创建)此唯一实例。

CollectionView是一种能够跟踪排序和/或过滤状态而不实际更改源的垫片。因此,如果相同的源数据被几个不同的Binding用法引用,每个用法都有不同的CollectionView,它们不会相互干扰。“默认”视图旨在优化不需要或不需要过滤和排序的非常常见且简单得多的情况。

总之,每ItemsControl一个数据绑定ItemsSource属性将始终结束与排序和过滤能力,一些流行的礼貌CollectionView。您可以IEnumerable通过CollectionViewItemsControl.Items属性中抓取和操作“默认”轻松地对任何给定对象执行过滤/排序,但请注意 UI 中所有最终使用该视图的数据绑定目标——要么是因为您明确绑定到CollectionViewSource.GetDefaultView(),要么因为您的来源根本不是CollectionView- 都将共享相同的排序/过滤效果。

在这个主题上不常提到的是,除了将源集合绑定(作为绑定目标)的ItemsSource属性之外,您还可以“同时”访问应用的过滤器/排序结果的有效集合--公开为-控件的属性(作为绑定)绑定的派生实例。ItemsControlCollectionViewSystem.Windows.Controls.ItemCollectionItems

这启用了许多简化的 XAML 方案:

  1. 如果IEnumerable您的应用程序具有针对给定源的单个全局共享过滤器/排序功能就足够了,那么只需直接绑定到ItemsSource. 仍然仅在XAML 中,然后您可以通过Items同一 Control 上的属性视为ItemCollection绑定来过滤/排序项目。它有许多有用的可绑定属性来控制过滤器/排序。如前所述,过滤/排序将IEnumerable在以这种方式绑定到同一源的所有 UI 元素之间共享。 - 或者 -

  2. 自己创建和应用一个或多个不同的(非“默认”)CollectionView实例。这允许每个数据绑定目标具有独立的过滤器/排序设置。这也可以在XAML中完成,和/或您可以创建自己的(List)CollectionView派生类。这种类型的方法在其他地方有很好的介绍,但我想在这里指出的是,在许多情况下,可以通过使用相同的数据绑定到ItemsControl.Items属性(作为绑定)技术来简化 XAML ,以便访问在有效CollectionView


简介:

使用XAML,您就可以将数据绑定到一个集合,该集合表示WPF 上任何当前过滤/排序的有效结果,方法是将其属性视为只读绑定。这将公开用于控制活动过滤器和排序标准的可绑定/可变属性。CollectionViewItemsControlItemsSystem.Windows.Controls.ItemCollection


[编辑] - 进一步的想法:

请注意,在将您IEnumerable直接绑定到的简单情况下ItemsSourceItemCollection您可以绑定到 atItemsControl.Items将是原始集合的CollectionViewSource.GetDefaultView(). 如上所述,在使用XAML的情况下,绑定到此 UI 包装器 (via ItemsControl.Items) 是显而易见的,而不是绑定到它包装的底层视图 (via CollectionViewSource.GetDefaultView),因为前一种方法为您节省了 (在XAML 中,尴尬)不得不明确提及任何问题的麻烦CollectionView

但进一步,因为它ItemCollection 包含了 default CollectionView,在我看来,即使在代码隐藏中(选择不太明显),绑定到 UI 发布的视图也可能更实用,因为这样最适合事实上的数据源两者的运行时功能它的UI控制目标。

  • -1 来自我,因为@Glenn Slayden 应该提供一些实际的实现,至少是相关的细节,而不是太多的讨论 - 毕竟,这就是这个网站的全部内容...... (4认同)
  • 我非常欣赏以清晰的方式进行的概念讨论。谢谢。 (2认同)