【问题标题】:Filter through a table to search through foreign key data通过表过滤以搜索外键数据
【发布时间】:2014-04-13 12:26:05
【问题描述】:

这个问题的标题可能听起来令人困惑,所以我会尽力解释自己。

我正在创建一个应用程序,该应用程序包含许多具有许多 foreign key 约束的表。例如,就我而言,我有一个学生。每个学生表与父母详细信息表和医疗详细信息表都有foreign key 关系。

为了使我的应用程序易于使用,我实现了一系列不同的filters 来帮助用户搜索大量数据。

我有一个listview 来显示学生记录,以及父母和医疗详细信息。但是,我想做的是根据父母详细信息中的一组标准搜索学生记录。例如,搜索父母姓名。例如;是一个学生的父母叫 Bob,listviewfilter 学生的父母叫 Bob。

这是我尝试过的;

   //Constructor;
   StudentList = new ObservableCollection<StudentViewModel>(GetStudents());

   CollectionViewSource.GetDefaultView(StudentList).Filter = new Predicate<object>(MainFilter);

   //Properties
   private string contactNameSearch;
   public string ContactNameSearch
   {
       get { return contactNameSearch; }
       set
       {
           contactNameSearch = value;
           CollectionViewSource.GetDefaultView(StudentList).Refresh();
           OnPropertyChanged("ContactNameSearch");
       }
   }

   private bool FilterContactNameSearch(object obj)
   {
       StudentContactViewModel item = obj as StudentContactViewModel;
       if (item == null) return false;
       if (String.IsNullOrWhiteSpace(ContactNameSearch)) return true;

       if (ContactNameSearch.Trim().Length == 0) return true;

       if (item.Name1.ToLower().Contains(ContactNameSearch.ToLower())) return true;
       return false;
   }

   public bool MainFilter(object o)
   {
       return FilterContactNameSearch(o); // &... and more filters
   }

   //Xaml
   <TextBox Height="23" Name="txtContactName" Width="100" 
                    Text="{Binding ContactNameSearch, UpdateSourceTrigger=PropertyChanged}"/>

上面的代码 sn-p 是我为我的另一个 filter 实现的,它们都可以正常工作。但是,当我在我的应用程序中 bind 这个 propertytextbox 时,突然之间填充 listview 的数据消失了。 This link here shows the before and after

如果我在 ContactNameSearch property 周围加上 breakpoint,我还会出现“无窗口源”对话框。

我整理了一个小样本,可以在by click here找到它

因此,我的问题是;我是否正确实施了这一点,如果没有,是否有其他方法可以做到这一点?

【问题讨论】:

  • 阅读您在示例中显示的代码,您是否尝试使用“||”进行更改而不是这里的“&”?返回 FilterSchoolSearch(o) & FilterContactNameSearch(o) & FilterNameSearch(o) & FilterFormSearch(o) & FilterIDSearch(o) & FilterEnrollment(o) & FilterNameSearch(o);因为如果你放一个“&”,如果其中一个过滤器返回 false,那么 MainFilter 的所有结果都将为 false...
  • @MauroBilotti 感谢您的回复。我会改变它,看看是否有效。
  • 不客气!告诉我它是否能解决您的问题...
  • 我应该把它们都改成|而不是&?
  • 我认为使用触发事件的按钮然后将 ListView 绑定到过滤后的 ObservableCollection 会更容易。

标签: wpf listview binding filter


【解决方案1】:

在我的应用程序中为用户提供过滤功能时,我倾向于使用两个集合。一个拥有整个未过滤的集合,并且一旦填充,就保持不变。另一种是仅包含第一个集合中与给定过滤条件匹配的项目。第二个集合是数据绑定到 UI 中的 ItemsControl.ItemsSource 属性的集合。

public ObservableCollection<YourDataType> DataTypes
{
    get { return dataTypes; }
    set
    {
        if (dataTypes != value) 
        {
            dataTypes = value; 
            NotifyPropertyChanged("DataTypes");
            FilterDataTypes();
        }
    }
}

public ObservableCollection<YourDataType> FilteredDataTypes // Data bind this one
{
    get { return filteredDataTypes ?? (filteredDataTypes = DataTypes); }
    private set { filteredDataTypes = value; NotifyPropertyChanged("FilteredDataTypes"); }
}

现在,您的FilterDataTypes 方法基本上需要通过您认为合适的任何方式过滤DataTypes 集合并填充FilteredDataTypes 集合。此示例使用 string 输入,该输入是数据绑定到 UI 中的筛选框,实际筛选条件在 CheckFields 方法中。

private void FilterDataTypes()
{
    filteredDataTypes = new ObservableCollection<YourDataType>();
    string filterText = FilterText.Trim().ToLower();
    if (filterText == string.Empty)
    {
        foreach (YourDataType dataType in DataTypes)
        {
            FilteredDataTypes.Add(dataType);
        }
    }
    else
    {
        foreach (YourDataType dataType in DataTypes.Where(m => CheckFields(m)))
        {
            FilteredDataTypes.Add(dataType);
        }
    }
    NotifyPropertyChanged("FilteredDataTypes");
}

private bool CheckFields(YourDataType dataType)
{
    string filterText = FilterText.Trim().ToLower();
    return filterText == string.Empty ? true : 
        dataType.Parent.Name.ToLower().Contains(filterText);
}

public string FilterText
{
    get { return filterText; }
    set
    {
        if (filterText != value)
        {
            filterText = value;
            NotifyPropertyChanged("FilterText");
            FilterDataTypes(); // <-- Filters collection when value is changed
        }
    }
}

现在这个简单示例只有一个过滤器输入,但您可以使用其他方法(如 CheckFields 方法)添加任意数量的过滤器,但基于其他数据绑定属性的值:

private void FilterDataTypes()
{
    filteredDataTypes = new ObservableCollection<YourDataType>();
    string filterText = FilterText.Trim().ToLower();
    if (filterText == string.Empty)
    {
        foreach (YourDataType dataType in DataTypes)
        {
            FilteredDataTypes.Add(dataType);
        }
    }
    else
    {
        foreach (YourDataType dataType in 
            DataTypes.Where(m => CheckFields(m) | CheckOptions(m)))
        {
            FilteredDataTypes.Add(dataType);
        }
    }
    NotifyPropertyChanged("FilteredDataTypes", "DataTypesCount");
}

public YourDataType SelectedItem // <-- Data bind to ItemsControl.SelectedItem
{
    get { return selectedItem; }
    set
    {
        if (selectedItem != value)
        {
            selectedItem = value;
            NotifyPropertyChanged("SelectedItem");
            FilterDataTypes();
        }
    }
}

private bool CheckOptions(YourDataType dataType) // <-- And use to filter collection
{
    string filterText = SelectedItem.Name.Trim().ToLower();
    return filterText == string.Empty ? true : 
        dataType.Doctor.Name.ToLower().Contains(filterText);
}

【讨论】:

  • 感谢您的回复。我正在查看您提供的代码,但有一些错误。首先,您参考“DataTypesCount”这个属性是什么?另外,我无法调用“AddRange(StudentList)”,因为没有扩展名。
  • 对不起,我忘了删除对DataTypesCount的调用...你可以忽略它。至于AddRange 方法,要么在ObservableCollection&lt;T&gt; 类中添加一个扩展方法来添加多个项目,要么只是在循环中使用Add 方法来添加它们。
  • 我了解您是如何实现这一点的,只是想将其合并到我的应用程序中。因此,对于您要过滤的每个新项目,您都将其添加到 FilterDataTypes() 方法中,对吗?我还收到以下错误;错误Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable&lt;StudentViewModel&gt;' to 'StudentViewModel'
  • Dude...FilterDataTypes 是一种方法,因此您无法向其中添加项目,我怎么知道您从哪里得到该错误?老实说,我觉得我已经花了很长时间回答你的问题,而且比大多数答案远远更详细。我真的希望您能自己解决剩下的问题,因为我没有时间教您编程的所有基础知识,例如foreach 循环和转换错误(您的最后一个错误)。如果你真的分不清IEnumerable&lt;StudentViewModel&gt;StudentViewModel 之间的区别,那我们就是在浪费时间。
  • 再看一遍我的回答……感觉已经很清楚了。
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
  • 2020-07-06
  • 1970-01-01
  • 2020-09-03
  • 2012-11-01
相关资源
最近更新 更多