amnesia
amnesia

Reputation: 1988

Need multiple views of same BindingList with sorting and filtering - WPF

I know this is very similar to other questions that have been asked, and I have looked at them but in one way or another the solutions don't work for this specific scenario.

I have a collection of objects in a BindingList:

private BindingList<PathologyModel> _patientPathologies;
public BindingList<PathologyModel> PatientPathologies { get { return _patientPathologies; } }

This collection needs to be bound to different XamDataGrid controls (Infragistics' version of a DataGrid). I need to use BindingList because I need to know when a user edits a particular item in the collection, which other types of collections don't seem to support.

I need the collection to be sorted, so for now I just have to do this every time an item is added/removed from the list:

    private void Pathologies_ListChanged(object sender, ListChangedEventArgs e)
    {
        if (e.ListChangedType == ListChangedType.ItemAdded || e.ListChangedType == ListChangedType.ItemDeleted)
        {
            _pathologies = new BindingList<PathologyModel>(_pathologies.OrderBy(x => x.Tooth.ToToothNumber()).ThenBy(x => x.DiagnosisDate).ToList());
        }
    }

It would be nice if this could be done automatically without the extra copying. But that's not my biggest problem right now.

I need the different XamDataGrids to have different filtered views of this same collection, which currently I am achieving with this:

    public ICollectionView AllPathologies { get { return CollectionViewSource.GetDefaultView(PatientPathologies); } }

    public ICollectionView TodaysPathologies { get { return CollectionViewSource.GetDefaultView(PatientPathologies.Where(x => x.DiagnosisDate.Date == DateTime.Today.Date)); } }

This almost works... I say almost because the views are showing the correct data, but the final requirement is that I also need to track the CurrentItemChanged event, so that I can enable/disable certain operations depending on which record the user is on. This works fine with the AllPathologies view, but does not ever get raised with TodaysPathologies, I'm guessing because it gets a different copy of the collection source every time you access the property? Strangely enough, the ListItem_Changed event still works properly against the original collection source.

I have tried making private CollectionViewSource objects to back the ICollectionView properties as I've seen in other articles, such as this:

private CollectionViewSource _todaysPathologies;
public ICollectionView TodaysPathologies { get { return _todaysPathologies.View; } }

...
_todaysPathologies = new CollectionViewSource{Source= _patientPathologies}.View;

But since the source is a BindingList I can't apply a filter predicate:

TodaysPathologies.CanFilter <--- false

So now I'm stuck. I place my fate in your hands, dear StackOverflowers.

Upvotes: 1

Views: 1283

Answers (1)

Algamest
Algamest

Reputation: 1529

"I need to know when a user edits a particular item in the collection, which other types of collections don't seem to support."

This isn't entirely true. A Collection used within a Class that inherits from INotifyPropertyChanged would solve this.

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx

I would recommend making an inner class in your window page. With a Property for each value and the editable properties would call the NotifyPropertyChanged event. You would then have a collection of these inner class objects. The inner class would represent a row in the grid.

Another way I've solved this before is to specify text column where users enter information:

In XAML:

<DataGridTextColumn //... Binding="{Binding Path=Value, Mode=TwoWay}">
    <DataGridTextColumn.EditingElementStyle>
         <Style TargetType="TextBox"/>
    </DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>

In code:

private string value;
public string Value
        {
            get
            { return value; }
            set
            {
                this.value = value;
                NotifyPropertyChanged("Value");
            }
        }

The inner class contains this Value Property as well as a reference to an object of the class I used to have a collection of.

Now I have a collection of objects of this inner class, which stores both. I use this to display info of the class and have an extra column to add a value. I then make a new object out of the old class information + this value.

If you've found this helpful and would like me to go into more detail, let me know. I would be more than happy to. That or someone will post :P

Upvotes: 0

Related Questions