真的是这个主题说明了一切。
<CollectionViewSource x:Key="MyData"
Source="{Binding}" Filter="{ SomethingMagicInXaml? }" />
并不是说我不能拥有代码。它只是唠叨我。
答案 0 :(得分:18)
如果你“努力”,up to writing whole programs in it,你可以在XAML中做很多事情。
你永远不会忘记代码(好吧,如果你使用库,你不必编写任何代码,但应用程序当然仍然依赖它),这里有一个例子,说明在这个特定情况下你可以做些什么: / p>
<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>
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);
}
// 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;
}
}
}
}
}
如果您想在XAML中执行某些操作,则标记扩展名是您的朋友。
(您可能想要拼出扩展名,即me:FilterExtension
,因为Visual Studio中的动态检查可能会无缘无故地抱怨,它仍然会编译并运行当然但是警告可能很烦人
另外,不要指望CollectionViewSource.Filter
出现在IntelliSense中,它不希望您通过XML-element-notation设置该处理程序)
答案 1 :(得分:16)
实际上您甚至不需要访问CollectionViewSource
实例,您可以直接在ViewModel中过滤源集合:
ICollectionView view = CollectionViewSource.GetDefaultView(collection);
view.Filter = predicate;
(请注意,ICollectionView.Filter
不是CollectionViewSource.Filter
之类的事件,它是Predicate<object>
类型的属性
答案 2 :(得分:1)
WPF 会自动创建CollectionView
或派生类型,例如ListCollectionView
,BindingListCollectionView
等(具体取决于您在源代码中检测到的功能)集合) - 对于任何ItemsSource
绑定,如果在将IEnumerable
派生的源直接绑定到ItemsControl.ItemsSource
属性时未提供一个绑定。
系统会在 每个集合 的基础上创建和维护此自动提供的CollectionView
实例(注意:不是每个UI控件或绑定目标)。换句话说,您绑定的每个源将只有一个全局共享的“默认”视图,并且可以在以下检索(或按需创建)此唯一CollectionView
实例。任何时候将IEnumerable
传递给静态方法CollectionViewSource.GetDefaultView()
。
有时即使您尝试将自己的特定CollectionView
派生类型显式绑定到ItemsSource
,WPF数据绑定引擎也可以将其包装(使用内部类型CollectionViewProxy
)。
在任何情况下,每个具有数据绑定ItemsControl
属性的ItemsSource
将始终以排序和过滤功能结束,这得益于一些流行的CollectionView
。您可以通过抓取并操纵其“默认”IEnumerable
轻松地对任何给定的CollectionView
执行过滤/排序,但请注意UI中最终使用该视图的所有数据绑定目标 - 要么因为您明确绑定到CollectionViewSource.GetDefaultView()
,或者因为您根本没有提供任何视图 - 所有视图都会共享相同的排序/过滤效果。
除了将源集合 绑定到
ItemsSource
的{{1}}属性之外,此主题上没有经常提及的内容(如绑定目标),您还可以“同时” 访问已应用过滤器/排序结果的有效集合 - 公开为{{1 -System.Windows.Controls.ItemCollection
的派生实例 - 通过绑定 来自 控件的ItemsControl
属性(作为绑定源 )。
这可以实现许多简化的XAML场景:
如果为您的应用提供针对给定CollectionView
来源的单一全局共享过滤器/排序功能,则只需直接绑定到Items
即可。仍然只在 XAML 中,您可以通过 将同一控件上的IEnumerable
属性视为ItemCollection
来对项目进行过滤/排序绑定来源。它有许多有用的可绑定属性来控制过滤器/排序。如上所述,过滤/排序将在以这种方式绑定到同一源ItemsSource
的所有UI元素之间共享。 --or -
自己创建并应用一个或多个不同的(非“默认”)Items
实例。这允许每个数据绑定目标具有独立的过滤器/排序设置。这也可以在 XAML 中完成,和/或您可以创建自己的IEnumerable
派生类。这种方法在其他地方有很好的涵盖,但我想在此指出的是,在许多情况下,通过使用 数据绑定到CollectionView
的相同技术可以简化XAML属性 (作为绑定源),以便访问 有效(List)CollectionView
。
<强>要点:强>
仅使用 XAML ,您就可以数据绑定到表示WPF ItemsControl.Items
上任何当前CollectionView
过滤/排序的有效结果的集合。将其CollectionView
属性视为只读绑定 源 。这将是ItemsControl
,它公开可绑定/可变属性以控制活动过滤器和排序条件。
Items
直接绑定到System.Windows.Controls.ItemCollection
的简单情况下,ItemCollection
可以绑定到IEnumerable
将成为原始集合ItemsSource
的包装器。如上所述,在 XAML 用法中,绑定到此UI包装器(通过ItemsControl.Items
)是明智的,而不是绑定到它包装的底层视图(通过{{1} }),因为前一种方法可以省去你提到CollectionViewSource.GetDefaultView()
的麻烦。
但更进一步,因为ItemsControl.Items
包装默认CollectionViewSource.GetDefaultView
,在我看来,即使在 代码隐藏中也是如此(选择不那么明显)它可能更加实用,可以绑定到UI发布的视图,因为这可能更好地适应数据源和的UI的功能控制目标。