Wie kann die Filter- und / oder Sortierreihenfolge in CollectionViewSource automatisch aktualisiert werden, wenn sich die Eigenschaft eines einzelnen Elements ändert?

Ok, daher bezieht sich diese Frage auf Windows Phone 7 / Silverlight (aktualisierte WP7-Tools, September 2010) und filtert speziell ein zugrunde liegendesObservableCollection<T>.

Während ich mich mit der Pivot-Steueranwendung der WP7-Vorlage beschäftige, bin ich auf ein Problem gestoßen, bei dem ein zugrunde liegendes Element in einem @ geändert wurdObservableCollection<T>, führt nicht zur Aktualisierung der angezeigten ListBox. Grundsätzlich verfügt die Beispiel-App über zwei Pivots, von denen der erste direkt an das zugrunde liegende @ gebunden isObservableCollection<T> und die zweite an ein @ gebundCollectionViewSource (d. h. Darstellung einer gefilterten Ansicht auf dem zugrunde liegendenObservableCollection<T>).

Die zugrunde liegenden Elemente, die zum @ hinzugefügt werdObservableCollection<T> implementINotifyPropertyChanged, wie so:

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

Dann wird in der Hauptklasse eine Datensammlung zusammengestellt (aus Gründen der Kürze reduzierte Liste). Beachten Sie außerdem, dass drei der LoadData () -Einträge im Gegensatz zu anderen Elementen IsSelected == true aufweisen:

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

In der MainPage.xaml-Datei hat der erste Pivot seinItemSource basiert direkt auf demObservableCollection<T> aufführen. Innerhalb des zweiten Pivots hat die auf dem Bildschirm angezeigte ListBox dasItemSource Eigenschaft auf ein @ gesetCollectionViewSource, dessen zugrunde liegende Quelle auf dem @ basieObservableCollection<T> bevölkert inLoadData() über

<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>

Beachten Sie, dass in der Datei MainPage.xaml.cs dasFilter Attribut auf demCollectionViewSource in demResourcesem obigen Abschnitt @ ist ein Filterhandler zugewiesen, der die Elemente mit @ durchsuchIsSelected auf true setzen:

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

Beachten Sie auch, dass ich unmittelbar nach dem Laden der Daten das @ erhaltCollectionViewSource und legen seine Datenquelle als @ feObservableCollection<T> Liste, damit es Basisdaten gibt, nach denen gefiltert werden kann.

Wenn die Anwendung geladen wird, werden die Daten wie erwartet mit den Elementen im @ -Zeichen angezeigObservableCollection<T> welche habenIsSelected true, wird im zweiten Pivot angezeigt:

Sie werden bemerken, dass ich die Anwendungsleistensymbole auskommentiert habe, von denen das erste das @ umschalteIsSelected -Eigenschaft des letzten Elements imObservableCollection<T> wenn angeklickt (siehe die letzte Funktion in MainPage.xaml.cs).

Hier ist der Kern meiner Frage - Wenn ich auf das entsprechende Balkensymbol klicke, kann ich sehen, wann das letzte Element in der Liste sein @ haIsSelected -Eigenschaft auf true gesetzt, der zweite Pivot zeigt dieses geänderte Element jedoch nicht an. Ich kann sehen, dass dasNotifyPropertyChanged()er @ -Handler wird für das Element ausgelöst, die Auflistung nimmt diesen Fakt jedoch nicht auf, und daher ändert sich das Listenfeld in Pivot 2 nicht, um der Tatsache Rechnung zu tragen, dass der Auflistung ein neues Element hinzugefügt werden sollte.

Ich bin mir ziemlich sicher, dass ich hier etwas Grundlegendes / Grundlegendes vermisse, aber weiß jemand, wie man die Sammlung und die zugrunde liegenden Elemente am besten zusammenbringt, um glücklich zusammen zu spielen?

Ich nehme an, dieses Problem gilt auch für das Sortieren und Filtern ((in dem Sinne, dass, wenn einCollectionViewSource basiert auf der Sortierung. Wenn sich dann eine Eigenschaft eines Elements ändert, das für die Sortierung verwendet wird, sollte dies auch in der Sortierreihenfolge der Sammlung berücksichtigt werden.))

Antworten auf die Frage(4)

Ihre Antwort auf die Frage