在 WPF 中,您可以在没有代码隐藏的情况下过滤 CollectionViewSource 吗?
确实,主题说明了一切。
<CollectionViewSource x:Key="MyData"
Source="{Binding}" Filter="{ SomethingMagicInXaml? }" />
这并不是说我不能有代码。它只是让我烦恼。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您“足够努力”,您可以在 XAML 中做几乎任何事情,甚至可以在其中编写整个程序。
您永远不会绕过后面的代码(好吧,如果您使用库,则不必编写任何内容,但应用程序当然仍然依赖于它),这是您在这种特定情况下可以执行的操作的示例:
标记扩展是您的如果你想在 XAML 中做点什么,朋友。
(您可能需要拼写出扩展名,即
me:FilterExtension
,因为 Visual Studio 中的即时检查可能会无缘无故地抱怨,当然它仍然可以编译并运行但警告可能会很烦人。另外,不要期望
CollectionViewSource.Filter
出现在 IntelliSense 中,它不会期望您通过 XML 元素表示法设置该处理程序)You can do pretty much anything in XAML if you "try hard enough", up to writing whole programs in it.
You will never get around code behind (well, if you use libraries you don't have to write any but the application still relies on it of course), here's an example of what you can do in this specific case:
Markup extensions are your friend if you want to do something in XAML.
(You might want to spell out the name of the extension, i.e.
me:FilterExtension
as the on-the-fly checking in Visual Studio may complain without reason, it still compiles and runs of course but the warnings might be annoying.Also do not expect the
CollectionViewSource.Filter
to show up in the IntelliSense, it does not expect you to set that handler via XML-element-notation)实际上,您甚至不需要访问
CollectionViewSource
实例,您可以直接在 ViewModel 中过滤源集合:(请注意,
ICollectionView.Filter
不是像ICollectionView.Filter
这样的事件code>CollectionViewSource.Filter,它是Predicate
Actually you don't even need access to the
CollectionViewSource
instance, you can filter the source collection directly in the ViewModel:(note that
ICollectionView.Filter
is not an event likeCollectionViewSource.Filter
, it's a property of typePredicate<object>
)WPF 自动创建 < code>CollectionView - 或其派生类型之一,例如
ListCollectionView
或BindingListCollectionView
- 每当您绑定任何IEnumerable
派生的源数据到ItemsControl.ItemsSource
属性。您获得哪种类型的CollectionView
取决于运行时在您提供的数据源上检测到的功能。有时,即使您尝试将自己的特定
CollectionView
派生类型显式绑定到ItemsSource
,WPF 数据绑定引擎也可能会包装它(使用内部类型CollectionViewProxy )。
自动提供的
CollectionView
实例由系统基于每个集合创建和维护(注意:不是 每个 UI 控件或每个 绑定目标)。换句话说,对于您绑定到的每个 s̲o̲u̲r̲c̲e̲ 集合,将有一个全局共享的“默认”视图,并且可以检索(或创建)这个唯一的CollectionView
实例按需)随时将相同的“原始”IEnumerable 实例传递回静态方法 CollectionViewSource。再次获取DefaultView()。CollectionView
是一个垫片,能够跟踪排序和/或过滤状态而无需实际更改源。因此,如果相同的源数据被多个不同的Binding
用法引用,每个用法都有不同的CollectionView
,它们不会相互干扰。 “默认”视图旨在优化非常常见且简单得多的不需要或不需要过滤和排序的情况。简而言之,每个具有数据绑定
ItemsSource
属性的ItemsControl
最终都会具有排序和过滤功能,这要归功于一些流行的CollectionView
。您可以通过从ItemsControl.Items
属性中获取和操作“默认”CollectionView
,轻松对任何给定的IEnumerable
执行过滤/排序,但请注意UI 中最终使用该视图的所有数据绑定目标 - 要么是因为您显式绑定到 CollectionViewSource.GetDefaultView() ,要么是因为您的源不是CollectionView
完全一样——都将共享相同的排序/过滤效果。这可以实现许多简化的 XAML 场景:
如果给定的 IEnumerable 源具有单个全局共享的过滤/排序功能足以满足您的应用程序的需求,则只需直接绑定到
ItemsSource< /代码>。仍然仅在XAML中,您可以通过将同一控件上的
Items
属性视为ItemCollection
绑定来源。它有许多有用的可绑定属性来控制过滤/排序。如前所述,过滤/排序将在以这种方式绑定到同一源IEnumerable
的所有 UI 元素之间共享。 --或者--自己创建并应用一个或多个不同的(非“默认”)
CollectionView
实例。这允许每个数据绑定目标具有独立的过滤/排序设置。这也可以在 XAML 中完成,和/或您可以创建自己的(List)CollectionView
派生类。这种类型的方法在其他地方已得到很好的介绍,但我在这里想指出的是,在许多情况下,可以通过使用与 ItemsControl 数据绑定相同的技术来简化 XAML。 Items 属性(作为绑定源),以便访问有效的CollectionView
.摘要:
仅使用 XAML,您就可以将数据绑定到代表任何当前
的有效结果的集合>CollectionView
通过将其Items
属性视为只读绑定来对 WPFItemsControl
进行过滤/排序源< /em>.这将是一个 System.Windows.Controls.ItemCollection ,它公开用于控制活动过滤器和排序条件的可绑定/可变属性。[编辑] - 进一步的想法:
请注意,在将
IEnumerable
直接绑定到ItemsSource
的简单情况下,< a href="https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.itemcollection" rel="nofollow noreferrer">ItemCollection
您可以绑定到ItemsControl.Items
将是原始集合的CollectionViewSource.GetDefaultView()
的包装器。如上所述,在使用 XAML 的情况下,绑定到此 UI 包装器(通过ItemsControl.Items
)是理所当然的事情,而不是绑定到底层视图它包装(通过CollectionViewSource.GetDefaultView
),因为前一种方法为您省去了(在XAML中,尴尬的)必须显式提及任何CollectionView
根本没有。但更进一步,因为
ItemCollection
包装了默认的CollectionView
,在我看来,即使在代码隐藏< /strong>(其中选择不太明显)绑定到 UI 发布的视图可能也更实用,因为这样最适合 事实上 的运行时功能两者都是数据源和它的 UI 控制目标。WPF automatically creates a
CollectionView
—or one of its derived types such asListCollectionView
, orBindingListCollectionView
—whenever you bind anyIEnumerable
-derived source data to anItemsControl.ItemsSource
property. Which type ofCollectionView
you get depends on the capabilities detected at runtime on the data source you provide.Sometimes even if you try to explicitly bind your own specific
CollectionView
-derived type to anItemsSource
, the WPF data binding engine may wrap it (using the internal typeCollectionViewProxy
).The automatically-supplied
CollectionView
instance is created and maintained by the system on a per collection basis (note: not per- UI control or per- bound target). In other words, there will be exactly one globally-shared "Default" view for each s̲o̲u̲r̲c̲e̲ collection that you bind to, and this uniqueCollectionView
instance can be retrieved (or created on demand) at any time by passing the same "original"IEnumerable
instance back to the static methodCollectionViewSource.GetDefaultView()
again.CollectionView
is a shim that is able to keep track of the sorting and/or filtering state without actually altering the source. Therefore, if the same source data is referenced by several differentBinding
usages each with a differentCollectionView
, they won't interfere with each other. The "Default" view is intended to optimize the very common--and much simpler--situations where filtering and sorting are not required or expected.In short, every
ItemsControl
with a data-boundItemsSource
property will always end up with sorting and filtering capabilities, courtesy of some prevailingCollectionView
. You can easily perform filtering/sorting for any givenIEnumerable
by grabbing and manipulating the "Default"CollectionView
from theItemsControl.Items
property, but note that all the data-bound targets in the UI that end up using that view--either because you explicitly bound toCollectionViewSource.GetDefaultView()
, or because your source wasn't aCollectionView
at all--will all share those same sorting/filtering effects.This enables numerous simplified XAML scenarios:
If having a single, globally-shared filter/sort capability for the given
IEnumerable
source is sufficient for your app, then just bind directly toItemsSource
. Still in XAML only, you can then filter/sort the items by treating theItems
property on the same Control as anItemCollection
binding source. It has many useful bindable properties for controlling the filter/sort. As noted, filtering/sorting will be shared amongst all UI elements which are bound to the same sourceIEnumerable
in this way. --or--Create and apply one or more distinct (non-"Default")
CollectionView
instances yourself. This allows each data-bound target to have independent filter/sort settings. This can also be done in XAML, and/or you can create your own(List)CollectionView
-derived classes. This type of approach is well-covered elsewhere, but what I wanted to point out here is that in many cases the XAML can be simplified by using the same technique of data-binding to theItemsControl.Items
property (as a binding source) in order to access the effectiveCollectionView
.Summary:
With XAML alone, you can data-bind to a collection representing the effective results of any current
CollectionView
filtering/sorting on a WPFItemsControl
by treating itsItems
property as a read-only binding source. This will be aSystem.Windows.Controls.ItemCollection
which exposes bindable/mutable properties for controlling the active filter and sort criteria.[edit] - further thoughts:
Note that in the simple case of binding your
IEnumerable
directly toItemsSource
, theItemCollection
you can bind to atItemsControl.Items
will be a wrapper on the original collection'sCollectionViewSource.GetDefaultView()
. As discussed above, in the case of XAML usage it's a no-brainer to bind to this UI wrapper (viaItemsControl.Items
), as opposed to binding to the underlying view it wraps (viaCollectionViewSource.GetDefaultView
), since the former approach saves you the (in XAML, awkward) trouble of having to explicitly mention anyCollectionView
at all.But further, because that
ItemCollection
wraps the defaultCollectionView
, it seems to me that, even in code-behind (where the choice is less obvious) it's perhaps also more utilitarian to bind to the view promulgated by the UI, since such is best attuned to the de-facto runtime capabilities of both the data source and its UI control target.我在使用 接受的解决方案时遇到了以下问题:
可以轻松解决此问题
通过更改为
I had the following issues with the accepted solution provided by H.B. using .NET FrameWork 4.6.1 (old, I know, but unfortunately a limitation for my current situation):
This was easily resolved by changing
to