在WPF中仅使用XAML基于TextBox的文本过滤ListBox的项目

我目前有一个ListBox绑定到一个项目集合。 由于集合很大,我们希望根据TextBox上输入的文本过滤显示的项目。

我要问的是,如果只使用XAML可以实现,我不想修改项目集合,我想根据filter修改每个项目的可见性。

希望它清楚,

谢谢!

您可以使用CollectionViewSource应用过滤,另一个示例可以在这里和这里找到。

像CodeNaked和devdigital告诉你CollectionViewSource / CollectionView / ICollectionView是你的目标的关键

这是一个MVVM模式,但这是一个仅与View相关的问题,因此我不想在ViewModel上使用此代码。

这不是正确的方式,因为View只显示她得到的但不应该修改所以它应该/必须是你的ViewModel handel更改

所以现在一些代码剪辑:

public class myVM { public CollectionViewSource CollViewSource { get; set; } public string SearchFilter { get; set { if(!string.IsNullOrEmpty(SearchFilter)) AddFilter(); CollViewSource.View.Refresh(); // important to refresh your View } } public myVM(YourCollection) { CollViewSource = new CollectionViewSource();//onload of your VM class CollViewSource.Source = YourCollection;//after ini YourCollection } } 

Xaml Snip:

      

编辑我忘了filter

 private void AddFilter() { CollViewSource.Filter -= new FilterEventHandler(Filter); CollViewSource.Filter += new FilterEventHandler(Filter); } private void Filter(object sender, FilterEventArgs e) { // see Notes on Filter Methods: var src = e.Item as YourCollectionItemTyp; if (src == null) e.Accepted = false; else if ( src.FirstName !=null && !src.FirstName.Contains(SearchFilter))// here is FirstName a Property in my YourCollectionItem e.Accepted = false; } 

您可以使用CollectionViewSource执行此操作。 您不希望在XAML中完全执行此操作,因为如果过滤代码位于视图模型中(假设MVVM设计模式),则更容易测试此操作。

只有在XAML中无法实现此目的。 但还有其他两种方式:1)使用转换器

       

2)更好更自然的方法是使用CollectionView.Filter属性。 它不会修改底层集合。

 var collectionView = CollectionViewSource.GetDefaultView(your_collection); collectionView.Filter = filter_predicate 

我终于使用了这里提供的答案:

CollectionViewSource上的触发器filter

所以我将function转移到ViewModel。 我仍然是VMVM模式的新手,所以有时候我搞砸了。

谢谢大家。

XAML唯一真正做的就是以声明方式封装逻辑。 使用标记扩展你可以做很多,这是一个例子:

                      

请注意,这可以工作,但它会使每个GUI设计器都跳闸,也没有事件的IntelliSense,因为它们通常不是通过元素语法设置的。

这里有几个标记扩展,其中两个创建处理程序,一个创建一个动作:

  • FilterExtension
  • ExecuteActionsHandlerExtension
  • CallMethodActionExtension

扩展名如下所示:

 [ContentProperty("Filters")] class FilterExtension : MarkupExtension { private readonly Collection _filters = new Collection(); public ICollection 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); } 

非常简单,只需循环过滤并应用它们。 ExecuteActionsHandlerExtension

 [ContentProperty("Actions")] public class ExecuteActionsHandlerExtension : MarkupExtension { private readonly Collection _actions = new Collection(); public Collection Actions { get { return _actions; } } public bool ThrowOnException { get; set; } public ExecuteActionsHandlerExtension() { ThrowOnException = true; } public override object ProvideValue(IServiceProvider serviceProvider) { return new RoutedEventHandler((s, e) => { try { foreach (var action in Actions) { action.Invoke(); } } catch (Exception) { if (ThrowOnException) throw; } }); } } 

现在最后一个扩展有点复杂,因为它实际上需要做一些具体的事情:

 [ContentProperty("Settings")] public class CallMethodActionExtension : MarkupExtension { //Needed to provide dependency properties as MarkupExtensions cannot have any public CallMethodActionSettings Settings { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { return new Action(() => { bool staticCall = Settings.TargetObject == null; var argsCast = Settings.MethodArguments.Cast(); var types = argsCast.Select(x => x.GetType()).ToArray(); var args = argsCast.ToArray(); MethodInfo method; if (staticCall) { method = Settings.TargetType.GetMethod(Settings.MethodName, types); } else { method = Settings.TargetObject.GetType().GetMethod(Settings.MethodName, types); } method.Invoke(Settings.TargetObject, args); }); } } public class CallMethodActionSettings : DependencyObject { public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName", typeof(string), typeof(CallMethodActionSettings), new UIPropertyMetadata(null)); public string MethodName { get { return (string)GetValue(MethodNameProperty); } set { SetValue(MethodNameProperty, value); } } public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register("TargetObject", typeof(object), typeof(CallMethodActionSettings), new UIPropertyMetadata(null)); public object TargetObject { get { return (object)GetValue(TargetObjectProperty); } set { SetValue(TargetObjectProperty, value); } } public static readonly DependencyProperty TargetTypeProperty = DependencyProperty.Register("TargetType", typeof(Type), typeof(CallMethodActionSettings), new UIPropertyMetadata(null)); public Type TargetType { get { return (Type)GetValue(TargetTypeProperty); } set { SetValue(TargetTypeProperty, value); } } public static readonly DependencyProperty MethodArgumentsProperty = DependencyProperty.Register("MethodArguments", typeof(IList), typeof(CallMethodActionSettings), new UIPropertyMetadata(null)); public IList MethodArguments { get { return (IList)GetValue(MethodArgumentsProperty); } set { SetValue(MethodArgumentsProperty, value); } } public CallMethodActionSettings() { MethodArguments = new List(); } } 

所有这些片段都只是快速草稿,以展示如何实现这一目标。 ( 可以在此答案中找到属性filter实现的草稿。

在collectin中项目的某些属性上使用数据触发器,您可以在xaml中完成所有操作。