我有ObservableCollection
和ComboBox
绑定。我想要实现的是过滤ObservableCollection
并仅让ComboBox
显示过滤的项目。后来某处我有一个foreach (item in ComboBox) loop
。过滤应该是通过写一些字母,如果ObservableCollection
中的项目的名称属性不包含该字母,请删除该项目。
我知道有一种方法可以直接在带有IsEditable
属性的ComboBox中输入,但是对于这个例子,我们只需要为用户的输入使用一个额外的TextBox。
对于练习,我使用的是ObservableCollection<string>
(而不是具有更多属性的<myClass>
。)
public MainWindow()
{
InitializeComponent();
names= new ObservableCollection<string>();
names.Add("Harry");
names.Add("Ron");
names.Add("Einstein");
names.Add("Frodo");
names.Add("Spiderman");
myComboBox.DataContext = this;
}
public ObservableCollection<string> names{ get; set; }
public ObservableCollection<string> filteredNames{ get; set; }
我创建了这个方法:
void toFilter()
{
filteredNames=new ObservableCollection<string>(names.Where(name=> name.StartsWith(myTextBox.Text)));
}
在text changed
:
private void myTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (myTextBox.Text.Length > 0)
{
toFilter();
}
myComboBox.DataContext = this; //Obviously doesn't work
}
所以我想保持原始集合的完整性(names
),并在文本框中输入内容时显示filteredNames
。我应该直接将组合框绑定到filteredNames
(最初等于names
),然后通过循环每次myTextBox_TextChanged
与文本框输入不匹配的名称来删除吗?
其他方法是在从names
到filteredNames
输入内容时更改comboBox的绑定。
如何以简单的方式实现这一目标?
编辑:
感谢您使用CollectionViewSource的建议,它在这个示例中完美运行,但在我的真实程序中我遇到了一些问题。我已将问题部分减少到此(来自XAML Lover解决方案)
view.Filter = delegate(object o)
{
if (o.ToString().StartsWith(myTextBox.Text))
{
return true;
}
return false;
};
我已经看到了下一个行为: 如果我没有写任何东西,一旦加载了文件,comboBox就会填充数据,而且一切都很好。如果我写的任何与“Unico.Canal”不同的东西,所有数据都从组合框中消失(Unico是我的命名空间,而Canal是CollectionViewSource的类),我通过反复试验意识到这一点。 代码有点混乱(而且非常长),因为我在那里有读取文件方法,你看到的东西可以给我那个错误吗?我想我没有把代码放在正确的位置。有人可以解释一下,“委托”到底是做什么的?
答案 0 :(得分:1)
WPF中用于过滤的正确方法是使用CollectionViewSource。 ICollectionView是任何WPF项目控件的主要数据对象,可以实现排序,分组和过滤等灵活性。从您的集合属性中获取默认视图。
var view = CollectionViewSource.GetDefaultView(this.names);
将Predicate设置为Filter属性,该属性将在集合中的所有项目上执行。
view.Filter = delegate(object o)
{
if (o.ToString().StartsWith(textbox.Text))
{
return true;
}
return false;
};
将视图设置为ComboBox ItemsSource,
myComboBox.ItemsSource = view;
在TextChanged事件上刷新视图以更新组合框。
private void Textbox_OnTextChanged(object sender, TextChangedEventArgs e)
{
((ICollectionView)myComboBox.ItemsSource).Refresh();
}
答案 1 :(得分:1)
使用CollectionViewSource并将其源设置为您的名称集。
在你的viewModel中,你将设置一个像这样的collectionViewSource;
CollectionViewSource myCollectionViewSource = new CollectionViewSource();
myCollectionViewSource.Source = names;
您需要设置谓词来过滤collectionViewSource中的项目
myCollectionViewSource.View.Filter = new Predicate(this.MyFilter);
public bool MyFilter(string item)
{
// put whatever filtering logic you have in here
return item.StartsWith(myTextBox.Text);
}
然后将collectionViewSource作为属性公开给视图。
public CollectionViewSource MyCollectionViewSource
{
get
{
return myCollectionViewSource;
}
set
{
myCollectionViewSource = value;
// make sure to raise INotifyPropertyChanged here
}
}
然后在您的XAML中,您的ComboBox将如下所示;
<ComboBox ItemsSource="{Binding MyCollectionViewSource.View}" />
答案 2 :(得分:0)
如果我理解你的问题, 我会改变这个
public ObservableCollection<string> FilteredNames{ get; set; }
到
public ObservableCollection<string> FilteredNames
{
get
{
if(IsNamesFilterd)
{
return _filteredNames;
}
else
{
return _names ;
}
}
}
更改事件处理程序代码中的布尔条件。 更改布尔值后也是NotifyPropertyChanged。
答案 3 :(得分:0)
使用ICollectionView
作为数据绑定属性类型而不是ObservableCollection<string>
:
namesView = CollectionViewSource.GetDefaultView(names);
namesView.Filter = item =>
{
if (myTextBox.Text.Length > 0)
{
return ((string)item).StartsWith(myTextBox.Text);
}
return true;
};
private void myTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
namesView.Refresh();
}