Sorting a listbox when SortDescription won't cut it [modified]
-
Hello, I have a listbox bound to a DataView showing rows from a table (ReportingUser) in a typed DataSet. The table has a DataRelation to another table (Reporting). Hence the (typed) row objects have a ReportingRow property that refers to the corresponding row in the related table. Each row is displayed using text from the Reporting related table:
I would like to sort the listbox by ReportingName as well. I have been struggling with this for two days. None of the solutions I found via Google work. They include: 1/ Use a SortDescription. But that mechanism doesn't seem capable of following property chains, unlike DisplayMemberPath. 2/ Grab the defaultView and set the Sort property. But the mechanism is string-based and gives access to the row's columns only. 3/ Cast the defaultView to a ListCollectionView and set a custom IComparer. But the cast fails. I also had an idea: use a partial class definition to add a new property, to be used in SortDescriptions:
partial class ReportingUserRow { public string ReportingName { get { return ReportingRow.ReportingName; } } }
Alas when I try to use it in either DisplayMemberPath or SortDescription, I get an exception that the property doesn't exist. UPDATE: I can use my property in DisplayMemberPath like this:
DisplayMemberPath="Row.ReportingName"
Which opens the question: using the debugger I see that my listbox contains a DataView that contains DataRowView objects which in turn contain a reference to a row object (of type ReportingUserRow). How does DataRowView find out what properties are available on a ReportingUserRow ? Why does it find the columns and not my extra property ?modified on Wednesday, April 13, 2011 6:03 AM
-
Hello, I have a listbox bound to a DataView showing rows from a table (ReportingUser) in a typed DataSet. The table has a DataRelation to another table (Reporting). Hence the (typed) row objects have a ReportingRow property that refers to the corresponding row in the related table. Each row is displayed using text from the Reporting related table:
I would like to sort the listbox by ReportingName as well. I have been struggling with this for two days. None of the solutions I found via Google work. They include: 1/ Use a SortDescription. But that mechanism doesn't seem capable of following property chains, unlike DisplayMemberPath. 2/ Grab the defaultView and set the Sort property. But the mechanism is string-based and gives access to the row's columns only. 3/ Cast the defaultView to a ListCollectionView and set a custom IComparer. But the cast fails. I also had an idea: use a partial class definition to add a new property, to be used in SortDescriptions:
partial class ReportingUserRow { public string ReportingName { get { return ReportingRow.ReportingName; } } }
Alas when I try to use it in either DisplayMemberPath or SortDescription, I get an exception that the property doesn't exist. UPDATE: I can use my property in DisplayMemberPath like this:
DisplayMemberPath="Row.ReportingName"
Which opens the question: using the debugger I see that my listbox contains a DataView that contains DataRowView objects which in turn contain a reference to a row object (of type ReportingUserRow). How does DataRowView find out what properties are available on a ReportingUserRow ? Why does it find the columns and not my extra property ?modified on Wednesday, April 13, 2011 6:03 AM
- I'm pretty sure that doesn't work... the implementation pretty much reflects on the current type and gets a property named "x". "Row.ReportingRow.ReportingName" is not the name of a valid property. 3) Should work just fine. I do it all over the place. How are you getting the default view? Show code. If the cast is failing, what IS GetDefaultView() returning?
-
- I'm pretty sure that doesn't work... the implementation pretty much reflects on the current type and gets a property named "x". "Row.ReportingRow.ReportingName" is not the name of a valid property. 3) Should work just fine. I do it all over the place. How are you getting the default view? Show code. If the cast is failing, what IS GetDefaultView() returning?
Relevant lines from Window_Loaded:
dataset = new DNLMHDataSet(); // a designer-generated typed dataset reportingUserAdapter = new ReportingUserTableAdapter(); reportingUserAdapter.Fill(dataset.ReportingUser); listBoxSelectedReporting.DataContext = dataset;
I run my program and make it break. In the Immediate window:
?System.Windows.Data.CollectionViewSource.GetDefaultView(listBoxSelectedReporting.DataContext)
{System.Windows.Data.BindingListCollectionView}
[System.Windows.Data.BindingListCollectionView]: {System.Windows.Data.BindingListCollectionView}
CanFilter: false
CanGroup: true
CanSort: false
Culture: null
CurrentItem: {System.Data.DataViewManagerListItemTypeDescriptor}
CurrentPosition: 0
Filter: null
GroupDescriptions: {System.Collections.ObjectModel.ObservableCollection}
Groups: null
IsCurrentAfterLast: false
IsCurrentBeforeFirst: false
IsEmpty: false
SortDescriptions: {System.ComponentModel.SortDescriptionCollection.EmptySortDescriptionCollection}
SourceCollection: {System.Data.DataViewManager}Let's try the cast:
?(ListCollectionView)System.Windows.Data.CollectionViewSource.GetDefaultView(listBoxSelectedReporting.DataContext)
Cannot cast 'System.Windows.Data.CollectionViewSource.GetDefaultView(listBoxSelectedReporting.DataContext)' (which has an actual type of 'System.Windows.Data.BindingListCollectionView') to 'System.Windows.Data.ListCollectionView'When I look at the MS headers I see that both ListCollectionView and BindingListCollectionView derive from CollectionView. They're siblings, hence no cast...
-
Hello, I have a listbox bound to a DataView showing rows from a table (ReportingUser) in a typed DataSet. The table has a DataRelation to another table (Reporting). Hence the (typed) row objects have a ReportingRow property that refers to the corresponding row in the related table. Each row is displayed using text from the Reporting related table:
I would like to sort the listbox by ReportingName as well. I have been struggling with this for two days. None of the solutions I found via Google work. They include: 1/ Use a SortDescription. But that mechanism doesn't seem capable of following property chains, unlike DisplayMemberPath. 2/ Grab the defaultView and set the Sort property. But the mechanism is string-based and gives access to the row's columns only. 3/ Cast the defaultView to a ListCollectionView and set a custom IComparer. But the cast fails. I also had an idea: use a partial class definition to add a new property, to be used in SortDescriptions:
partial class ReportingUserRow { public string ReportingName { get { return ReportingRow.ReportingName; } } }
Alas when I try to use it in either DisplayMemberPath or SortDescription, I get an exception that the property doesn't exist. UPDATE: I can use my property in DisplayMemberPath like this:
DisplayMemberPath="Row.ReportingName"
Which opens the question: using the debugger I see that my listbox contains a DataView that contains DataRowView objects which in turn contain a reference to a row object (of type ReportingUserRow). How does DataRowView find out what properties are available on a ReportingUserRow ? Why does it find the columns and not my extra property ?modified on Wednesday, April 13, 2011 6:03 AM
I tried yet another approach: sort the rows at the source, using this code:
dataset.ReportingUser.OrderBy( row => { System.Diagnostics.Trace.WriteLine("\*\*\* called \*\*\*"); return row.ReportingRow.ReportingName; });
I tried putting it before and after the call to reportingUserAdapter.Fill(dataset.ReportingUser) but it is never called. Feeling despaired... :sigh:
-
Relevant lines from Window_Loaded:
dataset = new DNLMHDataSet(); // a designer-generated typed dataset reportingUserAdapter = new ReportingUserTableAdapter(); reportingUserAdapter.Fill(dataset.ReportingUser); listBoxSelectedReporting.DataContext = dataset;
I run my program and make it break. In the Immediate window:
?System.Windows.Data.CollectionViewSource.GetDefaultView(listBoxSelectedReporting.DataContext)
{System.Windows.Data.BindingListCollectionView}
[System.Windows.Data.BindingListCollectionView]: {System.Windows.Data.BindingListCollectionView}
CanFilter: false
CanGroup: true
CanSort: false
Culture: null
CurrentItem: {System.Data.DataViewManagerListItemTypeDescriptor}
CurrentPosition: 0
Filter: null
GroupDescriptions: {System.Collections.ObjectModel.ObservableCollection}
Groups: null
IsCurrentAfterLast: false
IsCurrentBeforeFirst: false
IsEmpty: false
SortDescriptions: {System.ComponentModel.SortDescriptionCollection.EmptySortDescriptionCollection}
SourceCollection: {System.Data.DataViewManager}Let's try the cast:
?(ListCollectionView)System.Windows.Data.CollectionViewSource.GetDefaultView(listBoxSelectedReporting.DataContext)
Cannot cast 'System.Windows.Data.CollectionViewSource.GetDefaultView(listBoxSelectedReporting.DataContext)' (which has an actual type of 'System.Windows.Data.BindingListCollectionView') to 'System.Windows.Data.ListCollectionView'When I look at the MS headers I see that both ListCollectionView and BindingListCollectionView derive from CollectionView. They're siblings, hence no cast...
So, um... didn't you just answer your own question??? :doh: :doh: :doh: In your particular case, you have a BindingListCollectionView, not a ListCollectionView. Simply cast the GetDefaultView() return into a BindingListCollectionView object and use that. GetDefaultView() actually returns an ICollectionView object. So, it is possible to get ANYTHING implementing the ICollectionView interface (like BindingListCollectionView in this case). BindingListCollectionView implements everything you need. Like Comparer for example ;)
-
So, um... didn't you just answer your own question??? :doh: :doh: :doh: In your particular case, you have a BindingListCollectionView, not a ListCollectionView. Simply cast the GetDefaultView() return into a BindingListCollectionView object and use that. GetDefaultView() actually returns an ICollectionView object. So, it is possible to get ANYTHING implementing the ICollectionView interface (like BindingListCollectionView in this case). BindingListCollectionView implements everything you need. Like Comparer for example ;)
SledgeHammer01 wrote:
BindingListCollectionView implements everything you need. Like Comparer for example
...but the Comparer property is read-only :sigh: And it has the SortDescriptions but it's useless for my purpose... X|
-
SledgeHammer01 wrote:
BindingListCollectionView implements everything you need. Like Comparer for example
...but the Comparer property is read-only :sigh: And it has the SortDescriptions but it's useless for my purpose... X|
Oh right... sorry, yeah, I forgot some of the view classes randomly make useful properties read-only :). Ok, well, then there are a few ways you can proceed. 1) You are getting BindingListCollectionView because you are binding to a source that implements IBindingList. So you can repackage the data in something different like an ObservableCollection, etc. 2) You can try wrap your source in a CollectionViewSource. CollectionViewSource requires the source to implement IEnumerable which should work for you. #2 is probably easier, but if that doesn't work, you'll have to do #1 :). It kind of makes sense that what you are trying to do is not really supported directly.