不是自动完成的WPF组合框(但可能很接近)

时间:2013-05-29 08:26:44

标签: c# wpf binding filter combobox

我有ObservableCollectionComboBox绑定。我想要实现的是过滤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与文本框输入不匹配的名称来删除吗?

其他方法是在从namesfilteredNames输入内容时更改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的类),我通过反复试验意识到这一点。 代码有点混乱(而且非常长),因为我在那里有读取文件方法,你看到的东西可以给我那个错误吗?我想我没有把代码放在正确的位置。有人可以解释一下,“委托”到底是做什么的?

4 个答案:

答案 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();
}
相关问题