Is there an approach for programatically applying WPF DataGrid
sorting based on multiple properties?
I have a multi-column DataGrid
which contains a single column which I always want to be in alphabetical order within groupings of values when other columns are sorted.
All custom sort implementations I've seen use a IComparer
, but this only provides the values in the single column it's associated with.
For example, if we have the following two columns of unsorted data:
A
1
D
2
C
2
B
1
If we apply sorting to the second column, the first column becomes arbitrarily sorted within each grouping:
A
1
B
1
D
2
C
2
What I am looking for is for within any groups of identical values in the second column, the first column is alphabetised:
A
1
B
1
C
2
D
2
Is there an alternative to IComparer
which exposes the full model?
Have you looked into SortMemberPath?
<DataGrid.Columns>
<DataGridTextColumn Header="Some Caption" Width="200"
CanUserSort="True"
Binding="{Binding SomeDataField}"
SortMemberPath="OtherNonShowingField"/>
</DataGrid.Columns>
So if you are listing data from a List or from a DataTable via its DataColumn reference, you could always add another field or column that has the combined A + B parts in that field. So even if you don't show the column, it can be used as the basis of a sort.
Since I do not know of another way to utilize the SortMemberPath to do both an ascending AND descending in the same, I wrote a function that you can try to use in your code. I called it NegativeString, thus a reversal of alphabetical order and numbers. Anything else is "as-is".
private static string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static string LowerCase = "abcdefghijklmnoprqstuvwxyz";
private static string Numbers = "0123456789";
public string NegativeString( string incoming )
{
// take incoming string, put into a character array
var inB = incoming.ToCharArray();
var outStr = "";
for( var i= 0; i < inB.Length; i++ )
{
// So, if I Look for "A" in the upper-case string, it is found
// in position 0, so I want the character 0 from the end
// which is the letter Z and vice-versa.
var atPos = UpperCase.IndexOf(inB[i]);
if (atPos > -1)
outStr += UpperCase.Substring(UpperCase.Length - atPos - 1, 1);
else
{
// if not upper case, then look for lower
atPos = LowerCase.IndexOf(inB[i]);
if (atPos > -1)
outStr += LowerCase.Substring(LowerCase.Length - atPos - 1, 1);
else
{
// if not lower, try numbers
atPos = Numbers.IndexOf(inB[i]);
if (atPos > -1)
outStr += Numbers.Substring(Numbers.Length - atPos - 1, 1);
else
// anything else comes along as-is
outStr += inB[i];
}
}
}
return outStr;
}
So, a new property on your class could be something like
public string YourMultiSortProperty
{ get { return NormalField + NegativeString( OtherField ); }}