2

I'm trying to pivot my data by creating a 'view' of an Observable Collection based on certain criteria. Here's a simple example.

I have two ListViews. One is bound directly to a collection of Dates, the other is bound to a DatesAfterToday collection derived from the first collection using Where(x => x.Date > DateTime.Today)

When I add a new item to my Dates collection, only the first ListView changes. The ListView bound to DatesAfterToday does not update at all. I've tried adding a PropertyChangedEventHandler to the viewmodel and firing it when the dates collection is updated, but it's not working.

MainPage.xaml

<StackPanel>
    <ListView x:Name="ListOne" ItemsSource="{Binding Dates}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Date}"></TextBlock>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <ListView x:Name="ListTwo" ItemsSource="{Binding DatesAfterToday}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Date}"></TextBlock>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <Button Click="Button_Click_1">Press Me to Add a Date</Button>
</StackPanel>

View Model

public class Model : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Model()
    {
        _Dates = new ObservableCollection<DateTime>();
    }
    private ObservableCollection<DateTime> _Dates;
    public ObservableCollection<DateTime> Dates
    {
        get
        {
            return _Dates;
        }
        set
        {
            _Dates = value;
            if (PropertyChanged != null){
                PropertyChanged(this, new PropertyChangedEventArgs("_Dates"));
                PropertyChanged(this, new PropertyChangedEventArgs("Dates"));
                PropertyChanged(this, new PropertyChangedEventArgs("DatesAfterToday"));
            }
        }
    }
    public ObservableCollection<DateTime> DatesAfterToday 
    { 
        get {
            return new ObservableCollection<DateTime>(
                _Dates.Where(t => t.Date > DateTime.Today).ToList()
            );
        }
    }
}

MainPage.xaml.cs

public sealed partial class ListTest : Page
{
    public Model model;
    public ListTest()
    {
        this.InitializeComponent();
        model = new Model();
        model.Dates.Add(new DateTime(2012, 11, 12, 0, 0, 0));
        model.Dates.Add(new DateTime(2012, 11, 15, 0, 0, 0));
        model.Dates.Add(new DateTime(2012, 11, 17, 0, 0, 0));
        model.Dates.Add(new DateTime(2012, 11, 20, 0, 0, 0));
        model.Dates.Add(new DateTime(2012, 11, 22, 0, 0, 0));
        this.DataContext = model;
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        model.Dates.Add(new DateTime(2012, 11, 24, 0, 0, 0));
    }
}

UPDATE: Edited the question to make it a bit easier to read.

4

1 回答 1

3

Modify your Model constructor as follows:

public Model()
{
    _Dates = new ObservableCollection<DateTime>();

    _Dates.CollectionChanged += (s, e) =>
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs("DatesAfterToday"));
            }
        };
}

The thing is that when you add/remove items from the _Dates collection, the setter won't be called, and that's why the property change event for DatesAfterToday is never raised.

For collections, WPF also registers for the CollectionChanged event, which is exposed by the INotifyCollectionChanged interface implemented by ObservableCollection. So what you can do is raise the notification for DatesAfterToday whenever the _Dates collection is modified.

于 2012-11-22T13:22:41.133 回答