简体   繁体   中英

WPF binding ObservableCollection with converter

I have an ObservableCollection of strings and I'm tring to bind it with converter to ListBox and show only the strings that start with some prefix.
I wrote:

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

public MainWindow()
{
    InitializeComponent();
    Names= new ObservableCollection<Names>();
    DataContext = this;
}

and the converter:

class NamesListConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return null;
        return (value as ICollection<string>).Where((x) => x.StartsWith("A"));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

and the XAML:

<ListBox x:Name="filesList" ItemsSource="{Binding Path=Names, Converter={StaticResource NamesListConverter}}" />

but the listbox do not update after its beed update (add or remove).
I have notice that if I removes the converter from the binding its works perfectly. What is wrong with my code?

Your converter is creating new collection from objects in the original ObservableCollection. The ItemsSource that is set using your binding is no longer the original ObservableCollection. To understand better, this is equal to what you have wrote:

 public object Convert(object value, Type targetType, object parameter,  System.Globalization.CultureInfo culture)
  {
      if (value == null)
         return null;
      var list = (value as ICollection<string>).Where((x) => x.StartsWith("A")).ToList();
      return list;
   }

The list that converter is returning is new object with copy of data from source collection. Further changes in original collection are not reflected in that new list so the ListBox does not know about that changes. If you want to filter your data take a look into CollectionViewSource .

EDIT: How to filter

     public ObservableCollection<string> Names { get; set; }
     public ICollectionView View { get; set; }
     public MainWindow()
     {
       InitializeComponent();

       Names= new ObservableCollection<string>();
       var viewSource  = new CollectionViewSource();
       viewSource.Source=Names;

      //Get the ICollectionView and set Filter
       View = viewSource.View;

      //Filter predicat, only items that start with "A"
       View.Filter = o => o.ToString().StartsWith("A");

       DataContext=this;
    }

In the XAML set the ItemsSource to the CollectionView

<ListBox x:Name="filesList" ItemsSource="{Binding Path=View}"/>

Probably the converter isn't used when you add or remove elements. The simplest way to achieve what you want may be to implement INotifyPropertyChanged in your class and fire the PropertyChanged event everytime you add or remove items. In general the "correct" way would be to use a CollectionView .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM