【问题标题】:Not an autocomplete WPF Combobox (but maybe close)不是自动完成的 WPF 组合框(但可能关闭)
【发布时间】:2013-05-24 10:04:39
【问题描述】:

我绑定了一个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 时更改组合框的绑定。

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

编辑:

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

view.Filter = delegate(object o)
                        {

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

                        };

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

【问题讨论】:

    标签: c# wpf binding filter combobox


    【解决方案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】:

      在 WPF 中进行过滤的正确方法是使用 CollectionViewSource。 ICollectionView 是任何 WPF 项控件的主要数据对象,它允许排序、分组和过滤等灵活性。从您的集合属性中获取默认视图。

      var view = CollectionViewSource.GetDefaultView(this.names);
      

      为过滤器属性设置一个谓词,它将在集合中的所有项目上执行。

      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();
          }
      

      【讨论】:

      • 有没有办法将它实现到可编辑组合框?组合框的“TextInput”和文本框的“OnTextChanged”一样吗?
      • TextInput 不等同于 OnTextChanged。而是使用 TextBoxBase.TextChanged 事件。
      • 我有一些意想不到的行为。我已经编辑了我的问题,你能看一下吗?
      【解决方案3】:

      使用ICollectionView 作为数据绑定属性类型而不是ObservableCollection&lt;string&gt;

      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();
      }
      

      【讨论】:

      • 这适用于更一般的集合吗?在 myClass 中,我不仅对查看名称感兴趣。该名称仅供用户使用,但在内部我将使用该对象的属性 .
      • 是的,确实如此。 ICollectionView 不仅适用于内置类型。
      • 我很努力,但仍然无法适应我的自定义课程。我想过滤它的 name 属性。我在这里发布了一个单独的问题:stackoverflow.com/questions/16816983/…
      【解决方案4】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-13
        • 1970-01-01
        • 2011-01-06
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 2013-11-25
        相关资源
        最近更新 更多