【问题标题】:Create a TextBoxSearch to filter from ListView WPF创建一个 TextBoxSearch 以从 ListView WPF 中过滤
【发布时间】:2014-04-19 05:28:24
【问题描述】:

我正在创建一个应用程序,允许用户使用 WPF 将一些员工详细信息添加到 EntityFramework 模型中。

到目前为止,我有一个 ListView 来表示员工姓名列表,当您选择员工姓名时,它会选择另一个 ListView 中的特定数据。我使用PredicateICollectionSource 完成了这项工作。

但我现在想要实现的,是拥有一个所谓的搜索引擎。因此,当用户在 TextBox 中输入员工姓名时,它会根据在搜索框中输入的内容过滤员工姓名。

我使用This Link 作为指导,但我不太确定如何在我自己的设计中实现它;在示例中,他们使用了Resource 并使用了Array

这是我尝试过的,使用Predicate;

    private EmployeeListViewModel()
        : base("")
    {
        EmployeeList = new ObservableCollection<EmployeeViewModel>(GetEmployees());
        this._view = new ListCollectionView(this.employeeList);
    }

    private ListCollectionView _view;
    public ICollectionView View
    {
         get { return this._view; }
    }

    private string _TextSearch;
    public string TextSearch
    {
        get { return _TextSearch; }
        set
        {
            _TextSearch = value;
            OnPropertyChanged("TextSearch");

            if (String.IsNullOrEmpty(value))
                View.Filter = null;
            else
                View.Filter = new Predicate<object>(o => ((EmployeeViewModel)o).FirstName == value);
        }
    }

在我看来;

<TextBox Height="23" Name="txtSearch" VerticalAlignment="Bottom" Margin="70,0,0,183" Width="100" Grid.Row="1"
          Text="{Binding TextSearch, UpdateSourceTrigger=PropertyChanged}"/>

但是似乎发生的事情是,当我输入某些内容时,它会引发此异常;

Object reference not set to an instance of an object.

所以我的问题是,我怎样才能实现它,以便它实际上使我能够像在搜索框中一样过滤名称列表?

如有任何帮助或指导如何实现这一目标,我们将不胜感激。

【问题讨论】:

  • 在行上你得到这个错误?您是否尝试过一步一步地遵循您的代码,以确保所有内容都按您的预期调用?
  • 好吧,因为你的例外,所以只是一些建议。你的View 是否包含元素或者它可能是空的? EmployeeList 真的是 employeeList 的封装吗? FirstName 也是一个字符串,也许你应该只为测试设置一个默认值
  • employeeList 获取员工列表并绑定到Listview(在问题中简要提及)。 FirstName 是一个字符串,它是来自子 VM 的属性。如果有帮助,我可以发布整个 ViewModel 代码,让您更好地了解正在发生的事情。
  • 那会比我创建一个测试项目更好:)
  • 这是可能对您有所帮助的代码。 gist.github.com/gregorybmclub/b0a39435812f1506d7d2

标签: c# wpf listview mvvm


【解决方案1】:

好的,创建测试项目后我无法重现您的异常

这是我的工作代码:

MainWindow.xaml

<Window x:Class="gregory.bmclub.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBox Text="{Binding TextSearch,UpdateSourceTrigger=PropertyChanged}"/>
        <ListView Height="380" HorizontalAlignment="Left" Name="lsNames" VerticalAlignment="Top" Width="170" 
             ScrollViewer.VerticalScrollBarVisibility="Visible" 
             ScrollViewer.HorizontalScrollBarVisibility="Visible" 
             SelectedItem="{Binding SelectedEmployee}" 
             ItemsSource="{Binding View}" Grid.RowSpan="2" Grid.Row="1">
            <!--ItemsSource changed to "View"-->
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding FirstName}" Width="80" />
                    <GridViewColumn Header="Surname" DisplayMemberBinding="{Binding Surname}" Width="80" />
                </GridView>
            </ListView.View>
        </ListView>
    </StackPanel>
</Window>

MainWindow.cs

using System.Windows;

namespace gregory.bmclub
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new EmployeeListViewModel();
        }
    }
}

EmployeeViewModel.cs

namespace gregory.bmclub
{
    public class EmployeeViewModel
    {
        string firstname;

        public string FirstName
        {
            get { return firstname; }
            set { firstname = value; }
        }
    }
}

EmployeeListViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;

namespace gregory.bmclub
{
    class EmployeeListViewModel : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion

        public EmployeeListViewModel()//modified to public
        {
            EmployeeList = new ObservableCollection<EmployeeViewModel>(GetEmployees());
            this._view = new ListCollectionView(this.employeeList);
        }

        #region nonModifiedCode

        private ListCollectionView _employeeCol;
        public ICollectionView EmployeeCollection
        {
            get { return this._employeeCol; }
        }

        private ObservableCollection<EmployeeViewModel> employeeList;
        public ObservableCollection<EmployeeViewModel> EmployeeList
        {
            get { return employeeList; }
            set
            {
                employeeList = value;
                OnPropertyChanged("EmployeeList");
            }
        }

        private ListCollectionView _view;
        public ICollectionView View
        {
            get { return this._view; }
        }

        private string _TextSearch;
        public string TextSearch
        {
            get { return _TextSearch; }
            set
            {
                _TextSearch = value;
                OnPropertyChanged("TextSearch");

                if (String.IsNullOrEmpty(value))
                    View.Filter = null;
                else
                    View.Filter = new Predicate<object>(o => ((EmployeeViewModel)o).FirstName == value);
            }
        }

        #endregion

        //created for testing
        private List<EmployeeViewModel> GetEmployees()
        {
            var mylist = new List<EmployeeViewModel>();
            mylist.Add(new EmployeeViewModel() { FirstName = "nummer1" });
            mylist.Add(new EmployeeViewModel() { FirstName = "nummer2" });

            return mylist;
        }
    }
}

【讨论】:

  • 看来您的问题出在其他地方
  • 嗨@WiiMaxx,这与我的绑定有关。我仍然将我的 NameList 绑定到集合,而不是视图。它现在似乎起作用了。谢谢:)。
  • 你定义了 private ListCollectionView _employeeCol;public ICollectionView EmployeeCollection 但从不使用它们
  • 另外,我真的不明白如何将文本搜索中的字符串转换为视图模型,就像在这一行中所做的那样:(EmployeeViewModel)o,这让我很困惑为什么会这样被标记为解决方案
【解决方案2】:

我有以下代码与我一起工作,但我不得不放弃 Textsearch 方法并应用了一个不同的方法,我添加了查看代码行,希望能够使您的代码正常工作。

private EmployeeListViewModel()
    : base("")
{
    EmployeeList = new ObservableCollection<EmployeeViewModel>(GetEmployees());
    this._view = new ListCollectionView(this.employeeList);
     myEmployeeList = new CollectionViewSource();
        myEmployeeList.Source = this.EscortList;
        myEmployeeList.Filter += ApplyFilter;
}
    internal CollectionViewSource employeeList { get; set; }

        internal CollectionViewSource myEmployeeList { get; set; }
        private ObservableCollection<EmployeeViewModel> employeeList;
    public ObservableCollection<EmployeeViewModel> EmployeeList
    {
        get { return employeeList; }
        set
        {
            employeeList = value;
            OnPropertyChanged("EmployeeList");
        }
    }

private ListCollectionView _view;
// the collection below is the collection you will need to be your listview itemsource {Binding View}
public ICollectionView View
{
     //you need to return your CollectionViewSource here
     get { return myEmployeeList._view; }
}

// you need to use the following filtering methods as it did work for methods
 private void OnFilterChanged()
    {
        myEmployeeList.View.Refresh();
    }

    private string filter;

    public string Filter
    {
        get { return this.filter; }
        set
        {
            this.filter = value;
            OnFilterChanged();
        }
    }

    void ApplyFilter(object sender, FilterEventArgs e)
    {
        EmployeeViewModel svm = (EmployeeViewModel)e.Item;

        if (string.IsNullOrWhiteSpace(this.Filter) || this.Filter.Length == 0)
        {
            e.Accepted = true;
        }
        else
        {
        // you can change the property you want to search your model
            e.Accepted = svm.Surname.Contains(Filter);
        }
    }

这是我要绑定到 Listview 的 Xaml 代码

<ListView Name="lsvEscort" HorizontalAlignment="Left" Height="297" ItemsSource="{Binding View}">

这是我的文本搜索过滤器绑定路径

<TextBox x:Name="txtSearch"  Grid.Column="1" Text="{Binding Path=Filter,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

希望这能解决您的问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多