Search code examples
c#wpfdata-bindingobservablecollection

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?


Solution

  • 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}"/>