0

我有一个ObservableCollection和一个ComboBox绑定到它。我想要实现的是过滤它ObservableCollection,只让ComboBox显示过滤的项目。后来在某个地方我有一个foreach (item in ComboBox) loop. 过滤应该是写一些字母,如果其中项目的名称属性ObservableCollection不包含该字母,则删除该项目。

我知道有一种方法可以直接在带有IsEditable属性的 ComboBox 中输入,但是对于这个示例,我们只使用一个额外的 TextBox 来进行用户输入。

为了练习,我正在使用 a ObservableCollection<string>(而不是使用<myClass>具有更多属性的 my 。)

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其他方法是在从to键入内容时更改组合框的绑定filteredNames

如何以简单的方式实现这一目标?

编辑:

感谢使用 CollectionViewSource 的建议,它在本示例中运行良好,但在我的实际程序中我遇到了一些问题。我已将问题部分减少到此(来自 XAML Lover 解决方案)

view.Filter = delegate(object o)
                        {

                            if (o.ToString().StartsWith(myTextBox.Text))
                            {
                                return true;
                            }
                            return false;

                        };

我已经看到了下一个行为:如果我什么都不写,一旦加载文件,comboBox 就会填充数据并且一切正常。如果我写了与“Unico.Canal”不同的任何内容,所有数据都会从组合框中消失(Unico 是我的命名空间,而 Canal 是 CollectionViewSource 的类),我已经通过反复试验意识到这一点。代码有点乱(而且很长),因为我在那里有读取文件的方法,你有没有看到可能给我这个错误的东西?我想我没有把代码放在正确的地方。有人可以解释一下那个“代表”到底在做什么以及它是如何工作的吗?

4

4 回答 4

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();
    }
于 2013-05-29T08:51:10.350 回答
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}" />
于 2013-05-29T08:57:37.767 回答
0

如果我正确理解你的问题,我会改变这个

public ObservableCollection<string> FilteredNames{ get; set; }

public ObservableCollection<string> FilteredNames
{ 
    get
       {
            if(IsNamesFilterd)
            {
                return _filteredNames;
            }
            else
            {
                return _names ;
            }
       }
 }

通过更改事件处理程序代码中的布尔条件。更改布尔值后还 NotifyPropertyChanged。

于 2013-05-29T08:43:17.520 回答
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();
}
于 2013-05-29T08:45:59.223 回答