¿Cómo actualizar automáticamente el filtro y / o el orden de clasificación en CollectionViewSource, cuando cambia la propiedad de un elemento individual?

Ok, entonces esta pregunta está relacionada con Windows Phone 7 / Silverlight (herramientas WP7 actualizadas, septiembre de 2010), específicamente filtrando un subyacenteObservableCollection<T>.

Al jugar con la aplicación de control de Pivot de plantilla WP7, me he encontrado con un problema por el cual cambiar un elemento subyacente en unObservableCollection<T>, no da como resultado que se actualice ListBox en pantalla. Básicamente, la aplicación de muestra tiene dos pivotes, el primero directamente vinculado al subyacenteObservableCollection<T>, y el segundo vinculado a unCollectionViewSource (es decir, que representa una vista filtrada en el subyacenteObservableCollection<T>)

Los elementos subyacentes que se agregan alObservableCollection<T> implementarINotifyPropertyChanged, al igual que:

public class ItemViewModel : INotifyPropertyChanged
{       
    public string LineOne
    {
        get { return _lineOne; }
        set
        {
            if (value != _lineOne)
            {
                _lineOne = value;
                NotifyPropertyChanged("LineOne");
            }
        }
    } private string _lineOne;

    public string LineTwo
    {
        get { return _lineTwo; }
        set
        {
            if (value != _lineTwo)
            {
                _lineTwo = value;
                NotifyPropertyChanged("LineTwo");
            }
        }
    } private string _lineTwo;

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != _isSelected)
            {
                _isSelected = value;
                NotifyPropertyChanged("IsSelected");
            }
        }
    } private bool _isSelected = false;

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Luego, en la clase principal, se confecciona una recopilación de datos (la lista se reduce por brevedad, también tenga en cuenta que, a diferencia de otros elementos, tres de las entradas LoadData () tienen IsSelected == true):

 public class MainViewModel : INotifyPropertyChanged
 {
  public MainViewModel()
  {
   this.Items = new ObservableCollection<ItemViewModel>();
  }

  public ObservableCollection<ItemViewModel> Items { get; private set; }

  public bool IsDataLoaded
  {
   get;
   private set;
  }

   public void LoadData()
  {
   this.Items.Add(new ItemViewModel() { LineOne = "runtime one", IsSelected = true, LineTwo = "Maecenas praesent accumsan bibendum" });
   this.Items.Add(new ItemViewModel() { LineOne = "runtime two", LineTwo = "Dictumst eleifend facilisi faucibus" });
   this.Items.Add(new ItemViewModel() { LineOne = "runtime three", IsSelected = true, LineTwo = "Habitant inceptos interdum lobortis" });
   this.Items.Add(new ItemViewModel() { LineOne = "runtime four", LineTwo = "Nascetur pharetra placerat pulvinar" });
   this.Items.Add(new ItemViewModel() { LineOne = "runtime five", IsSelected = true, LineTwo = "Maecenas praesent accumsan bibendum" });
   this.Items.Add(new ItemViewModel() { LineOne = "runtime six", LineTwo = "Dictumst eleifend facilisi faucibus" });
   this.IsDataLoaded = true;
  }

  public event PropertyChangedEventHandler PropertyChanged;
  public void NotifyPropertyChanged(String propertyName)
  {
   if (null != PropertyChanged)
   {
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }
  }
 }

En el archivo MainPage.xaml, el primer Pivot tiene suItemSource basado directamente en elObservableCollection<T> lista. Dentro del segundo Pivot, el ListBox en pantalla tiene suItemSource Propiedad establecida en unCollectionViewSource, cuya fuente subyacente se basa en elObservableCollection<T> poblado enLoadData() encima.

<phone:PhoneApplicationPage.Resources>
    <CollectionViewSource x:Key="IsSelectedCollectionView" Filter="CollectionViewSource_SelectedListFilter">
    </CollectionViewSource>
</phone:PhoneApplicationPage.Resources>

<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
    <!--Pivot Control-->
    <controls:Pivot Title="MY APPLICATION">
        <!--Pivot item one-->
        <controls:PivotItem Header="first">
            <!--Double line list with text wrapping-->
            <ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                      <StackPanel Margin="0,0,0,17" Width="432">
                          <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                          <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
                      </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </controls:PivotItem>

        <!--Pivot item two-->
        <controls:PivotItem Header="second"> 
            <!--Triple line list no text wrapping-->
            <ListBox x:Name="SecondListBox" Margin="0,0,-12,0" ItemsSource="{Binding  Source={StaticResource IsSelectedCollectionView}}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17">
                                <TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                                <TextBlock Text="{Binding LineThree}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
        </controls:PivotItem>
    </controls:Pivot>
</Grid>

<!--Sample code showing usage of ApplicationBar-->
<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
        <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1" Click="ApplicationBarIconButton_Click"/>
        <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
        <shell:ApplicationBar.MenuItems>
            <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
            <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
        </shell:ApplicationBar.MenuItems>
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

Tenga en cuenta que en MainPage.xaml.cs, elFilter atributo en elCollectionViewSource en elResources la sección anterior tiene asignado un controlador de filtro, que examina los elementos que tienenIsSelected establecido en verdadero:

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
        DataContext = App.ViewModel;
        this.Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        if (!App.ViewModel.IsDataLoaded)
        {
            App.ViewModel.LoadData();
            CollectionViewSource isSelectedListView = this.Resources["IsSelectedCollectionView"] as CollectionViewSource;
            if (isSelectedListView != null)
            {
                isSelectedListView .Source = App.ViewModel.Items;
            }
        }
    }

    private void CollectionViewSource_SelectedListFilter(object sender, System.Windows.Data.FilterEventArgs e)
    {
        e.Accepted = ((ItemViewModel)e.Item).IsSelected;
    }

    private void ApplicationBarIconButton_Click(object sender, EventArgs e)
    {
        ItemViewModel item = App.ViewModel.Items[App.ViewModel.Items.Count - 1];
        item.IsSelected = !item.IsSelected;
    }
}

También tenga en cuenta que inmediatamente después de cargar los datos, obtengo elCollectionViewSource y establece su fuente de datos comoObservableCollection<T> lista, para que haya datos base sobre los que pueda tener lugar el filtrado.

Cuando se carga la aplicación, los datos se muestran como se esperaba, con esos elementos en elObservableCollection<T> cual tieneIsSelected cierto, se muestra en el segundo Pivot:

Notarás que he descomentado los iconos de la barra de aplicaciones, el primero de los cuales alterna elIsSelected propiedad del último elemento en elObservableCollection<T> cuando se hace clic (ver la última función en MainPage.xaml.cs).

Aquí está el quid de mi pregunta - Cuando hago clic en el icono de la barra correspondiente, puedo ver cuándo el último elemento de la lista tiene suIsSelected propiedad establecida en true, sin embargo, el segundo Pivot no muestra este elemento modificado. Puedo ver que elNotifyPropertyChanged() se está disparando el controlador sobre el elemento, sin embargo, la colección no está detectando este hecho, y por lo tanto, el cuadro de lista en Pivot 2 no cambia para reflejar el hecho de que debería haber un nuevo elemento agregado a la colección.

Estoy bastante seguro de que me estoy perdiendo algo bastante fundamental / básico aquí, pero si eso falla, ¿alguien sabe la mejor manera de obtener la colección y sus elementos subyacentes para jugar felices juntos?

Supongo que este problema también se aplica a la clasificación y al filtrado ((en el sentido de que si unCollectionViewSource se basa en la clasificación, luego, cuando cambia una propiedad de un elemento que se usa en la clasificación, el orden de clasificación de la colección también debería reflejar esto))

Respuestas a la pregunta(2)

Su respuesta a la pregunta