这个问题的标题可能听起来令人困惑,所以我会尝试以最好的方式解释自己。
我正在创建一个包含许多foreign key
个约束的表的应用程序。例如,在我的情况下,我有一个学生。每个学生表与父母详细信息表和医疗详细信息表都有foreign key
关系。
为了使我的应用程序易于使用,我实现了一系列不同的filters
来帮助用户搜索大量数据。
我有一个listview
来显示学生记录,并且与父母和医疗详细信息相同。但是,我想要做的是根据父母详细信息中的一组标准搜索学生记录。例如,搜索父母姓名。例如;如果学生有一个名为Bob的父母,listview
将filter
的父母称为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}"/>
我上面的代码片段是我为其他filter
实现的,所有这些都可以正常工作。但是,当我bind
property
到我的应用程序中的textbox
时,突然填充listview
的数据消失了。 This link here shows the before and after
如果我在 ContactNameSearch breakpoint
周围加property
,我也会看到“No Window Source”对话框。
我已经汇总了一个可以找到的小样本by click here
因此,我的问题是;我是否正确地实现了这一点,如果没有,是否有另一种方法可以做到这一点?
答案 0 :(得分: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);
}