I am working on a scheduling program in which items have a scheduled date, but the user can elect to override this for a date they choose. To implement this, my Item object uses two properties: ScheduledDate (DateTime) and ActualDate (DateTime?). Therefore, if the ActualDate property is null, the user has not overridden the schedule for this item.
In one of my views, I need to display these items in a ListBox
, sorted by the actual date. The trouble I am having is how to implement a CollectionViewSource
with these two properties.
I know it's not correct, but I need something like this:
<CollectionViewSource x:Key="TransactionsViewSource"
Source="{Binding ElementName=ThisControl,
Path=Items}">
<CollectionViewSource.SortDescriptions>
<cm:SortDescription PropertyName="ActualDate ?? ScheduledDate"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
(ThisControl is the name of the UserControl
that hosts the ListBox
.)
If I add a second SortDescriptor (like below), I get a list sorted by ActualDate, then by Scheduled Date, which groups all of the overridden items together. This is not the desired behavior.
<CollectionViewSource x:Key="TransactionsViewSource"
Source="{Binding ElementName=ThisControl,
Path=Items}">
<CollectionViewSource.SortDescriptions>
<cm:SortDescription PropertyName="ActualDate"/>
<cm:SortDescription PropertyName="ScheduledDate"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Thanks.
I ended up creating a new method in my UserControl
class that used LINQ to keep the underlying ObservableCollection
sorted. I then called this method whenever an item was edited (actual date overridden) or if a new item was added. Finally, I removed the CollectionViewSource
from the XAML and bound the ListBox
to the Items
property (which I already had as a dependency property). The result looks like this:
XAML:
<ListBox ItemsSource="{Binding ElementName=ThisControl,
Path=Items}"/>
C#:
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items",
typeof(ObservableCollection<MyItem>),
typeof(MyControl),
new UIPropertyMetadata(null));
public ObservableCollection<MyItem> Items
{
get { return (ObservableCollection<MyItem>) GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
private void SortItems()
{
Items = new ObservableCollection<MyItem>(Items.OrderBy(i => i.ActualDate ??
i.ScheduledDate));
}
Then I just use SortItems()
anywhere that the items in the collection or the collection itself changes.
It works perfectly, and I didn't have to create and manage a new property. I can live with the little bit of overhead that LINQ creates.